I understand why C developers don't use gets, since there are vulnerabilities that can be exploited with a buffer overflow attack, but why even have this function if it is safer to use fgets(). I suppose the question that I am asking is, are there any implications of gets() that are safe from a security standpoint?
-
8`gets()` is no longer in standard C because of that. – Shawn Jun 01 '22 at 12:22
-
You're seeing the effect of history here; `gets()` is a quick-and-dirty function that was created decades ago (and long before the modern internet), and we've subsequently gotten an appreciation for the security issues involved. – Steve Friedl Jun 01 '22 at 12:53
-
1It's a common mistake to think there was some manner of rationale behind which functions that ended up in the original C standard. The committee just grabbed various existing Unix functions at a whim, with diverse quality of their API, and made them standard. Apart of broken-by-design ones like `gets`, `ato*` and `strncpy`, there's also a lot of functions with plain bad API design: everything-stdio.h, everything-stdarg.h, `strtok` and so on. – Lundin Jun 01 '22 at 13:46
1 Answers
gets
was invented in the early days of the C language, about 50 years ago, before people had thought of the concept of buffer overflow attacks and when it was assumed that users of your program would be friendly. Obviously times have changed, and in retrospect its design was a mistake. It cannot be used safely and therefore should not be used at all, and current versions of the C language standard have actually removed it. See Why is the gets function so dangerous that it should not be used?
As to why it existed in the first place, most of the stdio functions have specialized versions that operate on stdin/stdout instead of on an arbitrary stream. For instance, there is fprintf
which prints to an arbitrary stream, and printf
which assumes stdout
. It's Likewise there is fscanf/scanf
, getc/getchar
, and so on. It's mainly for convenience, so that you can save the trouble of typing stdout
everywhere.
For line-based I/O, there was fputs/fgets
for arbitrary streams, and puts/gets
for stdout/stdin. Note that puts/gets
had the special feature that they would automatically append/strip a newline character, so gets(buf)
is not exactly equivalent to fgets(stdin, buf, INT_MAX)
.
It's not entirely clear why they decided that fgets
should take a size parameter but gets
should not. There may have been an implicit assumption that stdin was more likely to be "nice" input, like terminal input or text files with reasonable line length, whereas an arbitrary file opened with fopen
might be more likely to need to handle extremely long lines and such. There are certainly many such aspects of the original C language that, again with the benefit of hindsight, were not well thought out.

- 48,811
- 6
- 54
- 82
-
1*its design was a mistake*... Indeed it should have been `char *gets(char *s, int n)` for consistency with `fgets()` and if designed now, the `int` size argument should be a `size_t`. – chqrlie Jun 01 '22 at 13:19
-
@chqrlie why couldn't you just make the int argument an unsigned int, rather than a size_t. As far as I understand wouldn't they be treated the same way on equivalent systems? – neutron02 Jun 01 '22 at 17:29
-
@neutron02: The correct type is `size_t`, but `fgets()` uses `int` for historical reasons: it predates `size_t` and even `unsigned`, and for some bizarre reason it was not fixed for ANSI-C – chqrlie Jun 01 '22 at 18:11