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:
Juha Niskanen 2016-11-10 06:09:57 -06:00 committed by Gregory Nutt
parent ab19292787
commit b7ed12ebd3
4 changed files with 57 additions and 13 deletions

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}