X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Usermode%2FLibraries%2Flibc.so_src%2Fstrtoi.c;h=84bf0005919edbacef6a2dc0967f07fffe40d88c;hb=92c5980925e773c6e1d6775c50c9d86c77b84d23;hp=db6684f0aa7d04a77882c9dc720c6be81be1bb11;hpb=0b3db65a6c3babf70808360b455f9b9e1886655f;p=tpg%2Facess2.git diff --git a/Usermode/Libraries/libc.so_src/strtoi.c b/Usermode/Libraries/libc.so_src/strtoi.c index db6684f0..84bf0005 100644 --- a/Usermode/Libraries/libc.so_src/strtoi.c +++ b/Usermode/Libraries/libc.so_src/strtoi.c @@ -12,7 +12,7 @@ unsigned long long strtoull(const char *str, char **end, int base) { - long long ret = 0; + unsigned long long ret = 0; if( !str || base < 0 || base > 36 || base == 1 ) { if(end) @@ -43,6 +43,10 @@ unsigned long long strtoull(const char *str, char **end, int base) if( base == 0 ) base = 10; + // Value before getting within 1 digit of ULLONG_MAX + // - Used to avoid overflow in more accurate check + unsigned long long max_before_ullong_max = ULLONG_MAX / base; + unsigned int space_above = ULLONG_MAX - max_before_ullong_max * base; while( *str ) { int next = -1; @@ -58,22 +62,30 @@ unsigned long long strtoull(const char *str, char **end, int base) if( 'a' <= *str && *str <= 'a'+base-10-1 ) next = *str - 'a' + 10; } + //_SysDebug("strtoull - ret=0x%llx,next=%i,str='%s'", ret, next, str); if( next < 0 ) break; + // If we're already out of range, keep eating if( ret == ULLONG_MAX ) { errno = ERANGE; str ++; // Keep eating until first unrecognised character continue; } - if( ret > (ULLONG_MAX-next)/base ) { - //_SysDebug("strtoull - Out of range (0x%llx > 0x%llx)", ret, (ULLONG_MAX-next)/base); - //_SysDebug("strtoull - (%llu > %llu)", ret, (ULLONG_MAX-next)/base); - ret = ULLONG_MAX; - errno = ERANGE; - str ++; - continue; + + // Rough then accurate check against max value + if( ret >= max_before_ullong_max ) + { + //_SysDebug("strtoull - 0x%llx>0x%llx", ret, max_before_ullong_max); + if( (ret - max_before_ullong_max) * base + next > space_above ) { + //_SysDebug("strtoull - %u*%u+%u (%u) > %u", + // (unsigned int)(ret - max_before_ullong_max), base, next, space_above); + ret = ULLONG_MAX; + errno = ERANGE; + str ++; + continue; + } } ret *= base; ret += next; @@ -126,7 +138,8 @@ long long strtoll(const char *str, char **end, int base) //_SysDebug("strtoll - neg=%i,ret=%llu", neg, ret); if( neg ) { - if( -ret < LLONG_MIN ) { + // Abuses unsigned integer overflow + if( ret + LLONG_MIN < ret ) { errno = ERANGE; return LLONG_MIN; }