Eroare off-by-one

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

O eroare off-by-one ( OBOE ), numită și OBOB ( off-by-one bug ), este o eroare logică de programare care apare atunci când o buclă iterativă se repetă o dată prea multe sau o dată mai puțin, datorită unei erori la specificarea condiția de adevăr: apare de obicei atunci când programatorul pune în mod greșit simbolul mai mic sau egal în locul simbolului mai mic sau simbolul mai mare sau egal în locul celui mai mare sau când face o eroare la inițializarea variabilei testate, setându-l la zero în loc de unul: aceasta cauzează probleme de exemplu dacă se referă la indexul unui tablou (care în multe limbaje de programare începe de la zero); sau în cazul în care este apoi utilizat într-o diviziune (caz în care este bine să fie setat la alte valori decât zero, pentru a evita excepții precum divizarea cu zero ).

Ierații dincolo de termenul matricei

Să luăm în considerare o serie de obiecte, dintre care să le procesăm pe cele incluse de la o anumită valoare m la un n (extreme incluse). Câte elemente sunt în această gamă? Un răspuns intuitiv ar putea fi n - m , dar aceasta este doar o eroare individuală, mai precis de tipul stâlpului de gard; răspunsul corect este de fapt ( n - m ) + 1.

Tocmai din cauza acestei contra-intuitivități, intervalele din informatică sunt adesea reprezentate de intervale semi-deschise; de fapt, intervalul de la m la n inclusiv este reprezentat de elementele variind de la m (inclusiv) la n + 1 (exclus), tocmai pentru a evita erorile în fancepost. De exemplu, o buclă care repetă de cinci ori (de la 0 la 4 inclusiv) poate fi scrisă ca un interval semi-deschis de la 0 la 5:

 pentru ( i = 0 ; i < 5 ; i ++ )
{
    // Corpul ciclului
}

Corpul buclei este executat mai întâi când i este egal cu 0; ulterior i asum valorile 1,2,3, până la atingerea valorii finale 4 în timpul iterațiilor. În acest moment, voi lua valoarea 5 și, din moment ce i <5 este fals, bucla se termină. În orice caz, dacă comparația utilizată ar fi fost <= (mai mică sau egală cu), ciclul s-ar fi repetat de 6 ori: aș presupune de fapt valorile 0,1,2,3,4 și 5 (cu o ultimă repetare la presupunerea valorii 5). În mod similar, dacă i s-ar fi inițializat la 1 în loc de 0, ar fi avut loc doar patru iterații, referitoare la valorile 1,2,3 și 4 asumate de i.

Ambele situații ar provoca erori off-by-one.

Un alt tip de eroare poate apărea dacă o buclă do-while este utilizată în locul unui timp (sau invers), deoarece bucla do-while se repetă în mod necesar cel puțin o dată prin construcție.

Erorile legate de matrice pot fi, de asemenea, rezultatul diferențelor conceptuale dintre diferite limbaje de programare. Numerotarea care se referă la prima celulă ca celulă 0 este foarte obișnuită, dar unele limbi o numesc 1. Pascal folosește tablouri cu indexuri definite de utilizator, făcând posibilă modelarea acestora după problema domeniului.

Eroare post de gard

Un gard drept cu n secțiuni are n + 1 mize

O eroare a stâlpului de gard (literalmente „gard”, numit și stâlp de telegraf , stâlp de lampă sau gard de pichet ) este un tip specific de eroare off-by-one. O descriere primitivă a acestei erori a apărut în textele lui Vitruvius . [1] Problema poate fi ilustrată după cum urmează:

"Dacă construiești un gard drept de 30 de metri lungime, cu stâlpi la 3 metri distanță, de câte stâlpi ai nevoie?"

Cel mai imediat răspuns, 10, este greșit. De fapt, gardul este format din 10 secțiuni și 11 posturi.

Eroarea inversă apare atunci când se cunoaște numărul de postări și se presupune că numărul de secțiuni este același. Numărul real de secțiuni trebuie să fie întotdeauna cu unul mai mic decât numărul de postări.

Mai general, problema poate fi pusă după cum urmează:

"Dacă aveți n postări, câte secțiuni există între ele?"

Răspunsul corect ar trebui să fie n - 1 dacă secvența de mize este deschisă la sfârșit, n dacă se înconjoară sau n + 1 dacă partea deschisă a secvenței de mize este considerată o secțiune. Trebuie să acordați o atenție deosebită definiției precise a problemei, deoarece configurarea unei anumite configurații ar putea oferi un răspuns greșit pentru alții. Erorile Fencepost derivă, în esență, din numărarea elementelor, mai degrabă decât din spațiile care le separă și invers, sau din neglijarea luării în considerare a obiectului în cauză numai în unul sau ambele capete ale rândului.

