NetBSD Problem Report #59198
From www@netbsd.org Wed Mar 19 23:22:14 2025
Return-Path: <www@netbsd.org>
Received: from mail.netbsd.org (mail.netbsd.org [199.233.217.200])
(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256
client-signature RSA-PSS (2048 bits) client-digest SHA256)
(Client CN "mail.NetBSD.org", Issuer "mail.NetBSD.org CA" (not verified))
by mollari.NetBSD.org (Postfix) with ESMTPS id 1EE841A9239
for <gnats-bugs@gnats.NetBSD.org>; Wed, 19 Mar 2025 23:22:14 +0000 (UTC)
Message-Id: <20250319232212.8609C1A923C@mollari.NetBSD.org>
Date: Wed, 19 Mar 2025 23:22:12 +0000 (UTC)
From: alx@kernel.org
Reply-To: alx@kernel.org
To: gnats-bugs@NetBSD.org
Subject: Reject negative input in strtou(3), reporting ERANGE
X-Send-Pr-Version: www-1.0
>Number: 59198
>Category: lib
>Synopsis: Reject negative input in strtou(3), reporting ERANGE
>Confidential: no
>Severity: non-critical
>Priority: medium
>Responsible: lib-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Wed Mar 19 23:25:00 +0000 2025
>Last-Modified: Fri Mar 21 20:35:00 +0000 2025
>Originator: Alejandro Colomar
>Release: 10.1
>Organization:
Linux man-pages project, C Committee (WG14), shadow-utils
>Environment:
>Description:
strtou(3), just like the standard strtoumax(3) family of functions, first converts negative values into huge positive values, and then performs the range checks.
This is behavior that most programmers don't even know, less expect.
In every use case of this API, I've always wanted to reject negative input. In the standard strtoumax(3), and also in the strtou(3) API. However, I think it is more relevant in strtou(3), because we have explicit range checks. If I say the minimum acceptable value is 0, then -1 is certainly not an acceptable value, not even converted via modulo arithmetics into UINTMAX_MAX. It should result in ERANGE.
I have developed my own wrapper, strtou_noneg():
uintmax_t
strtou_noneg(const char *s, char **restrict endp, int base,
uintmax_t min, uintmax_t max, int *restrict status)
{
int st;
if (status == NULL)
status = &st;
if (strtoi(s, endp, base, 0, 1, status) == 0 && *status == ERANGE)
return min;
return strtou(s, endp, base, min, max, status);
}
and I always call that, because the behavior of strtou(3) is just evil. Would you mind reforming strtou(3) to behave like that, rejecting negative input? I suspect there are no real users of that misfeature, and probably many callers will silently have their bugs fixed.
While discussing standardization of this API, we found some bugs in GNU gettext where the author was unaware that strtoul(3) had this evil behavior. There are many more programmers that are unaware of this.
>How-To-Repeat:
strtou("-1", NULL, 0, 0, UINTMAX_MAX, &status);
// status will be 0, but should be ERANGE
>Fix:
I have developed my own wrapper, strtou_noneg():
uintmax_t
strtou_noneg(const char *s, char **restrict endp, int base,
uintmax_t min, uintmax_t max, int *restrict status)
{
int st;
if (status == NULL)
status = &st;
if (strtoi(s, endp, base, 0, 1, status) == 0 && *status == ERANGE)
return min;
return strtou(s, endp, base, min, max, status);
}
This should be the actual implementation of strtou(3).
>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: misc-bug-people->lib-bug-people
Responsible-Changed-By: martin@NetBSD.org
Responsible-Changed-When: Thu, 20 Mar 2025 08:42:13 +0000
Responsible-Changed-Why:
Over to the library team
From: Alejandro Colomar <alx@kernel.org>
To: gnats-bugs@netbsd.org
Cc: Bruno Haible <bruno@clisp.org>
Subject: Re: lib/59198: Reject negative input in strtou(3), reporting ERANGE
Date: Fri, 21 Mar 2025 21:25:36 +0100
--jrofmsi74wrqmdsk
Content-Type: text/plain; protected-headers=v1; charset=utf-8
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable
From: Alejandro Colomar <alx@kernel.org>
To: gnats-bugs@netbsd.org
Cc: Bruno Haible <bruno@clisp.org>
Subject: Re: lib/59198: Reject negative input in strtou(3), reporting ERANGE
References: <pr-misc-59198@gnats.netbsd.org>
<20250319232212.8609C1A923C@mollari.NetBSD.org>
<20250319232500.4D8401A923C@mollari.NetBSD.org>
MIME-Version: 1.0
In-Reply-To: <20250319232500.4D8401A923C@mollari.NetBSD.org>
Hi,
Actually, considering the name strtou(3), which is about **unsigned**
integers, maybe negative numbers should not trigger an ERANGE error, but
actually an ECANCELED error. The sign, even a positive sign, should not
be part of an unsigned number.
Here are some example implementations for this:
unsigned long
strtoul_nn(const char *restrict s, char **restrict endp, int base)
{
while (isspace((unsigned char) *s))
s++;
if (!isdigit((unsigned char) *s))
return 0;
return strtoul(s, endp, base);
}
uintmax_t
strtou_nn(const char *restrict s, char **restrict endp, int base,
uintmax_t min, uintmax_t max, int *status)
{
while (isspace((unsigned char) *s))
s++;
if (!isdigit((unsigned char) *s)) {
if (status)
*status =3D ECANCELED;
return min;
}
return strtou(s, endp, base, min, max, status);
}
I'm going to expand the BUGS section in the strtoul(3) Linux manual
page, and mention the strtoul_nn() example as a workaround for this bug
in the standard strtoul(3).
The strtou_nn() should be the ideal behavior of strtou(3).
(I hope this arrives at the bug ticket.)
Cheers,
Alex
--=20
<https://www.alejandro-colomar.es/>
--jrofmsi74wrqmdsk
Content-Type: application/pgp-signature; name="signature.asc"
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEES7Jt9u9GbmlWADAi64mZXMKQwqkFAmfdyzkACgkQ64mZXMKQ
wqmUkBAAi/WCW17t22OdSSJOMnHOcE4VudxM0Y7PZls5jE9oKxPIUoEcTlTR9566
QKHMCJPswkazqUqrJMb4/4Gsr2RyHcJPJTz9HYqIK7BX4MZWOl/4BXe7Qam6POvn
YIdBhKmUoePKfK+diicGqqfcWWUZXJIqZM1PD1JASveemrs6KxP5Iqjo5RzTJogV
VSNwmLVgnqy3DO50usehl2bEeiDQLxGNPoKsIg9YRY0T3x3dVkcYkcV0guGw3riL
7EhcJWFA6ENbuGrfRgAZhfXw2ltO5vb9KMxjplbjSLIPEDytDAFvtrfKuvV4pcbK
7zEM3ql7lNH8czoeI6t/mkauUjnRkWLJ/dgnZvOm3eo0jjzcNsI3ZUlsjnklayHY
8lzleyTBGLMZ3k76QPSXaQkaj109juWU02U7XKhlF+2CH+X+J3gDuvWZuJt3F6Ik
PMk6Sb5vb12RI0NxS1LSX0NyXMZ7Y7ns+DD6M9aEY89hjhsaVgVtsu94LRyFRv1m
G3fwhVAPPx1zmcZLtigWnv1PLKeYsVHydn85rcAouN3aCqvNLYezg9nXXbirrLOI
yIeSAO1acFXVIprC/RBhBs9NIo8/Qj501pGtQ0TVfxZGhhvWKH51ERghybfQzQ3G
TV5gfMRiSv9YkELM7uSCioXok5Z6sw77oMopRPS5Jj1fxrJYkTo=
=RFuY
-----END PGP SIGNATURE-----
--jrofmsi74wrqmdsk--
From: Alejandro Colomar <alx@kernel.org>
To: gnats-bugs@netbsd.org
Cc: Bruno Haible <bruno@clisp.org>
Subject: Re: lib/59198: Reject negative input in strtou(3), reporting ERANGE
Date: Fri, 21 Mar 2025 21:34:42 +0100
--77v3ngsjjqengmmj
Content-Type: text/plain; protected-headers=v1; charset=utf-8
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable
From: Alejandro Colomar <alx@kernel.org>
To: gnats-bugs@netbsd.org
Cc: Bruno Haible <bruno@clisp.org>
Subject: Re: lib/59198: Reject negative input in strtou(3), reporting ERANGE
References: <pr-misc-59198@gnats.netbsd.org>
<20250319232212.8609C1A923C@mollari.NetBSD.org>
<20250319232500.4D8401A923C@mollari.NetBSD.org>
<knzempljqvci4o5v4qnunnog7l5yarhc5ttxktgyynkrfzyniv@2yj6ku46u76m>
MIME-Version: 1.0
In-Reply-To: <knzempljqvci4o5v4qnunnog7l5yarhc5ttxktgyynkrfzyniv@2yj6ku46u76m>
On Fri, Mar 21, 2025 at 09:25:38PM +0100, Alejandro Colomar wrote:
> Hi,
>=20
> Actually, considering the name strtou(3), which is about **unsigned**
> integers, maybe negative numbers should not trigger an ERANGE error, but
> actually an ECANCELED error. The sign, even a positive sign, should not
> be part of an unsigned number.
>=20
> Here are some example implementations for this:
>=20
> unsigned long
> strtoul_nn(const char *restrict s, char **restrict endp, int base)
> {
> while (isspace((unsigned char) *s))
> s++;
> if (!isdigit((unsigned char) *s))
This should call isxdigit(3).
> return 0;
>=20
> return strtoul(s, endp, base);
> }
>=20
> uintmax_t
> strtou_nn(const char *restrict s, char **restrict endp, int base,
> uintmax_t min, uintmax_t max, int *status)
> {
> while (isspace((unsigned char) *s))
> s++;
> if (!isdigit((unsigned char) *s)) {
This should call isxdigit(3).
> if (status)
> *status =3D ECANCELED;
> return min;
> }
>=20
> return strtou(s, endp, base, min, max, status);
> }
>=20
> I'm going to expand the BUGS section in the strtoul(3) Linux manual
> page, and mention the strtoul_nn() example as a workaround for this bug
> in the standard strtoul(3).
>=20
> The strtou_nn() should be the ideal behavior of strtou(3).
>=20
> (I hope this arrives at the bug ticket.)
>=20
>=20
> Cheers,
> Alex
>=20
> --=20
> <https://www.alejandro-colomar.es/>
--=20
<https://www.alejandro-colomar.es/>
--77v3ngsjjqengmmj
Content-Type: application/pgp-signature; name="signature.asc"
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEES7Jt9u9GbmlWADAi64mZXMKQwqkFAmfdzWEACgkQ64mZXMKQ
wqkpLg/+LKjyFbj58SpjPDdXb/TKevnJ4mGg5b7x8d1VWuf+AO4zTu8Vqzvc7stH
6nuGZxaurPGkEj+zxfOUUHwWUZzZ+xFIM4y69B9x+ldM8EHyATjzehR08+UPo3cY
gt7pUDVYFVTTQEvcMZmdUXJUX/jV8zS1/ZO/pw9yXk6jgRQl4i1PDrg0Dzobz/zz
WTYqhlBwsr6RYjFwvZFCGUpL5QuFV/8ssWkrF9hIa1O/fbPA1KQm26otIgziIk+k
uHGN1E5IZavAS2Lp0sjVh9akMys945Shp4vk7gT3xMAXfLAiEIJg2BHw4cM3KFHb
oMOCrY6x9GmkipJPGrRS3AbRcFBLOIG6DNfEJRXpKaOpbs7+54CJpAgrFTNKIdtL
uTWxH2qrqUK/j/C3opnjER23poDJJNe6iLh/pERnp1cRAuPv5etzB6eZHQZzJaTx
I420QqfKU2smX/3bKD1s7Le+G0svdRzmzuXz/WhWjkkBpHhrjX+xKBBiEHRSuvlh
NByBBOTtmJ92RisUzJBaFFgBPDz8ywXw76R7u7hbOtS5MazeBljZWL4A65kmsIld
Z5fkff57Q/uSklWUarx1lI+oEcudabY+zOxfo/ChUGOSUVfa99rlSrRwVc4wg+Pd
t6lhf5+h2XnO5/yEMXD6xg8XJWxl/DOYiOnVUNIhJynO604D8ao=
=SOm5
-----END PGP SIGNATURE-----
--77v3ngsjjqengmmj--
>Unformatted:
(Contact us)
$NetBSD: query-full-pr,v 1.47 2022/09/11 19:34:41 kim Exp $
$NetBSD: gnats_config.sh,v 1.9 2014/08/02 14:16:04 spz Exp $
Copyright © 1994-2025
The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.