Heap Korruption unter Win32; wie ausfindig zu machen?

stimmen
54

Ich arbeite an einer multithreaded C ++ Anwendung, die den Haufen korrumpiert. Die üblichen Werkzeuge , um diese Korruption zu finden scheinen nicht anwendbar zu sein. Altbauten (18 Monate alt) des Quellcodes zeigen das gleiche Verhalten wie die neuste Version, so dass dies hat sich für eine lange Zeit und war einfach nicht bemerkt; Auf der anderen Seite Quelle Deltas nicht verwendet werden können , um festzustellen , wann der Fehler eingeführt wurde - es gibt eine Menge von Code - Änderungen im Repository.

Die Eingabeaufforderung für behaviuor Absturz wird der Durchsatz in diesem System zu erzeugen, - Socket Übertragung von Daten, die in eine interne Darstellung munged wird. Ich habe eine Reihe von Testdaten, die in regelmäßigen Abständen die App Ausnahme verursachen (verschiedene Orte, verschiedene Ursachen - einschließlich Haufen Alloc Versagen, also: Heapbeschädigung).

Das Verhalten scheint an CPU-Leistung oder Speicherbandbreite im Zusammenhang; je mehr jeder der Maschine hat, desto leichter ist es zum Absturz bringen. einen Hyper-Threading-Kern oder einen Dual-Core-Kern Deaktivierung reduziert die Rate des (aber nicht beseitigt) Korruption. Dies deutet auf ein Timing-Problem im Zusammenhang.

Jetzt ist hier das Problem :
Wenn es unter einem leichten Debug - Umgebung laufen gelassen (sagen wir Visual Studio 98 / AKA MSVC6) die Heapbeschädigung recht leicht zu reproduzieren - zehn oder fünfzehn Minuten vergehen , bevor etwas horrend und Ausnahmen nicht, wie ein , alloc;wenn sie unter einem anspruchsvollen Debug - Umgebung (Rational Purify ausgeführt wird , VS2008/MSVC9oder auch Microsoft Application Verifier) wird der Systemspeicher-Geschwindigkeit gebunden und nicht abstürzt (Memory-gebunden: CPU nicht oben bekommen 50%, Plattenlicht nicht eingeschaltet ist, ist das Programm so schnell gehen kann es, Box raubend 1.3Gvon 2G RAM) . Also habe ich eine andere Wahl zwischen der Lage, das Problem zu reproduzieren (aber nicht identifiziert die Ursache) oder um die Ursache zu idenify in der Lage , oder ein Problem , das ich nicht reproduzieren kann.

Meine aktuellen beste Vermutungen, wo man als nächstes:

  1. Holen Sie sich eine irrsinnig grunty Box (die aktuelle dev Box zu ersetzen: 2 GB RAM in einem E6550 Core2 Duo); Dadurch wird es möglich , den Absturz verursacht Fehl Verhalten repro , wenn sie unter einer leistungsfähigen Debug - Umgebung ausgeführt wird ; oder
  2. Rewrite - Betreiber newund deletezu verwenden VirtualAllocund VirtualProtectSpeicher zu markieren als schreibgeschützt, sobald es mit fertig ist. Führen Sie unter MSVC6und haben das Betriebssystem die bad-guy zu fangen , die auf freigegebenen Speicher schreibt. Ja, das ist ein Zeichen der Verzweiflung: Wer zum Teufel umschreibt newund delete?! Ich frage mich , ob das wird es so langsam machen , wie unter Entschlacken et al.

Und, nein: Versand mit Instrumentierung Entschlacken eingebaut ist keine Option.

Ein Kollege ging einfach vorbei und fragte: „Stack Overflow? Sind wir Stack immer überläuft jetzt?!?“

Und nun die Frage: Wie finde ich den Haufen corruptor?


Aktualisieren: Ausgleich new[]und delete[]einen langen Weg bekam einen Beitrag zur Lösung des Problems zu sein scheint. Statt 15 Minuten, geht die App jetzt etwa zwei Stunden vor dem Absturz. Noch nicht da. Weitergehende Vorschläge? Die Heapbeschädigung weiterhin besteht.

Update: ein Release - Build unter Visual Studio 2008 scheint dramatisch besser; Strom Verdacht beruht auf der STLImplementierung , die Schiffe mit VS98.


  1. Reproduzieren des Problems. Dr Watsonwird einen Dump erzeugen , die in der weiteren Analyse hilfreich sein könnten.

