summaryrefslogtreecommitdiff
path: root/payloads/libpayload/libc
diff options
context:
space:
mode:
authorJulius Werner <jwerner@chromium.org>2019-03-27 14:47:09 -0700
committerPatrick Georgi <pgeorgi@google.com>2019-04-10 10:44:31 +0000
commit0de2fa0a622d72d63d64a3d73b4b7ead24380314 (patch)
treeb8d820e3021c60baf65afdd45eb126518cfee476 /payloads/libpayload/libc
parent18c1b6b240b675c877b8bd731dfd58f5723d0c57 (diff)
libpayload: Deduplicate strtol and strtoull
Our strtol() and strtoull() function contain almost exactly the same code. This is a) bad in general and b) may cause the code to get out of sync, such as it recently happened with CB:32029. This patch changes strtol() to be based on strtoull() so that the main parsing code exists only once, and also adds a strtoll() to round off the library. Also fix the bounds imposed by strtoul() to be based on the actual length of a 'long', not hardcoded to 32-bits (which is not equivalent on all architectures). Change-Id: I919c65a773cecdb11739c3f22dd0d182ed50c07f Signed-off-by: Julius Werner <jwerner@chromium.org> Reviewed-on: https://review.coreboot.org/c/coreboot/+/32086 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Patrick Georgi <pgeorgi@google.com>
Diffstat (limited to 'payloads/libpayload/libc')
-rw-r--r--payloads/libpayload/libc/string.c65
1 files changed, 25 insertions, 40 deletions
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;
}