Application Verifier in Kombination mit Debugging Tools für Windows ist ein erstaunliches Setup. Sie können beides als Teil des Windows-Treiberkits oder des leichteren Windows SDK erhalten . ( Ich habe bei der Untersuchung einer früheren Frage zu einem Problem mit der Heap-Beschädigung von Application Verifier erfahren.) Ich habe in der Vergangenheit auch BoundsChecker und Insure ++ (in anderen Antworten erwähnt) verwendet, obwohl ich überrascht war, wie viel Funktionalität in Application Verifier vorhanden war.
Electric Fence (auch bekannt als "efence"), dmalloc , valgrind usw. sind alle erwähnenswert, aber die meisten davon sind unter * nix viel einfacher zum Laufen zu bringen als unter Windows. Valgrind ist lächerlich flexibel: Ich habe große Serversoftware mit vielen Heap-Problemen getestet.
Wenn alles andere fehlschlägt, können Sie Ihrem eigenen globalen Operator neue / delete- und malloc / calloc / realloc-Überladungen bereitstellen. Die Vorgehensweise hängt vom Compiler und der Plattform ab. Dies ist eine Investition. aber es kann sich auf lange Sicht auszahlen. Die Liste der wünschenswerten Funktionen sollte aus dmalloc und electricfence und dem überraschend hervorragenden Buch Writing Solid Code bekannt sein :
- Wachposten : Lassen Sie vor und nach jeder Zuweisung etwas mehr Platz, um die maximale Ausrichtungsanforderung zu berücksichtigen. Füllen Sie mit magischen Zahlen (hilft dabei, Pufferüber- und -unterläufe und gelegentliche "wilde" Zeiger abzufangen)
- Alloc Fill : Füllen Sie neue Allokationen mit einem magischen Wert ungleich 0 - Visual C ++ erledigt dies bereits in Debug-Builds für Sie (hilft bei der Verwendung nicht initialisierter Vars).
- free fill : Füllen Sie den freigegebenen Speicher mit einem magischen Wert ungleich 0 aus, der einen Segfault auslöst, wenn er in den meisten Fällen dereferenziert wird (hilft beim Auffangen baumelnder Zeiger).
- verzögert frei : Geben Sie den freigegebenen Speicher für eine Weile nicht auf den Heap zurück, halten Sie ihn frei gefüllt, aber nicht verfügbar (hilft dabei, mehr baumelnde Zeiger abzufangen, fängt nahegelegene doppelte Freigaben ab).
- Tracking : Manchmal kann es nützlich sein, aufzuzeichnen, wo eine Zuordnung vorgenommen wurde
Beachten Sie, dass wir in unserem lokalen Homebrew-System (für ein eingebettetes Ziel) das Tracking von den meisten anderen Dingen getrennt halten, da der Laufzeitaufwand viel höher ist.
Wenn Sie an weiteren Gründen für die Überladung dieser Zuordnungsfunktionen / Operatoren interessiert sind, lesen Sie meine Antwort auf " Gibt es einen Grund, den globalen Operator neu zu überladen und zu löschen?" ;; Abgesehen von der schamlosen Eigenwerbung werden andere Techniken aufgelistet, die bei der Verfolgung von Heap-Korruptionsfehlern hilfreich sind, sowie andere anwendbare Tools.
Da ich hier bei der Suche nach zugewiesenen / freien / Zaunwerten, die MS verwendet, immer wieder meine eigene Antwort finde, finden Sie hier eine weitere Antwort, die Microsoft-Dbgheap-Füllwerte abdeckt .
Sie können viele Heap-Beschädigungsprobleme erkennen, indem Sie Page Heap für Ihre Anwendung aktivieren. Dazu müssen Sie gflags.exe verwenden, das Teil der Debugging-Tools für Windows ist
Führen Sie Gflags.exe aus und aktivieren Sie in den Image-Dateioptionen für Ihre ausführbare Datei die Option "Seitenheap aktivieren".
Starten Sie nun Ihre Exe neu und hängen Sie sie an einen Debugger an. Wenn der Seitenheap aktiviert ist, bricht die Anwendung in den Debugger ein, wenn eine Heap-Beschädigung auftritt.
quelle
Fügen Sie
main()
in Microsoft Visual Studio C ++ Folgendes hinzu, um die Laufzeit erheblich zu verlangsamen und zahlreiche Laufzeitprüfungen durchzuführenquelle
Ein sehr relevanter Artikel ist das Debuggen von Heap-Beschädigungen mit Application Verifier und Debugdiag .
quelle
Machen Sie ungezogene Dinge mit Speicher, z. B. Schreiben nach dem Ende eines Puffers oder Schreiben in einen Puffer, nachdem dieser wieder auf dem Heap freigegeben wurde.
Verwenden Sie ein Instrument, das Ihrer ausführbaren Datei eine automatische Überprüfung der Grenzen hinzufügt: z. B. valgrind unter Unix oder ein Tool wie BoundsChecker (Wikipedia schlägt auch Purify and Insure ++ vor) unter Windows.
Beachten Sie, dass diese Ihre Anwendung verlangsamen, sodass sie möglicherweise unbrauchbar werden, wenn es sich bei Ihrer Anwendung um eine Soft-Echtzeit-Anwendung handelt.
Ein weiteres mögliches Debugging-Hilfsmittel / Tool könnte der HeapAgent von MicroQuill sein.
quelle
Ein kurzer Tipp, den ich beim Erkennen des Zugriffs auf freigegebenen Speicher erhalten habe, lautet:
quelle
Das beste Tool, das ich nützlich fand und das jedes Mal funktioniert hat, ist die Codeüberprüfung (mit guten Codeüberprüfern).
Abgesehen von der Codeüberprüfung würde ich zuerst Page Heap ausprobieren . Das Einrichten von Page Heap dauert einige Sekunden und kann mit etwas Glück Ihr Problem lokalisieren.
Wenn Sie mit Page Heap kein Glück haben, laden Sie die Debugging-Tools für Windows von Microsoft herunter und lernen Sie die Verwendung von WinDbg. Leider konnte ich Ihnen keine spezifischere Hilfe geben, aber das Debuggen von Multithread-Heap-Korruption ist eher eine Kunst als eine Wissenschaft. Google für "WinDbg Heap Korruption" und Sie sollten viele Artikel zu diesem Thema finden.
quelle
Möglicherweise möchten Sie auch überprüfen, ob Sie eine Verknüpfung mit der dynamischen oder statischen C-Laufzeitbibliothek herstellen. Wenn Ihre DLL-Dateien mit der statischen C-Laufzeitbibliothek verknüpft sind, haben die DLL-Dateien separate Heaps.
Wenn Sie also ein Objekt in einer DLL erstellen und versuchen, es in einer anderen DLL freizugeben, erhalten Sie dieselbe Meldung wie oben. Auf dieses Problem wird in einer anderen Frage zum Stapelüberlauf verwiesen: Freigeben des in einer anderen DLL zugewiesenen Speichers .
quelle
Welche Art von Zuordnungsfunktionen verwenden Sie? Ich habe kürzlich einen ähnlichen Fehler bei der Zuweisung von Heap * -Stilen festgestellt.
Es stellte sich heraus, dass ich fälschlicherweise den Heap mit der
HEAP_NO_SERIALIZE
Option erstellt habe. Dadurch werden die Heap-Funktionen im Wesentlichen ohne Thread-Sicherheit ausgeführt. Es ist eine Leistungsverbesserung, wenn es richtig verwendet wird, sollte aber niemals verwendet werden, wenn Sie HeapAlloc in einem Multithread-Programm verwenden [1]. Ich erwähne dies nur, weil in Ihrem Beitrag erwähnt wird, dass Sie eine Multithread-App haben. Wenn Sie HEAP_NO_SERIALIZE irgendwo verwenden, löschen Sie das und es wird wahrscheinlich Ihr Problem beheben.[1] Es gibt bestimmte Situationen, in denen dies legal ist. Sie müssen jedoch Aufrufe an Heap * serialisieren. Dies ist bei Multithread-Programmen normalerweise nicht der Fall.
quelle
Wenn diese Fehler zufällig auftreten, besteht eine hohe Wahrscheinlichkeit, dass Sie auf Datenrennen gestoßen sind. Überprüfen Sie bitte: Ändern Sie gemeinsam genutzte Speicherzeiger aus verschiedenen Threads? Intel Thread Checker kann helfen, solche Probleme in Multithread-Programmen zu erkennen.
quelle
Neben der Suche nach Werkzeugen sollten Sie auch nach einem wahrscheinlichen Schuldigen suchen. Gibt es eine Komponente, die Sie verwenden, die möglicherweise nicht von Ihnen geschrieben wurde und die möglicherweise nicht für die Ausführung in einer Multithread-Umgebung entwickelt und getestet wurde? Oder einfach eine, die Sie nicht kennen, ist in einer solchen Umgebung gelaufen.
Das letzte Mal, als es mir passiert ist, war es ein natives Paket, das seit Jahren erfolgreich aus Batch-Jobs verwendet wurde. Es war jedoch das erste Mal in diesem Unternehmen, dass es von einem .NET-Webdienst (der Multithread-fähig ist) verwendet wurde. Das war es - sie hatten gelogen, dass der Code threadsicher sei.
quelle
Sie können VC CRT Heap-Check-Makros für _CrtSetDbgFlag verwenden : _CRTDBG_CHECK_ALWAYS_DF oder _CRTDBG_CHECK_EVERY_16_DF .. _CRTDBG_CHECK_EVERY_1024_DF .
quelle
Ich möchte meine Erfahrung hinzufügen. In den letzten Tagen habe ich eine Instanz dieses Fehlers in meiner Anwendung behoben. In meinem speziellen Fall waren die Fehler im Code:
Control.Invoke
ein verwaltetes Objekt auf und entsorgen Sie es, das das native Objekt umschließt, zu dem der Rückruf gehört.Control.Invoke
Ende blockiert ). Ich sollte klarstellen, dass ich verwendeboost::thread
, also verwende ich eine Member-Funktion als Thread-Funktion.Control.BeginInvoke
Sie stattdessen (meine GUI wird mit Winforms erstellt), damit der native Thread beendet werden kann, bevor das Objekt zerstört wird (der Zweck des Rückrufs besteht darin, genau zu benachrichtigen, dass der Thread beendet wurde und das Objekt zerstört werden kann).quelle
Ich hatte ein ähnliches Problem - und es tauchte ganz zufällig auf. Vielleicht war etwas in den Build-Dateien beschädigt, aber ich habe es behoben, indem ich zuerst das Projekt bereinigt und dann neu erstellt habe.
Also zusätzlich zu den anderen Antworten:
Welche Art von Dingen kann diese Fehler verursachen? Etwas beschädigt in der Build-Datei.
Wie debugge ich sie? Projekt reinigen und neu erstellen. Wenn es behoben ist, war dies wahrscheinlich das Problem.
quelle