Variabila neinicializată

De la Wikipedia, enciclopedia liberă.
Salt la navigare Salt la căutare

În informatică , o variabilă neinițializată este o variabilă declarată, dar neinicializată la o valoare cunoscută definită înainte de a fi utilizată. Va avea o anumită valoare, dar nu este previzibil care. Tocmai de aceea este o eroare de programare și o sursă obișnuită de bug-uri software.

Exemplu în limbaj C.

O presupunere comună făcută de programatorii începători este că toate variabilele sunt setate la o valoare cunoscută, cum ar fi zero, atunci când sunt declarate. Deși acest lucru este valabil pentru multe limbi, nu este adevărat pentru toate, deci există riscul de a face această greșeală. Limbi precum C folosesc spațiu de stivă rezervat pentru variabile, colecția de variabile alocate pentru un subrutină este cunoscută sub numele de cadru de stivă . Deși computerul rezervă spațiul adecvat pentru cadrul stivei, de obicei o face pur și simplu prin ajustarea valorii indicatorului stivei și nu setează memoria în sine la o nouă stare (de obicei din motive de eficiență). Prin urmare, orice conținut al acelei zone de memorie în acel moment va fi valoarea inițială a variabilelor care ocupă acele adrese.

Iată un exemplu simplu în C:

 void conta ( nul )
{
    int k , i ;
    
    pentru ( i = 0 ; i < 10 ; i ++ )
    {
        k = k + 1 ;
    }
    
    printf ( "% d" , k );
}

Valoarea finală a lui k nu este definită. Răspunsul care trebuie să fie 10 presupune că a început de la zero, ceea ce poate fi sau nu adevărat. Rețineți că în exemplu variabila i este inițializată la zero de prima clauză a instrucțiunii for . Un alt exemplu este atunci când avem de-a face cu structuri . În următorul fragment de cod, scris în C, avem o struct studente care conține câteva variabile care descriu informații despre un student. Funcția registra_studente își pierde memoria deoarece nu reușește să inițializeze complet membrii struct studente nuovo_studente . Dacă aruncăm o privire mai atentă, la eta început, semestre și numero_studente sunt inițializate. Dar inițializarea primul și cognome nome de membri este incorectă. Acest lucru se datorează faptului că dacă lungimea nome și cognome tablou de caractere este mai mică de 16 octeți, atunci când apelăm funcția strcpy , nu vom putea inițializa complet cei 16 octeți de memorie rezervată pentru fiecare dintre acești membri. Apoi, după ce funcția memcpy() structura rezultată în output , o parte din memoria stivei este transmisă apelantului.

 struct student {
    vârsta int nesemnată ;
    semestru int nesemnat ;
    char prenume_nume [ 16 ];
    char last_name [ 16 ];
    unsigned int student_number ;
};

int register_student ( struct student * output , int age , char * name , char * surname )
{
    // Dacă oricare dintre acești indicatori sunt NULL, nu reușește.
    if ( ! ieșire || ! nume || ! prenume )
    {
        printf ( "Eroare! \ n " );
        retur -1 ;
    }

    // Ne asigurăm că lungimea șirurilor este mai mică de 16 octeți (inclusiv caracterul terminator)
    // pentru a evita revărsarea
    if ( strlen ( prenume ) > 15 || strlen ( prenume ) > 15 ) {
      printf ( "Numele și prenumele nu pot avea mai mult de 16 caractere! \ n " );
      retur -1 ;
    }

    // Inițializarea membrilor
    struct student new_student ;
    nou_student . vârstă = vârstă ;
    nou_student . semestru = 1 ;
    nou_student . student_number = get_new_student_number ();
    
    strcpy ( nou_student . nume , nume );
    strcpy ( nou_student . prenume , prenume );

    // Copia structurii rezultate în ieșire
    memcpy ( output , & new_student , sizeof ( struct student ));
    retur 0 ;
}

Cu toate acestea, chiar și atunci când o variabilă este inițial implicită la o valoare implicită, cum ar fi 0, aceasta nu este de obicei valoarea corectă. Inițializat nu înseamnă corect dacă valoarea este implicită, cu toate acestea inițializarea implicită la 0 este o bună practică pentru pointeri și tablouri de pointer, deoarece le face nevalide înainte ca acestea să fie inițializate la valoarea corectă. În C, variabilele cu durata de stocare statică care nu sunt inițializate explicit sunt inițializate la zero (sau nule, pentru pointeri). [1]

Variabilele neinițializate nu numai că sunt o cauză frecventă a erorilor, dar acest tip de eroare este deosebit de gravă, deoarece este posibil să nu fie reproductibil: de exemplu, o variabilă poate rămâne neinitializată doar în unele ramuri ale programului. În unele cazuri, programele cu variabile neinițializate pot trece chiar și teste software .

Impacturi

Variabilele neinițializate sunt erori puternice, deoarece pot fi exploatate pentru a face scurgeri de memorie arbitrare, pentru a obține suprascrierea memoriei sau pentru a obține execuție de cod arbitrar, după caz. Atunci când utilizați software care utilizează randomizarea aspectului spațiului de adrese (ASLR), este adesea necesar să cunoașteți adresa de bază a software-ului în memorie. Exploatarea unei variabile neinitializate pentru a forța software-ul să scurgă un indicator din spațiul său de adrese poate fi utilizată pentru a ocoli ASLR.

Se utilizează în diferite limbi

Variabilele neinițializate sunt o problemă specială în limbaje precum limbajul de asamblare, C și C ++, care sunt proiectate pentru programarea sistemelor . Dezvoltarea acestor limbaje a dus la o filozofie de proiectare în care conflictele dintre performanță și securitate au fost rezolvate în general în favoarea performanței. Programatorului i sa dat sarcina de a fi conștient de problemele problematice și / sau periculoase, cum ar fi variabilele neinițializate.

În alte limbi, variabilele sunt adesea inițializate la valori cunoscute atunci când sunt create. Cateva exemple:

  • VHDL inițializează toate variabilele standard la o valoare specială „U”. Este utilizat în simulare, pentru depanare, pentru a anunța utilizatorul când valorile inițiale fără interes , prin logică multivalorată , afectează ieșirea.
  • Java nu are variabile neinițializate. Câmpurile claselor și obiectelor care nu au inițializator explicit și elemente matrice sunt inițializate automat cu valoarea implicită pentru tipul lor (fals pentru boolean, 0 pentru toate tipurile numerice, nul pentru toate tipurile de referință). [2] Variabilele locale din Java trebuie să fie atribuite permanent înainte de a le accesa, altfel aceasta este o eroare de compilare.
  • Python inițializează variabilele locale la NULL (altele decât None ) și aruncă UnboundLocalError atunci când o astfel de variabilă este accesată înainte de a fi (re) inițializată la o valoare validă.
  • D inițializează toate variabilele, cu excepția cazului în care programatorul specifică în mod explicit să nu.

Chiar și în limbile în care sunt permise variabile neinițializate, mulți compilatori vor încerca să identifice utilizarea variabilelor neinițializate și să le raporteze ca erori în timpul compilării .

Notă

  1. ^ open-std.org , http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf . Adus 26-09-2008 . Secțiunea 6.7.8, paragraful 10.
  2. ^ docs.oracle.com , http://docs.oracle.com/javase/specs/jls/se8/html/jls-4.html#jls-4.12.5 . Adus 18-10-2008 .

Elemente conexe

Lecturi suplimentare

  • CWE-457 Utilizarea variabilelor neinițializate[1] .