[C++] Tool um Verursacher von Memory Corruption zu finden

oskopia

Newbie
Registriert
Mai 2005
Beiträge
3
Hallo

Windows 2000, Visual Studio (egal ob VS 6, oder VS 7). Ich schreibe eine Dll, die ich in eine (Fremd)Exe lade. Wenn ich _DEBUG definiere, läuft sie. Wenn nicht (NDEBUG), stürtzt die Fremdexe mitsamt der Dll ab. Die FremdExe hat keine DebugInfo, meine Dll hat schon eine. Die Stelle, wo ich abstürze ist in VS 6 oder in VS 7 verschieden. Der Callstack ist ständig völlig verschieden. Manchmal ist die Fremdexe drin, manchmal nur Microsoft Dlls.
Was passiert, ist, daß "jemand" Speicher freigibt, den meine Dll alloziert hat (new).
Drum ist auch klar, daß es in der _DEBUG Version nicht passiert, weil dort die delete und free Routinen auf Gültigkeit des freizugebenden Speichers checken.

Es könnte ein Fehler in der FremdExe sein, es könnte ein Fehler bei mir sein. Es könnte rein theoretisch auch ein Fehler in einer Microsoft Dll sein. Ich kann die Fremdprogramme nicht kompilieren.

Ich habe alle statischen Klassenvariablen entfernt. Die initialisiere ich jetzt in der Dll Main als Pointer. Ich komme in VS7 wunderbar durch die DllMain (Prozess_attach und alle Thread_attach), wunderbar durch die Initialisierungsroutine, die die fremdexe dann in meiner dll aufruft.
Ein Callstack sieht zum Beispiel so aus:
mfc42.dll!6c290631()
icad.exe!004c4867()
icad.exe!00514b5d()
icad.exe!00514945()
mfc42.dll!6c27da60()
mfc42.dll!6c29199b()
mfc42.dll!6c2932a2()
mfc42.dll!6c279fed()
mfc42.dll!6c290ffd()
mfc42.dll!6c2799d5()
mfc42.dll!6c2788ee()
mfc42.dll!6c278afb()
mfc42.dll!6c2a13a8()
USER32.DLL!77e2a3d0()
USER32.DLL!77e04605()
USER32.DLL!77e05b77()

Die Fehlermeldung ist
Unbehandelte Ausnahme bei 0x6c290631 in icad.exe: 0xC0000005: Zugriffsverletzung-Leseposition 0x00000084.

In VS6 gibt es diesen Stack
ICAD! 005059c2()
MFC42! 6c279e49()
MFC42! 6c2799d5()
MFC42! 6c2788ee()
MFC42! 6c278afb()
MFC42! 6c2a13a8()
USER32! 77e2a3d0()
USER32! 77e04605()
USER32! 77e05b77()

oder das nächste Mal diesen
ICAD! 004780be()
ICAD! 0055192d()
OBJPROPTB! 03a87236()
Die Fehlermeldung ist "Zugriffsverletzung"


Man sieht, mit Logik ist da nichts zu machen. Irgend"jemand" gibt Speicher frei, der ihm nicht gehört . Wäre wenigstens ne Möglichkeit.

Und nun suche ich ein Tool, mit dem ich Memory Corruption überprüfen kann, ohne daß ich die zu überprüfenden Exes, Dlls neu kompilieren muß.
Gefunden habe ich:
- Rational Purify (die Evaluaton Version läßt sich bei mir nicht lizensieren, eventuell frage ich doch noch bei IBM Support nach)

- GlowCode - das geht bei dem Absturz gleich mit runter

- Heap Agent - die möchten gerne, daß man _DEBUG definiert (dann ist ja alles in Ordnung) und außerdem muß man die Loadables neu kompilieren. Das ist nicht, was ich suche

- Memory Validator - Der findet alle Dlls, die beim Startup von icad. exe geladen werden, aber ich muß meine dll nachher per Kommando innerhalb des Programmes laden - und ich sehe nie Routinen von meiner Dll in Memory Validator. Außerdem scheint das keine Memory Corruption zu merken, sondern sich einfach auf Leaks zu konzentrieren.

Ich gebe ja zu, ich habe meine Lernzeit für diese Tools ein bißchen knapp bemeßen - aber ich sitze an diesem blöden Bug nun schon drei Tage und hoffe jetzt, daß mir vielleicht hier im Forum jemand weiterhelfen kann.

