Indiana University Indiana University Indiana University

tällä sivulla:

  • yleiskatsaus
  • esimerkkejä yleisistä segfaulteista
  • selvitä Out-of-bounds array-viitteet
  • Tarkista Shellin rajat
  • käytä debuggerit segfaulttien diagnosointiin
  • 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, arrayfooon määriteltyindex = 0,1, 2, ... 999for silmukka kuitenkin viimeisessä iteraatiossa ohjelma yrittää päästäfoo. Tästä seuraa segfault, jos kyseinen muistipaikka sijaitsee sen muistisegmentin ulkopuolella, jossa foo 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 alueella 0, 1, ... 999, se saattaa aiheuttaa segfaultin. Olipa se tai ei, se on varmasti bugi.
      • tapauksessa C muistinjako muuttujalle foo2 on jäänyt huomioimatta, joten foo2 viittaa satunnaiseen paikkaan muistissa. Pääsy foo2 johtaa todennäköisesti segfault.
    • 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ä muistipaikalla 1000, mutta yllä oleva funktiokutsu yrittäisi lukea kokonaislukutiedot muistipaikaksi 0foo.

    • 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 backtracecoreg-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.

    Aiheeseen liittyvät asiakirjat

    Vastaa

    Sähköpostiosoitettasi ei julkaista. Pakolliset kentät on merkitty *