mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-09-21 13:34:59 +02:00
Use a much less clever scan_signed no-overflow hack
This commit is contained in:
parent
a7207329a8
commit
6bc052365a
@ -3060,7 +3060,7 @@ digit_to_num(char d)
|
|||||||
* success, store the result in <b>out</b>, advance bufp to the next
|
* success, store the result in <b>out</b>, advance bufp to the next
|
||||||
* character, and return 0. On failure, return -1. */
|
* character, and return 0. On failure, return -1. */
|
||||||
static int
|
static int
|
||||||
scan_unsigned(const char **bufp, unsigned long *out, int width, int base)
|
scan_unsigned(const char **bufp, unsigned long *out, int width, unsigned base)
|
||||||
{
|
{
|
||||||
unsigned long result = 0;
|
unsigned long result = 0;
|
||||||
int scanned_so_far = 0;
|
int scanned_so_far = 0;
|
||||||
@ -3073,7 +3073,7 @@ scan_unsigned(const char **bufp, unsigned long *out, int width, int base)
|
|||||||
|
|
||||||
while (**bufp && (hex?TOR_ISXDIGIT(**bufp):TOR_ISDIGIT(**bufp))
|
while (**bufp && (hex?TOR_ISXDIGIT(**bufp):TOR_ISDIGIT(**bufp))
|
||||||
&& scanned_so_far < width) {
|
&& scanned_so_far < width) {
|
||||||
int digit = hex?hex_decode_digit(*(*bufp)++):digit_to_num(*(*bufp)++);
|
unsigned digit = hex?hex_decode_digit(*(*bufp)++):digit_to_num(*(*bufp)++);
|
||||||
// Check for overflow beforehand, without actually causing any overflow
|
// Check for overflow beforehand, without actually causing any overflow
|
||||||
// This preserves functionality on compilers that don't wrap overflow
|
// This preserves functionality on compilers that don't wrap overflow
|
||||||
// (i.e. that trap or optimise away overflow)
|
// (i.e. that trap or optimise away overflow)
|
||||||
@ -3119,14 +3119,15 @@ scan_signed(const char **bufp, long *out, int width)
|
|||||||
if (neg && result > 0) {
|
if (neg && result > 0) {
|
||||||
if (result > ((unsigned long)LONG_MAX) + 1)
|
if (result > ((unsigned long)LONG_MAX) + 1)
|
||||||
return -1; /* Underflow */
|
return -1; /* Underflow */
|
||||||
// Avoid overflow on the cast to signed long when result is LONG_MIN
|
else if (result == ((unsigned long)LONG_MAX) + 1)
|
||||||
// by subtracting 1 from the unsigned long positive value,
|
*out = LONG_MIN;
|
||||||
// then, after it has been cast to signed and negated,
|
else {
|
||||||
// subtracting the original 1 (the double-subtraction is intentional).
|
/* We once had a far more clever no-overflow conversion here, but
|
||||||
// Otherwise, the cast to signed could cause a temporary long
|
* some versions of GCC apparently ran it into the ground. Now
|
||||||
// to equal LONG_MAX + 1, which is undefined.
|
* we just check for LONG_MIN explicitly.
|
||||||
// We avoid underflow on the subtraction by treating -0 as positive.
|
*/
|
||||||
*out = (-(long)(result - 1)) - 1;
|
*out = -(long)result;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (result > LONG_MAX)
|
if (result > LONG_MAX)
|
||||||
return -1; /* Overflow */
|
return -1; /* Overflow */
|
||||||
|
Loading…
Reference in New Issue
Block a user