According to the man page, fscanf returns EOF on error, but nowhere can I find specified if overflow is an error. I heard that strtol() is probably closely linked to this process, and what it does is consume all the numbers in the file, and then return LONG_MIN on underflow, or LONG_MAX on overflow, and sets errno to ERANGE. But the question is will it pass on the error to fscanf().
I don't want to consume an infinite amount of numbers, and I want to 100% be sure that fscanf() will return EOF in a case of overflow.
How do I do that? ld
?
CodePudding user response:
Returning EOF
due to integer overflow would violate the C standard. Setting errno
to ERANGE
on integer overflow is not specified by the standard (indeed, the conversion results in undefined behavior)1, but library functions are allowed to set errno
to a non-zero value on success.
Presumably, the implementation that sets errno
to ERANGE
on integer overflow would allow the caller to detect this error by setting errno = 0;
before the call:
int val;
int ret;
errno = 0;
ret = fscanf(fp, "%d", &val);
if (ret == EOF) {
/* Normal error. */
} else if (ret == 0) {
/* val not read. */
} else {
/* val read. */
if (errno == ERANGE) {
/* There was an overflow. */
}
}
In the glibc C library (at least up to version 2.36), this does not work properly for integer types that are narrower than long
. For example, on my 64-bit GNU/Linux system (with 64-bit long
and 32-bit int
), reading the input 12345678901 into an int
does not set errno
, but reading the input 12345678901234567890 into an int
does set errno
to ERANGE
. Not setting errno
on integer overflow is not a bug in the glibc library. From what I can tell, the only place where this error is documented is in the Linux man-pages from release 3.01 up to at least 6.01 at the time of writing. In my humble opinion, the scanf(3) man page should not mention ERANGE
at all.
1 As mentioned by @chux in the question comments, converting an input number that cannot be represented by the target object type results in undefined behavior (unless the assignment suppression flag *
was used). Refer to C17 7.21.6.2/10 (for fscanf
), 7.29.2.2/10 (for fwscanf
):
[...] Unless assignment suppression was indicated by a
*
, the result of the conversion is placed in the object pointed to by the first argument following the format argument that has not already received a conversion result. If this object does not have an appropriate type, or if the result of the conversion cannot be represented in the object, the behavior is undefined.
It seems strange that a conforming program that uses scanf
to read an integer without carefully specifying a maximum field width cannot prevent undefined behavior caused by incorrect or malicious input. The optional "Annex K" functions such as scanf_s
allow the implementation to treat the incorrect input as a runtime constraint violation, but do not require it to do so.
"A strange game. The only winning move is not to play." ― Joshua/WOPR, WarGames (1983)