From: Alejandro Colomar <alx@kernel.org>
To: bug-gnulib@gnu.org
Cc: "Alejandro Colomar" <alx@kernel.org>,
"Paul Eggert" <eggert@cs.ucla.edu>,
"Bruno Haible" <bruno@clisp.org>,
"Đoàn Trần Công Danh" <congdanhqx@gmail.com>,
"Eli Schwartz" <eschwartz93@gmail.com>,
"Sam James" <sam@gentoo.org>, "Serge Hallyn" <serge@hallyn.com>,
"Iker Pedrosa" <ipedrosa@redhat.com>,
"Michael Vetter" <jubalh@iodoru.org>,
liba2i@lists.linux.dev
Subject: [PATCH v1 1/2] xstrtol: Correctly handle an invalid base
Date: Fri, 19 Jul 2024 14:53:34 +0200 [thread overview]
Message-ID: <20240719125312.15885-3-alx@kernel.org> (raw)
In-Reply-To: <20240719125312.15885-2-alx@kernel.org>
[-- Attachment #1: Type: text/plain, Size: 4072 bytes --]
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 = 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 = 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 strtol")
Cc: Paul Eggert <eggert@cs.ucla.edu>
Cc: Bruno Haible <bruno@clisp.org>
Cc: Đoàn Trần Công Danh <congdanhqx@gmail.com>
Cc: Eli Schwartz <eschwartz93@gmail.com>
Cc: Sam James <sam@gentoo.org>
Cc: Serge Hallyn <serge@hallyn.com>
Cc: Iker Pedrosa <ipedrosa@redhat.com>
Cc: Michael Vetter <jubalh@iodoru.org>
Cc: <liba2i@lists.linux.dev>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
---
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 = endptr ? endptr : &t_ptr;
- *p = (char *) nptr;
+ char *e = NULL;
if (! TYPE_SIGNED (__strtol_t))
{
@@ -82,14 +80,21 @@ __xstrtol (char const *nptr, char **endptr, int base,
while (isspace (ch))
ch = *++q;
if (ch == '-')
- return LONGINT_INVALID;
+ {
+ if (endptr)
+ *endptr = (char *) nptr;
+ return LONGINT_INVALID;
+ }
}
errno = 0;
- __strtol_t tmp = __strtol (nptr, p, base);
+ __strtol_t tmp = __strtol (nptr, &e, base);
strtol_error err = LONGINT_OK;
- if (*p == nptr)
+ if (endptr && e)
+ *endptr = e;
+
+ if (e == 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;
}
- if (**p != '\0')
+ if (*e != '\0')
{
int xbase = 1024;
int suffixes = 1;
strtol_error overflow;
- if (!strchr (valid_suffixes, **p))
+ if (!strchr (valid_suffixes, *e))
{
*val = tmp;
return err | LONGINT_INVALID_SUFFIX_CHAR;
}
- 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. */
if (strchr (valid_suffixes, '0'))
- switch (p[0][1])
+ switch (e[1])
{
case 'i':
- if (p[0][2] == 'B')
+ if (e[2] == 'B')
suffixes += 2;
break;
@@ -153,7 +158,7 @@ __xstrtol (char const *nptr, char **endptr, int base,
}
}
- switch (**p)
+ switch (*e)
{
case 'b':
overflow = bkm_scale (&tmp, 512);
@@ -224,8 +229,10 @@ __xstrtol (char const *nptr, char **endptr, int base,
}
err |= overflow;
- *p += suffixes;
- if (**p)
+ e += suffixes;
+ if (endptr)
+ *endptr = e;
+ if (*e)
err |= LONGINT_INVALID_SUFFIX_CHAR;
}
--
2.45.2
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
next prev parent reply other threads:[~2024-07-19 12:53 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-07-19 12:53 [PATCH v1 0/2] xstrtol() fixes Alejandro Colomar
2024-07-19 12:53 ` Alejandro Colomar [this message]
2024-07-19 13:09 ` [PATCH v1 1/2] xstrtol: Correctly handle an invalid base Alejandro Colomar
2024-07-19 13:10 ` Alejandro Colomar
2024-07-19 12:53 ` [PATCH v1 2/2] xstrtol: Add defensive check against undocumented errors Alejandro Colomar
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240719125312.15885-3-alx@kernel.org \
--to=alx@kernel.org \
--cc=bruno@clisp.org \
--cc=bug-gnulib@gnu.org \
--cc=congdanhqx@gmail.com \
--cc=eggert@cs.ucla.edu \
--cc=eschwartz93@gmail.com \
--cc=ipedrosa@redhat.com \
--cc=jubalh@iodoru.org \
--cc=liba2i@lists.linux.dev \
--cc=sam@gentoo.org \
--cc=serge@hallyn.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox