diff options
author | H.J. Lu <hjl.tools@gmail.com> | 2017-06-08 12:52:42 -0700 |
---|---|---|
committer | H.J. Lu <hjl.tools@gmail.com> | 2017-06-08 12:52:42 -0700 |
commit | 37b66c0b1a2156a43fb813499326230639ba2773 (patch) | |
tree | b39f1559b927e4e0487d7da71a826e032560de03 /elf/dl-misc.c | |
parent | 199fc19d3aaaf57944ef036e15904febe877fc93 (diff) | |
download | glibc-37b66c0b1a2156a43fb813499326230639ba2773.zip glibc-37b66c0b1a2156a43fb813499326230639ba2773.tar.gz glibc-37b66c0b1a2156a43fb813499326230639ba2773.tar.bz2 |
ld.so: Consolidate 2 strtouls into _dl_strtoul [BZ #21528]
There are 2 minimal strtoul implementations in ld.so:
1. __strtoul_internal in elf/dl-minimal.c.
2. tunables_strtoul in elf/dl-tunables.c.
This patch adds _dl_strtoul to replace them. Tested builds with and
without --enable-tunables.
[BZ #21528]
* elf/dl-minimal.c (__strtoul_internal): Removed.
(strtoul): Likewise.
* elf/dl-misc.c (_dl_strtoul): New function.
* elf/dl-tunables.c (tunables_strtoul): Removed.
(tunable_initialize): Replace tunables_strtoul with _dl_strtoul.
* elf/rtld.c (process_envvars): Likewise.
* sysdeps/unix/sysv/linux/dl-librecon.h (_dl_osversion_init):
Likewise.
* sysdeps/generic/ldsodefs.h (_dl_strtoul): New prototype.
Diffstat (limited to 'elf/dl-misc.c')
-rw-r--r-- | elf/dl-misc.c | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/elf/dl-misc.c b/elf/dl-misc.c index c5d3e0e..c469b5a 100644 --- a/elf/dl-misc.c +++ b/elf/dl-misc.c @@ -360,3 +360,87 @@ _dl_higher_prime_number (unsigned long int n) return *low; } + +/* A stripped down strtoul-like implementation for very early use. It + does not set errno if the result is outside bounds because it may get + called before errno may have been set up. */ + +uint64_t +internal_function +_dl_strtoul (const char *nptr, char **endptr) +{ + uint64_t result = 0; + bool positive = true; + unsigned max_digit; + + while (*nptr == ' ' || *nptr == '\t') + ++nptr; + + if (*nptr == '-') + { + positive = false; + ++nptr; + } + else if (*nptr == '+') + ++nptr; + + if (*nptr < '0' || *nptr > '9') + { + if (endptr != NULL) + *endptr = (char *) nptr; + return 0UL; + } + + int base = 10; + max_digit = 9; + if (*nptr == '0') + { + if (nptr[1] == 'x' || nptr[1] == 'X') + { + base = 16; + nptr += 2; + } + else + { + base = 8; + max_digit = 7; + } + } + + while (1) + { + 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 >= (UINT64_MAX - digval) / base) + { + if (endptr != NULL) + *endptr = (char *) nptr; + return UINT64_MAX; + } + result *= base; + result += digval; + ++nptr; + } + + if (endptr != NULL) + *endptr = (char *) nptr; + + /* Avoid 64-bit multiplication. */ + if (!positive) + result = -result; + + return result; +} |