Frage

Das ist für mich ziemlich seltsam, aber ich erhalte einen unerwarteten und zufälligen Segmentierungsfehler, wenn ich mein Programm starte.Manchmal funktioniert es, manchmal stürzt es ab.Der Debugger von Dev-C++ weist mich auf eine Zeile der Datei hin:stl_construct.h

/**
   * @if maint
   * Constructs an object in existing memory by invoking an allocated
   * object's constructor with an initializer.
   * @endif
   */
  template<typename _T1, typename _T2>
    inline void
    _Construct(_T1* __p, const _T2& __value)
    {
      // _GLIBCXX_RESOLVE_LIB_DEFECTS
      // 402. wrong new expression in [some_]allocator::construct
     -> ::new(static_cast<void*>(__p)) _T1(__value);
    }

Ich nutze die STL übrigens ausgiebig.Was muss ich tun, um den Ursprung des Segfaults zu ermitteln?Gibt es Tools, die helfen können?Was sind die Gründe, die zu zufälligen Abstürzen wie diesem führen können?

Bearbeiten:

Mein Programm umfasst rund 5000 Codezeilen.Ich weiß nicht, welchen Teil des Codes ich anzeigen muss, um Hilfe zu erhalten, da ich keine Ahnung von der Ursache des Problems habe. Der Debugger hat mir nur gesagt, dass es mit der STL zu tun hat.

Bearbeiten:

ich zog nach Code::Blocks Hier ist nun der Aufrufstapel:

#0 00464635 std::_Construct<std::pair<double const, int>, std::pair<double const, int> >(__p=0xb543e8, __value=@0x10) (C:/Program Files/CodeBlocks/MinGW/bin/../lib/gcc/mingw32/3.4.5/../../../../include/c++/3.4.5/bits/stl_construct.h:81)
#1 00462306 std::_Rb_tree<double, std::pair<double const, int>, std::_Select1st<std::pair<double const, int> >, std::less<double>, std::allocator<std::pair<double const, int> > >::_M_create_node(this=0x406fe50, __x=@0x10) (C:/Program Files/CodeBlocks/MinGW/bin/../lib/gcc/mingw32/3.4.5/../../../../include/c++/3.4.5/bits/stl_tree.h:367)
#2 00461DA7 std::_Rb_tree<double, std::pair<double const, int>, std::_Select1st<std::pair<double const, int> >, std::less<double>, std::allocator<std::pair<double const, int> > >::_M_clone_node(this=0x406fe50, __x=0x0) (C:/Program Files/CodeBlocks/MinGW/bin/../lib/gcc/mingw32/3.4.5/../../../../include/c++/3.4.5/bits/stl_tree.h:379)
#3 004625C6 std::_Rb_tree<double, std::pair<double const, int>, std::_Select1st<std::pair<double const, int> >, std::less<double>, std::allocator<std::pair<double const, int> > >::_M_copy(this=0x406fe50, __x=0x0, __p=0x406fe54) (C:/Program Files/CodeBlocks/MinGW/bin/../lib/gcc/mingw32/3.4.5/../../../../include/c++/3.4.5/bits/stl_tree.h:1029)
#4 00462A9D std::_Rb_tree<double, std::pair<double const, int>, std::_Select1st<std::pair<double const, int> >, std::less<double>, std::allocator<std::pair<double const, int> > >::_Rb_tree(this=0x406fe50, __x=@0xb59a7c) (C:/Program Files/CodeBlocks/MinGW/bin/../lib/gcc/mingw32/3.4.5/../../../../include/c++/3.4.5/bits/stl_tree.h:559)
#5 0045A928 std::map<double, int, std::less<double>, std::allocator<std::pair<double const, int> > >::map(this=0x406fe50, __x=@0xb59a7c) (C:/Program Files/CodeBlocks/MinGW/bin/../lib/gcc/mingw32/3.4.5/../../../../include/c++/3.4.5/bits/stl_map.h:166)
#6 0040B7E2 VehicleManager::get_vehicles_distances(this=0xb59a50) (C:/Program Files/CodeBlocks/MinGW/projects/AHS/VehicleManager.cpp:232)
#7 00407BDA Supervisor::IsMergeInstruction(id_vehicle=1) (C:/Program Files/CodeBlocks/MinGW/projects/AHS/Supervisor.cpp:77)
#8 00408430 CheckingInstructionsThread(arg=0x476100) (C:/Program Files/CodeBlocks/MinGW/projects/AHS/Supervisor.cpp:264)
#9 00413950 _glfwNewThread@4() (??:??)
#10 75A24911    KERNEL32!AcquireSRWLockExclusive() (C:\Windows\system32\kernel32.dll:??)
#11 00476100    std::__ioinit() (??:??)
#12 0406FFD4    ??() (??:??)
#13 76E5E4B6    ntdll!RtlInitializeNtUserPfn() (C:\Windows\system32\ntdll.dll:??)
#14 00476100    std::__ioinit() (??:??)
#15 70266582    ??() (??:??)
#16 00000000    ??() (??:??)

