Op deze pagina:
- Overzicht
- Voorbeelden van veel voorkomende segfaults
- Zoeken out-of-bounds array referenties
- kijk shell grenzen
- Gebruik debuggers te diagnosticeren segfaults
Overzicht
Een segmentation fault (ook bekend als een segmentatie fout geeft) is een veel voorkomende aandoening die ervoor zorgt dat programma ‘ s crashen; ze worden vaak geassocieerd met een bestand met de naam core
. Segfaults worden veroorzaakt door een programma dat probeert te lezen of schrijven van een illegale geheugenlocatie.
het Programma-geheugen is verdeeld in verschillende segmenten: een tekst-segment voor programma-instructies, een segment van gegevens voor de variabelen en arrays gedefinieerd tijdens het compileren, een stack segment voor tijdelijke (of automatische) variabelen die zijn gedefinieerd in subroutines en functies, en een hoop segment voor variabelen toegewezen tijdens runtime-functies, zoals malloc
(in C) en allocate
(in Fortran). Zie Over programmasegmenten voor meer informatie.
een segfault treedt op wanneer een verwijzing naar een variabele buiten het segment valt waar die variabele zich bevindt, of wanneer een schrijfpoging wordt gedaan naar een locatie die zich in een alleen-lezen segment bevindt. In de praktijk zijn segfaults bijna altijd te wijten aan het lezen of schrijven van een niet-bestaand array-element, het niet goed definiëren van een aanwijzer voordat het wordt gebruikt, of (in C-programma ‘ s) per ongeluk het gebruik van de waarde van een variabele als een adres (zie het scanf
voorbeeld hieronder).
Voorbeelden van veel voorkomende segfaults
- bijvoorbeeld, bellen
memset()
zoals hieronder getoond zou ertoe leiden dat een programma een segmentatie fout geeft:memset((char *)0x0, 1, 100);
- De volgende drie gevallen illustreren de meest voorkomende vormen van array-gerelateerde segfaults:
Geval Een /* "Array out of bounds" error valid indices for array foo are 0, 1, ... 999 */ int foo; for (int i = 0; i <= 1000 ; i++) foo = i;
Geval B /* Illegal memory access if value of n is not in the range 0, 1, ... 999 */ int n; int foo; for (int i = 0; i < n ; i++) foo = i;
Zaak C /* Illegal memory access because no memory is allocated for foo2 */ float *foo, *foo2; foo = (float*)malloc(1000); foo2 = 1.0;
- In geval van Een, array
foo
gedefinieerd voorindex = 0,1, 2, ... 999
. In de laatste iteratie van de lusfor
probeert het programma echter toegang te krijgen totfoo
. Dit zal resulteren in een segfault als die geheugenlocatie buiten het geheugensegment ligt waarfoo
zich bevindt. Zelfs als het geen segfault veroorzaakt, is het nog steeds een bug. - in geval B kan integer
n
een willekeurige waarde zijn. Zoals in het geval A, als het niet in het bereik0, 1, ... 999
ligt, kan het een segfault veroorzaken. Of het nu wel of niet, het is zeker een bug. - in geval C wordt de toewijzing van geheugen voor variabele
foo2
over het hoofd gezien, dusfoo2
wijst naar een willekeurige locatie in het geheugen. Toegang totfoo2
zal waarschijnlijk resulteren in een segfault.
- In geval van Een, array
- een andere veel voorkomende programmeerfout die leidt tot segfaults is oversight in het gebruik van pointers. Bijvoorbeeld, de c functie
scanf()
verwacht het adres van een variabele als zijn tweede parameter; daarom zal het volgende waarschijnlijk ervoor zorgen dat het programma crasht met een segfault:int foo = 0; scanf("%d", foo); /* Note missing & sign ; correct usage would have been &foo */
de variabele
foo
kan worden gedefinieerd op geheugenlocatie1000
, maar de bovenstaande functie aanroep zou proberen om integer gegevens in geheugenlocatie te lezen0
volgens de definitie vanfoo
. - een segfault zal optreden wanneer een programma probeert op een geheugenlocatie te werken op een manier die niet is toegestaan (bijvoorbeeld, pogingen om een alleen-lezen locatie te schrijven zouden resulteren in een segfault).
- Segfaults kunnen ook optreden wanneer uw programma geen stackruimte meer heeft. Dit is misschien geen bug in je programma, maar het kan te wijten zijn aan het feit dat je shell de limiet voor stackgrootte te klein heeft ingesteld.
Find out-of-bounds array references
De meeste Fortran compilers hebben een optie die code invoegt om grenzen te controleren op alle array referenties tijdens runtime. Als een toegang buiten het indexbereik valt dat is gedefinieerd voor een array, zal het programma stoppen en je vertellen waar dit gebeurt. Voor de meeste Fortran-compilers is de optie -C
, of -check
gevolgd door een trefwoord. Zie de gebruikershandleiding van uw compiler om de exacte optie te krijgen. Gebruik bounds controle alleen bij het debuggen, omdat het zal vertragen uw programma. Sommige C compilers hebben ook een optie om grenzen te controleren.
Check shell limieten
zoals opgemerkt in het laatste voorbeeld hierboven, zijn sommige segfault problemen niet te wijten aan bugs in uw programma, maar worden in plaats daarvan veroorzaakt door systeemgeheugen limieten die te laag zijn ingesteld. Meestal is het de limiet op stapelgrootte die dit soort problemen veroorzaakt. Om geheugenlimieten te controleren, gebruik je de opdracht ulimit
In bash
of ksh
, of de opdracht limit
In csh
of tcsh
. Probeer het instellen van de stacksize hoger, en vervolgens opnieuw uitvoeren van uw programma om te zien of de segfault verdwijnt.
gebruik debuggers om segfaults te diagnosticeren
Als u het probleem niet op een andere manier kunt vinden, kunt u een debugger proberen. U kunt bijvoorbeeld GNU ‘ s bekende debugger GDB
gebruiken om de backtrace te bekijken van een core
bestand gedumpt door uw programma; wanneer programma ‘ s segfault, dumpen ze meestal de inhoud van (hun sectie van het) geheugen op het moment van de crash in een core
bestand. Start uw debugger met het commando gdb core
, en gebruik vervolgens het commando backtrace
om te zien waar het programma was toen het crashte. Deze eenvoudige truc zal u toelaten om zich te concentreren op dat deel van de code.
als het gebruik van backtrace
op het core
g bestand het probleem niet vindt, moet u het programma mogelijk uitvoeren onder debugger control, en dan stap door de code één functie, of één broncode regel, tegelijk. Om dit te doen, moet u uw code compileren zonder optimalisatie, en met de -g
vlag, zodat informatie over broncode regels zal worden ingebed in het uitvoerbare bestand. Voor meer, zie stap-voor-stap voorbeeld voor het gebruik van GdB binnen Emacs om een C orC++ programma te debuggen.