Segmentatiefouten in C++ oplossen

Ik schrijf een platformonafhankelijk C++-programma voor Windows en Unix. Aan de Window-kant zal de code zonder problemen worden gecompileerd en uitgevoerd. Aan de Unix-kant zal het compileren, maar wanneer ik het probeer uit te voeren, krijg ik een segmentatiefout. Mijn eerste vermoeden is dat er een probleem is met pointers.

Wat zijn goede methoden om fouten in segmentatiefouten te vinden en op te lossen?


Antwoord 1, autoriteit 100%

  1. Compileer je applicatie met -g, dan heb je debug-symbolen in het binaire bestand.

  2. Gebruik gdbom de gdb-console te openen.

  3. Gebruik fileen geef het door aan het binaire bestand van uw toepassing in de console.

  4. Gebruik runen geef eventuele argumenten op die uw toepassing nodig heeft om te starten.

  5. Doe iets om een Segmentatiefoutte veroorzaken.

  6. Typ btin de gdb-console om een stacktracering van de Segmentation Faultte krijgen.


Antwoord 2, autoriteit 24%

Soms is de crash zelf niet de echte oorzaak van het probleem — misschien is het geheugen eerder kapot gegaan, maar het duurde even voordat de corruptie zichtbaar werd. Bekijk valgrind, dat veel controles heeft op aanwijzerproblemen (inclusief het controleren van arraygrenzen). Het vertelt je waar het probleem begint, niet alleen de regel waar de crash optreedt.


Antwoord 3, autoriteit 14%

Voordat het probleem zich voordoet, probeer het zoveel mogelijk te vermijden:

  • Compileer en voer uw code zo vaak mogelijk uit. Het defecte onderdeel is gemakkelijker te vinden.
  • Probeer low-level / foutgevoelige routines in te kapselen, zodat je zelden direct met geheugen hoeft te werken (let op de modellering van je programma)
  • Houd een test-suite bij. Het hebben van een overzicht van wat momenteel werkt, wat is er niet meer aan het werk, enz., Helpt u om erachter te komen waar het probleem is (boost-test is een mogelijke oplossing, ik gebruik het zelf niet, maar de documentatie kan helpen begrijpen wat voor soort informatie moet worden weergegeven) .

Gebruik geschikte hulpmiddelen voor foutopsporing. Op Unix:

  • GDB kan u vertellen waar u een crash programmeert en u kunt zien welke context.
  • Valgrind helpt u om veel geheugengerelateerde fouten te detecteren.
  • Met GCC kunt u wadflap met GCC, gebruiken Clang en sinds oktober experimenteel MSVC U kunt gebruiken adres / geheugen sanitizer . Het kan enkele fouten detecteren die Valtrin niet en het prestatieverlies is lichter. Het wordt gebruikt door het samen te stellen met de -fsanitize=addressvlag.

Eindelijk zou ik de gebruikelijke dingen aanbevelen. Hoe meer uw programma leesbaar, onderhoudbaar, duidelijk en netjes is, het gemakkelijkst dat het zal zijn om te debuggen.


Antwoord 4, Autoriteit 4%

Op Unix kun je valgrindgebruiken om problemen te vinden. Het is gratis en krachtig. Als je het liever zelf doet, kun je de operators newen deleteoverbelasten om een configuratie in te stellen waarbij je 1 byte hebt met 0xDEADBEEFvoor en na elk nieuw object. Houd vervolgens bij wat er bij elke iteratie gebeurt. Dit kan niet alles vangen (je bent niet gegarandeerd dat je die bytes zelfs maar aanraakt), maar het heeft in het verleden voor mij gewerkt op een Windows-platform.


Antwoord 5, autoriteit 2%

Ja, er is een probleem met pointers. Zeer waarschijnlijk gebruik je er een die niet correct is geïnitialiseerd, maar het is ook mogelijk dat je je geheugenbeheer verprutst met dubbele vrijgaven of iets dergelijks.

Om niet-geïnitialiseerde pointers als lokale variabelen te voorkomen, kunt u proberen ze zo laat mogelijk te declareren, bij voorkeur (en dit is niet altijd mogelijk) wanneer ze kunnen worden geïnitialiseerd met een zinvolle waarde. Overtuig uzelf dat ze een waarde hebben voordat ze worden gebruikt, door de code te onderzoeken. Als je daar moeite mee hebt, initialiseer ze dan naar een null-pointerconstante (meestal geschreven als NULLof 0) en controleer ze.

Om niet-geïnitialiseerde pointers als lidwaarden te voorkomen, moet u ervoor zorgen dat ze correct zijn geïnitialiseerd in de constructor en correct worden behandeld in kopieerconstructors en toewijzingsoperators. Vertrouw niet op een init-functie voor geheugenbeheer, hoewel u dat wel kunt doen voor andere initialisaties.

Als je klas geen kopieerconstructors of toewijzingsoperators nodig heeft, kun je ze declareren als privélidfuncties en ze nooit definiëren. Dat veroorzaakt een compilerfout als ze expliciet of impliciet worden gebruikt.

Gebruik indien van toepassing slimme aanwijzers. Het grote voordeel hier is dat, als je je eraan houdt en ze consequent gebruikt, je het schrijven van deletevolledig kunt vermijden en dat er niets dubbel wordt verwijderd.

Gebruik waar mogelijk C++-tekenreeksen en containerklassen in plaats van tekenreeksen en arrays in C-stijl. Overweeg om .at(i)te gebruiken in plaats van [i], omdat dit het controleren van de grenzen zal forceren. Kijk of je compiler of bibliotheek kan worden ingesteld om grenzen te controleren op [i], in ieder geval in debug-modus. Segmentatiefouten kunnen worden veroorzaakt door bufferoverschrijdingen die rommel over perfect goede pointers schrijven.

Als u deze dingen doet, wordt de kans op segmentatiefouten en andere geheugenproblemen aanzienlijk verkleind. Ze zullen ongetwijfeld niet alles oplossen, en daarom moet je af en toe valgrind gebruiken als je geen problemen hebt, en valgrind en gdb als je dat wel doet.


Antwoord 6

Ik ken geen methode om dit soort dingen op te lossen. Ik denk niet dat het mogelijk zou zijn om er een te bedenken, want het probleem zelf is dat het gedrag van je programma niet gedefinieerd is (ik ken geen enkel geval waarin SEGFAULT niet is veroorzaakt door een soort van UB) .

Er zijn allerlei “methodologieën” om het probleem te voorkomen voordat het zich voordoet. Een belangrijke is RAII.

Bovendien moet je er gewoon je beste psychische energie voor inzetten.

Other episodes