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.
This commit is contained in:
H.J. Lu 2017-06-08 12:52:42 -07:00
parent 199fc19d3a
commit 37b66c0b1a
7 changed files with 104 additions and 155 deletions

View File

@ -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> 2017-06-08 Zack Weinberg <zackw@panix.com>
* libio/bits/types/FILE.h, libio/bits/types/__FILE.h * libio/bits/types/FILE.h, libio/bits/types/__FILE.h

View File

@ -41,12 +41,6 @@ static void *alloc_ptr, *alloc_end, *alloc_last_block;
/* Declarations of global functions. */ /* Declarations of global functions. */
extern void weak_function free (void *ptr); extern void weak_function free (void *ptr);
extern void * weak_function realloc (void *ptr, size_t n); 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. */ /* 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) rtld_hidden_weak (__assert_perror_fail)
#endif #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 #undef _itoa
/* We always use _itoa instead of _itoa_word in ld.so since the former /* 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 also has to be present and it is never about speed when these

View File

@ -360,3 +360,87 @@ _dl_higher_prime_number (unsigned long int n)
return *low; 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;
}

View File

@ -102,73 +102,6 @@ get_next_env (char **envp, char **name, size_t *namelen, char **val,
return NULL; 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, \ #define TUNABLE_SET_VAL_IF_VALID_RANGE(__cur, __val, __type, __default_min, \
__default_max) \ __default_max) \
({ \ ({ \
@ -233,7 +166,7 @@ tunable_initialize (tunable_t *cur, const char *strval)
if (cur->type.type_code != TUNABLE_TYPE_STRING) if (cur->type.type_code != TUNABLE_TYPE_STRING)
{ {
val = tunables_strtoul (strval); val = _dl_strtoul (strval, NULL);
valp = &val; valp = &val;
} }
else else

View File

@ -2409,8 +2409,7 @@ process_envvars (enum mode *modep)
/* Mask for the important hardware capabilities. */ /* Mask for the important hardware capabilities. */
if (!__libc_enable_secure if (!__libc_enable_secure
&& memcmp (envline, "HWCAP_MASK", 10) == 0) && memcmp (envline, "HWCAP_MASK", 10) == 0)
GLRO(dl_hwcap_mask) = __strtoul_internal (&envline[11], NULL, GLRO(dl_hwcap_mask) = _dl_strtoul (&envline[11], NULL);
0, 0);
break; break;
#endif #endif

View File

@ -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) extern unsigned long int _dl_higher_prime_number (unsigned long int n)
internal_function attribute_hidden; 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 /* Function used as argument for `_dl_receive_error' function. The
arguments are the error code, error string, and the objname the arguments are the error code, error string, and the objname the
error occurred in. */ error occurred in. */

View File

@ -28,7 +28,7 @@ _dl_osversion_init (char *assume_kernel)
for (i = 0; i < 3; i++, p = q + 1) 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 != '.')) if (j >= 255 || p == q || (i < 2 && *q && *q != '.'))
{ {
osversion = 0; osversion = 0;