Indiana University Indiana University Indiana University

på denna sida:

  • översikt
  • exempel på vanliga segfaults
  • ta reda på Out-of-bounds array referenser
  • kontrollera skalgränser
  • använd felsökare för att diagnostisera segfaults

översikt

ett segmenteringsfel (aka segfault) är ett vanligt tillstånd som får program att krascha; De är ofta associerade med en fil med namnet core. Segfaults orsakas av ett program som försöker läsa eller skriva en olaglig minnesplats.

programminnet är uppdelat i olika segment: ett textsegment för programinstruktioner, ett datasegment för variabler och arrayer definierade vid kompileringstid, ett stacksegment för tillfälliga (eller automatiska) variabler definierade i underrutiner och funktioner och ett heapsegment för variabler som tilldelats under körning av funktioner, till exempel malloc (I C) och allocate (I Fortran). För mer information, se om programsegment.

en segfault inträffar när en referens till en variabel faller utanför det segment där variabeln finns, eller när en skrivning försöks till en plats som är i ett skrivskyddat segment. I praktiken beror segfaults nästan alltid på att man försöker läsa eller skriva ett obefintligt arrayelement, inte korrekt definiera en pekare innan man använder den, eller (i C-program) av misstag använder en variabels värde som adress (se scanf exempel nedan).

exempel på vanliga segfaults

  • till exempel ringer memset() som visas nedan skulle orsaka ett program till segfault:
    memset((char *)0x0, 1, 100);
  • följande tre fall illustrerar de vanligaste typerna av array-relaterade 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;

    case 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;

    case c

    /* Illegal memory access because no memory is allocated for foo2 */ float *foo, *foo2; foo = (float*)malloc(1000); foo2 = 1.0;

    • i fall A, array foo definieras för index = 0,1, 2, ... 999. Men i den sista iterationen av for loop försöker programmet komma åt foo. Detta resulterar i en segfault om minnesplatsen ligger utanför minnessegmentet där foo finns. Även om det inte orsakar en segfault är det fortfarande en bugg.
    • i fall B kan heltal n vara vilket slumpmässigt värde som helst. Som i fall A, om det inte ligger i intervallet 0, 1, ... 999, kan det orsaka en segfault. Oavsett om det gör det eller inte, det är verkligen en bugg.
    • i fall C, tilldelning av minne för variabel foo2 har förbises, så foo2 kommer att peka på en slumpmässig plats i minnet. Åtkomst till foo2 kommer sannolikt att resultera i en segfault.
  • ett annat vanligt programmeringsfel som leder till segfaults är övervakning vid användning av pekare. Till exempel förväntar sig C-funktionen scanf() adressen till en variabel som sin andra parameter; därför kommer följande sannolikt att orsaka att programmet kraschar med en segfault:
    int foo = 0; scanf("%d", foo); /* Note missing & sign ; correct usage would have been &foo */

    variabeln foo kan definieras på minnesplats 1000, men ovanstående funktionssamtal skulle försöka läsa heltalsdata till minnesplats 0 enligt definitionen av foo.

  • en segfault kommer att inträffa när ETT program försöker fungera på en minnesplats på ett sätt som inte är tillåtet (till exempel försök att skriva en skrivskyddad plats skulle resultera i en segfault).
  • Segfaults kan också uppstå när programmet tar slut stack utrymme. Det här kanske inte är ett fel i ditt program, men kan bero på att ditt skal ställer in stackstorleksgränsen för liten.

ta reda på Out-of-bounds array referenser

de flesta Fortran kompilatorer har ett alternativ som kommer att infoga kod för att göra bounds kontroll på alla array referenser under körning. Om en åtkomst faller utanför indexområdet definierat för en array stannar programmet och berättar var detta inträffar. För de flesta Fortran-kompilatorer är alternativet -C eller -check följt av ett nyckelord. Se kompilatorns användarhandbok för att få det exakta alternativet. Använd bounds kontroll endast vid felsökning, eftersom det kommer att sakta ner ditt program. Vissa C-kompilatorer har också ett alternativ för gränskontroll.

kontrollera skalgränser

som noterats i det sista exemplet ovan beror vissa segfault-problem inte på fel i ditt program, utan orsakas istället av att systemminnesgränserna är för låga. Vanligtvis är det gränsen för stackstorlek som orsakar denna typ av problem. För att kontrollera minnesgränserna, använd kommandot ulimit I bash eller ksh, eller kommandot limit I csh eller tcsh. Försök ställa in stacksize högre och kör sedan programmet igen för att se om segfault försvinner.

använd felsökare för att diagnostisera segfaults

Om du inte hittar problemet på något annat sätt kan du prova en debugger. Du kan till exempel använda GNU: s välkända debugger GDB för att visa backtrace för en core fil dumpad av ditt program; när program segfault, dumpar de vanligtvis innehållet i (deras avsnitt av) minnet vid kraschen till en core fil. Starta din debugger med kommandot gdb core och använd sedan kommandot backtrace för att se var programmet var när det kraschade. Detta enkla trick låter dig fokusera på den delen av koden.

Om du använder backtracecoreg-filen inte hittar problemet kan du behöva köra programmet under felsökningskontroll och sedan gå igenom koden en funktion, eller en källkodsrad, åt gången. För att göra detta måste du kompilera din kod utan optimering, och med flaggan -g, så kommer information om källkodslinjer att inbäddas i den körbara filen. Mer information finns i steg-för-steg-exempel för att använda GDB inom Emacs för att felsöka ett C orC++ – program.

relaterade dokument

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *