Frage

Also, ich brauche etwas Hilfe.Ich arbeite an einem Projekt in C++.Ich glaube jedoch, dass ich es irgendwie geschafft habe, meinen Heap zu beschädigen.Dies basiert auf der Tatsache, dass ich eine hinzugefügt habe std::string einer Klasse zuordnen und ihr einen Wert von einer anderen zuweisen std::string:

std::string hello = "Hello, world.\n";
/* exampleString = "Hello, world.\n" would work fine. */
exampleString = hello;

stürzt auf meinem System mit einem Stack-Dump ab.Also im Grunde muss ich es tun stoppen Und ich gehe alle meine Code- und Speicherverwaltungsaufgaben durch und finde heraus, wo ich Fehler gemacht habe.Die Codebasis ist immer noch klein (ca. 1000 Zeilen), sodass dies problemlos möglich ist.

Trotzdem bin ich mit solchen Sachen überfordert, also dachte ich, ich schmeiße es raus.Ich verwende ein Linux-System und habe damit herumgestöbert valgrind, und obwohl ich nicht genau wusste, was ich tue, wurde berichtet, dass die std::stringDer Destruktor von war ein ungültiger Free.Ich muss zugeben, dass ich bei einer Google-Suche den Begriff „Heap Corruption“ gefunden habe.Wir würden uns auch über allgemeine Artikel zu solchen Themen freuen.

(Vorher rm -rf ProjectDir, mach es noch einmal in C# :D)

BEARBEITEN:Ich habe es nicht klar zum Ausdruck gebracht, aber ich frage nach Möglichkeiten und Ratschlägen zur Diagnose dieser Art von Gedächtnisproblemen.Ich weiß, dass das std::string-Zeug richtig ist, also habe ich es getan (oder es ist ein Fehler, aber es gibt kein Problem mit Select).Ich bin mir sicher, dass ich den Code, den ich geschrieben habe, überprüfen könnte und Sie sehr kluge Leute würden das Problem in kürzester Zeit erkennen, aber ich möchte diese Art der Codeanalyse sozusagen zu meinem „Werkzeugkasten“ hinzufügen.

War es hilfreich?

Lösung

Dies sind relativ kostengünstige Mechanismen, um das Problem möglicherweise zu lösen:

  1. Behalte meine im Auge Frage zur Haufenkorruption - Ich aktualisiere die Antworten, sobald sie herauskommen.Das erste war das Ausbalancieren new[] Und delete[], aber das machst du schon.
  2. Geben Valgrind eher ein Versuch;Es ist ein hervorragendes Tool, und ich wünschte nur, es wäre unter Windows verfügbar.Ich verlangsame Ihr Programm nur um etwa die Hälfte, was im Vergleich zu den Windows-Äquivalenten ziemlich gut ist.
  3. Denken Sie darüber nach, das zu verwenden Google-Leistungstools als Ersatz malloc/neu.
  4. Haben Sie alle Ihre Objektdateien bereinigt und von vorne begonnen?Vielleicht ist Ihre Make-Datei ..."suboptimal"
  5. Das bist du nicht assert()ing genug in Ihrem Code.Woher weiß ich das, ohne es gesehen zu haben?Wie Zahnseide, niemand assert()Das ist genug in ihrem Code.Fügen Sie eine Validierungsfunktion für Ihre Objekte hinzu und rufen Sie diese am Methodenanfang und -ende auf.
  6. Bist du Kompilierungswand?Wenn nicht, tun Sie es.
  7. Besorgen Sie sich ein solches Fusselwerkzeug PC-Lint.Eine kleine App wie Ihre könnte da reinpassen PC-Lint-Demo Seite, d.h. kein Kauf für Sie!
  8. Überprüfen Sie, ob Sie Zeiger nach dem Löschen auf NULL setzen.Niemand mag einen baumelnden Zeiger.Gleicher Auftritt mit deklarierten, aber nicht zugewiesenen Zeigern.
  9. Hören Sie auf, Arrays zu verwenden.Benutze einen Vektor stattdessen.
  10. Verwenden Sie keine Rohzeiger.Benutze einen intelligenter Zeiger.Nicht verwenden auto_ptr!Das Ding ist...überraschend;seine Semantik ist sehr seltsam.Wählen Sie stattdessen eines der Steigern Sie intelligente Zeiger, oder etwas aus die Loki-Bibliothek.

Andere Tipps

Wir hatten einmal einen Fehler, der allen regulären Techniken, Valgrind, Purify usw., entgangen ist.Der Absturz trat nur auf Rechnern mit viel Arbeitsspeicher und nur bei großen Eingabedatensätzen auf.

Schließlich haben wir es mithilfe von Debugger-Überwachungspunkten aufgespürt.Ich versuche die Vorgehensweise hier zu beschreiben:

1) Finden Sie die Ursache des Fehlers.Aus Ihrem Beispielcode geht hervor, dass der Speicher für „exampleString“ beschädigt ist und daher nicht beschrieben werden kann.Fahren wir mit dieser Annahme fort.

