På denne side:
- oversigt
- eksempler på almindelige segfaults
- Find out-of-bounds array referencer
- kontroller shell grænser
- brug debuggere til diagnosticering af segfaults
oversigt
en segmenteringsfejl (aka segfault) er en almindelig tilstand, der får programmer til at gå ned; de er ofte forbundet med en fil med navnet core
. Segfaults er forårsaget af et program forsøger at læse eller skrive en ulovlig hukommelse placering.
programhukommelse er opdelt i forskellige segmenter: et tekstsegment for programinstruktioner, et datasegment for variabler og arrays defineret på kompileringstidspunktet, et staksegment for midlertidige (eller automatiske) variabler defineret i underrutiner og funktioner og et heap-segment for variabler tildelt under runtime efter funktioner, såsommalloc
(i C) ogallocate
(i Fortran). For mere, se om programsegmenter.
en segmenteringsfejl opstår, når en henvisning til en variabel falder uden for det segment, hvor variablen befinder sig, eller når en skrivning forsøges til en placering, der er i et skrivebeskyttet segment. I praksis skyldes segfaults næsten altid at forsøge at læse eller skrive et ikke-eksisterende array-element, der ikke definerer en markør korrekt, før den bruges, eller (i C-programmer) ved et uheld at bruge en variabels værdi som en adresse (se scanf
eksempel nedenfor).
eksempler på almindelige segfaults
- for eksempel kalder
memset()
som vist nedenfor ville få ET program til segfault:memset((char *)0x0, 1, 100);
- de følgende tre tilfælde illustrerer de mest almindelige typer array-relaterede segfaults:
Case A /* "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;
sag 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;
sag C /* Illegal memory access because no memory is allocated for foo2 */ float *foo, *foo2; foo = (float*)malloc(1000); foo2 = 1.0;
- i tilfælde A, array
foo
er defineret forindex = 0,1, 2, ... 999
. I den sidste iteration affor
loop forsøger programmet at få adgang tilfoo
. Dette vil resultere i en segfault, hvis denne hukommelsesplacering ligger uden for hukommelsessegmentet, hvorfoo
ligger. Selvom det ikke forårsager en segfault, er det stadig en fejl. - i tilfælde B, heltal
n
kunne være en tilfældig værdi. Som i tilfælde A, hvis det ikke er i området0, 1, ... 999
, kan det forårsage en segfault. Uanset om det gør det eller ej, er det bestemt en fejl. - i tilfælde C, tildeling af hukommelse til variabel
foo2
er blevet overset, såfoo2
vil pege på en tilfældig placering i hukommelsen. Adgang tilfoo2
vil sandsynligvis resultere i en segfault.
- en anden almindelig programmeringsfejl, der fører til segfaults, er tilsyn med brugen af pointers. For eksempel C-funktionen
scanf()
forventer adressen på en variabel som dens anden parameter; derfor vil følgende sandsynligvis få programmet til at gå ned med en segfault:int foo = 0; scanf("%d", foo); /* Note missing & sign ; correct usage would have been &foo */
variablen
foo
kan defineres på hukommelsesplacering1000
, men ovenstående funktionsopkald ville forsøge at læse heltalsdata til hukommelsesplacering0
ifølge definitionen affoo
.- der opstår en segfault, når ET program forsøger at operere på en hukommelsesplacering på en måde, der ikke er tilladt (for eksempel vil forsøg på at skrive en skrivebeskyttet placering resultere i en segfault).
- Segfaults kan også forekomme, når dit program løber tør for stakplads. Dette er muligvis ikke en fejl i dit program, men kan i stedet skyldes, at din skal indstiller stakstørrelsesgrænsen for lille.
Find out-of-bounds array referencer
de fleste Fortran compilere har en mulighed, der vil indsætte kode til at gøre grænser kontrol på alle array referencer under runtime. Hvis en adgang falder uden for det indeksområde, der er defineret for et array, stopper programmet og fortæller dig, hvor dette sker. For de fleste Fortran-kompilatorer er indstillingen
-C
eller-check
efterfulgt af et nøgleord. Se din kompilators brugervejledning for at få den nøjagtige mulighed. Brug kun grænsekontrol, når du debugger, da det vil bremse dit program. Nogle C-kompilatorer har også en mulighed for grænsekontrol.kontroller shell-grænser
som bemærket i det sidste eksempel ovenfor skyldes nogle segfault-problemer ikke fejl i dit program, men skyldes i stedet, at systemhukommelsesgrænser er indstillet for lave. Normalt er det grænsen for stack størrelse, der forårsager denne form for problem. For at kontrollere hukommelsesgrænser skal du bruge kommandoen
ulimit
ibash
ellerksh
eller kommandoenlimit
icsh
div>ellertcsh
. Prøv at indstille stackstørrelsen højere, og kør derefter dit program igen for at se, om segfault forsvinder.brug debuggere til at diagnosticere segfaults
Hvis du ikke kan finde problemet på nogen anden måde, kan du prøve en debugger. For eksempel kan du bruge GNU ‘ s velkendte debugger
GDB
for at se backtrace af encore
fil dumpet af dit program; når programmer segfault, dumper de normalt indholdet af (deres sektion af) hukommelsen på tidspunktet for nedbruddet i encore
fil. Start din debugger med kommandoengdb core
, og brug derefter kommandoenbacktrace
for at se, hvor programmet var, da det styrtede ned. Dette enkle trick giver dig mulighed for at fokusere på den del af koden.Hvis du bruger
backtrace
påcore
g-filen ikke finder problemet, skal du muligvis køre programmet under debugger-kontrol og derefter gå gennem koden en funktion eller en kildekodelinje ad gangen. For at gøre dette skal du kompilere din kode uden optimering, og med-g
flag, så oplysninger om kildekodelinjer vil blive indlejret i den eksekverbare fil. For mere, Se trin-for-trin eksempel for at bruge GDB i Emacs til at debugge et c orC++ – program.relaterede dokumenter
- i tilfælde A, array