Fix special case for C2x strtol binary constant handling (BZ# 30371)

When the base is 0 or 2 and the first two characters are '0' and 'b',
but the rest are no binary digits.  In this case this is no error,
and strtol must return 0 and ENDPTR points to the 'x' or 'b'.

Checked on x86_64-linux-gnu and i686-linux-gnu.

Reviewed-by: Florian Weimer <fweimer@redhat.com>
This commit is contained in:
Adhemerval Zanella 2023-05-25 08:14:37 -03:00
parent e0189b2540
commit 95c9a6e806
10 changed files with 65 additions and 39 deletions

View File

@ -526,11 +526,15 @@ INTERNAL (__strtol_l) (const STRING_TYPE *nptr, STRING_TYPE **endptr,
noconv: noconv:
/* We must handle a special case here: the base is 0 or 16 and the /* We must handle a special case here: the base is 0 or 16 and the
first two characters are '0' and 'x', but the rest are no first two characters are '0' and 'x', but the rest are no
hexadecimal digits. This is no error case. We return 0 and hexadecimal digits. Likewise when the base is 0 or 2 and the
ENDPTR points to the `x`. */ first two characters are '0' and 'b', but the rest are no binary
digits. This is no error case. We return 0 and ENDPTR points to
the 'x' or 'b'. */
if (endptr != NULL) if (endptr != NULL)
{ {
if (save - nptr >= 2 && TOUPPER (save[-1]) == L_('X') if (save - nptr >= 2
&& (TOUPPER (save[-1]) == L_('X')
|| (bin_cst && TOUPPER (save[-1]) == L_('B')))
&& save[-2] == L_('0')) && save[-2] == L_('0'))
*endptr = (STRING_TYPE *) &save[-1]; *endptr = (STRING_TYPE *) &save[-1];
else else

View File

@ -20,6 +20,7 @@
#undef _GNU_SOURCE #undef _GNU_SOURCE
#define CHAR char #define CHAR char
#define WIDE 0
#define FNPFX strto #define FNPFX strto
#define L_(C) C #define L_(C) C
#define TEST_C2X 0 #define TEST_C2X 0

View File

@ -23,6 +23,7 @@
#define _ISOC2X_SOURCE #define _ISOC2X_SOURCE
#define CHAR char #define CHAR char
#define WIDE 0
#define FNPFX strto #define FNPFX strto
#define L_(C) C #define L_(C) C
#define TEST_C2X 1 #define TEST_C2X 1

View File

@ -25,6 +25,7 @@
#define __GLIBC_USE_C2X_STRTOL 0 #define __GLIBC_USE_C2X_STRTOL 0
#define CHAR char #define CHAR char
#define WIDE 0
#define FNPFX strto #define FNPFX strto
#define L_(C) C #define L_(C) C
#define TEST_C2X 0 #define TEST_C2X 0

View File

@ -18,6 +18,7 @@
<https://www.gnu.org/licenses/>. */ <https://www.gnu.org/licenses/>. */
#define CHAR char #define CHAR char
#define WIDE 0
#define FNPFX strto #define FNPFX strto
#define L_(C) C #define L_(C) C
#define TEST_C2X 1 #define TEST_C2X 1

View File

@ -21,6 +21,7 @@
#include <locale.h> #include <locale.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <wchar.h> #include <wchar.h>
#include <support/check.h> #include <support/check.h>
@ -32,13 +33,19 @@
#define CONCAT(X, Y) CONCAT_ (X, Y) #define CONCAT(X, Y) CONCAT_ (X, Y)
#define FNX(FN) CONCAT (FNPFX, FN) #define FNX(FN) CONCAT (FNPFX, FN)
#define CHECK_RES(ARG, RES, EP, EXPECTED) \ #if WIDE
# define STRCHR wcschr
#else
# define STRCHR strchr
#endif
#define CHECK_RES(ARG, RES, EP, EXPECTED, EXPECTED_EP) \
do \ do \
{ \ { \
if (TEST_C2X) \ if (TEST_C2X) \
{ \ { \
TEST_COMPARE ((RES), EXPECTED); \ TEST_COMPARE ((RES), EXPECTED); \
TEST_COMPARE (*(EP), 0); \ TEST_VERIFY ((EP) == EXPECTED_EP); \
} \ } \
else \ else \
{ \ { \
@ -51,95 +58,102 @@
while (0) while (0)
static void static void
one_check (const CHAR *s, long int expected_l, unsigned long int expected_ul, one_check (const CHAR *s, const CHAR *expected_p, long int expected_l,
long long int expected_ll, unsigned long long int expected_ull) unsigned long int expected_ul, long long int expected_ll,
unsigned long long int expected_ull)
{ {
expected_p = expected_p == NULL ? STRCHR (s, '\0') : expected_p;
CHAR *ep; CHAR *ep;
long int ret_l; long int ret_l;
unsigned long int ret_ul; unsigned long int ret_ul;
long long int ret_ll; long long int ret_ll;
unsigned long long int ret_ull; unsigned long long int ret_ull;
ret_l = FNX (l) (s, &ep, 0); ret_l = FNX (l) (s, &ep, 0);
CHECK_RES (s, ret_l, ep, expected_l); CHECK_RES (s, ret_l, ep, expected_l, expected_p);
ret_l = FNX (l) (s, &ep, 2); ret_l = FNX (l) (s, &ep, 2);
CHECK_RES (s, ret_l, ep, expected_l); CHECK_RES (s, ret_l, ep, expected_l, expected_p);
ret_ul = FNX (ul) (s, &ep, 0); ret_ul = FNX (ul) (s, &ep, 0);
CHECK_RES (s, ret_ul, ep, expected_ul); CHECK_RES (s, ret_ul, ep, expected_ul, expected_p);
ret_ul = FNX (ul) (s, &ep, 2); ret_ul = FNX (ul) (s, &ep, 2);
CHECK_RES (s, ret_ul, ep, expected_ul); CHECK_RES (s, ret_ul, ep, expected_ul, expected_p);
ret_ll = FNX (ll) (s, &ep, 0); ret_ll = FNX (ll) (s, &ep, 0);
CHECK_RES (s, ret_ll, ep, expected_ll); CHECK_RES (s, ret_ll, ep, expected_ll, expected_p);
ret_ll = FNX (ll) (s, &ep, 2); ret_ll = FNX (ll) (s, &ep, 2);
CHECK_RES (s, ret_ll, ep, expected_ll); CHECK_RES (s, ret_ll, ep, expected_ll, expected_p);
ret_ull = FNX (ull) (s, &ep, 0); ret_ull = FNX (ull) (s, &ep, 0);
CHECK_RES (s, ret_ull, ep, expected_ull); CHECK_RES (s, ret_ull, ep, expected_ull, expected_p);
ret_ull = FNX (ull) (s, &ep, 2); ret_ull = FNX (ull) (s, &ep, 2);
CHECK_RES (s, ret_ull, ep, expected_ull); CHECK_RES (s, ret_ull, ep, expected_ull, expected_p);
ret_ll = FNX (imax) (s, &ep, 0); ret_ll = FNX (imax) (s, &ep, 0);
CHECK_RES (s, ret_ll, ep, expected_ll); CHECK_RES (s, ret_ll, ep, expected_ll, expected_p);
ret_ll = FNX (imax) (s, &ep, 2); ret_ll = FNX (imax) (s, &ep, 2);
CHECK_RES (s, ret_ll, ep, expected_ll); CHECK_RES (s, ret_ll, ep, expected_ll, expected_p);
ret_ull = FNX (umax) (s, &ep, 0); ret_ull = FNX (umax) (s, &ep, 0);
CHECK_RES (s, ret_ull, ep, expected_ull); CHECK_RES (s, ret_ull, ep, expected_ull, expected_p);
ret_ull = FNX (umax) (s, &ep, 2); ret_ull = FNX (umax) (s, &ep, 2);
CHECK_RES (s, ret_ull, ep, expected_ull); CHECK_RES (s, ret_ull, ep, expected_ull, expected_p);
#if TEST_Q #if TEST_Q
ret_ll = FNX (q) (s, &ep, 0); ret_ll = FNX (q) (s, &ep, 0);
CHECK_RES (s, ret_ll, ep, expected_ll); CHECK_RES (s, ret_ll, ep, expected_ll, expected_p);
ret_ll = FNX (q) (s, &ep, 2); ret_ll = FNX (q) (s, &ep, 2);
CHECK_RES (s, ret_ll, ep, expected_ll); CHECK_RES (s, ret_ll, ep, expected_ll, expected_p);
ret_ull = FNX (uq) (s, &ep, 0); ret_ull = FNX (uq) (s, &ep, 0);
CHECK_RES (s, ret_ull, ep, expected_ull); CHECK_RES (s, ret_ull, ep, expected_ull, expected_p);
ret_ull = FNX (uq) (s, &ep, 2); ret_ull = FNX (uq) (s, &ep, 2);
CHECK_RES (s, ret_ull, ep, expected_ull); CHECK_RES (s, ret_ull, ep, expected_ull, expected_p);
#endif #endif
#if TEST_LOCALE #if TEST_LOCALE
locale_t loc = xnewlocale (LC_NUMERIC_MASK, "C", (locale_t) 0); locale_t loc = xnewlocale (LC_NUMERIC_MASK, "C", (locale_t) 0);
ret_l = FNX (l_l) (s, &ep, 0, loc); ret_l = FNX (l_l) (s, &ep, 0, loc);
CHECK_RES (s, ret_l, ep, expected_l); CHECK_RES (s, ret_l, ep, expected_l, expected_p);
ret_l = FNX (l_l) (s, &ep, 2, loc); ret_l = FNX (l_l) (s, &ep, 2, loc);
CHECK_RES (s, ret_l, ep, expected_l); CHECK_RES (s, ret_l, ep, expected_l, expected_p);
ret_ul = FNX (ul_l) (s, &ep, 0, loc); ret_ul = FNX (ul_l) (s, &ep, 0, loc);
CHECK_RES (s, ret_ul, ep, expected_ul); CHECK_RES (s, ret_ul, ep, expected_ul, expected_p);
ret_ul = FNX (ul_l) (s, &ep, 2, loc); ret_ul = FNX (ul_l) (s, &ep, 2, loc);
CHECK_RES (s, ret_ul, ep, expected_ul); CHECK_RES (s, ret_ul, ep, expected_ul, expected_p);
ret_ll = FNX (ll_l) (s, &ep, 0, loc); ret_ll = FNX (ll_l) (s, &ep, 0, loc);
CHECK_RES (s, ret_ll, ep, expected_ll); CHECK_RES (s, ret_ll, ep, expected_ll, expected_p);
ret_ll = FNX (ll_l) (s, &ep, 2, loc); ret_ll = FNX (ll_l) (s, &ep, 2, loc);
CHECK_RES (s, ret_ll, ep, expected_ll); CHECK_RES (s, ret_ll, ep, expected_ll, expected_p);
ret_ull = FNX (ull_l) (s, &ep, 0, loc); ret_ull = FNX (ull_l) (s, &ep, 0, loc);
CHECK_RES (s, ret_ull, ep, expected_ull); CHECK_RES (s, ret_ull, ep, expected_ull, expected_p);
ret_ull = FNX (ull_l) (s, &ep, 2, loc); ret_ull = FNX (ull_l) (s, &ep, 2, loc);
CHECK_RES (s, ret_ull, ep, expected_ull); CHECK_RES (s, ret_ull, ep, expected_ull, expected_p);
#endif #endif
} }
static int static int
do_test (void) do_test (void)
{ {
one_check (L_("0b101"), 5, 5, 5, 5); {
one_check (L_("0B101"), 5, 5, 5, 5); const CHAR *input = L_("0b");
one_check (L_("-0b11111"), -31, -31, -31, -31); one_check (input, input + 1, 0L, 0UL, 0LL, 0ULL);
one_check (L_("-0B11111"), -31, -31, -31, -31); }
one_check (L_("0b111111111111111111111111111111111"), one_check (L_("0b101"), NULL, 5, 5, 5, 5);
one_check (L_("0B101"), NULL, 5, 5, 5, 5);
one_check (L_("-0b11111"), NULL, -31, -31, -31, -31);
one_check (L_("-0B11111"), NULL, -31, -31, -31, -31);
one_check (L_("0b111111111111111111111111111111111"), NULL,
LONG_MAX >= 0x1ffffffffLL ? (long int) 0x1ffffffffLL : LONG_MAX, LONG_MAX >= 0x1ffffffffLL ? (long int) 0x1ffffffffLL : LONG_MAX,
(ULONG_MAX >= 0x1ffffffffULL (ULONG_MAX >= 0x1ffffffffULL
? (unsigned long int) 0x1ffffffffULL ? (unsigned long int) 0x1ffffffffULL
: ULONG_MAX), : ULONG_MAX),
0x1ffffffffLL, 0x1ffffffffULL); 0x1ffffffffLL, 0x1ffffffffULL);
one_check (L_("0B111111111111111111111111111111111"), one_check (L_("0B111111111111111111111111111111111"), NULL,
LONG_MAX >= 0x1ffffffffLL ? (long int) 0x1ffffffffLL : LONG_MAX, LONG_MAX >= 0x1ffffffffLL ? (long int) 0x1ffffffffLL : LONG_MAX,
(ULONG_MAX >= 0x1ffffffffULL (ULONG_MAX >= 0x1ffffffffULL
? (unsigned long int) 0x1ffffffffULL ? (unsigned long int) 0x1ffffffffULL
: ULONG_MAX), : ULONG_MAX),
0x1ffffffffLL, 0x1ffffffffULL); 0x1ffffffffLL, 0x1ffffffffULL);
one_check (L_("-0b111111111111111111111111111111111"), one_check (L_("-0b111111111111111111111111111111111"), NULL,
LONG_MIN <= -0x1ffffffffLL ? (long int) -0x1ffffffffLL : LONG_MIN, LONG_MIN <= -0x1ffffffffLL ? (long int) -0x1ffffffffLL : LONG_MIN,
(ULONG_MAX >= 0x1ffffffffULL (ULONG_MAX >= 0x1ffffffffULL
? (unsigned long int) -0x1ffffffffULL ? (unsigned long int) -0x1ffffffffULL
: ULONG_MAX), : ULONG_MAX),
-0x1ffffffffLL, -0x1ffffffffULL); -0x1ffffffffLL, -0x1ffffffffULL);
one_check (L_("-0B111111111111111111111111111111111"), one_check (L_("-0B111111111111111111111111111111111"), NULL,
LONG_MIN <= -0x1ffffffffLL ? (long int) -0x1ffffffffLL : LONG_MIN, LONG_MIN <= -0x1ffffffffLL ? (long int) -0x1ffffffffLL : LONG_MIN,
(ULONG_MAX >= 0x1ffffffffULL (ULONG_MAX >= 0x1ffffffffULL
? (unsigned long int) -0x1ffffffffULL ? (unsigned long int) -0x1ffffffffULL

View File

@ -20,6 +20,7 @@
#undef _GNU_SOURCE #undef _GNU_SOURCE
#define CHAR wchar_t #define CHAR wchar_t
#define WIDE 1
#define FNPFX wcsto #define FNPFX wcsto
#define L_(C) L ## C #define L_(C) L ## C
#define TEST_C2X 0 #define TEST_C2X 0

View File

@ -23,6 +23,7 @@
#define _ISOC2X_SOURCE #define _ISOC2X_SOURCE
#define CHAR wchar_t #define CHAR wchar_t
#define WIDE 1
#define FNPFX wcsto #define FNPFX wcsto
#define L_(C) L ## C #define L_(C) L ## C
#define TEST_C2X 1 #define TEST_C2X 1

View File

@ -25,6 +25,7 @@
#define __GLIBC_USE_C2X_STRTOL 0 #define __GLIBC_USE_C2X_STRTOL 0
#define CHAR wchar_t #define CHAR wchar_t
#define WIDE 1
#define FNPFX wcsto #define FNPFX wcsto
#define L_(C) L ## C #define L_(C) L ## C
#define TEST_C2X 0 #define TEST_C2X 0

View File

@ -18,6 +18,7 @@
<https://www.gnu.org/licenses/>. */ <https://www.gnu.org/licenses/>. */
#define CHAR wchar_t #define CHAR wchar_t
#define WIDE 1
#define FNPFX wcsto #define FNPFX wcsto
#define L_(C) L ## C #define L_(C) L ## C
#define TEST_C2X 1 #define TEST_C2X 1