[OSy] pointer arithmetics overflow
Marek Vasut
marek.vasut at gmail.com
Wed Feb 23 01:19:04 CET 2011
On Wednesday 23 February 2011 00:56:14 Adam Hraska wrote:
> Dobry den,
>
> zaujimalo by ma, ako zapisat v standardnom C pripadne
> C++ test, ktory overi, ze volna oblast zacinajuca
> na "freeStart" a dlha "freeSize" byte-ov nezasahuje
> do naalokovanej oblasti zacinajucej na "nextStart".
> Vieme pritom, ze freeStart < nextStart. freeStart
> i freeSize urcuje uzivatel.
>
> Tato uloha sa vyskytla pri implementacii fcii vma_map
> s VF_VA_USER. Problemom je napisat test bez pointer
> arithmetic overflow.
Jestli to chapu dobre, tak staci rict, ze BFU muze alokovat treba minimalne 2
bajty (a ne jeden bajt) ... pak adresu, kterou BFU zada, podelit dvema (nebo
kolik je minimalni zvolena alokacni jednotka) a pocitat s tim. Pak uz zadnej
overflow nenastane, ne ?
>
> Diagram situacie:
>
> +----------------+ ... +------
>
> | <- freeSize -> | ` nextStart
>
> ` freeStart
>
>
> 1) Prvy pokus:
>
> bool isOk(char *freeStart, size_t freeSize, char *nextStart)
> {
> ASSERT(freeStart < nextStart);
> if(freeStart + freeSize <= nextStart){
> // Free sa zmesti pred oblast nextStart.
> return true;
> }
> else{
> // Free oblast koliduje s nextStart.
> return false;
> }
> }
>
> Tento fragment ma problem, ze freeStart + freeSize
> moze overflow-nut pointer, co je podla standardu
> undefined behavior [1] a v praxi fatalna chyba.
>
>
> 2) Pokus s overflow testom:
>
> if(freeStart + freeSize < freeStart){
> return (freeStart + freeSize <= nextStart);
> }
> else{
> // Koliduje!
> return false;
> }
>
> V tomto fragmente sa najprv pokusame overit, ci nedojde
> k pointer overflow. Bohuzial, pri teste na pointer
> overflow sposobujeme samotny overflow. Standard jasne
> specifikuje, ze pointer overflow je undefined behavior
> a v praxi gcc uvedeny test kompletne odstrani ako sucast
> optimalizacie.
>
>
> 3) Rozdiel pointerov.
>
> if(freeSize <= nextStart - freeStart){
> // Free sa zmesti pred nextStart.
> return true;
> }
> else{
> // Koliduje!
> return false;
> }
>
> K ziadnemu pointer overflowu tentokrat nedochadza.
> Bohuzial, rozdiel pointerov je podla standardu typu
> ptrdiff_t, co je signed integer typ [2]. Podla [3] je
> overflow signed integer-u implementation-defined.
> Nemozeme sa teda spolahnut, ze prekladac vygeneruje
> vhodny kod pre situaciu: INT_MAX < nextStart - freeStart.
>
>
> 4) Pseudo-riesenie.
> V nasom kerneli sme sa nakoniec rozhodli pre variantu
> (3), kedze v praxi prekladac pocita i signed arithmetics
> v two's complement, ktory sa vhodne konvertuje na unsigned
> size_t pri porovnani s freeSize. Dalej sme sa poistili
> flagmi -fwrapv a -fno-strict-overflow [4].
>
> Zaver
> -----
> Zaujimalo by ma, ako sa dari realnym OS vyriesit tuto
> elementarnu operaciu bez vyuzivania nestandardneho
> chovania prekladaca (napr. flagov).
>
> Dakujem.
>
> S pozdravom
>
> Adam Hraska
>
> PS: Uvedomujem si, ze na MIPS je najvacsi segment
> velky INT_MAX + 1, a tak by stacilo najprv testovat,
> ci sa vobec volna oblast cela zmesti do segmentu.
> Tento pristup vsak nemozno aplikovat na architekturach,
> kde mozu mat segmenty vyrazne vacsiu velkost (napr.
> x86).
>
> [1] c++98.std.expr.add 5.7.5
> [2] c++98.std.expr.add 5.7.6
> [3] c++98.std.conv.intergral 4.7.3
> [4] http://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html
>
> _______________________________________________
> OSy mailing list
> OSy at d3s.mff.cuni.cz
> https://d3s.mff.cuni.cz/mailman/listinfo/osy
More information about the NSWI004
mailing list