Ich werde eine Kenntnis nehmen, aber ich bin besorgt darüber, dass Dr. Watson wird erst nach der Tatsache ausgelöst wird, nicht, wenn der Haufen stürmt auf wird immer.

Ein weiterer Versuch könnte unter Verwendung sein WinDebugals Debugging - Tool , das sehr mächtig ist auch leicht zugleich zu sein.

Haben Sie das im Moment geht, wieder: nicht viel helfen, bis etwas schief geht. Ich möchte die Vandalen auf frischer Tat erwischen.

Vielleicht werden diese Tools können Sie zumindest das Problem auf bestimmte Komponente verengen.

Ich halte nicht viel Hoffnung, aber verzweifelte Zeiten erfordern ...

Und sind Sie sicher , dass alle Komponenten des Projektes korrekte Laufzeitbibliothek Einstellungen haben ( C/C++ tab, Code - Generierung Kategorie in VS 6.0 Projekteinstellungen)?

Nein, ich bin nicht, und ich werde ein paar Stunden morgen verbringen gehen durch den Arbeitsbereich (58 Projekte in it) und überprüft sie alle Kompilieren und Linken mit den entsprechenden Flags.


Update: Das dauerte 30 Sekunden. Wählen Sie alle Projekte im SettingsDialog abzuwählen , bis Sie das Projekt (s) , die nicht die richtigen Einstellungen haben (sie alle die richtigen Einstellungen hatte).

Veröffentlicht am 04/08/2008 um 08:30
quelle vom benutzer
In anderen Sprachen...                            


15 antworten

stimmen
26

Meine erste Wahl wäre ein dedizierter Haufen Werkzeug wie sein Pageheap.exe .

Umschreiben von neuen und löschen könnte nützlich sein, aber das nicht fängt die Allocs von untergeordnetem Code verpflichtet. Wenn das ist , was Sie wollen, besser Detour die low-level alloc APIs mit Microsoft Detours.

Auch Plausibilitätsprüfungen wie zum Beispiel: überprüfen Sie Ihre Laufzeitbibliotheken Spiel (Release vs. debug, multi-threaded vs. Single-Thread, dll gegen statische lib), suchen Sie nach schlechten Löschungen (zB streichen delete [] sein sollte verwendet), stellen Sie sicher, dass Sie Ihre Allocs nicht Mischen und Anpassen.

Versuchen Sie auch drehen selektiv Fäden ab und sehen Sie, wenn / falls das Problem verschwindet.

Wie sieht der Call-Stack etc wie zum Zeitpunkt der ersten Ausnahme?

Beantwortet am 04/08/2008 um 08:51
quelle vom benutzer

stimmen
11

Ich habe dieselben Probleme in meiner Arbeit (wir verwenden auch VC6manchmal). Und es gibt keine einfache Lösung dafür. Ich habe nur ein paar Hinweise:

  • Versuchen Sie, mit automatischen Crash - Dumps auf Produktionsmaschine (siehe Process Dumper ). Meine Erfahrung sagt Dr. Watson ist nicht perfekt für Dumping.
  • Entfernen Sie alle catch (...) aus dem Code. Sie verstecken sich oft schwerwiegende Speicher Ausnahmen.
  • Überprüfen Advanced Windows Debugging - es gibt viele gute Tipps für Probleme wie das Ihre. Ich empfehle dies mit ganzem Herzen.
  • Wenn Sie STLversuchen , STLPortund überprüft baut. Ungültige Iterator ist die Hölle.

Viel Glück. Probleme wie das Ihre nehmen uns Monate zu lösen. Seien Sie bereit für dieses ...

Beantwortet am 06/08/2008 um 13:41
quelle vom benutzer

stimmen
8

Führen Sie die ursprüngliche Anwendung mit ADplus -crash -pn appnename.exe Wenn das Speicherproblem erscheint-up Sie einen schönen großen Dump erhalten.

Sie können die Dump analysieren , um Abbildung , welche Speicherstelle beschädigt wurde. Wenn man Glück hat der Überschreibspeicher ist eine eindeutige Zeichenfolge , die Sie herausfinden können , woher es kam. Wenn Sie nicht das Glück haben, müssen Sie graben win32Haufen und Figur , was die Orignal Speichereigenschaften war. (Heap -x helfen könnte)

Nachdem Sie wissen , was-up messed wurde, können Sie AppVerifier Nutzung mit speziellen Heap - Einstellungen verengen. dh Sie können angeben , was DLLSie überwachen, oder welche Zuordnungsgröße zu überwachen.

