Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Date: Fri, 7 Oct 2022 13:12:27 +0000
From: Pascal Cuoq <>
To: "" <>
Subject: fgets behavior for n<=0 (and =1)

Dear all,

the function fgets is defined in the C standard. In C17 ( ):


      #include <stdio.h>
      char *fgets(char * restrict s, int n,
            FILE * restrict stream);


The fgets function reads at most one less than the number of characters specified by n from the stream pointed to by stream into the array pointed to by s. No additional characters are read after a new-line character (which is retained) or after end-of-file. A null character is written immediately after the last character read into the array.


The fgets function returns s if successful. If end-of-file is encountered and no characters have been read into the array, the contents of the array remain unchanged and a null pointer is returned. If a read error occurs during the operation, the array contents are indeterminate and a null pointer is returned.

It has come to our attention that it is possible to interpret the informal specification above in several ways for n <= 0, and that indeed several interpretations co-exist. All links are provided “as of this writing”, with snippets illustrating the interesting lines for clarity and against obsolescence of this message.

A/ For n <= 0, return a null pointer without setting errno.


      if (n <= 0)       /* sanity check */
            return (NULL);

  if (n <= 0) return NULL;

B/ Same as A but also do not write anything for n=1 (arguably incorrect)

  if (n < 2)                  /* sanity check */
    return 0;

C/ Have undefined behavior for n=INT_MIN

Since undefined behavior can be anything and worse, and the C standard's description does not explicitly allow “anything and worse” for any value of n, this is arguably incorrect.

      if (n--<=1) {

D/ Same as C (and rather a worse kind of UB in practice) but also write a nul character for n=0 (which is also arguably incorrect in itself)

      for (p = dst, max--; max > 0; max--) {
            if ((c = fgetc (fp)) == EOF)
            *p++ = c;
            if (c == '\n')
      *p = 0;

E/ Document implementation-dependent result for n=1 and set errno to EINVAL for n<=0 in addition to returning a null pointer

From :

> Whether fgets() can possibly fail with a size argument of 1 is implementation-dependent. On OpenBSD, fgets() will never return NULL when size is 1.
> …
>    The given size is less than or equal to 0.

      if (n <= 0) {           /* sanity check */
            errno = EINVAL;
            return (NULL);

Does anyone have any remarks about what the consensual behavior of fgets should be or how to get closer to a point where the consensual behavior is more widely implemented?


Content of type "text/html" skipped

Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.