[SOLVED] [C+Windows 7] Zugriffsverletzung beim Versuch, etwas auf stdout auszugeben



  • Eine Bibliothek von mir stellt Funktionen zur Verfügung, denen man einen Pointer auf ein struct FILE* übergibt (zusammen mit anderen Parametern, die hier nichts zur Sache tun) und die dann intern über fprintf Daten in den angegebenen Stream schreiben. Beispiel:

    void edx_print(FILE* stream,uint32_t edx)
    {
            fprintf(stream,"Flag value: %u\n",edx);
            return;
    }
    

    Einfache Sache halt. Und im Hauptprogramm haben wir dann:

    edx_print(stdout,1);
    

    Ganz einfache Sache, und wenn ich das Ganze unter Linux laufen lasse, funktioniert das auch blendend.

    Anders sieht das unter WIndows 7 (32 Bit Version mit VS2010) aus. Wenn ich hier versuche, das Programm aufzurufen, erhalte ich einen Laufzeitfehler beim Aufruf von EnterCriticalSection in _lock_file in der _file.c - hervorgerufen durch den fprintf -Call in edx_print .

    Nach einer guten Packung Debugging habe ich folgendes herausgefunden:

    1. Wenn ich in der Bibliotheksfunktion statt des Parameters stream direkt stdout verwende, schmiert das Programm nicht ab.
    2. Wenn ich stdout in einem Zeiger auf dem Stack speichere, zeigt mir der Debugger an, dass stream und stdou den gleichen Wert haben. Dennoch funktioniert stdout , während stream nicht funktioniert.
    3. Wenn ich versuche, das Problem im gleichen Modul nachzuvollziehen:

    #include <stdio.h>
    
    void edx_print(FILE*stream,unsigned int edx)
    {
    	fprintf(stream,"Bla: %lu\n",edx);
    	return;
    }
    
    int main(void)
    {
    	edx_print(stdout,1);
    	return 0;
    }
    

    , dann funktioniert dies aus.

    Ich dachte zuerst, dass ich durch einen vorherigen Funktionsaufruf (welcher Inline-Assembler verwendet, aber die Register werden auf dem Stack gesichert, bevor sie neu beschrieben werden) was kaputtgemacht habe, weswegen ich diese Aufrufe auskommentiert habe. Das hat aber nichts an der Zugriffsverletzung geändert - auch, wenn der Call der einzige im kompletten Programm ist.

    Andere Funktionen aus der Bibliothek funktionieren übrigens ohne Probleme - egal, ob sie jetzt nur die Zeit auf stdout ausgeben (auch hier wieder über einen stream -Zeiger) oder nur einfaches Bitshifting machen. Wobei die Angabe, dass es sich um stdout handelt, jetzt immer von innerhalb der Lib kommt, und nicht von außerhalb ...

    Ich weiß jetzt ehrlich gesagt nicht, wo ich noch suchen soll, und habe gehofft, dass jemand hier noch einen Denkanstoß hat, wie man das eigentliche Problem weiter eingrenzen kann. Weiß jemand, ob es vielleicht unter Windows gar nicht erlaubt ist, solche File-Handles an andere Module weiterzureichen?

    Vielen Dank für etwaige Hilfe im Voraus!



  • Das sieht böse aus. Ich habe es auf meinem Rechner getestet und keinen Fehler gefunden.

    1.) Überprüfe mal ob die fprintf Implementierung etwas pingelig ist und fprintf(stream,"Flag value: %lu\n",edx); will.

    2.) Funktioniert das Ganze wenn man statt stdout ein Dateihandle von fopen() nutzt?

    3.) Überprüfe ob uint32_t stimmt, in dem du die Definition suchst.



  • @dachschaden
    Welche CRT-Version verwendest du in der DLL und welche in der EXE?

    Wenn beide die identische DLL-Runtime verwenden (selber Compiler, beide Debug oder beide Release etc.), dann sollte es gehen.
    In allen anderen Varianten kann ich mir gut vorstellen dass es Probleme gibt.



  • *stirnklatsch*

    Debugmodus vs, Releasemodus ... das ABI wird da wahrscheinlich unterschiedlich sein. Und weil sich das bei Linux auch dann nicht ändert, wenn ich mit Debuginformationen kompiliere ... ja klar. Ugh, Schuss in den Fuß, jetzt funktioniert's hervorragend.

    Danke für die Denkanstöße. Wieder was über Windows gelernt.



  • An der/dem ABI ändert sich nixe.
    Aber du findest in MSVC Headers oft so Sachen wie

    class Foo
    {
    ...
    #ifdef _DEBUG
        int m_stuffThatIOnlyNeedInDebugMode;
    #endif
    };
    

    Und natürlich sind die Runtime DLLs eben einfach unterschiedliche DLLs. Dass die eine dann nix mit den Objekten der anderen anfangen kann, verwundert auch nicht unbedingt.



  • hustbaer schrieb:

    An der/dem ABI ändert sich nixe.

    Öhm, gelernt habe ich, dass, wenn sich das Layout öffentlicher Strukturen ändert, dass das dann eine Änderung der binären Schnittstelle des Programms ist (deswegen auch ABI).

    Und OpenSSL sieht das auch so, als Beispie.
    Und wenn sich dann das Layout von Strukturen innerhalb verschiedener Builds ändert, dann, habe ich zumindest noch gelernt, ist das eine Änderung des ABI.

    Die Wikipedia hat auch was dazu zu sagen

    en.wikipedia.org schrieb:

    ABIs cover details such as [...] the sizes, layout, and alignment of data types

    Falls dem nicht so sein sollte, lasse ich mich gerne belehren und erwarte Gegeninformationen. 🙂



  • Dein Wikipediazitat passt schon.
    Was du aber nicht berücksichtigst ist: es ändert sich durch das #ifdef der Source.
    Es handelt sich also um zwei Verschiedene Klassen, die bloss dummerweise den selben Namen haben.

    Nach meiner Auffassung definiert das ABI die Regeln. Das ABI plus der Source der Standard-Library entscheiden dann wie Klassen aussehen. Ändert sich der Source ändert sich das Layout, aber deswegen ändert sich das ABI (=die Regeln) ja nicht.


Log in to reply