Noch ein paar Präzisierungen:

1/ Es handelt sich um eine Multithread-Anwendung.2/ Die Methode:get_vehicles_distances();gibt eine Karte zurück.3/ Es ist möglich, dass die Karte zum Zeitpunkt des Aufrufs durch IsMergeInstruction() nicht initialisiert ist;

Bearbeiten:

Anscheinend ist die Zeile, die den Segfault verursacht, folgende:

vehicles_distances_.erase(vehicles_distances_.begin(), vehicles_distances_.end());

Wobei „vehikel_distanzen_“ die Karte ist.Diese Zeile ist Teil der Methode:VehicleManager::MoveAllVehicles();

void VehicleManager::MoveAllVehicles() {

     vehicles_distances_.erase(vehicles_distances_.begin(), vehicles_distances_.end());

     vector<Vehicle>::iterator iter_end = VehicleManager::vehicles_.end();
     for(vector<Vehicle>::iterator iter = VehicleManager::vehicles_.begin();
     iter != iter_end; ++iter) {

          (*iter).MoveVehicle();

          vehicles_distances_[(*iter).get_vec_vehicle_position().y] = (*iter).get_id_vehicle();

     }

}

Was stimmt damit nicht ?

Bearbeiten:

Ich habe versucht, map::clear();als Ersatz für map::erase();aber das gleiche Problem tritt auf!

Bearbeiten:

Ich glaube, ich verstehe...Ein Thread versucht, „vehicles_distances_“ zu nutzen, während er gelöscht wird.(?)

Bearbeiten:

Problem gelöst!Es kam also von der Map::erase();wie erwartet.Ich habe das Problem umgangen, indem ich eine weitere Kartenvariable erstellt habe, in der sich das Paar befindet <key, value> wurde invertiert, damit ich die Karte aktualisieren kann.(Da der Schlüssel, den ich brauche, die Entfernung ist, und die Entfernung nicht eindeutig ist, da sie sich jedes Mal ändert, aber das id_vehicle ist eindeutig!).Am Ende habe ich einfach diese Karte genommen und sie invertiert <key, value> erneut und übertrug es auf die ursprüngliche Karte, die in jedem Zyklus neu deklariert werden kann ...

Vielen Dank an alle!

War es hilfreich?

Lösung

Erstens aus Liebe zu allem, was, nun ja, liebenswert ist, Verwenden Sie kein Dev-C++.Ich wünschte, ich wüsste, wie die Leute immer wieder auf dieses Stück Müll stoßen.Es wurde nicht gewartet Jahre, und selbst als es gewartet wurde, war es immer noch ein fehlerhaftes Stück Schrott, dem es an grundlegender Funktionalität mangelte.Vergessen Sie es und entscheiden Sie sich für eine der unzähligen besseren kostenlosen Alternativen.

Nun zu Ihrer Frage:Ihr Programm weist willkürlich einen Seg-Fehler auf, weil Sie zuvor etwas Illegales getan haben.Tu das nicht.;)

