[PATCH] strto[iu](3): Make the implementation portable
Alejandro Colomar
alx at kernel.org
Sun Jul 21 10:26:34 UTC 2024
On Sat, Jul 20, 2024 at 09:03:34PM GMT, Alejandro Colomar wrote:
> POSIX allows systems that report EINVAL when no digits are found. On
> such systems the only way to differentiate EINVAL and ECANCELED is to
> initialized the end pointer to NULL before the call. On EINVAL cases,
> strto*max(3) will leave the pointer unmodified, so we'll read back the
> original NULL. On ECANCELED cases, strto*max(3) will set it to nptr.
>
> Link: <https://lists.freedesktop.org/archives/libbsd/2024-July/000456.html>
> Cc: Guillem Jover <guillem at hadrons.org>
> Cc: christos <christos at netbsd.org>
> Cc: Đoàn Trần Công Danh <congdanhqx at gmail.com>
> Cc: Eli Schwartz <eschwartz93 at gmail.com>
> Cc: Sam James <sam at gentoo.org>
> Cc: Serge Hallyn <serge at hallyn.com>
> Cc: Iker Pedrosa <ipedrosa at redhat.com>
> Cc: Michael Vetter <jubalh at iodoru.org>
> Cc: <libbsd at lists.freedesktop.org>
> Cc: <liba2i at lists.linux.dev>
> Signed-off-by: Alejandro Colomar <alx at kernel.org>
> ---
>
> Hi Christos,
>
> I'm not sure if this patch is wanted in NetBSD. It doesn't fix any bugs
> there. It would be interesting for those pasting this code in other
> systems (which is currently done by libbsd). Just in case you're
> interested, here it is.
>
> I didn't test it (I don't have a NetBSD build around), so please review
> thoroughly.
>
> BTW, the line
>
> + if (nptr == e && (*rstatus == 0 || *rstatus == EINVAL))
>
> You could also choose to simplify it as just `if (nptr == e)`, since
> all existing implementations (AFAIK) only arrive at nptr == e with errno
> being either 0 or EINVAL. However, for preventing ENOMEM or other
> strange errors that an implementation might add, those tests are there.
> Feel free to drop them (I didn't add them in my own strtoi(3)
> implementation). I've kept them here for completeness (and because you
> already had a test `*rstatus == 0` in that line, which was already
> superfluous, so I guessed you were preventing that kind of problems.
Self-correction: it was not superfluous. It was there to prevent
reading `*endptr` when the base is invalid, which would have been UB,
since it was uninitialized.
>
> Have a lovely day!
> Alex
>
> common/lib/libc/stdlib/_strtoi.h | 17 ++++++++++-------
> 1 file changed, 10 insertions(+), 7 deletions(-)
>
> diff --git a/common/lib/libc/stdlib/_strtoi.h b/common/lib/libc/stdlib/_strtoi.h
> index b838608f6b52..bea6a9f285a7 100644
> --- a/common/lib/libc/stdlib/_strtoi.h
> +++ b/common/lib/libc/stdlib/_strtoi.h
> @@ -3,6 +3,7 @@
> /*-
> * Copyright (c) 1990, 1993
> * The Regents of the University of California. All rights reserved.
> + * Copyright (c) 2024, Alejandro Colomar <alx at kernel.org>
> *
> * Redistribution and use in source and binary forms, with or without
> * modification, are permitted provided that the following conditions
> @@ -69,7 +70,7 @@ INT_FUNCNAME(_int_, _FUNCNAME, _l)(const char * __restrict nptr,
> int serrno;
> #endif
> __TYPE im;
> - char *ep;
> + char *e;
> int rep;
>
> _DIAGASSERT(hi >= lo);
> @@ -77,8 +78,7 @@ INT_FUNCNAME(_int_, _FUNCNAME, _l)(const char * __restrict nptr,
> _DIAGASSERT(nptr != NULL);
> /* endptr may be NULL */
>
> - if (endptr == NULL)
> - endptr = &ep;
> + e = NULL;
>
> if (rstatus == NULL)
> rstatus = &rep;
> @@ -90,9 +90,9 @@ INT_FUNCNAME(_int_, _FUNCNAME, _l)(const char * __restrict nptr,
>
> #if defined(_KERNEL) || defined(_STANDALONE) || \
> defined(HAVE_NBTOOL_CONFIG_H) || defined(BCS_ONLY)
> - im = __WRAPPED(nptr, endptr, base);
> + im = __WRAPPED(nptr, &e, base);
> #else
> - im = __WRAPPED_L(nptr, endptr, base, loc);
> + im = __WRAPPED_L(nptr, &e, base, loc);
> #endif
>
> #if !defined(_KERNEL) && !defined(_STANDALONE)
> @@ -100,8 +100,11 @@ INT_FUNCNAME(_int_, _FUNCNAME, _l)(const char * __restrict nptr,
> errno = serrno;
> #endif
>
> + if (endptr != NULL && e != NULL)
> + *endptr = e;
> +
> /* No digits were found */
> - if (*rstatus == 0 && nptr == *endptr)
> + if (nptr == e && (*rstatus == 0 || *rstatus == EINVAL))
> *rstatus = ECANCELED;
>
> if (im < lo) {
> @@ -117,7 +120,7 @@ INT_FUNCNAME(_int_, _FUNCNAME, _l)(const char * __restrict nptr,
> }
>
> /* There are further characters after number */
> - if (*rstatus == 0 && **endptr != '\0')
> + if (*rstatus == 0 && *e != '\0')
> *rstatus = ENOTSUP;
>
> return im;
>
> base-commit: 7a4c6afd05862bf8c28f0730d8d9cd7e2dce2a50
> --
> 2.45.2
>
--
<https://www.alejandro-colomar.es/>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <https://lists.freedesktop.org/archives/libbsd/attachments/20240721/88acfb12/attachment.sig>
More information about the libbsd
mailing list