[svn] Don't assume that strtoll_type is 64 bits wide. Don't rely on undefined

behavior to check overflow.
This commit is contained in:
hniksic 2006-06-26 11:24:38 -07:00
parent f2756871a6
commit 48f21f4a71
2 changed files with 39 additions and 22 deletions

View File

@ -1,3 +1,9 @@
2006-06-26 Hrvoje Niksic <hniksic@xemacs.org>
* cmpt.c (strtoll): Check for overflow and underflow without
relying on (technically) undefined behavior. Don't assume that
strtoll_type is 64 bits wide.
2006-06-21 Hrvoje Niksic <hniksic@xemacs.org> 2006-06-21 Hrvoje Niksic <hniksic@xemacs.org>
* utils.c (base64_encode): Cast void pointer to char * before * utils.c (base64_encode): Cast void pointer to char * before

View File

@ -1315,18 +1315,19 @@ char_value (char c, int base)
return value; return value;
} }
#define LL strtoll_type /* long long or __int64 */ #define TYPE_MAXIMUM(t) ((t) (~ (~ (t) 0 << (sizeof (t) * CHAR_BIT - 1))))
/* These constants assume 64-bit strtoll_type. */ #define STRTOLL_MAX TYPE_MAXIMUM (strtoll_type)
/* This definition assumes two's complement arithmetic */
#define STRTOLL_MIN (-STRTOLL_MAX - 1)
/* A roundabout way of writing 2**63-1 = 9223372036854775807 */ /* Like a%b, but always returns a positive number when A is negative.
#define STRTOLL_OVERFLOW (((LL) 1 << 62) - 1 + ((LL) 1 << 62)) (C doesn't guarantee the sign of the result.) */
/* A roundabout way of writing -2**63 = -9223372036854775808 */ #define MOD(a, b) ((strtoll_type) -1 % 2 == 1 ? (a) % (b) : - ((a) % (b)))
#define STRTOLL_UNDERFLOW (-STRTOLL_OVERFLOW - 1)
/* A strtoll replacement for systems that have LFS but don't supply /* A strtoll-like replacement for systems that have an integral type
strtoll. The headers typedef strtoll_type to long long or to larger than long but don't supply strtoll. This implementation
__int64. */ makes no assumptions about the size of strtoll_type. */
strtoll_type strtoll_type
strtoll (const char *nptr, char **endptr, int base) strtoll (const char *nptr, char **endptr, int base)
@ -1355,7 +1356,7 @@ strtoll (const char *nptr, char **endptr, int base)
else else
negative = false; negative = false;
/* If base is 0, determine the real base based on the beginning on /* If BASE is 0, determine the real base based on the beginning on
the number; octal numbers begin with "0", hexadecimal with "0x", the number; octal numbers begin with "0", hexadecimal with "0x",
and the others are considered octal. */ and the others are considered octal. */
if (*nptr == '0') if (*nptr == '0')
@ -1383,33 +1384,38 @@ strtoll (const char *nptr, char **endptr, int base)
if (!negative) if (!negative)
{ {
/* Parse positive number, checking for overflow. */ /* Parse positive number, checking for overflow. */
int val; int digit;
for (; (val = char_value (*nptr, base)) != -1; ++nptr) /* Overflow watermark. If RESULT exceeds it, overflow occurs on
this digit. If result==WATERMARK, current digit may not
exceed the last digit of maximum value. */
const strtoll_type WATERMARK = STRTOLL_MAX / base;
for (; (digit = char_value (*nptr, base)) != -1; ++nptr)
{ {
strtoll_type newresult = base * result + val; if (result > WATERMARK
if (newresult < result) || (result == WATERMARK && digit > STRTOLL_MAX % base))
{ {
result = STRTOLL_OVERFLOW; result = STRTOLL_MAX;
errno = ERANGE; errno = ERANGE;
break; break;
} }
result = newresult; result = base * result + digit;
} }
} }
else else
{ {
/* Parse negative number, checking for underflow. */ /* Parse negative number, checking for underflow. */
int val; int digit;
for (; (val = char_value (*nptr, base)) != -1; ++nptr) const strtoll_type WATERMARK = STRTOLL_MIN / base;
for (; (digit = char_value (*nptr, base)) != -1; ++nptr)
{ {
strtoll_type newresult = base * result - val; if (result < WATERMARK
if (newresult > result) || (result == WATERMARK && digit > MOD (STRTOLL_MIN, base)))
{ {
result = STRTOLL_UNDERFLOW; result = STRTOLL_MIN;
errno = ERANGE; errno = ERANGE;
break; break;
} }
result = newresult; result = base * result - digit;
} }
} }
out: out:
@ -1417,4 +1423,9 @@ strtoll (const char *nptr, char **endptr, int base)
*endptr = (char *) nptr; *endptr = (char *) nptr;
return result; return result;
} }
#undef STRTOLL_MAX
#undef STRTOLL_MIN
#undef ABS
#endif /* NEED_STRTOLL */ #endif /* NEED_STRTOLL */