Nedefinisano ponašanje

Iz Vikipedije, slobodne enciklopedije
Idi na navigaciju Idi na pretragu

U programiranju, nedefinisano ponašanje (UB) je rezultat izvršavanja koda računara napisanog u nekom programskom jeziku za koji specifikacija jezika ne propisuje kako se treba postupati sa kodom. Nedefinisano ponašanje je nepredvidivo i često uzrok softverskih grešaka.

Ponašanje nekih programskih jezika-najpoznatiji S i S++ - je definisano u nekim slučajevima.[1] U standardima ovih jezika, semantike pojedinih operacija su nedefinisane. Implementaciji je dozvoljeno da  pretpostavi da se takve operacije nikada ne dešavaju u standardu-u skladu programskog koda; implementacijom će se smatrati ispravno sve što radi u takvim slučajevima, analogno nebitnim vrednostima u digitalnoj logici. Ova pretpostavka može da pravi najrazličitije programske transformacije da važe ili da pojednostavi svoje dokaze o ispravnosti, dajući fleksibilnost u implementaciji. To je odgovornost programera za pisanje koda koji nikada ne priziva definisano ponašanje, iako su implementacije kompajlera slobodne da pokrenu dijagnostiku kada se ovo desi.

Na primer, u S upotreba bilo koje automatske promenljive pre nego što je inicializovana ima za ishod nedefinisano ponašanje, kao što to čini deljenje sa nulom ili indeksiranje niza izvan definisanih granica (vidi bafer prelivanja). U principu, svaka instanca nedefinisanog ponašanja ostavlja apstraktnu mašinu za ubijanje u nepoznatom stanju, a svako naknadno ponašanje je takođe nedefinisano. Ako nije potrebno da prevodilac dijagnostikuje nedefinisano ponašanje, programi pozivajući se na nedefinisano ponašanje mogu sastaviti i pokrenuti proizvodnju ispravnih rezultata, netačnih rezultate, ili imaju bilo kakvo drugo ponašanje. Zbog toga, nedefinisano ponašanje mogu stvoriti greške koje je teško otkriti.

Pod određenim okolnostima mogu postojati posebna ograničenja nedefinisanog ponašanja. Na primer, set instrukcija specifikacije CPU može da napusti ponašanje nekih oblika koja su uputstvom definisana, ali ako CPU podržava zaštitu memorije onda će specifikacija verovatno uključiti blanko pravilo navodeći da nijedan korisnik ne može da pristupi i da uputstvo može izazvati rupu u bezbednosti operativnog sistema; tako da će stvarnom procesoru biti dozvoljeno da korumpirane korisnike registruje kao odgovor na takvu instrukciju, ali neće mu biti dozvoljeno da se, na primer, prebaci u režim supervizora.

U S i C++, implementacijom definisano ponašanje se koristi, gde standardni jezik ne određuje ponašanje, ali primena mora izabrati ponašanje i dokument i mora da poštuje svoja pravila. Ovi standardi takođe koriste neodređeno ponašanje da znači da je od datog skupa mogućnosti nije navedeno koje ponašanje implementacija mora da izabere, to ne mora da dokumentuje izbor ili čak biti u skladu, ali mora da izabere jednu mogućnost.

U S zajednici, nedefinisano ponašanje može biti duhovito nazvano kao "nazalni demoni" post o Usenet-u  koji je objasnio nedefinisano ponašanje kao ponašanje koje dozvoljava da kompajler ne izabere ništa, čak i "da demoni lete iz nosa ".[2]

Primeri u C i C++[uredi]

Pokušaj da se izmeni bukvalni niz izaziva nedefinisano ponašanje:[3]

char *p = "wikipedia"; // лоше формирана C++11, застарела C++98/C++03
p[0] = 'W'; // недефинисано понашање

Jedan od načina da se spreči ovo je definisanje kao niz umesto pokazivača.

char p[] = "wikipedia"; // ТАЧНО
p[0] = 'W';

U C++, osoba može upotrebiti standardni string kao u nastavku:

std::string s = "wikipedia"; // ТАЧНО
s[0] = 'W';

Celobrojno deljenje nulom rezultuje u nedefinisano ponašanje:[4]

int x = 1;
return x / 0; // недефинисано понашање

Neki pokazivači operacija mogu dovesti do nedefinisanog ponašanja:[5]

int arr[4] = {0, 1, 2, 3};
int *p = arr + 5; // недефинисано понашање

Postizanje kraja funkcije vrednosti povratka (osim glavnog ()) bez povratne izjave mogu dovesti do nedefinisanog ponašanja:

int f()
{
} /* недефинисано понашање */

Originalna knjiga S programskog jezika navodi sledeće primere koda koji "mogu (i koji to rade) proizvode različite rezultate na različitim mašinama”[6] (što bi se moglo smatrati samo neodređenim ili implementacijom definisanom ponašanjem u današnjim uslovima):

printf("%d %d\n", ++n, power(2, n)); /* НЕТАЧНО */
a[i] = i++;

Kasnije ANSI C standard je odlučio da napusti slične konstrukcije nedefinisanog, na primer, "Ovaj stav čini nedefinisanu izjavu izraze kao što su i = ++i + 1; dok dozvoljava i = i + 1;”.[7]

Rizici nedefinisanog ponašanja[uredi]

HTML verzije 4 i ranije su napustile grešku rukovanja nedefinisanim. Vremenom su stranice počele da se oslanjaju na neodređeno oporavka grešaka sprovođenih u popularnim pretraživačima. Ovo je izazvalo probleme za proizvođače manje popularnih pretraživača koji su bili primorani da preokrenu-inženjering i implementiraju bag kompatibilni oporavak greške. To je dovelo do de fakto standarda koji je bio mnogo komplikovaniji nego što je mogao da bude da je takvo ponašanje navedeno od samog početka.

Nedefinisano ponašanje u server programima može da izazove bezbednosne probleme. Kada su GCC programeri promenili kompajler u 2008. godini tako da je izostavljeno određeno prelivanje provere koje se oslanjalo na nedefinisano ponašanje, CERT je izdao upozorenje protiv novijih verzija kompajlera.[8] Linux Weekly News je istakao da je isto ponašanje posmatrano u PathScale C, Microsoft Visual C++ 2005 i nekoliko drugih kompajlera ;[9] upozorenje je kasnije izmenjeno da upozori o različitim kompajlerima.[10]

Reference[uredi]

  1. ^ Lattner, Chris (13. 5. 2011). „What Every C Programmer Should Know About Undefined Behavior”. LLVM Project Blog. LLVM.org. Pristupljeno 24. 5. 2011. 
  2. ^ „nasal demons”. The Jargon File. Pristupljeno 12. 6. 2014. 
  3. ^ ISO/IEC (2003). ISO/IEC 14882|ISO/IEC 14882:2003(E): Programming Languages - C++ §2.13.4 String literals [lex.string] para. 2
  4. ^ ISO/IEC (2003). ISO/IEC 14882 §5.6 Multiplicative operators [expr.mul] para. 4
  5. ^ ISO/IEC (2003). ISO/IEC 14882 §5.7 Additive operators [expr.add] para. 5
  6. ^ Kernighan & Ritchie 1978, str. 50.
  7. ^ ANSI X3.159-1989 Programming Language C, footnote 26
  8. ^ „Vulnerability Note VU#162289 — gcc silently discards some wraparound checks”. Vulnerability Notes Database. CERT. 4. 4. 2008. Arhivirano iz originala na datum 9. 4. 2014. 
  9. ^ Corbet, Jonathan (16. 4. 2008). „GCC and pointer overflows”. Linux Weekly News. 
  10. ^ „Vulnerability Note VU#162289 — C compilers may silently discard some wraparound checks”. Vulnerability Notes Database. CERT. 8. 10. 2008 [4 April 2008]. 

Literatura[uredi]

Spoljašnje veze[uredi]