Erorile de gard pot apărea și în alte unități decât lungimile. De exemplu, „Piramida timpului” este o construcție formată din 120 de blocuri care trebuie amplasate la 10 ani distanță. Prin urmare, va dura 1190 de ani pentru construcția completă, de la amplasarea primului bloc până la ultimul și nu 1200. Una dintre primele erori de tipul stâlpului de gard a implicat unitatea de măsurare a timpului, în cazul specific al calendarului iulian. . Inițial, calcula incorect anii bisecți , considerându-i mai degrabă decât exclusivi, devenind astfel unul la fiecare 3 ani în loc de patru.

O eroare a postului de gard poate fi, în cazuri rare, legată de o eroare introdusă de regularități neașteptate în valorile de intrare, care pot (de exemplu) să intre în conflict complet cu o implementare eficientă din punct de vedere teoretic a arborilor binari sau a funcțiilor hash . Această eroare poate duce la apariția celui mai rău caz al algoritmului, mai degrabă decât la cele așteptate.

Când utilizați numere foarte mari, repetarea poate să nu fie o problemă atât de vizibilă. Atunci când aveți de-a face cu numere mai mici, mai ales în cazuri specifice în care precizia este esențială, a face o greșeală individuală poate fi dezastruos. Uneori, eroarea poate fi repetată și chiar agravată, în cazul în care o succesiune de oameni folosesc același calcul greșit și o poartă cu ei din când în când (evident, eroarea ar putea fi, de asemenea, corectată).

Un exemplu de când poate apărea o astfel de eroare implică limbajul MATLAB , în timp ce se utilizează funcția linspace() . Parametrii acestei funcții sunt (limita inferioară, limita superioară, numărul de valori) și non (limita inferioară, limita superioară, numărul de trepte). Un programator care înțelege greșit cel de-al treilea parametru, adică „număr de trepte”, ar putea crede că linspace(0,10,5) ar genera secvența [0, 2, 4, 6, 8, 10] , în timp ce în realitate ieșire ar fi [0, 2.5, 5, 7.5, 10] .

Implementări de securitate

O eroare off-by-one care poate submina securitatea unui sistem informatic poate rezulta din utilizarea incorectă a funcției strncat , a bibliotecii standard C. O concepție greșită obișnuită cu acest tip de funcție este că terminatorul de siguranță nu va fi scris dincolo de lungimea maximă a unui șir. În realitate, acest lucru se întâmplă, iar terminatorul va fi scris exact cu un octet peste lungimea maximă admisă specificată. Codul de mai jos are o eroare ca aceasta:

 voo foo ( char * s )
{
    char buf [ 15 ];
    memset ( buf , 0 , sizeof ( buf ));
    strncat ( buf , s , sizeof ( buf )); // Parametrul final ar trebui să fie: sizeof (buf) - 1
}

Erorile off-by-one sunt frecvente atunci când se utilizează bibliotecile C, deoarece sunt incompatibile între ele în situații în care, ca în exemplu, trebuie să vă amintiți să scădeți un octet: funcții precum fgets() și strncpy nu vor scrie niciodată dincolo lungimea șirului indicat lor ( fgets() scade 1 și returnează numai (lungime - 1) octet), în timp ce alții ca strncat fac; din acest motiv programatorul trebuie să-și amintească pentru ce funcții va fi necesar să se scadă un octet și pentru care nu.

În unele sisteme (în special arhitecturi endiene mici ) această inconsecvență poate provoca o suprascriere a ultimului octet semnificativ al indicatorului cadru. Acest lucru creează o condiție exploatabilă pentru un atacator, care poate deturna variabila locală pentru rutina de apelare.

O abordare utilă pentru a încerca să preveniți unele probleme este de a utiliza variante ale acestor funcții, care calculează cât să scrieți pe baza lungimii totale a bufferului, mai degrabă decât numărul maxim de caractere de scris. Acestea pot fi funcții precum strlcat și strlcpy , adesea considerate mai sigure, deoarece facilitează prevenirea strlcpy accidentale după sfârșitul bufferului (în exemplul de cod de mai sus, apelarea strlcat(buf, s, sizeof(buf)) rezolva problema )

Notă

  1. ^ (EN) Istoricul erorii post-gard , pe dsm.fordham.edu. Adus la 4 noiembrie 2017 (arhivat din original la 7 noiembrie 2017) .
    «Iată ce a spus Vitruvius despre eroarea de gard-post: In araeostylis enim libertas est quantum cuique libet constitutendi. Sed ita columnae in peripteris conlocentur uti quot intercolumnia sunt in front, totidem bis intercolumnia fiant in lateribus. Ita înim erit duplex longitudinal operis ad latitudinem. Namque qui columnarum duplicationes fecerunt erravisse videntur, quod unum intercolumnium in longitude plus quam oportet procurrere videtur. " .

Elemente conexe

linkuri externe

Informatică Portal IT : accesați intrările Wikipedia care se ocupă cu IT