2) Setzen Sie einen Haltepunkt an der letzten bekannten Stelle, an der „exampleString“ problemlos verwendet oder geändert werden kann.

3) Fügen Sie dem Datenelement von „exampleString“ einen Überwachungspunkt hinzu.Bei meiner Version von g++ wird die Zeichenfolge in gespeichert _M_dataplus._M_p.Wir möchten wissen, wann sich dieses Datenelement ändert.Die GDB-Technik hierfür ist:

(gdb) p &exampleString._M_dataplus._M_p
$3 = (char **) 0xbfccc2d8
(gdb)  watch *$3
Hardware watchpoint 1: *$3

Ich verwende hier natürlich Linux mit g++ und gdb, aber ich glaube, dass Speicherüberwachungspunkte bei den meisten Debuggern verfügbar sind.

4) Fahren Sie fort, bis der Überwachungspunkt ausgelöst wird:

Continuing.
Hardware watchpoint 2: *$3

Old value = 0xb7ec2604 ""
New value = 0x804a014 ""
0xb7e70a1c in std::string::_M_mutate () from /usr/lib/libstdc++.so.6
(gdb) where

Die GDB where Der Befehl gibt eine Rückverfolgung aus, die zeigt, was zu der Änderung geführt hat.Dies ist entweder eine völlig legale Änderung. In diesem Fall fahren Sie einfach fort – oder wenn Sie Glück haben, handelt es sich um eine Änderung aufgrund der Speicherbeschädigung.Im letzteren Fall sollten Sie nun in der Lage sein, den Code zu überprüfen Wirklich das Problem verursachen und es hoffentlich beheben.

Die Ursache unseres Fehlers war ein Array-Zugriff mit negativem Index.Der Index war das Ergebnis einer Umwandlung eines Zeigers auf ein „int“-Modul, das der Größe des Arrays entspricht.Der Fehler wurde von Valgrind et al. übersehen.da die Speicheradressen, die bei der Ausführung unter diesen Tools zugewiesen wurden, nie „> MAX_INT" und führte daher nie zu einem negativen Index.

Oh, wenn Sie wissen möchten, wie Sie das Problem beheben können, ist das ganz einfach.Holen Sie sich zuerst ein totes Huhn.Dann, Fang an, es zu schütteln.

Im Ernst, ich habe keinen einheitlichen Weg gefunden, diese Art von Fehlern aufzuspüren.Da es so viele potenzielle Probleme gibt, gibt es keine einfache Checkliste, die man durchgehen kann.Ich würde jedoch Folgendes empfehlen:

  1. Machen Sie sich mit einem Debugger vertraut.
  2. Fangen Sie an, im Debugger herumzustöbern, um zu sehen, ob Sie etwas finden, das Ihnen verdächtig vorkommt.Überprüfen Sie insbesondere, was während der passiert exampleString = hello; Linie.
  3. Überprüfen Sie, ob es tatsächlich abstürzt exampleString = hello; Zeile, und nicht beim Verlassen eines umschließenden Blocks (was dazu führen könnte, dass Destruktoren ausgelöst werden).
  4. Überprüfen Sie die Zeigermagie, die Sie möglicherweise ausführen.Zeigerarithmetik, Casting usw.
  5. Überprüfen Sie alle Ihre Zuweisungen und Freigaben, um sicherzustellen, dass sie übereinstimmen (keine doppelten Freigaben).
  6. Stellen Sie sicher, dass Sie keine Verweise oder Zeiger auf Objekte im Stapel zurückgeben.

