diff options
author | Siddhesh Poyarekar <siddhesh@redhat.com> | 2012-04-25 11:52:39 +0530 |
---|---|---|
committer | Siddhesh Poyarekar <siddhesh@redhat.com> | 2012-04-25 12:27:03 +0530 |
commit | ceab42c380901dee40dc8b1fda0453b8ca918cc8 (patch) | |
tree | 60f68677ced022ef8e13cd686fac51635875eeaf /elf/dl-minimal.c | |
parent | 3ce2865f93d42f4721d58088dd6ab1dac06ea85b (diff) | |
download | glibc-ceab42c380901dee40dc8b1fda0453b8ca918cc8.tar.gz |
Parse hexadecimal and octal strings correctly
The current implementation of __strtoul_internal seems to only pretend
to support hex and octal strings by detecting a preceding 0x or 0 and
marking base as 8 or 16. When it comes to the actual processing of the
string, it only considers numeric values within, thus breaking hex
values that may have [a-f] in them. Fixed with this commit.
Diffstat (limited to 'elf/dl-minimal.c')
-rw-r--r-- | elf/dl-minimal.c | 32 |
1 files changed, 25 insertions, 7 deletions
diff --git a/elf/dl-minimal.c b/elf/dl-minimal.c index 316de99b8f..4a97f56faa 100644 --- a/elf/dl-minimal.c +++ b/elf/dl-minimal.c @@ -1,6 +1,5 @@ /* Minimal replacements for basic facilities used in the dynamic linker. - Copyright (C) 1995-1998,2000-2002,2004-2006,2007,2009 - Free Software Foundation, Inc. + Copyright (C) 1995-2012 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -232,6 +231,7 @@ __strtoul_internal (const char *nptr, char **endptr, int base, int group) { unsigned long int result = 0; long int sign = 1; + unsigned max_digit; while (*nptr == ' ' || *nptr == '\t') ++nptr; @@ -253,6 +253,7 @@ __strtoul_internal (const char *nptr, char **endptr, int base, int group) assert (base == 0); base = 10; + max_digit = 9; if (*nptr == '0') { if (nptr[1] == 'x' || nptr[1] == 'X') @@ -261,14 +262,31 @@ __strtoul_internal (const char *nptr, char **endptr, int base, int group) nptr += 2; } else - base = 8; + { + base = 8; + max_digit = 7; + } } - while (*nptr >= '0' && *nptr <= '9') + while (1) { - unsigned long int digval = *nptr - '0'; - if (result > ULONG_MAX / 10 - || (result == ULONG_MAX / 10 && digval > ULONG_MAX % 10)) + unsigned long int digval; + if (*nptr >= '0' && *nptr <= '0' + max_digit) + digval = *nptr - '0'; + else if (base == 16) + { + if (*nptr >= 'a' && *nptr <= 'f') + digval = *nptr - 'a' + 10; + else if (*nptr >= 'A' && *nptr <= 'F') + digval = *nptr - 'A' + 10; + else + break; + } + else + break; + + if (result > ULONG_MAX / base + || (result == ULONG_MAX / base && digval > ULONG_MAX % base)) { errno = ERANGE; if (endptr != NULL) |