În știința calculatoarelor, un pointer null sau o referință null este o valoare salvată pentru a indica faptul că sau nu se referă la un obiect valid. Programele folosesc în mod obișnuit valoarea null pentru a reprezenta condiții precum sfârșitul unei de lungime necunoscută sau incapacitatea de a efectua o acțiune; această utilizare a indicatorilor null poate fi comparată cu și cu valoarea Nimic pentru un .
Un pointer null nu trebuie confundat cu un : un pointer null garantează faptul că nu este egal la comparație cu niciun pointer care indică către un obiect valid. Cu toate acestea, în funcție de limbaj și de implementare, un pointer neinițializat poate să nu dea o astfel de garanție. Acesta ar putea să fie egal la comparație cu alți pointeri valizi; sau ar putea fi egal la comparație cu pointerii null; și s-ar putea comporta chiar în ambele feluri la momente diferite; ori comparația ar putea avea .
Deoarece un pointer null nu indică un obiect cu vreo semnificație, o încercare de a accesa datele stocate în acea locație de memorie (invalidă) poate provoca o eroare de rulare sau o blocare imediată a programului. Aceasta este eroarea de null pointer. Este unul dintre cele mai comune tipuri de slăbiciuni de software, iar Tony Hoare, care a introdus conceptul, l-a denumit „o greșeală de un miliard de dolari”.
C În C, se garantează că doi pointeri null de orice tip sunt egali.ISO/IEC 9899, clause 6.3.2.3, paragraph 4. Macroul de preprocesare NULL este definit ca o constantă de tip pointer definită la implementare în <>,ISO/IEC 9899, clause 7.17, paragraph 3: NULL... which expands to an implementation-defined null pointer constant... care în poate fi exprimată într-o manieră portabilă ca ((void *)0), valoarea întreagă 0 la tipul void*.ISO/IEC 9899, clause 6.3.2.3, paragraph 3. Standardul C nu spune că pointerul null ar fi același cu indicatorul către 0, deși în practică se poate întâmpla. unui pointer null este în C,ISO/IEC 9899, clause 6.5.3.2, paragraph 4, esp. footnote 87. și unei implementări conforme i se permite să presupună că orice pointer care este dereferențiat nu este null.
În practică, dereferențiarea unui pointer null poate duce la o încercare de citire sau scriere dintr-o zonă de memorie care nu este mapată, declanșând o sau o încălcare a regulilor de acces la memorie în sistemul de operare. Acest lucru se poate manifesta prin oprirea cu eroare a programului sau poate fi transformată într-o software care poate fi prinsă de codul programului. Există, totuși, anumite circumstanțe în care nu este cazul. De exemplu, în la procesoare x86, adresa 0000:0000 este citibilă și, de obicei, poate fi scrisă, iar dereferențierea unui pointer către acea adresă este o acțiune perfect validă, dar de obicei nedorită, care poate duce la un comportament nedefinit, dar care nu se blochează în aplicație. Există ocazii când dereferențiarea pointerului către adresa zero este intenționată și bine definită; de exemplu, codul BIOS scris în C pentru dispozitivele x86 în mod real pe 16 biți poate suprascrie (IDT) la adresa fizică 0 al mașinii prin dereferențierea unui pointer null pentru scriere. De asemenea, compilatorul ar putea și să optimizeze dereferențierea pointerului null, evitând eroarea de segmentare, dar provocând un alt comportament nedorit.
Dereferențiere de null În C++, macro-ul NULL a fost moștenit de la C, dar literalul întreg pentru zero a fost în mod tradițional preferat pentru a reprezenta o constantă de indicator null. Cu toate acestea, a introdus constanta explicită de pointer null și tipul pentru a fi folosit în schimb.
Alte limbaje În unele medii de limbaje de programare (cel puțin o implementare proprietară Lisp, de exemplu), valoarea folosită ca indicator de null (denumit nil în Lisp ) poate fi de fapt un pointer către un bloc de date interne utile pentru implementare (dar nu accesibil în mod explicit din programele utilizatorului), permițând astfel folosirea aceluiași registru ca o constantă utilă și o modalitate rapidă de accesare a elementelor interne de implementare. Acesta este cunoscut ca vectorul nil.
În limbile cu o , un pointer posibil null poate fi înlocuit cu o uniune etichetată care impune gestionarea explicită a cazului excepțional; de fapt, un pointer posibil null poate fi văzut ca un pointer etichetat cu o etichetă calculată.
Limbajele de programare folosesc literale diferite pentru indicatorul null. În Python, de exemplu, o valoare nulă se numește None. În Pascal și Swift, un indicator nul se numește nil. În Eiffel, se numește referință void.
Dereferențierea nullului Deoarece un pointer null nu indică adresa unui obiect semnificativ, o încercare de dereferențiere (adică accesarea datelor stocate în acea locație de memorie) un pointer null provoacă de obicei (dar nu întotdeauna) o eroare de rulare sau o blocare imediată a programului. enumeră eroarea de pointer null drept una dintre cele mai frecvent exploatate slăbiciuni ale software-ului.
In C, dereferențierea unui pointer null este comportament nedefinit. Multe implementări fac ca execuția unui astfel de cod să fie oprită cu încălcare a regulilor de acces, deoarece reprezentarea pointerului null este aleasă în așa fel încât să fie o adresă care nu este niciodată alocată de sistem pentru stocarea de obiecte. Acest comportament nu este însă universal. Nici nu este garantat, deoarece compilatoarelor li se permite să optimizeze programele sub presupunerea că nu au comportamente nedefinite. În Delphi și în multe alte implementări de Pascal, constanta reprezintă un pointer null către prima adresă de memorie care este utilizată și pentru a inițializa variabile valide. Dereferențierea ridică o excepție externă a sistemului de operare care este mapată pe o instanță de excepție Pascal dacă unitatea este legată de clauza . În Java, accesul la o referință null cauzează un (NPE), care poate fi prinsă de codul care tratează erori, dar practica preferată este de a asigura că asemenea excepții nu au loc niciodată. În Lisp, este un obiect de clasa I. Prin convenție, (first nil) este , la fel ca (rest nil). Astfel că dereferențierea lui în aceste contexte nu va cauza o eroare, dar codul prost scris poate intra în buclă infinită. În .NET, accesul la referințele null cauzează aruncarea unei . Deși prinderea acestora este în general considerată o rea practică, acest tip de excepție poate fi prins și tratat de program. În , se pot trimite mesaje la un obiect (care este un pointer null) fără a cauza întreruperea programului; mesajul este pur și simplu ignorat, și valoarea returnată (dacă există) este sau , în funcție de tip. Până la introducerea Supervisor Mode Access Prevention (SMAP), o dereferențiere de pointer null putea fi exploatată prin maparea paginii zero în spațiul de adresă al atacatorului și deci transformarea oricărui pointer null într-un pointer care trimite la acea regiune, ceea ce în unele cazuri putea duce la execuție de cod arbitrar.
Atenuarea efectelor Există tehnici pentru a facilita depanarea dereferințelor de pointer null. Bond et al. sugerează modificarea mașinii virtuale Java (JVM) pentru a ține evidența propagării nullurilor.
Limbajele funcționale pure și codul de utilizator rulat în multe limbaje interpretate sau de mașină virtuală nu suferă problema dereferențierii pointerului null, deoarece nu este oferit acces direct la pointeri și, în cazul limbajelor funcționale pure, tot codul și datele sunt imuabile.
În cazul în care un limbaj furnizează sau utilizează indicatori care altfel ar putea deveni null, este posibil să se atenueze sau să se evite dereferențierile de null în timpul executării prin furnizarea unor prin sau alte tehnici, și este în plină desfășurare o tranziție către asistența sintactică din partea caracteristicilor limbajului, cum ar fi cele văzute în versiunile moderne ale , D, și Rust.
Analize similare pot fi efectuate folosind instrumente externe, în unele limbaje.
Istorie În 2009, Tony Hoare a declarat că a inventat referința null în 1965 ca parte a limbajului La data declarației, Hoare își descria invenția ca o „greșeală de un miliard de dolari”:
Note de completare
Note bibliografice
Bibliografie
Categorie:Tipuri de date