NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

lib/57828: strtoi(3), strtou(3): When both ERANGE and ENOTSUP conditions happen, ERANGE should be more important



>Number:         57828
>Category:       lib
>Synopsis:       strtoi(3), strtou(3): When both ERANGE and ENOTSUP conditions happen, ERANGE should be more important
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    lib-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sun Jan 07 22:30:01 +0000 2024
>Originator:     Alejandro Colomar
>Release:        9.3
>Organization:
Linux man-pages
>Environment:
N/A
>Description:
In strtoi(3) and strtou(3), the conditions for both ERANGE and
ENOTSUP can ahppen at in the same call.  Consider the following:

    strtoi("42z", &end, 0, 3, 7, &status);

>From ERANGE, or ENOTSUP, I argue it should return ERANGE.

-  The information about ENOTSUP can be extracted from 'end', as
   (*end != '\0').  So if we report ERANGE, a caller can still
   check for trailing text easily.  However, there's no secondary
   way to check ERANGE; if it's shadowed by ENOTSUP, that vital
   information is completely lost.
-  It is usual to expect trailing text after the number, as
   when parsing some formatted text, where numbers are mixed with
   other text.  On the other hand, out-of-range values should
   usually be rejected as invalid input, and also warned about.
   If ENOTSUP shadows ERANGE, we're in a bad position.

The following two calls are currently equivalent:

    strtoi("7z", &end, 0, 3, 7, &status);
    strtoi("42z", &end, 0, 3, 7, &status);

I argue they shouldn't; there should be a way to distinguish them.


Here's a discussion in the shadow mailing list, where I originally reported this bug:
<https://lists.sr.ht/~hallyn/shadow/%3CZZoQDms6Sv6e5SPE%40debian%3E>
>How-To-Repeat:
Call strtoi(3) or strtou(3) with a string that overflows or underflows the [min, max] range, *and* contains trailing text.
>Fix:
I've implemented my own strtoi() and strtou(), using GNU C11, which report ERANGE if both ERANGE and ENOTSUP happen:


alx@debian:~/src/shadow/shadow/getlong$ grepc -tfd shadow_strtoi .
./lib/atoi/strtoi.c:intmax_t
shadow_strtoi(const char *str, char **restrict endptr, int base,
    intmax_t min, intmax_t max, int *restrict status)
{
	return strtoN(str, endptr, base, min, max, status, intmax_t);
}
alx@debian:~/src/shadow/shadow/getlong$ grepc -tfd shadow_strtou .
./lib/atoi/strtoi.c:uintmax_t
shadow_strtou(const char *str, char **restrict endptr, int base,
    uintmax_t min, uintmax_t max, int *restrict status)
{
	return strtoN(str, endptr, base, min, max, status, uintmax_t);
}
alx@debian:~/src/shadow/shadow/getlong$ grepc strtoN .
./lib/atoi/strtoi.c:#define strtoN(str, endptr, base, min, max, status, TYPE)                     \
({                                                                            \
	const char  *str_ = str;                                              \
	char        **endptr_ = endptr;                                       \
	int         base_ = base;                                             \
	TYPE        min_ = min;                                               \
	TYPE        max_ = max;                                               \
	int         *status_ = status;                                        \
                                                                              \
	int         errno_saved_, s_;                                         \
	char        *e_;                                                      \
	TYPE        n_;                                                       \
                                                                              \
	if (endptr_ == NULL)                                                  \
		endptr_ = &e_;                                                \
	if (status_ == NULL)                                                  \
		status_ = &s_;                                                \
                                                                              \
	if (base_ < 0 || base_ > 36) {                                        \
		*status_ = EINVAL;                                            \
		n_ = 0;                                                       \
                                                                              \
	} else {                                                              \
		errno_saved_ = errno;                                         \
		errno = 0;                                                    \
		n_ = strtoNmax(TYPE, str_, endptr_, base_);                   \
                                                                              \
		if (*endptr_ == str_)                                         \
			*status_ = ECANCELED;                                 \
		else if (errno == ERANGE)                                     \
			*status_ = ERANGE;                                    \
		else if (n_ < min_ || n_ > max_)                              \
			*status_ = ERANGE;                                    \
		else if (**endptr_ != '\0')                                   \
			*status_ = ENOTSUP;                                   \
		else                                                          \
			*status_ = 0;                                         \
                                                                              \
		errno = errno_saved_;                                         \
	}                                                                     \
	SATURATE(min_, max_, n_);                                             \
})
alx@debian:~/src/shadow/shadow/getlong$ grepc strtoNmax .
./lib/atoi/strtoi.c:#define strtoNmax(TYPE, ...)                                                  \
(                                                                             \
	_Generic((TYPE) 0,                                                    \
		intmax_t:  strtoimax,                                         \
		uintmax_t: strtoumax                                          \
	)(__VA_ARGS__)                                                        \
)
alx@debian:~/src/shadow/shadow/getlong$ grepc SATURATE .
./lib/atoi/strtoi.h:#define SATURATE(min, max, n)  MAX(min, MIN(max, n))



Home | Main Index | Thread Index | Old Index