This is an old revision of the document!
Integer overflow
Do integer overflow-a dolazi kada se pokuša pohraniti vrijednost u varijablu koja je veća od maksimalno dopuštene. Sve numeričke vrijednosti tokom izvođenja operacija u kojima su oni operandi sačuvane su u registrima. U današnje vrijeme to su najčešće 64 bitni registri.
Veličine riječi u asemblerskom jeziku: Byte (8 bitova) Word (2 bajta) Doubleword (4 bajta) Quadword (8 bajta)
Ovisno o jeziku, operacije velikim brojevima znaju biti implementirane stringom (npr. python) čime se izbjegava mogućnost integer overflowa.
Primjer:
Recimo da je varijabla a definirana kao byte. Byte ima 8 bitova, što znači da je u nju moguće upisati 2^8 (256) različitih vrijednosti:
- U unsigned notaciji: [0, 255]
- U signed notaciji : [-128, 127]
Najveća vrijednost koju ona može sadržati u sebi jest broj 1111 1111(2) S obzirom da su svi numerički operandi nalaze u registru (npr. 64 bitnom) zapis vrijednosti varijable a (recimo broj 255) u registru koji sadržu njenu vrijednost biti će : 00000…1111 1111(2) gdje je broj nula 64-8 = 56.
Kada bismo tom registru dodali vrijednost 1, zapis bi izgledao ovako: 0000….1 0000 0000(2), što bi značilo da se vrijednost varijable promijenilo u 0 umjesto 256, jer samo prvih 8 bitova označavaju raspon varijable a. Kada bi se taj registar dalje koristio za upcastanje (npr. prikaz riječi dword) njegova vrijednost bi bila 256.
Sličan princip vrijedi i za overflowanje cijelog registra, odnosno riječi veličine qword (8 bajtova, 64 bita). Sklopovlje za zbrajanje registara interno koristi tzv. carry flag (rflags/eflags/status registra) To znači da kada se registar preplavi (odnosno upiše vrijednost veća od 2^64) on ispravlja svoj sadržaj (odnosno prikazuje upisanu vrijednost % 2^64 gdje je % operacija modulo-ostatak) i postavlja postavlja carry flag. Kada bi se taj registar dalje koristio za operacije bile bi prikazane vrijednost manje od 2^64.
Tajni chat
Zastavica će se ispisati ako vrijedi uvjet (status→odobren && status→moze_citati_flag). Potrebno je preplaviti status i postaviti ga na ispravne vrijednosti. Jedini unos je preko scanf-a:
scanf("%10s",popis_pozivatelja[i].ime);
scanf("%10s",popis_pozivatelja[i].kontakt);
Objekt status nalazi se iza popis_pozivatelja. Unos scanf-a ograničen je iteracijom po broju pozivatelja:
for(long long i=0; i<broj_pozivatelja; i++) ...
Također postavljan je uvjet na donju granicu broja pozivatelja:
if(broj_pozivatelja > 0) //Dakle broj pozivatelja ne smije biti negativan
Potrebno je napraviti overflow na način da iteracija omogućuje veći ispis po gomili od veličine popis_pozivatelja:
long long broj_pozivatelja; //qword (8 bajtova/64 bita)
2^64 = 18,446,744,073,709,551,616 različitih vrijednosti:
- U unsigned notaciji: [0, 18 446 744 073 709 551 615]
- U signed notaciji : [-9 223 372 036 854 775 808, 9 223 372 036 854 775 807]
Veličina popis_pozivatelja je određena s:
broj_pozivatelja * sizeof(struct pozivatelj)
Sizeof je operacija koja vraća tip size_t (unsigned int) i u ovom slučaju to će biti vrijednost 20 (10 char + 10 char gdje je char riječ definirana kao byte) Broj_pozivatelja je long long Rezultat množenja je tip long long (implicit casting - uvijek se upcasta na najkompleksniji operand u operaciji npr. float*long *int *short = float).
Kako bi se izveo overflow na razini registra koji čuva vrijednost umnoška potrebno je unijeti vrijednost za broj_pozivatelja na načina da je rezultat veći od 2^64 jer:
Broj_pozivatelja*sizeof(struct pozivatelj) = (broj_pozivatelja*sizeof (struct pozivatelj) ) % 2^64 = (broj_pozivatelja*20)%2^64
2^64 / 20 = 922337203685477581 kada se zaokruži na gornju granicu. Time je ostatak 4 unutar malloc-a. Naravno, moguće je izvesti overflow i s drukčijim brojevima.
Rješenje je dakle:
- Unos_1: 922337203685477581
- Unos_2: Unos stringa do adrese status i preplavljivanje varijable moze_citati_flag