Hoffentlich wird dies die Überwachung Speedup genug, um die Täter zu fangen.

Nach meiner Erfahrung, die ich brauchte nie voll Haufen Verifizierer-Modus, aber ich verbrachte viel Zeit mit der Analyse der Crash-Dump (n) und das Surfen Quellen.

PS: Sie können mit DebugDiag die Deponien zu analysieren. Es kann die darauf hinweist, DLLbesitzen die beschädigten Haufen, und gibt Ihnen andere nützliche Details.

Beantwortet am 16/09/2008 um 08:33
quelle vom benutzer

stimmen
7

Wir haben ziemlich viel Glück gehabt durch unsere eigenen malloc und free-Funktionen zu schreiben. In der Produktion nennen sie nur die Standard-malloc und frei, aber in debug, was sie tun können, was Sie wollen. Wir haben auch eine einfache Basisklasse, die nichts tut, sondern die neue überschreiben und Operatoren löschen diese Funktionen zu nutzen, dann ist jede Klasse, die Sie einfach schreiben können, von dieser Klasse erben. Wenn Sie eine Tonne Code haben, kann es eine große Aufgabe zu ersetzen Anrufe malloc und kostenlos auf die neue malloc und frei sein (nicht vergessen realloc!), Aber auf lange Sicht ist es sehr hilfreich.

