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
foo
este definit pentruindex = 0,1, 2, ... 999
. Cu toate acestea, în ultima iterație a bucleifor
, programul încearcă să accesezefoo
. Acest lucru va duce la un segfault dacă acea locație de memorie se află în afara segmentului de memorie undefoo
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 variabila
foo2
a fost trecută cu vederea, decifoo2
va indica o locație aleatorie în memorie. Accesareafoo2
va duce probabil la un segfault.
- În cazul a, matrice
- 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 memoriei1000
, dar apelul funcției de mai sus ar încerca să citească date întregi în locația memoriei0
conform definițieifoo
. - 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
pecore
fiș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++.