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 | |
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.
-rw-r--r-- | ChangeLog | 13 | ||||
-rw-r--r-- | elf/dl-minimal.c | 84 | ||||
-rw-r--r-- | elf/dl-misc.c | 84 | ||||
-rw-r--r-- | elf/dl-tunables.c | 69 | ||||
-rw-r--r-- | elf/rtld.c | 3 | ||||
-rw-r--r-- | sysdeps/generic/ldsodefs.h | 4 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/dl-librecon.h | 2 |
7 files changed, 104 insertions, 155 deletions
@@ -1,3 +1,16 @@ +2017-06-08 H.J. Lu <hongjiu.lu@intel.com> + + [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. + 2017-06-08 Zack Weinberg <zackw@panix.com> * libio/bits/types/FILE.h, libio/bits/types/__FILE.h diff --git a/elf/dl-minimal.c b/elf/dl-minimal.c index 1a35baf..59e159a 100644 --- a/elf/dl-minimal.c +++ b/elf/dl-minimal.c @@ -41,12 +41,6 @@ static void *alloc_ptr, *alloc_end, *alloc_last_block; /* Declarations of global functions. */ extern void weak_function free (void *ptr); extern void * weak_function realloc (void *ptr, size_t n); -extern unsigned long int weak_function __strtoul_internal (const char *nptr, - char **endptr, - int base, - int group); -extern unsigned long int weak_function strtoul (const char *nptr, - char **endptr, int base); /* Allocate an aligned memory block. */ @@ -236,84 +230,6 @@ Inconsistency detected by ld.so: %s: %u: %s%sUnexpected error: %s.\n", rtld_hidden_weak (__assert_perror_fail) #endif -unsigned long int weak_function -__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; - - if (*nptr == '-') - { - sign = -1; - ++nptr; - } - else if (*nptr == '+') - ++nptr; - - if (*nptr < '0' || *nptr > '9') - { - if (endptr != NULL) - *endptr = (char *) nptr; - return 0UL; - } - - assert (base == 0); - 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) - { - 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) - *endptr = (char *) nptr; - return ULONG_MAX; - } - result *= base; - result += digval; - ++nptr; - } - - if (endptr != NULL) - *endptr = (char *) nptr; - return result * sign; -} - - #undef _itoa /* We always use _itoa instead of _itoa_word in ld.so since the former also has to be present and it is never about speed when these 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; +} diff --git a/elf/dl-tunables.c b/elf/dl-tunables.c index 76e8c5c..b3c1392 100644 --- a/elf/dl-tunables.c +++ b/elf/dl-tunables.c @@ -102,73 +102,6 @@ get_next_env (char **envp, char **name, size_t *namelen, char **val, return NULL; } -/* A stripped down strtoul-like implementation for very early use. It does not - set errno if the result is outside bounds because it gets called before - errno may have been set up. */ -static uint64_t -tunables_strtoul (const char *nptr) -{ - uint64_t result = 0; - long int sign = 1; - unsigned max_digit; - - while (*nptr == ' ' || *nptr == '\t') - ++nptr; - - if (*nptr == '-') - { - sign = -1; - ++nptr; - } - else if (*nptr == '+') - ++nptr; - - if (*nptr < '0' || *nptr > '9') - 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) - return UINT64_MAX; - result *= base; - result += digval; - ++nptr; - } - - return result * sign; -} - #define TUNABLE_SET_VAL_IF_VALID_RANGE(__cur, __val, __type, __default_min, \ __default_max) \ ({ \ @@ -233,7 +166,7 @@ tunable_initialize (tunable_t *cur, const char *strval) if (cur->type.type_code != TUNABLE_TYPE_STRING) { - val = tunables_strtoul (strval); + val = _dl_strtoul (strval, NULL); valp = &val; } else @@ -2409,8 +2409,7 @@ process_envvars (enum mode *modep) /* Mask for the important hardware capabilities. */ if (!__libc_enable_secure && memcmp (envline, "HWCAP_MASK", 10) == 0) - GLRO(dl_hwcap_mask) = __strtoul_internal (&envline[11], NULL, - 0, 0); + GLRO(dl_hwcap_mask) = _dl_strtoul (&envline[11], NULL); break; #endif diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h index 695ac24..4508365 100644 --- a/sysdeps/generic/ldsodefs.h +++ b/sysdeps/generic/ldsodefs.h @@ -254,6 +254,10 @@ extern int _dl_name_match_p (const char *__name, const struct link_map *__map) extern unsigned long int _dl_higher_prime_number (unsigned long int n) internal_function attribute_hidden; +/* A stripped down strtoul-like implementation. */ +uint64_t internal_function _dl_strtoul (const char *, char **) + internal_function attribute_hidden; + /* Function used as argument for `_dl_receive_error' function. The arguments are the error code, error string, and the objname the error occurred in. */ diff --git a/sysdeps/unix/sysv/linux/dl-librecon.h b/sysdeps/unix/sysv/linux/dl-librecon.h index a6e54be..e726ff2 100644 --- a/sysdeps/unix/sysv/linux/dl-librecon.h +++ b/sysdeps/unix/sysv/linux/dl-librecon.h @@ -28,7 +28,7 @@ _dl_osversion_init (char *assume_kernel) for (i = 0; i < 3; i++, p = q + 1) { - j = __strtoul_internal (p, &q, 0, 0); + j = _dl_strtoul (p, &q); if (j >= 255 || p == q || (i < 2 && *q && *q != '.')) { osversion = 0; |