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>
* 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. */
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

View File

@ -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;
}

View File

@ -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

View File

@ -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

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)
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. */

View File

@ -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;