2 Stimmen

Seltsame Speicherbeschädigung

Dieser Fehler tritt nur auf, wenn ich mit dem WinDDK nmake Compiler in 'free' (release), der Optimierungen durchführt, baue. Ich kann nicht reproduzieren dies in der "überprüft" Build oder Kompilieren mit VS.

Hier ist ein Pseudocode, der zeigt, was in meinem Code passiert:

main()
{
   //variable init and other code
    fprintf(log, "pre nullValue: %lu\n", NULL);  //printf added for debugging
   otherFunc();
   funcWithError(str1, str2, NULL);
    fprintf(log, "post nullValue: %lu\n", NULL); 
    fprintf(log, "post2 nullValue: %lu, %lu, %lu\n", NULL, 0, NULL);
}

BOOL otherFunc()
{
   //variable init and other code
   callToDll();
    //...doing stuff
   libusb_usb_open(var1);    //If I remove this line there is no problem!!
    //...doing more stuff
}

BOOL funcWithError(char* s1, char* s2, FUNC_PTR fp)
{
    fprintf(log, "inFunc nullValue: %lu, %lu\n", NULL, fp);
   if(fp != NULL)
      return FALSE;        //This line is being executed erroneously!!
}

Ausgabe im Protokoll:
pre nullValue: 0
inFunc nullValue: 0, 251208
post nullWert: 251208
post2 nullValue: 251208, 251208, 251208
Hinweis: Die wiederkehrende Nummer (251208) ist bei jeder Ausführung des Programms eine andere Nummer.

Allein die Änderung dieser einen Zeile behebt/verursacht das Problem. Es ist die libusb usb_open anrufen.

  1. Letztlich geht es mir darum, herauszufinden, wie das Problem behoben werden kann (ich kann diesen Anruf nicht vermeiden).
  2. Aber nur auf einem Stack / Speicher-Management-Ebene, wie ist es überhaupt möglich, NULL nicht Null haben und haben einen literalen Wert '0' als nicht Null drucken?

Lassen Sie mich wissen, welche weiteren Informationen hilfreich sein könnten...

3voto

Hans Passant Punkte 894572

Das ist kein völliger Reinfall. Aber es ist sehr wahrscheinlich, dass der Stack im Ungleichgewicht ist. Prüfen Sie im Debugger (ja, Sie können den Release-Build debuggen) den Wert des ESP-Registers vor und nach dem Aufruf. Er sollte derselbe sein. Das ist nicht der Fall, wenn die Aufrufkonvention für die Funktion falsch ist. Wie __stdcall vs __cdecl.

Das kann sich gut verstecken, wenn man Programme mit nmake.exe baut, man vergisst leicht, die Option /RTCs im Debug-Build zu aktivieren, so dass Stack-Checking-Code ausgegeben wird. Und das ESP-Register neigt dazu, sich selbst bei einer Funktionsrückkehr wiederherzustellen. Bis Sie die Release-Version bauen, in der Funktionen inlined werden und die Verwendung von EBP optimiert wird, so dass ESP sich nicht mehr selbst wiederherstellt.

0voto

Sogger Punkte 15426

Update: Ich habe windbg endlich dazu gebracht, in die DLL einzudringen und einige Dinge zu untersuchen. Es war, wie ich ursprünglich vermutete und Hans feststellte, eine Beschädigung des Stacks, die durch eine unpassende Aufrufkonvention verursacht wurde.

Was es nur im Release-Build sichtbar machte, war, dass der Compiler die 0/Null-Werte so optimierte, dass sie den Wert des ebx-Registers benutzten, anstatt 0 zu übergeben. In OtherFunc() benutzten die Optimierungen ebx, um mehrere andere Werte zu speichern, dann beschädigte der Aufruf von Usb_Open() den Stack, und als OtherFunc() versuchte, den Stack zu öffnen, um den ursprünglichen ebx-Wert wiederherzustellen, stellte es Müll statt '0' wieder her. Zurück in main() verwendete also jeder optimierte Verweis auf NULL diesen Garbage-Wert.

Hinweis: Der Grund, warum die anderen DLL-Aufrufe den Stack nicht beschädigt haben, war, dass sie ohne Parameter waren.

Zusammenfassend also die Antworten:

  1. Rufen Sie die libusb unter Verwendung der richtigen Konvention auf (libusb verwendet die Aufrufkonvention __cdecl, NMAKE verwendet standardmäßig __stdcall)
  2. Auch wenn NULL und '0' im Quellcode hart kodiert sind, kann der Compiler optimieren, um ein Register zu verwenden, anstatt einen Wert zu übergeben, und Register sind anfällig für Beschädigungen durch schlechten Code.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X