Home > Mobile >  How to make sure that fscanf() returns an overflow error for %ld?
How to make sure that fscanf() returns an overflow error for %ld?

Time:12-09

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)

  •  Tags:  
  • c
  • Related