Questionable behavior of strtoi(3bsd) / strtou(3bsd)

Alejandro Colomar alx at kernel.org
Sun Jan 7 22:37:24 UTC 2024


[I've added some CCs, from
 `git log -- common/lib/libc/stdlib/strtoi.c | grep Author`]

Hi Thorsten,

On Sun, Jan 07, 2024 at 10:01:57PM +0000, Thorsten Glaser wrote:
> Alejandro Colomar dixit:
> 
> >> I didn't design the functions, so not sure whether that was an
> >> intentional choice or not, from the code PoV I can see the structure
> >> making sense (in first making sure the string parsed is correct, before
> >> evaluating what got parsed from it),
> 
> These functions are… rare, too.
> 
> But for this…
> 
> >That's not correct.  strtol(3) and relatives have (ignoring EINVAL) 3
> >stages, not 2.  Firstly we make sure we parsed a number, secondly we
> 
> … compare prior art: OpenBSD strtonum(3).

Heh, indeed!  The implementation of strtonum(3) is the only place in the
entire NetBSD tree where changing strtoi(3) according to this proposal
would break existing code.  I'd say it's because strtonum(3) is...
special.  It's not something you'd use for writing a parser.  It's
more like a very specialized tool for parsing a command line argument
that should only be a number, or things like that, and unsuitable for
anything else.

From the strtoi(3) manual page, I get that it's a function that attempts
to be generic, and intends to replace every call to strtol(3) by this
simpler API.

I retire my "not correct" statement, since it's an accepted
simplification in some circles.  :)

> tg at tglase-bsd:~ $ ./a.out
> a.out: strtonum: errstr=<invalid>: Invalid argument
> tg at tglase-bsd:~ $ cat x.c
> #include <err.h>
> #include <errno.h>
> #include <limits.h>
> #include <stdlib.h>
> 
> int
> main(void)
> {
>         const char *errstr = NULL;
>         long long ret;
>         int eno;
> 
>         errno = 0;
>         ret = strtonum("123456xyzzy", 1, 32767, &errstr);
>         err(0, "strtonum: errstr=<%s>", errstr == NULL ? "nil" : errstr);
>         /* NOTREACHED */
> }
> 
> Indeed it checks for a valid number first, only then it checks the range
> as that needs a valid number in the first place.

You're right.  I only learned that when investigating the current NetBSD
code to check what would break.  :)

Have a lovely day,
Alex

-- 
<https://www.alejandro-colomar.es/>
Looking for a remote C programming job at the moment.
-------------- 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/20240107/99aff341/attachment.sig>


More information about the libbsd mailing list