summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--payloads/libpayload/include/stdlib.h1
-rw-r--r--payloads/libpayload/libc/string.c65
2 files changed, 26 insertions, 40 deletions
diff --git a/payloads/libpayload/include/stdlib.h b/payloads/libpayload/include/stdlib.h
index 3f94d2119a..06fb735b75 100644
--- a/payloads/libpayload/include/stdlib.h
+++ b/payloads/libpayload/include/stdlib.h
@@ -186,6 +186,7 @@ static inline void *xmemalign_work(size_t align, size_t size, const char *file,
* @{
*/
long int strtol(const char *s, char **nptr, int base);
+long long int strtoll(const char *s, char **nptr, int base);
unsigned long int strtoul(const char *s, char **nptr, int base);
unsigned long long int strtoull(const char *s, char **nptr, int base);
long atol(const char *nptr);
diff --git a/payloads/libpayload/libc/string.c b/payloads/libpayload/libc/string.c
index f563f6338a..6c257cbdaa 100644
--- a/payloads/libpayload/libc/string.c
+++ b/payloads/libpayload/libc/string.c
@@ -33,6 +33,7 @@
#include <string.h>
#include <ctype.h>
#include <inttypes.h>
+#include <limits.h>
#include <errno.h>
/**
@@ -419,59 +420,43 @@ static int _offset(char ch, int base)
* @return A signed integer representation of the string
*/
-long int strtol(const char *ptr, char **endptr, int base)
+long long int strtoll(const char *orig_ptr, char **endptr, int base)
{
- int ret = 0;
- int negative = 1;
-
- if (endptr != NULL)
- *endptr = (char *) ptr;
+ const char *ptr = orig_ptr;
+ int is_negative = 0;
/* Purge whitespace */
for( ; *ptr && isspace(*ptr); ptr++);
if (ptr[0] == '-') {
- negative = -1;
+ is_negative = 1;
ptr++;
}
- if (!*ptr)
- return 0;
+ unsigned long long uval = strtoull(ptr, endptr, base);
- /* Determine the base */
+ /* If the whole string is unparseable, endptr should point to start. */
+ if (endptr && *endptr == ptr)
+ *endptr = (char *)orig_ptr;
- if (base == 0) {
- if (ptr[0] == '0' && (ptr[1] == 'x' || ptr[1] == 'X'))
- base = 16;
- else if (ptr[0] == '0') {
- base = 8;
- ptr++;
- }
- else
- base = 10;
- }
-
- /* Base 16 allows the 0x on front - so skip over it */
+ if (uval > (unsigned long long)LLONG_MAX + !!is_negative)
+ uval = (unsigned long long)LLONG_MAX + !!is_negative;
- if (base == 16) {
- if (ptr[0] == '0' && (ptr[1] == 'x' || ptr[1] == 'X'))
- ptr += 2;
- }
-
- /* If the first character isn't valid, then don't
- * bother */
-
- if (!*ptr || !_valid(*ptr, base))
- return 0;
-
- for( ; *ptr && _valid(*ptr, base); ptr++)
- ret = (ret * base) + _offset(*ptr, base);
-
- if (endptr != NULL)
- *endptr = (char *) ptr;
+ if (is_negative)
+ return -uval;
+ else
+ return uval;
+}
- return ret * negative;
+long int strtol(const char *ptr, char **endptr, int base)
+{
+ long long int val = strtoll(ptr, endptr, base);
+ if (val > LONG_MAX)
+ return LONG_MAX;
+ if (val < LONG_MIN)
+ return LONG_MIN;
+ return val;
}
long atol(const char *nptr)
@@ -534,7 +519,7 @@ unsigned long long int strtoull(const char *ptr, char **endptr, int base)
unsigned long int strtoul(const char *ptr, char **endptr, int base)
{
unsigned long long val = strtoull(ptr, endptr, base);
- if (val > UINT32_MAX) return UINT32_MAX;
+ if (val > ULONG_MAX) return ULONG_MAX;
return val;
}