Es gibt auch viele andere Dinge, die man ausprobieren kann.Ich bin mir sicher, dass auch einige andere Leute ihre Ideen einbringen werden.

Einige Orte zum Starten:

Wenn Sie unter Windows arbeiten und Visual C++6 verwenden (ich hoffe Gott, dass es heutzutage niemand mehr verwendet), ist die Implementierung von std::string nicht threadsicher und kann zu so etwas führen.

Hier ist ein Artikel, den ich gefunden habe und der viele der häufigsten Ursachen für Speicherverluste und -beschädigungen erklärt.

An meinem vorherigen Arbeitsplatz haben wir Compuware Boundschecker verwendet, um dabei zu helfen.Es ist kommerziell und sehr teuer, daher ist es möglicherweise keine Option.

Hier sind ein paar kostenlose Bibliotheken, die von Nutzen sein können

http://www.codeguru.com/cpp/misc/misc/memory/article.php/c3745/

http://www.codeproject.com/KB/cpp/MemLeakDetect.aspx

Hoffentlich hilft das.Speicherbeschädigung ist ein beschissener Ort!

Es könnte sich um Heap-Beschädigung handeln, aber es ist genauso wahrscheinlich, dass es sich um Stack-Beschädigung handelt.Jim hat recht.Wir brauchen wirklich etwas mehr Kontext.Diese beiden Quellenzeilen sagen uns für sich genommen nicht viel.Dafür kann es eine ganze Reihe von Ursachen geben (was das wahre Vergnügen von C/C++ ist).

Wenn Sie Ihren Code gerne veröffentlichen, können Sie ihn sogar komplett auf einen Server hochladen und einen Link posten.Ich bin mir sicher, dass Sie auf diese Weise viel mehr Ratschläge erhalten würden (einige davon haben zweifellos nichts mit Ihrer Frage zu tun).

Der Code war lediglich ein Beispiel dafür, wo mein Programm fehlschlug (er wurde auf dem Stapel zugewiesen, Jim).Ich suche eigentlich nicht nach „Was habe ich falsch gemacht“, sondern eher nach „Wie kann ich diagnostizieren, was ich falsch gemacht habe“.Bring einem Mann das Fischen bei und so weiter.Obwohl ich mir die Frage ansehe, habe ich das nicht klar genug gemacht.Gott sei Dank für die Bearbeitungsfunktion.:')

Außerdem habe ich tatsächlich das std::string-Problem behoben.Wie?Durch Ersetzen durch einen Vektor, Kompilieren und erneutes Ersetzen der Zeichenfolge.Es War Ständig stürzte es dort ab, und das wurde behoben, obwohl es ... nicht konnte.Da ist etwas Schlimmes, und ich bin mir nicht sicher, was.Ich wollte jedoch das eine Mal überprüfen, in dem ich manuell Speicher auf dem Heap zuordne:

 this->map = new Area*[largestY + 1];
 for (int i = 0; i < largestY + 1; i++) {
     this->map[i] = new Area[largestX + 1];
 }

und es löschen:

for (int i = 0; i < largestY + 1; i++) {
    delete [] this->map[i];
}
delete [] this->map;

Ich habe noch nie ein 2D-Array mit C++ zugewiesen.Es scheint zu funktionieren.

Außerdem habe ich tatsächlich das std::string-Problem behoben.Wie?Durch Ersetzen durch einen Vektor, Kompilieren und erneutes Ersetzen der Zeichenfolge.Dort stürzte es ständig ab, und das wurde behoben, obwohl es... nicht möglich war.Da ist etwas Schlimmes, und ich bin mir nicht sicher, was.

Das hört sich an, als hättest du wirklich ein Huhn geschüttelt.Wenn Sie es nicht wissen Warum Es funktioniert jetzt, dann ist es immer noch kaputt und es wird Sie garantiert später wieder belästigen (nachdem Sie noch mehr Komplexität hinzugefügt haben).

Führen Sie Purify aus.

Es ist ein nahezu magisches Tool, das meldet, wenn Sie Speicher überlasten, den Sie nicht anfassen sollten, Speicher verlieren, indem Sie Dinge nicht freigeben, doppelt freigeben usw.

Es funktioniert auf Maschinencode-Ebene, sodass Sie nicht einmal über den Quellcode verfügen müssen.

Eine der angenehmsten Telefonkonferenzen mit Anbietern, an denen ich je teilgenommen habe, war, als Purify ein Speicherleck in ihrem Code feststellte und wir fragen konnten: „Ist es möglich, dass Sie in Ihrer Funktion foo() keinen Speicher freigeben?“ und uns das anhören konnten Erstaunen in ihren Stimmen.

Sie dachten, wir würden Götter debuggen, aber dann verrieten wir ihnen das Geheimnis, damit sie Purify ausführen konnten, bevor wir ihren Code verwenden mussten.:-)

http://www-306.ibm.com/software/awdtools/purify/unix/

(Es ist ziemlich teuer, aber es gibt einen kostenlosen Evaluierungs-Download)

Eine der Debugging-Techniken, die ich häufig verwende (außer in Fällen der extremsten Verrücktheit), ist das Teilen und Herrschen.Wenn Ihr Programm derzeit aufgrund eines bestimmten Fehlers fehlschlägt, teilen Sie es auf irgendeine Weise in zwei Hälften und prüfen Sie, ob immer noch derselbe Fehler auftritt.Offensichtlich besteht der Trick darin, zu entscheiden, wo Sie Ihr Programm aufteilen möchten!

Ihr Beispiel zeigt nicht genügend Kontext, um festzustellen, wo der Fehler liegen könnte.Wenn jemand anderes Ihr Beispiel ausprobieren würde, würde es gut funktionieren.Versuchen Sie also, in Ihrem Programm so viele zusätzliche Dinge zu entfernen, die Sie uns nicht gezeigt haben, und prüfen Sie, ob es dann funktioniert.Wenn ja, fügen Sie den anderen Code nach und nach wieder hinzu, bis er fehlschlägt.Dann ist wahrscheinlich das, was Sie gerade hinzugefügt haben, das Problem.

Beachten Sie, dass bei einem Multithread-Programm wahrscheinlich größere Probleme auftreten.Wenn nicht, sollten Sie es auf diese Weise eingrenzen können.Viel Glück!

Anders als bei Tools wie Boundschecker oder Purify besteht die beste Möglichkeit, Probleme wie dieses zu lösen, darin, Code richtig gut zu lesen und sich mit dem Code, an dem Sie arbeiten, vertraut zu machen.

Speicherbeschädigung ist eines der am schwierigsten zu behebenden Probleme. Normalerweise werden solche Probleme gelöst, indem man Stunden/Tage in einem Debugger verbringt und etwas wie „Hey, Zeiger X wird verwendet, nachdem er gelöscht wurde!“ bemerkt.

Wenn es irgendetwas hilft, ist es etwas, in dem Sie mit zunehmender Erfahrung besser werden.

Ihre Speicherzuordnung für das Array scheint korrekt zu sein, aber stellen Sie sicher, dass Sie auch alle Stellen überprüfen, an denen Sie auf das Array zugreifen.

Wie ich sehen kann, enthält Ihr Code keine Fehler.Wie bereits erwähnt, ist mehr Kontext erforderlich.

Wenn Sie es noch nicht versucht haben, installieren Sie gdb (den GCC-Debugger) und kompilieren Sie das Programm mit -g.Dadurch werden Debugging-Symbole kompiliert, die von GDB verwendet werden können.Sobald Sie gdb installiert haben, führen Sie es mit dem Programm (gdb) aus. Das ist ein nützlicher Cheatsheat für die Verwendung von GDB.

Legen Sie einen Haltepunkt für die Funktion fest, die den Fehler verursacht, und sehen Sie, welchen Wert exampleString hat.Machen Sie dasselbe auch für jeden Parameter, den Sie an exampleString übergeben.Dies sollte Ihnen zumindest sagen, ob die std::strings gültig sind.

Ich habe die Antwort von gefunden Dieser Artikel um ein guter Leitfaden für Hinweise zu sein.

Soweit ich das beurteilen kann, ist Ihr Code korrekt.Angenommen, exampleString ist ein std::string mit dem von Ihnen beschriebenen Klassenbereich, sollten Sie ihn auf diese Weise initialisieren/zuweisen können.Vielleicht gibt es noch ein anderes Problem?Vielleicht würde ein Ausschnitt des tatsächlichen Codes helfen, es in einen Kontext zu bringen.

Frage:Ist exampleString ein Zeiger auf ein mit new erstelltes String-Objekt?

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top