In Steve Maguire Buch Schreibt Fest - Code (sehr empfehlenswert), gibt es Beispiele von Debug - Sachen , die Sie in diesen Routinen tun, wie:

  • Behalten Sie den Überblick der Zuweisungen Lecks zu finden
  • Weisen Sie mehr Speicher als notwendig und setzen Markierungen am Anfang und Ende des Speichers - während der freien Routine, können Sie sicherstellen, diese Marker sind immer noch da
  • memset den Speicher mit einer Markierung auf Allocation (Verwendung von nicht initialisierten Speicher zu finden) und auf frei (Nutzung von free'd Speicher zu finden)

Eine weitere gute Idee ist es , nie Dinge zu verwenden , wie strcpy, strcatoder sprintf- immer verwenden strncpy, strncatund snprintf. Wir haben unsere eigenen Versionen davon , wie gut geschrieben, um sicherzustellen, dass wir abschreiben nicht das Ende eines Puffers, und diese haben viele Probleme zu verfangen.

Beantwortet am 22/08/2008 um 18:11
quelle vom benutzer

stimmen
4

Sie sollten dieses Problem angreifen sowohl mit der Laufzeit und der statischen Analyse.

Für die statische Analyse betrachtet mit PREfast Kompilieren ( cl.exe /analyze). Es erkennt nicht übereinstimmen deleteund delete[], Pufferüberläufe und eine Vielzahl anderer Probleme. Seien Sie darauf vorbereitet, zu aber waten durch viele Kilobyte L6 Warnung, vor allem , wenn Ihr Projekt noch hat L4nicht festgelegt.

PREfast ist mit Visual Studio Team System und, offenbar , als Teil von Windows SDK.

Beantwortet am 12/10/2008 um 22:55
quelle vom benutzer

stimmen
3

Ist das in niedrigen Speicherbedingungen? Wenn dem so ist es sein könnte , dass neue zurückkehrt , NULLanstatt zu werfen std :: bad_alloc. Ältere VC++Compiler hat das nicht richtig implementieren. Es gibt einen Artikel über Legacy - Speicherzuordnungsfehler abstürzt STLapps gebaut mit VC6.

Beantwortet am 02/09/2008 um 07:03
quelle vom benutzer

stimmen
3

Die scheinbare Zufälligkeit des Speicherfehlers klingt sehr viel wie ein roten Faden Synchronisierungsproblem - ein Fehler auf Maschinengeschwindigkeit wiedergegeben wird, abhängig. Wenn Objekte (chuncks Speicher) zwischen Threads und Synchronisierung gemeinsam genutzt werden (kritischem Abschnitt, Mutex, Semaphore, andere) Primitive sind nicht auf pro-Klasse (pro-Objekt, pro-Klasse) Basis, dann ist es möglich, eine Situation zu kommen, wobei Klasse (Teil des Speichers) gelöscht wird / während der Benutzung befreit, oder verwendet wird, nachdem gelöscht / befreit.

Als Test für das, könnten Sie Synchronisierungsgrund für jede Klasse und Methode hinzufügen. Dadurch wird Ihr Code langsamer machen, da viele Objekte aufeinander warten müssen, aber wenn dies die Heapbeschädigung beseitigt, wird Ihr Heap-Korruption Problem eine Code-Optimierung werden eins.

Beantwortet am 25/08/2008 um 20:55
quelle vom benutzer

stimmen
1

Wenn Sie sich neu neu zu schreiben / löschen, ich habe dies getan und haben eine einfache Quellcode an:

http://gandolf.homelinux.org/~smhanov/blog/?id=10

Dies fängt Speicherlecks und fügt auch Schutzdaten vor und nach dem Speicherblock Heapbeschädigung zu erfassen. Sie können nur mit ihm integrieren, indem #include „debug.h“ an der Spitze jeder CPP-Datei und definieren DEBUG und DEBUG_MEM setzen.

Beantwortet am 17/09/2008 um 14:40
quelle vom benutzer

stimmen
1

Also von den begrenzten Informationen, die Sie haben, kann dies eine Kombination aus einem oder mehreren Dingen:

  • Bad Heap-Nutzung, das heißt doppelt frees, nach frei zu lesen, nach frei schreiben, die HEAP_NO_SERIALIZE Flagge mit Allocs Einstellung und befreit von mehreren Threads auf dem gleichen Heap
  • Nicht genügend Arbeitsspeicher
  • Bad Code (dh Pufferüberlauf, Pufferunterschreitungen, etc.)
  • "Zeitprobleme

Wenn es überhaupt die ersten beiden, aber nicht das letzte Mal, sollten Sie es entweder mit Pageheap.exe jetzt gefangen haben.

Welche bedeutet wahrscheinlich ist es darauf zurückzuführen, wie der Code gemeinsam genutzten Speicher zugreift. Leider werden wird, dass das Aufspüren ziemlich schmerzhaft. Nicht synchronisierten Zugriff auf gemeinsam genutzten Speicher manifestiert oft als seltsam „Timing“ Fragen. Dinge wie nicht acquire / release Semantik für mit einem Flag Zugriff auf gemeinsam genutzten Speicher zu synchronisieren, keine Sperren in geeigneter Weise verwendet wird, usw.

Zumindest würde es helfen, Zuweisungen zu können irgendwie verfolgen, wie bereits vorgeschlagen. Zumindest dann können Sie sehen, was tatsächlich bis zum Heapbeschädigung passiert und versuchen, sich von dem zu diagnostizieren.

Auch, wenn Sie leicht Zuweisungen an mehrere Haufen umleiten können, möchten Sie vielleicht, dass, um zu versuchen, um zu sehen, ob das entweder das Problem oder die Ergebnisse in mehr reproduzierbaren Buggy Verhalten behebt.

Wenn Sie mit VS2008 testen, haben Sie laufen mit HeapVerifier mit Conserve Speichern auf Ja festgelegt? Das könnte die Auswirkungen auf die Leistung des Haufens allocator reduzieren. (Plus, müssen Sie laufen mit ihm Debug-> Beginnen Sie mit Application Verifier, aber Sie können bereits wissen.)

Sie können auch mit Windbg und verschiedene Verwendungen des! Heap Befehl Debuggen versuchen.

MSN

Beantwortet am 22/08/2008 um 17:51
quelle vom benutzer

stimmen
0

Ein paar Vorschläge. Sie erwähnen die reichlichen Warnungen an W4 - Ich würde vorschlagen, die Zeit nehmen, um Ihren Code zu beheben sauber auf Warnstufe zu kompilieren 4 - dies schwer, einen langen Weg zu verhindern subtilen gehen Bugs zu finden.

Zweitens - für die / analysieren Schalter - es ist in der Tat reichlich Warnungen zu erzeugen. Um diesen Schalter in meinem eigenen Projekt zu verwenden, was ich tat, war eine neue Header-Datei zu erstellen, die #pragma Warnung verwendete auszuschalten all zusätzliche Warnungen generierten von / analysieren. Dann weiter unten in der Datei, wende ich mich nur auf diese Warnungen mich interessiert. Verwenden Sie dann die / FI-Compiler-Option diese Header-Datei zu zwingen, zuerst in allen Übersetzungseinheiten enthalten sein. Dies sollte Ihnen ermöglichen, Schalter der / analysieren zu verwenden, während die Ausgabe controling

Beantwortet am 03/10/2009 um 17:48
quelle vom benutzer

stimmen
0

Glauben Sie, das eine Race-Bedingung ist? Sind mehrere Threads teilen sich ein Haufen? Können Sie jedem Thread einen eigenen Haufen mit HeapCreate geben, dann können sie schnell mit HEAP_NO_SERIALIZE laufen. Andernfalls sollte ein Haufen Thread-sicher sein, wenn Sie die Multi-Thread-Version der Systembibliotheken verwenden.

Beantwortet am 30/07/2009 um 14:48
quelle vom benutzer

stimmen
0

Die kleine Zeit, die ich hatte ein ähnliches Problem zu lösen. Wenn das Problem weiterhin besteht Ich schlage vor, Sie dies tun: alle Anrufe an neuen Monitor / Löschen und malloc / calloc / realloc / frei. Ich mache einzelne DLL eine Funktion für das Register alle Anrufe zu exportieren. Mit dieser Funktion erhält Parameter für Ihren Source-Code, Zeiger auf zugewiesenen Bereich und Art des Anrufs zu identifizieren, diese Informationen in einer Tabelle zu speichern. Alle zugewiesenen / befreit Paar eliminiert. Am Ende und nach benötigen Sie einen Anruf an eine andere Funktion machen für Bericht für linke Daten erstellen. Mit diesem können Sie falsche Anrufe (neu / kostenlos oder malloc / Löschen) oder fehlende identifizieren. Wenn irgendein Fall von Puffer im Code überschrieben haben gespeichert die Informationen falsch sein, aber jeder Test / kann erkennen entdecken / umfassen eine Lösung des Scheiterns identifiziert. Viele Läufe zu helfen, die Fehler zu identifizieren. Viel Glück.

Beantwortet am 19/12/2008 um 12:52
quelle vom benutzer

stimmen
0

Graeme Vorschlag von benutzerdefinierten malloc / free ist eine gute Idee. Sehen Sie, wenn Sie einige Muster über die Korruption charakterisieren können Sie einen Griff zu geben, zu nutzen.

Zum Beispiel, wenn es immer in einem Block von gleicher Größe (zB 64 Bytes) dann malloc / free Paar ändern, um immer zuteile 64-Byte-Blöcke in ihrer eigenen Seite. Wenn Sie ein 64-Byte-Chunk frei dann die Bits Speicherschutz gesetzt auf dieser Seite zu verhindern liest und wites (mit Virtual). Dann jemand versucht, diesen Speicher zuzugreifen wird eine Ausnahme statt korrumpieren den Heap erzeugen.

Dies gilt davon aus, dass die Anzahl der ausstehenden 64-Byte-Chunks nur mäßig ist, oder Sie haben eine Menge Speicher in der Box zu verbrennen!

Beantwortet am 02/09/2008 um 05:23
quelle vom benutzer

stimmen
0

Meine erste Aktion würde wie folgt aussehen:

  1. Bauen Sie die Binärdateien in „Release“ Version, aber sie schaffen Debug-Info-Datei (Sie werden diese Möglichkeit in Projekteinstellungen finden).
  2. Verwenden Sie Dr. Watson als defualt Debugger (drwtsn32 -I) auf einem Computer, auf dem das Problem reproduzieren möchten.
  3. Repdroduce das Problem. Dr. Watson wird einen Dump erzeugen, die in der weiteren Analyse hilfreich sein könnten.

Ein weiterer Versuch könnte mit WinDebug als Debugging-Tool sein, die sehr mächtig sind auch leicht zugleich zu sein.

Vielleicht werden diese Tools können Sie zumindest das Problem auf bestimmte Komponente verengen.

Und sind Sie sicher, dass alle Komponenten des Projektes haben korrekte Laufzeitbibliothek Einstellungen (C / C ++ Registerkarte Kategorie Codeerstellung in VS 6.0 Projekteinstellungen)?

Beantwortet am 04/08/2008 um 09:26
quelle vom benutzer

stimmen
0

Sie haben versucht, Altbauten, aber gibt es einen Grund, warum Sie nicht weiter zu gehen zurück in der Repository Geschichte zu halten und zu sehen, wann genau der Fehler eingeführt wurde?

Ansonsten würde ich einfache Protokollierung irgendeine Art vorschlagen, das Hinzufügen, das Problems zu helfen, die Spur zu kommen, wenn ich mit einem Verlust von bin, was speziell mögen Sie vielleicht loggen sein.

Wenn Sie herausfinden können, was genau dieses Problem verursachen können über Google und Dokumentation der Ausnahmen, die Sie bekommen, vielleicht wird das geben weitere Einblicke auf das, was in dem Code zu suchen.

Beantwortet am 04/08/2008 um 08:48
quelle vom benutzer

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more