Ich danke Euch für Eure Zeit

Monika
 
Hallo Monika,

von der Art des Fehler her, würde ich mal vermuten das in Deinem Code ein Pufferüberlauf ist. Z.B. ein Strcpy oder memcpy über eine Arraygrenze hinaus. Solche Sachen findest Du mit Purify sofort.

Die Demo lies sich bei mir problemlos installieren.

MfG

Arnd
 
Hi Monika!

Erstmal interessehalber eine Frage - wird deine DLL synchron oder asynchron gerufen?

Dass das ganze im Debug-Modus läuft und anderwärtig nicht, ist schonmal ein guter Anhaltspunkt. Die These mit den Speicherhandlern im Debug-Modus kannst Du aber wieder verwerfen. Die machen im Fehlerfall nämlich nur eines - dein Programm gezielt abstürzen zu lassen (abort()). Vielmehr klingt es für mich danach, als wenn Du dich auf Code innerhalb von Debug-Macros verlässt, z.B. sowas hier:

Code:
int p*;
ASSERT( p = new int[5]);

Diese Macros und ihr gesamter Inhalt fliegen in der Releaseversion raus. D.h. die Zeile mit dem ASSERT wäre nicht existent, inklusive der Speicheranforderung. Code wie das Beispiel sollte man sowieso vermeiden - der Standard definiert, dass new im Fehlerfall eine bad_alloc Exception wirft.

Ich hoffe, das ist schonmal ein Anhaltspunkt für Dich. Purify ist übrigens mit Abstand das beste Tool, das ich kenne.
 
Hallo Monika,

ein Ansatz ist ganz simpel mal alle Stellen mit new, memcpy, memset, strcpy, ... zu suchen und auf Fehler zu überprüfen.

Bei überschreiten von Bereichsgrenzen, Abfrage auf NULL Pointer, ...

MfG

Arnd
 
Danke für Eure Antworten
Heute habe ich eine "Minimalapp" erstellt, die zum Glück auch noch abstürzte, aber nicht, wenn ich Optimierung auf "schnellstmögliche Geschwindigkeit" gestellt habe. Ich hatte ja vorher schon schwer den Verdacht, daß ich nichts damit zu tun habe.

Und, was noch viel besser ist, auf der IBM Seite muß ich am Freitag grade eine fehlerhafte Purify Exe erwischt haben. Heute lag eine andere da, und die geht.
Und erzählt mir, daß meine Fremdexe schon beim Startup Fehler macht. (Overlapping block copy, Invalid Pointer read in CreateMDIWindowA, Array Bounds Write, Insufficient parameter Match).

Leider gelangt die Fremdexe mit Purify in eine Endlosschleife und ich kann meine Dlls gar nicht mehr laden. Aber mit diesem Wissen im Hintergrund kann ich mich mit dem Hersteller der Fremdexe in Verbindung setzen.

Und mein Chef hat gar nix dagegen, Purify zu kaufen. Schon nach 20 Minuten finde ich es wirklich gut. Die Woche, wo ich nun gesucht habe, war auch teuerer als das Programm.

Nein, keine ASSERTs, verwende ich nie. Ich hatte ja gar nix mehr drin, das einzige, was vielleicht noch ungut ist, ist, daß ich eine WinApp mitführe obwohl ich in einer Fremdexe laufe.

Jetzt wendet sich alles zum Besseren. Nochmal Vielen Dank für Euere Antworten.

Viele Grüße
Monika
 
Äh, 7H3 N4C3R
was ist synchrones oder asynchrones Aufrufen einer dll?

Monika
 
Naja, Deine DLL wird angeladen und dann Funktionen aus ihr benutzt. Und diese können eben synchron oder asynchron aufgerufen werden (reentrant oder nicht). Also, wird deine Funktion immer nur nacheinander von einem Thread aufgerufen, oder auch von verschiedenen Threads zur gleichen Zeit betreten?
 
Hallo Monika,

also meine Erfahrungen mit Compiler Optimierungen sind bescheiden bis sehr schlecht.

Wenn man zuviel optimiert bekommt man sehr schnell Programme die schnell abstürzen, da der Compiler zuviel optimiert hat.

Daher stell mal in der Release Version alle Optimierungen ab und stell fest ob es dann noch Probleme gibt.

Das mit der Reentrance Fähigkeit der DLL sollte aber auch bei einer DebugVersion zu Problemen führen.

MfG

Arnd
 
Zurück
Oben