4

This is fgets()'s official prototype:

char *fgets(char *str, int n, FILE *stream);

Why specify the size (n) ? Is it to prevent buffer overflow of some sort? Or is it just a design flaw?

I would think that it's caused by gets() tendency to cause buffer overflow and segfault your program, but that's only my guess.

In any case, this may be related to the fact that fgets() is a file function, but I would also have no idea.

This is in the context of a recent video on buffer overflow, and in a security context, is this a risk? Is the size a limitation, and in this context, prone to segfaulting?

10
  • 4
    fgets has a size to prevent buffer overflow. It's absolutely not a "design flaw". When you call fgets you tell the size of the provided buffer and fgets makes sure not to write more data to the buffer than the size. So assuming you call the function correct, there won't be any buffer overflow. That's why fgets is much better than gets. And better than scanf where many programmers forget to specify a size limit. In (at least) 9 out of 10 cases fgets is the best way to read input. Commented Sep 7, 2024 at 5:11
  • 3
    Design flaw?!! Nah, man, this is the opposite of a flaw. scanf() is flawed in all kinds of horrid ways. fgets() is well-designed. Commented Sep 7, 2024 at 5:21
  • 4
    @Dúthomhas — fgets() is reasonably well designed. It would be better designed if it returned the number of characters it placed in the buffer (either 0 or EOF could indicate EOF). If the input contains null bytes, you can't tell how many characters were read. Commented Sep 7, 2024 at 5:31
  • 1
    In its defence, fgets() works fine on text files and text files do not contain null bytes. However, it would still be better if it reported the number of bytes read. Commented Sep 7, 2024 at 5:37
  • 1
    @JonathanLeffler "text files do not contain null bytes." --> When a text file is encoded using UTF16 (not so rare) or UTF32 (rare), there are often many null characters. Of course fgets() is not the function to read that type of text file, yet error handling of using the wrong input function is additionally complicated since fgets() and reading null characters has the extra problem you pointed out. Commented Sep 7, 2024 at 8:46

2 Answers 2

3

From cppreference.com C documentation:

fgets
Reads at most count - 1 characters from the given file stream and stores them in the character array pointed to by str
...
count - maximum number of characters to write (typically the length of str)

(emphasis is mine)

count is the size parameter named n in your question.

According to the Linux manual page, fgets should read at most n - 1 (i.e. count - 1) bytes:

The fgets() function shall read bytes from stream into the array pointed to by s until n-1 bytes are read, or ...

So the bottom line:
fgets reads at most n - 1 characters and writes them to str. Since it adds a zero ('\0') termination, it will write at most n bytes.

But anyway - basically, the answer is yes; it is for preventing a buffer overflow when filling str (assuming you pass the proper size of str).
It is definitely not a design flaw.

Sign up to request clarification or add additional context in comments.

3 Comments

Kind of funny that the documentation says: "typically the length of str". It's wrong in at least two ways.
Concerning the count. Maybe in means, eg 10 chars which is 0-9 which is 10-1. But, then you need to factor for terminating null.
2

Why does fgets() require a maximum size of user input?

To limit the amount of data that is saved - preventing buffer overflow cases.


Why specify the size?

To prevent fgets() from saving too many characters.

It also stops reading characters.
fgets() could have read excess characters in a line and not save them, yet the design is to read up to size - 1 characters and save them and then append a null character. If the buffer fills without a '\n', the rest of the line remains to be read.

Is it to prevent buffer overflow of some sort?

Yes, this prevents a buffer overflow. It also stops the reading of characters from the file.

Or is it just a design flaw?

It is by design as a limiting alternate to code like gets() (no longer parts of the C library) and scanf("%s", ... which remains risky.

Other (and later) functions that specify the buffer size are of type size_t. fgets() with its int size is a minor design flaw.

and in a security context, is this a risk?

Passing in a limiting size reduces risk.

Is the size a limitation, and in this context, prone to segfaulting?

The size reduces segment faults.


Reading a line in C is only partially handled by fgets().
Issues remain (some are pedantic):

  • How to detect and handle when not all the line was read?

  • Quieting unsigned_to_signed warnings that come up when a size_t variable is passed as the size.

  • Detecting the number of characters read when fgets() unusually reads a null character as strlen(), to find the number read, will stop on the read null character and not the appended one.

  • Many applications do not want to save the '\n'. So when the destination is size n, code needs additional helper code to read and save up to n-1 characters and then lop off the possible '\n or maybe still read if the buffer was full.

  • There are 4 reasons why fgets() stops reading: '\n' read, full buffer, end-of-file detected, rare input stream error occurs. Additional code must be careful to discriminate.

  • A size of 0 or negative is a pathological problem.

C deserves a better readline function.

1 Comment

Thank you! This is absolutely amazing and answered my question completely!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.