tällä sivulla:
yleiskatsaus
segmentaatiovika (eli segfault) on yleinen ehto, joka aiheuttaa ohjelmien kaatumisen; ne liitetään usein tiedostoon nimeltä core
. Segfaulteja aiheuttaa ohjelma, joka yrittää lukea tai kirjoittaa laitonta muistipaikkaa.
ohjelman muisti on jaettu eri segmentteihin: ohjelmaohjeiden tekstisegmentti, kääntöaikaan määriteltyjen muuttujien ja ryhmien datasegmentti, alirutiineissa ja funktioissa määriteltyjen väliaikaisten (tai automaattisten) muuttujien pinosegmentti sekä funktioiden ajonaikana jakamien muuttujien kasasegmentti, kuten malloc
(C) ja allocate
(Fortran). Katso lisätietoja ohjelmasta segmentit.
segfault tapahtuu, kun viittaus muuttujaan jää sen janan ulkopuolelle, jossa kyseinen muuttuja sijaitsee, tai kun kirjoitusta yritetään paikkaan, joka on vain luku-janan sisällä. Käytännössä segfaultit johtuvat lähes aina siitä, että yritetään lukea tai kirjoittaa olematonta array-elementtiä, ei määritellä oikein osoitinta ennen sen käyttöä, tai (C-ohjelmissa) käytetään vahingossa muuttujan arvoa osoitteena (katso scanf
esimerkki alla).
Examples of common segfaults
- For example, calling
memset()
kuten alla on esitetty aiheuttaisi ohjelman segfaultille:memset((char *)0x0, 1, 100);
- seuraavat kolme tapausta havainnollistavat yleisintä joukkoihin liittyvää segfaultia:
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;
/* Illegal memory access because no memory is allocated for foo2 */ float *foo, *foo2; foo = (float*)malloc(1000); foo2 = 1.0;
- tapauksessa a, array
foo
on määriteltyindex = 0,1, 2, ... 999
for
silmukka kuitenkin viimeisessä iteraatiossa ohjelma yrittää päästäfoo
. Tästä seuraa segfault, jos kyseinen muistipaikka sijaitsee sen muistisegmentin ulkopuolella, jossafoo
asuu. Vaikka se ei aiheuttaisikaan segfault, se on silti bugi. - tapauksessa B kokonaisluku
n
voi olla mikä tahansa satunnainen arvo. Kuten tapauksessa A, Jos se ei ole alueella0, 1, ... 999
, se saattaa aiheuttaa segfaultin. Olipa se tai ei, se on varmasti bugi. - tapauksessa C muistinjako muuttujalle
foo2
on jäänyt huomioimatta, jotenfoo2
viittaa satunnaiseen paikkaan muistissa. Pääsyfoo2
johtaa todennäköisesti segfault.
- tapauksessa a, array
- toinen yleinen ohjelmointivirhe, joka johtaa segfaulteihin, on osoittimien käytön valvonta. Esimerkiksi C-funktio
scanf()
odottaa toisena parametrinaan muuttujan osoitetta; siksi seuraava todennäköisesti aiheuttaa ohjelman kaatumisen segfaultilla:int foo = 0; scanf("%d", foo); /* Note missing & sign ; correct usage would have been &foo */
muuttuja
foo
voitaisiin määritellä muistipaikalla1000
, mutta yllä oleva funktiokutsu yrittäisi lukea kokonaislukutiedot muistipaikaksi0
foo
. - segfault tapahtuu, kun ohjelma yrittää toimia muistipaikalla tavalla, joka ei ole sallittua (esimerkiksi yritykset kirjoittaa vain luku-sijainti johtaisivat segfault).
- Segfaulteja voi esiintyä myös silloin, kun ohjelmalta loppuu pino-tila. Tämä ei ehkä ole ohjelmasi vika, mutta se voi johtua sen sijaan komentotulkkisi asettamisesta pinon kokorajoitukseksi liian pieneksi.
Etsi Out-of-bounds array-viitteet
useimmilla Fortran-kääntäjillä on vaihtoehto, joka lisää koodin boundsin tarkistamiseen kaikista array-viittauksista suorituksen aikana. Jos pääsy jää matriisille määritellyn indeksialueen ulkopuolelle, ohjelma pysähtyy ja kertoo missä tämä tapahtuu. Useimpien Fortran-kääntäjien kohdalla vaihtoehto on -C
tai -check
, jota seuraa avainsana. Katso kääntäjän käyttöohje saadaksesi tarkan vaihtoehdon. Käytä bounds-tarkistusta vain virheenkorjauksen yhteydessä, koska se hidastaa ohjelmaasi. Jotkut C kääntäjät on myös bounds tarkistaa vaihtoehto.
Tarkista komentotulkin rajat
kuten edellisessä esimerkissä todettiin, jotkut segfault-ongelmat eivät johdu ohjelmasi vioista, vaan ne johtuvat järjestelmän muistirajojen asettamisesta liian alhaisiksi. Yleensä se on raja pinon koko, joka aiheuttaa tällaista ongelmaa. Muistirajojen tarkistamiseen käytetään ulimit
komento bash
tai ksh
tai limit
komento tai tcsh
. Yritä asettaa pinokoko suurempi, ja sitten uudelleen ajaa ohjelman nähdä, jos segfault menee pois.
käytä debuggereita segfaulttien diagnosointiin
Jos et löydä ongelmaa muulla tavalla, voit kokeilla debuggeria. Voit esimerkiksi käyttää GNU: n tunnettua debuggeria GDB
nähdäksesi core
ohjelman dumppaaman tiedoston; aina kun ohjelmat segfault, ne yleensä dumppaavat (oman osionsa) muistin sisällön kaatumishetkellä core
tiedostoon. Aloita debuggeri komennolla gdb core
ja käytä sitten backtrace
komentoa nähdäksesi, missä ohjelma oli kaatuessaan. Tämän yksinkertaisen kikan avulla voit keskittyä siihen osaan koodia.
Jos backtrace
core
g-tiedosto ei löydä ongelmaa, voit joutua ajamaan ohjelman debuggeriohjauksella ja sitten astumaan koodin yksi funktio tai yksi lähdekoodirivi kerrallaan läpi. Tätä varten sinun on käännettävä koodi ilman optimointia, ja -g
lipulla, joten tiedot lähdekoodiriveistä upotetaan suoritettavaan tiedostoon. Lisätietoja on ohjeaiheessa GDB: n käyttäminen Emacsin sisällä C Orc++ – ohjelman vianetsintään.