Indiana University Indiana University Indiana University

pe această pagină:

  • Prezentare generală
  • Exemple de segfaults comune
  • aflați referințe matrice în afara limitelor
  • Verificați limitele shell
  • depanatoare pentru a diagnostica segfaults

prezentare generală

o eroare de segmentare (aka segfault) este o afecțiune comună care determină blocarea programelor; acestea sunt adesea asociate cu un fișier numit core. Segfaults sunt cauzate de un program care încearcă să citească sau să scrie o locație de memorie ilegală.

memoria programului este împărțită în segmente diferite: un segment de text pentru instrucțiunile programului, un segment de date pentru variabile și matrice definite la momentul compilării, un segment de stivă pentru variabile temporare (sau automate) definite în subrutine și funcții și un segment heap pentru variabile alocate în timpul rulării de funcții, cum ar fimalloc (în C) șiallocate (în Fortran). Pentru mai multe informații, consultați despre segmentele de programe.

un segfault apare atunci când o referință la o variabilă se încadrează în afara segmentului în care se află acea variabilă sau când se încearcă o scriere într-o locație care se află într-un segment numai în citire. În practică, segfaults se datorează aproape întotdeauna încercării de a citi sau scrie un element de matrice inexistent, care nu definește corect un pointer înainte de al utiliza sau (în programele C) folosind accidental valoarea unei variabile ca adresă (vezi scanf exemplu de mai jos).

Exemple de segfaults comune

  • De exemplu, apelarea memset() așa cum se arată mai jos ar provoca un program de segfault:
    memset((char *)0x0, 1, 100);
  • următoarele trei cazuri ilustrează cele mai frecvente tipuri de segfaults legate de matrice:

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

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

    cazul c

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

    • În cazul a, matrice fooeste definit pentruindex = 0,1, 2, ... 999. Cu toate acestea, în ultima iterație a buclei for, programul încearcă să acceseze foo. Acest lucru va duce la un segfault dacă acea locație de memorie se află în afara segmentului de memorie unde foo se află. Chiar dacă nu provoacă un segfault, este totuși un bug.
    • în cazul B, integer n ar putea fi orice valoare aleatorie. Ca și în Cazul A, dacă nu este în intervalul0, 1, ... 999, ar putea provoca un segfault. Indiferent dacă este sau nu, este cu siguranță un bug.
    • în cazul C, alocarea memoriei pentru variabilafoo2 a fost trecută cu vederea, decifoo2 va indica o locație aleatorie în memorie. Accesarea foo2 va duce probabil la un segfault.
  • o altă eroare comună de programare care duce la segfaults este supravegherea în utilizarea indicatoarelor. De exemplu, funcția c scanf() așteaptă adresa unei variabile ca al doilea parametru; prin urmare, următoarele vor determina probabil blocarea programului cu un segfault:
    int foo = 0; scanf("%d", foo); /* Note missing & sign ; correct usage would have been &foo */

    variabila foo ar putea fi definită la locația memoriei 1000, dar apelul funcției de mai sus ar încerca să citească date întregi în locația memoriei 0 conform definiției foo.

  • un segfault va apărea atunci când un program încearcă să opereze pe o locație de memorie într-un mod care nu este permis (de exemplu, încercările de a scrie o locație numai în citire ar duce la un segfault).
  • Segfaults pot apărea, de asemenea, atunci când programul rămâne fără spațiu stivă. Este posibil să nu fie o eroare în programul dvs., dar se poate datora în schimb shell-ului dvs. care stabilește limita dimensiunii stivei prea mică.

aflați referințe matrice out-of-bounds

majoritatea compilatoarelor Fortran au o opțiune care va introduce cod pentru a face verificarea limitelor pe toate referințele matrice în timpul rulării. Dacă un acces se încadrează în afara intervalului de index definit pentru o matrice, programul se va opri și vă va spune unde se întâmplă acest lucru. Pentru majoritatea compilatoarelor Fortran, opțiunea este-C sau-check urmată de un cuvânt cheie. Consultați ghidul de utilizare al compilatorului pentru a obține opțiunea exactă. Utilizați verificarea limitelor numai la depanare, deoarece vă va încetini programul. Unele compilatoare C au, de asemenea, o opțiune de verificare a limitelor.

Verificați limitele shell

după cum s-a menționat în ultimul exemplu de mai sus, unele probleme segfault nu se datorează erorilor din programul dvs., ci sunt cauzate în schimb de limitele memoriei de sistem setate prea jos. De obicei, limita dimensiunii stivei este cea care provoacă acest tip de problemă. Pentru a verifica limitele de memorie, Utilizați comanda ulimit din bash sau ksh sau comanda limit din csh sau tcsh. Încercați să setați stacksize mai mare, apoi rulați din nou programul pentru a vedea dacă segfault dispare.

utilizați depanatoare pentru a diagnostica segfaults

dacă nu găsiți problema în alt mod, puteți încerca un depanator. De exemplu, puteți utiliza binecunoscutul depanator GNU GDB pentru a vizualiza backtrace-ul unui fișier core aruncat de programul dvs.; ori de câte ori programele segfault, de obicei aruncă conținutul (secțiunea lor din) memorie în momentul prăbușirii într-un fișier core. Porniți depanatorul cu comanda gdb core, apoi utilizați comanda backtrace pentru a vedea unde se afla programul când s-a prăbușit. Acest truc simplu vă va permite să vă concentrați asupra acelei părți a codului.

dacă folosindbacktrace pecorefișierul g nu găsește problema, este posibil să trebuiască să rulați programul sub controlul debugger și apoi să parcurgeți funcția code One sau o linie de cod sursă, la un moment dat. Pentru a face acest lucru, va trebui să compilați codul fără optimizare și cu steagul -g, astfel încât informațiile despre liniile de cod sursă vor fi încorporate în fișierul executabil. Pentru mai multe, consultați exemplu pas cu pas pentru utilizarea GDB în cadrul Emacs pentru a depana un program c orc++.

documente conexe

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *