[PATCH v1 1/2] xstrtol: Correctly handle an invalid base

Alejandro Colomar <[email protected]> Fri, 19 Jul 2024 14:53:34 +0200
Newsgroups dev.linux.lists.liba2i
Message-ID <[email protected]>
--os5zt5xuey5fttuk
Content-Type: text/plain; protected-headers=v1; charset=utf-8
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable
From: Alejandro Colomar <[email protected]>
To: [email protected]
Cc: Alejandro Colomar <[email protected]>, Paul Eggert <[email protected]>, 
	Bruno Haible <[email protected]>, 
	=?utf-8?B?xJBvw6BuIFRy4bqnbiBDw7RuZw==?= Danh <[email protected]>, Eli Schwartz <[email protected]>, Sam James <[email protected]>, 
	Serge Hallyn <[email protected]>, Iker Pedrosa <[email protected]>, 
	Michael Vetter <[email protected]>, [email protected]
Subject: [PATCH v1 1/2] xstrtol: Correctly handle an invalid base
References: <[email protected]>
MIME-Version: 1.0
In-Reply-To: <[email protected]>

strtol(3) doesn't set the end pointer if the base is invalid.  This
allows a caller to differentiate between "invalid base" (what
strtoi(3bsd) calls EINVAL) and an "no digits seen" (what strtoi(3bsd)
calls ECANCELED) in systems that report EINVAL on no digits seen (POSIX
allows this).

	strtol("foo", &e, 0);
	strtol("0", &e, -1);

The former call will set e =3D nptr.
The latter will leave e untouched.

The caller has no other way to portably differentiate the calls.

The way to differentiate those, thus, is to initialize e =3D NULL, to
allow reading it after the call.

While doing this, change the behavior of this function to only set
*endptr if strtol(3) has set it, leaving it untouched otherwise.

Fixes: 034a18049cbc (2014-12-20, "assure: new module")
Fixes: 64ddc975e72c (2024-07-18, "xstrtol: document and stray less from str=
tol")
Cc: Paul Eggert <[email protected]>
Cc: Bruno Haible <[email protected]>
Cc: =C4=90o=C3=A0n Tr=E1=BA=A7n C=C3=B4ng Danh <[email protected]>
Cc: Eli Schwartz <[email protected]>
Cc: Sam James <[email protected]>
Cc: Serge Hallyn <[email protected]>
Cc: Iker Pedrosa <[email protected]>
Cc: Michael Vetter <[email protected]>
Cc: <[email protected]>
Signed-off-by: Alejandro Colomar <[email protected]>
---
 lib/xstrtol.c | 35 +++++++++++++++++++++--------------
 1 file changed, 21 insertions(+), 14 deletions(-)

diff --git a/lib/xstrtol.c b/lib/xstrtol.c
index c3145171f3..592673557f 100644
--- a/lib/xstrtol.c
+++ b/lib/xstrtol.c
@@ -71,9 +71,7 @@ strtol_error
 __xstrtol (char const *nptr, char **endptr, int base,
            __strtol_t *val, char const *valid_suffixes)
 {
-  char *t_ptr;
-  char **p =3D endptr ? endptr : &t_ptr;
-  *p =3D (char *) nptr;
+  char *e =3D NULL;
=20
   if (! TYPE_SIGNED (__strtol_t))
     {
@@ -82,14 +80,21 @@ __xstrtol (char const *nptr, char **endptr, int base,
       while (isspace (ch))
         ch =3D *++q;
       if (ch =3D=3D '-')
-        return LONGINT_INVALID;
+        {
+          if (endptr)
+            *endptr =3D (char *) nptr;
+          return LONGINT_INVALID;
+        }
     }
=20
   errno =3D 0;
-  __strtol_t tmp =3D __strtol (nptr, p, base);
+  __strtol_t tmp =3D __strtol (nptr, &e, base);
   strtol_error err =3D LONGINT_OK;
=20
-  if (*p =3D=3D nptr)
+  if (endptr && e)
+    *endptr =3D e;
+
+  if (e =3D=3D nptr)
     {
       /* If there is no number but there is a valid suffix, assume the
          number is 1.  The string is invalid otherwise.  */
@@ -113,19 +118,19 @@ __xstrtol (char const *nptr, char **endptr, int base,
       return err;
     }
=20
-  if (**p !=3D '\0')
+  if (*e !=3D '\0')
     {
       int xbase =3D 1024;
       int suffixes =3D 1;
       strtol_error overflow;
=20
-      if (!strchr (valid_suffixes, **p))
+      if (!strchr (valid_suffixes, *e))
         {
           *val =3D tmp;
           return err | LONGINT_INVALID_SUFFIX_CHAR;
         }
=20
-      switch (**p)
+      switch (*e)
         {
         case 'E': case 'G': case 'g': case 'k': case 'K': case 'M': case '=
m':
         case 'P': case 'Q': case 'R': case 'T': case 't': case 'Y': case '=
Z':
@@ -138,10 +143,10 @@ __xstrtol (char const *nptr, char **endptr, int base,
              power-of-1024.  */
=20
           if (strchr (valid_suffixes, '0'))
-            switch (p[0][1])
+            switch (e[1])
               {
               case 'i':
-                if (p[0][2] =3D=3D 'B')
+                if (e[2] =3D=3D 'B')
                   suffixes +=3D 2;
                 break;
=20
@@ -153,7 +158,7 @@ __xstrtol (char const *nptr, char **endptr, int base,
               }
         }
=20
-      switch (**p)
+      switch (*e)
         {
         case 'b':
           overflow =3D bkm_scale (&tmp, 512);
@@ -224,8 +229,10 @@ __xstrtol (char const *nptr, char **endptr, int base,
         }
=20
       err |=3D overflow;
-      *p +=3D suffixes;
-      if (**p)
+      e +=3D suffixes;
+      if (endptr)
+        *endptr =3D e;
+      if (*e)
         err |=3D LONGINT_INVALID_SUFFIX_CHAR;
     }
=20
--=20
2.45.2


--os5zt5xuey5fttuk
Content-Type: application/pgp-signature; name="signature.asc"

-----BEGIN PGP SIGNATURE-----

iQIzBAABCgAdFiEE6jqH8KTroDDkXfJAnowa+77/2zIFAmaaYc4ACgkQnowa+77/
2zLvdg/7BpL+T18Odma2CpBhuL/vwdQFyy2UMkWz7gnBjNCxoO/1/2KYxnI/tebu
FoaQCN/xdL5rQBg9UATQTV3fco7sw0+CxcIteW5Iu5FGivQMv9Nbs/YTyrX3E84x
k16LfkrSi5ZYEBJkjxnY8EqASNVhTisW9/Pcx5tkDwvp1lgiYS6rd08O8Kd3Qo0f
fMKW2ZDNMfu5aZJu/3e/WN6B7pfaJxMyTmK4KCRGp7AT5OT6JdVPlmtYxxgt1Tf1
cNDesdHB+yZPXsR28cM2jlyx8/kqqRvaBwt81Iw5/Nb8L1EdAIpjKEBy9NwU2Lh3
kgo9LkvFSFLCO+J3psLdaR4yd6fmZOu3np6Y79/E4r51EWg6W/uKjIvVLU67dW0d
t1XfHclx7iBq0bqkSZo3hwrnz58QHT9XfkK81j+uaKTS7KFRYtAcHcZfVpm+JUH9
Gt9rN0/D/tr0T+BHgXLlT2z4HHFE47qWDu3QMmks5JE5HLjFMs2Zpuoxm9TWWq2s
surtB9rWWUe3TeTmxFv77GWb0D3h4sfFsXyga1YuR1Tg6qkCOLeJp1k5hR4kKXNu
kcRx6EKXqDMbROA1GeoM8kWLlUtVywt04qSTjDHI3I/aGj5/nLn1KiEboDujm9ZP
x5jCDyOSJcbQ3TGqIEAeBGQZPlY8a6r1ZZ74rRVvf80Mg1HeoO0=
=Sb8Q
-----END PGP SIGNATURE-----

--os5zt5xuey5fttuk--