Patch brings strtol() and related functions more conformant with POSIX. Corner cases like strtol(-2147483648, NULL, 10) now pass clang -fsanitize=integer without warnings.
This commit is contained in:
parent
ab19292787
commit
b7ed12ebd3
|
@ -41,6 +41,7 @@
|
|||
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "libc.h"
|
||||
|
||||
|
@ -60,7 +61,13 @@
|
|||
* nptr to a long integer value according to the given base, which must be
|
||||
* between 2 and 36 inclusive, or be the special value 0.
|
||||
*
|
||||
* Warning: does not check for integer overflow!
|
||||
* Returns:
|
||||
* - The converted value, if the base and number are valid
|
||||
* - 0 if an error occurs, and set errno to:
|
||||
* * EINVAL if base < 2 or base > 36
|
||||
* - LONG_MIN or LONG_MAX, of correct sign, if an overflow occurs,
|
||||
* and set errno to:
|
||||
* * ERANGE if the number cannot be represented using long
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
@ -91,11 +98,25 @@ long strtol(FAR const char *nptr, FAR char **endptr, int base)
|
|||
|
||||
accum = strtoul(nptr, endptr, base);
|
||||
|
||||
/* Correct the sign of the result */
|
||||
/* Correct the sign of the result and check for overflow */
|
||||
|
||||
if (negate)
|
||||
{
|
||||
return -(long)accum;
|
||||
const unsigned long limit = ((unsigned long)-(LONG_MIN + 1)) + 1;
|
||||
|
||||
if (accum > limit)
|
||||
{
|
||||
set_errno(ERANGE);
|
||||
return LONG_MIN;
|
||||
}
|
||||
|
||||
return (accum == limit) ? LONG_MIN : -(long)accum;
|
||||
}
|
||||
|
||||
if (accum > LONG_MAX)
|
||||
{
|
||||
set_errno(ERANGE);
|
||||
return LONG_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "libc.h"
|
||||
|
||||
|
@ -58,11 +59,17 @@
|
|||
* Name: strtoll
|
||||
*
|
||||
* Description:
|
||||
* The strtol() function converts the initial part of the string in
|
||||
* The strtoll() function converts the initial part of the string in
|
||||
* nptr to a long long integer value according to the given base, which
|
||||
* must be between 2 and 36 inclusive, or be the special value 0.
|
||||
*
|
||||
* Warning: does not check for integer overflow!
|
||||
* Returns:
|
||||
* - The converted value, if the base and number are valid
|
||||
* - 0 if an error occurs, and set errno to:
|
||||
* * EINVAL if base < 2 or base > 36
|
||||
* - LLONG_MIN or LLONG_MAX, of correct sign, if an overflow occurs,
|
||||
* and set errno to:
|
||||
* * ERANGE if the number cannot be represented using long long
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
@ -93,11 +100,25 @@ long long strtoll(FAR const char *nptr, FAR char **endptr, int base)
|
|||
|
||||
accum = strtoull(nptr, endptr, base);
|
||||
|
||||
/* Correct the sign of the result */
|
||||
/* Correct the sign of the result and check for overflow */
|
||||
|
||||
if (negate)
|
||||
{
|
||||
return -(long long)accum;
|
||||
const unsigned long long limit = ((unsigned long long)-(LLONG_MIN + 1)) + 1;
|
||||
|
||||
if (accum > limit)
|
||||
{
|
||||
set_errno(ERANGE);
|
||||
return LLONG_MIN;
|
||||
}
|
||||
|
||||
return (accum == limit) ? LLONG_MIN : -(long long)accum;
|
||||
}
|
||||
|
||||
if (accum > LLONG_MAX)
|
||||
{
|
||||
set_errno(ERANGE);
|
||||
return LLONG_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -52,14 +52,15 @@
|
|||
* Name: strtoul
|
||||
*
|
||||
* Description:
|
||||
* The strtol() function converts the initial part of the string in
|
||||
* The strtoul() function converts the initial part of the string in
|
||||
* nptr to a long unsigned integer value according to the given base, which
|
||||
* must be between 2 and 36 inclusive, or be the special value 0.
|
||||
*
|
||||
* Returns:
|
||||
* - The converted value, if the base and number are valid
|
||||
* - 0 if an error occurs, and seterrno to:
|
||||
* - 0 if an error occurs, and set errno to:
|
||||
* * EINVAL if base < 2 or base > 36
|
||||
* - ULONG_MAX if an overflow occurs, and set errno to:
|
||||
* * ERANGE if the number cannot be represented using unsigned long
|
||||
*
|
||||
****************************************************************************/
|
||||
|
@ -99,7 +100,7 @@ unsigned long strtoul(FAR const char *nptr, FAR char **endptr, int base)
|
|||
if (accum < prev)
|
||||
{
|
||||
set_errno(ERANGE);
|
||||
accum = 0;
|
||||
accum = ULONG_MAX;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,14 +55,15 @@
|
|||
* Name: strtoull
|
||||
*
|
||||
* Description:
|
||||
* The strtol() function converts the initial part of the string in
|
||||
* The strtoull() function converts the initial part of the string in
|
||||
* nptr to a long unsigned integer value according to the given base, which
|
||||
* must be between 2 and 36 inclusive, or be the special value 0.
|
||||
*
|
||||
* Returns:
|
||||
* - The converted value, if the base and number are valid
|
||||
* - 0 if an error occurs, and seterrno to:
|
||||
* - 0 if an error occurs, and set errno to:
|
||||
* * EINVAL if base < 2 or base > 36
|
||||
* - ULLONG_MAX if an overflow occurs, and set errno to:
|
||||
* * ERANGE if the number cannot be represented using unsigned long long
|
||||
*
|
||||
****************************************************************************/
|
||||
|
@ -102,7 +103,7 @@ unsigned long long strtoull(FAR const char *nptr, FAR char **endptr, int base)
|
|||
if (accum < prev)
|
||||
{
|
||||
set_errno(ERANGE);
|
||||
accum = 0;
|
||||
accum = ULLONG_MAX;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue