Fixes for strtoul/strtoull. Fixes Issue #1

This commit is contained in:
Sebastien Lorquet 2016-06-13 15:29:05 +02:00
parent 5073bf1de6
commit 15c92867de
3 changed files with 61 additions and 8 deletions

View File

@ -63,6 +63,11 @@
* Assumptions: * Assumptions:
* *ptr points to the first, non-whitespace character in the string. * *ptr points to the first, non-whitespace character in the string.
* *
* Returns:
* - if base is valid, the actual base to use, and pptr is updated to point
* at the first digit.
* - if base is invalid (<2 or >36), return -1.
*
****************************************************************************/ ****************************************************************************/
int lib_checkbase(int base, FAR const char **pptr) int lib_checkbase(int base, FAR const char **pptr)
@ -107,6 +112,12 @@ int lib_checkbase(int base, FAR const char **pptr)
} }
} }
/* Check for incorrect bases. */
else if (base < 2 || base > 26)
{
return -1; /* Means incorrect base */
}
/* Return the updated pointer and base */ /* Return the updated pointer and base */
*pptr = ptr; *pptr = ptr;

View File

@ -59,13 +59,17 @@
* nptr to a long unsigned integer value according to the given base, which * 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. * 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 seterrno to:
* * EINVAL if base < 2 or base > 36
* * ERANGE if the number cannot be represented using unsigned long
* *
****************************************************************************/ ****************************************************************************/
unsigned long strtoul(FAR const char *nptr, FAR char **endptr, int base) unsigned long strtoul(FAR const char *nptr, FAR char **endptr, int base)
{ {
unsigned long accum = 0; unsigned long prev, accum = 0;
int value; int value;
if (nptr) if (nptr)
@ -74,16 +78,32 @@ unsigned long strtoul(FAR const char *nptr, FAR char **endptr, int base)
lib_skipspace(&nptr); lib_skipspace(&nptr);
/* Check for unspecified base */ /* Check for unspecified or incorrect base */
base = lib_checkbase(base, &nptr); base = lib_checkbase(base, &nptr);
if (base < 0)
{
set_errno(EINVAL);
return 0;
}
/* Accumulate each "digit" */ /* Accumulate each "digit" */
while (lib_isbasedigit(*nptr, base, &value)) while (lib_isbasedigit(*nptr, base, &value))
{ {
accum = accum*base + value; prev = accum;
nptr++; accum = accum*base + value;
nptr++;
/* Check for overflow */
if (accum < prev)
{
set_errno(ERANGE);
accum = 0;
break;
}
} }
/* Return the final pointer to the unused value */ /* Return the final pointer to the unused value */

View File

@ -62,11 +62,17 @@
* nptr to a long unsigned integer value according to the given base, which * 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. * 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:
* * EINVAL if base < 2 or base > 36
* * ERANGE if the number cannot be represented using unsigned long long
*
****************************************************************************/ ****************************************************************************/
unsigned long long strtoull(FAR const char *nptr, FAR char **endptr, int base) unsigned long long strtoull(FAR const char *nptr, FAR char **endptr, int base)
{ {
unsigned long long accum = 0; unsigned long long prev, accum = 0;
int value; int value;
if (nptr) if (nptr)
@ -79,12 +85,28 @@ unsigned long long strtoull(FAR const char *nptr, FAR char **endptr, int base)
base = lib_checkbase(base, &nptr); base = lib_checkbase(base, &nptr);
if (base < 0)
{
set_errno(EINVAL);
return 0;
}
/* Accumulate each "digit" */ /* Accumulate each "digit" */
while (lib_isbasedigit(*nptr, base, &value)) while (lib_isbasedigit(*nptr, base, &value))
{ {
accum = accum*base + value; prev = accum;
nptr++; accum = accum*base + value;
nptr++;
/* Check for overflow */
if (accum < prev)
{
set_errno(ERANGE);
accum = 0;
break;
}
} }
/* Return the final pointer to the unused value */ /* Return the final pointer to the unused value */