Wenn Ihr Programm irgendwo außerhalb der Grenzen schreibt, kann alles passieren.Möglicherweise wird eine nicht zugewiesene Seite aufgerufen. In diesem Fall erhalten Sie einen Segfault.Oder es trifft möglicherweise auf nicht verwendete Daten auf einer Seite, die Ihrem Prozess zugeordnet ist. In diesem Fall hat es keine praktische Wirkung (es sei denn, es wird anschließend ordnungsgemäß initialisiert, wobei Ihr erster, illegaler Schreibvorgang überschrieben wird und Sie dann versuchen, daraus zu lesen , in der Erwartung, dass der ursprüngliche (ungültige) Wert noch vorhanden ist.Oder es trifft auf Daten zu, die tatsächlich verwendet werden. In diesem Fall erhalten Sie später Fehlermeldungen, wenn das Programm versucht, diese Daten zu lesen.

Beim Lesen von Daten gibt es nahezu die gleichen Szenarien.Sie können Glück haben und sofort einen Segfault erhalten, oder Sie können auf ungenutzten und nicht initialisierten Speicher zugreifen und fehlerhafte Daten auslesen (was höchstwahrscheinlich später zu einem Fehler führen wird, wenn diese Daten verwendet werden), oder Sie können aus Speicheradressen lesen, die vorhanden sind bereits in Gebrauch (wodurch auch Müll rauskommt).

Also ja, diese Fehler sind schwierig zu finden.Der beste Rat, den ich geben kann, ist: 1) Asserts über den gesamten Code zu verteilen, um sicherzustellen, dass grundlegende Invarianten beibehalten werden, und 2) das Programm Schritt für Schritt durchzugehen und bei jedem Schritt zu überprüfen, dass Sie nicht an Adressen lesen oder schreiben, die nicht an Adressen schreiben, an die keine Adressen gesendet werden. Es gehört nicht dir.

MSVC verfügt standardmäßig über eine sichere SCL-Option, die eine Grenzüberprüfung des STL-Codes durchführt, was dabei helfen kann, Fehler wie diesen zu erkennen.

Ich glaube, dass GCC eine Option hat, etwas Ähnliches zu tun (diese ist jedoch standardmäßig nicht aktiviert).

Segfaults sind böse.Wenn Menschen ein paar Mal von einem solchen Fehler betroffen sind, neigen sie dazu, viel disziplinierter zu werden und den Zugriff auf den Speicher außerhalb der Grenzen zu vermeiden.:) :)

Andere Tipps

Sie könnten versuchen, Valgrind als eine Möglichkeit, das Problem zu finden. In Anbetracht der Zeile, die Sie in die Frage gestellt habe, würde ich erraten, dass Sie entweder haben die Heap beschädigt, oder Sie haben einen Stapel Problem.

Die offensichtliche Frage sei: „Was ist _p“. Im Debugger sollten Sie bei der Aufrufliste aussehen können. Folgen Sie _p zurück zu seinem Ursprung. Bestätigen Sie seine die richtige Größe, dass sie nicht gelöscht, und dass es tatsächlich existiert.

Wenn das nicht so einfach ist, gibt es immer die Brute-Force-Methoden der Kommentierung stich (Verdacht) Code, bis es funktioniert oder geht zurück und diffing gegen eine bekannten, Arbeitskopie.

Das ist unglaublich vage, so ist es fast unmöglich zu beantworten. Ein offensichtlicher Vorschlag wäre, zu überprüfen, ob Sie die Initialisierung aller Variablen. Einige Compiler Ihre uninitialized Sachen in der Debug-Null aus und nicht, dass zum Beispiel in Release tun, was zu zufälligen und unerwarteten Ergebnissen führen.

Sie können mit _CrtSetDbgFlag() bei der einige Heap-Debugging-Optionen Ihres Programms beginnen zu ermöglichen. Siehe auch Der CRT Debug Heap . Dies können Ihnen helfen, nach unten zu verfolgen, wo Sie mit dem Gedächtnis schlechte Dinge tun. Es ist in Microsoft C-Laufzeit, mit dem Sie die MinGW Compiler Links gegen standardmäßig. Wenn Sie stattdessen GNU C-Laufzeit, dann werden Sie nicht in der Lage sein, diesen Weg zu gehen.

Das Problem ist viel wahrscheinlicher als in stl_construct.h in Ihrem Code zu sein. Ich gehe davon aus, dass Datei Teil der STL-Distribution für Dev-C ++ ist. Die Segmentierung Fehler können in Code geschehen, dass die Vorlagen in stl_construct.h instanziiert wurde mit, aber die Ursache des Problems wird an anderer Stelle sein. Ich würde versuchen, dieses Problem zu lösen, indem Sie den Stack-Trace zum Zeitpunkt des Absturzes zu bekommen. Für jede Funktion in dem Stack-Trace (vor allem diejenigen, die neu geschrieben werden), versuchen, den Code zu überprüfen und suchen Sie die folgenden Arten von möglichen Fehler:

  • Uninitialized Variablen (insbesondere Indizes für Array-Zugriff verwendet wird)
  • Speicher verwendet wird, nachdem es freigegeben oder gelöscht wurde.
  • Array Zugriff außerhalb der Grenzen des Arrays
  • Die Speicherzuordnung, die ohne Kontrolle für NULL verwendet wird (kein Problem, wenn Sie neu verwenden, da die NULL nicht zurück, es löst eine Ausnahme)

Ihre Beschreibung und der Call-Stack, deuten darauf hin, dass das Programm bei der Initialisierung von statischen Variablen abstürzt. Dies ist ein häufiger Fehler von C ++. Es gibt keine einfache Möglichkeit, die Reihenfolge der Initialisierung für statische Variablen zu steuern

Zum Beispiel Ihr Programm kann Objekt foo haben, die auf dem Objekt bar abhängt; aber es kann sein, dass das Programm den Konstruktor für foo ruft, bevor es bar konstruiert. Das wäre schlecht, und könnte die Art von Problem verursachen Sie beschreiben. (Ist CheckingInstructionsThread eine statische Variable, die einen Thread laicht? Das ist das Problem genau dort sein könnte.)

Um dies zu beheben, müssen Sie Ihr Programm CPP-Dateien für statische Variablen suchen bis (einschließlich der Klassen Statik und Globals), insbesondere solche, die einer Klasse-Typ sind. Es kann oder auch nicht helfen, Ihre Konstrukteure zu modifizieren einige Spuren zu stderr schreiben; verwenden fprintf anstatt cerr wenn Sie dies tun.

Bearbeiten : Wenn Sie nicht sicher sind, ob es etwas mit der Statik zu tun hat, versuchen Sie eine Zeile wie diese zu Beginn des main() setzen:

 fprintf(stderr, "main() entered\n");

Dies würde nicht statische Initialisierung als Ursache des Problems auszuschließen; auch wenn es nicht tut Absturz vor main(), könnten Sie noch Datenstrukturen haben falsch aufgebaut. Aber, wenn Sie nie auf die fprintf bekommen, dann Sie wissen, , dass statische Initialisierung ist die Ursache.

Was bedeutet der Stack-Trace Ihnen sagt, nach den Debugger mit der Core-Datei ausgeführt wird? laufen gdb die normale Art und Weise GDB a.out

dann untersucht die Core-Datei

  

Kern a.out.core

Und werfen Sie einen Blick auf den Stapel

  

bt

Dies ist höchstwahrscheinlich auf ungültig erklärten Iterator in Verbindung stehend - Suche nach Orten, wo man über Container durchlaufen und / oder Iteratoren in Behälter halten und entfernen / einfügen Elemente zugleich
Und wie alle andere bemerkt -. Verwenden, um eine Call- stapeln die genaue Stelle zu finden.

Das erste, was Sie tun müssen, wenn Sie im Code am Ende, die gründlich getestet wurden, die nicht dein ist den Call-Stack hinauf, bis Sie in Ihrem eigenen Code am Ende, wo Sie die Informationen finden, die dieses Problem verursacht passieren.

In der Call-Stack den wichtigsten Standorts zu suchen ist in Ihrem Code (der Anrufer) und die Parameter an die Funktion übergeben Sie (die Angerufene) genannt.

Ohne diese Informationen können wir Ihnen nicht mehr helfen. ; -)

Mehr über die Segmentierung Fehler: http://en.wikipedia.org/wiki/Segmentation_fault
(Muss-lesen, auch die Links unter „Siehe auch“ und „Externe Links“)

Karten sind nicht sehr fädeln freundlich. Wenn Sie Map-Operationen in Thread-Code ausführen müssen Sie wirklich sperren alle auf diese Karte zugreift und realisieren alle Iteratoren Sie halten kann für ungültig erklärt werden könnten.

Es sieht aus wie eine gefährliche Funktion:)

Eine Sache striked mich aber. Wohin geht die zugewiesenen Speicher? Intuitiv würde Ich mag einen Zeiger auf einen Zeiger als erstes Argument haben, und dann dereferenzieren. Wie folgt aus:

template<typename _T1, typename _T2>
    inline void
    _Construct(_T1** __p, const _T2& __value)
    {

       ::new(static_cast<void*>(*__p)) _T1(__value);
    }

Alternativ kann ein Verweis auf einen Zeiger:

template<typename _T1, typename _T2>
    inline void
    _Construct(_T1*& __p, const _T2& __value)
    {

       ::new(static_cast<void*>(__p)) _T1(__value);
    }

Der Debugger sollte lassen Sie den Call-Stack nach oben. Auf diese Weise sollten Sie den Platz in Ihrem eigenen Code zu sehen, der Lage sein, die den seg Fehler verursacht.

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