6

It seems to me that both have the potential to overflow the buffer. Yet I'm adviced to never use gets() but still encouraged to use scanf().

Is it just because of the formatting arguments allowed in scanf() or is there any other reason?

Dagoth Ulen
  • 520
  • 1
  • 5
  • 12
  • One, because of the escape characters, `gets()` doesn't filter endline – noMAD Mar 13 '13 at 16:16
  • 3
    Probably because while gets() is hopeless, with scanf you can avoid buffer overflows if you go through the pain of limiting input length **every** **single** **time** – loreb Mar 13 '13 at 16:18
  • IIRC `gets()` doesn't give you the line if there is no '\n', but `EOF` instead. – pampeho Mar 13 '13 at 16:21

6 Answers6

10

The gets function is not protected against buffer overflows.

With the scanf format string you can define the maximal length of the string to read from standard input and store in the given memory buffer. For example with scanf("%10s\n", str); a maximum of 10 characters will be read. The str buffer should be of 11 bytes to store the NULL terminating character.

Performance wise, if you only use scanf to workaround the buffer overflow issues of gets, prefer using the fgets function instead.

greydet
  • 5,509
  • 3
  • 31
  • 51
  • Doing some research i also found that: scanf() will not only allow you to enter more than one field, but it also allows you to enter **structured** data including the ability to specify what characters appear between fields. So i think that's also interesting to keep in mind. Source: Head First C, Daivid & Dawn Griffiths. – Dagoth Ulen Mar 13 '13 at 22:44
  • You are right, `scanf` and `gets` (or `fgets`) does not cover the same use cases. You use `fgets` to read one line from input stream. You use `scanf` for parsing data from input stream. This said you can use `scanf` to read one line from input stream as you would do with a `fgets` but it will result in a performance loss. – greydet Mar 14 '13 at 11:41
2

Because you can input more characters than size of the buffer and gets() will happily allow it. Moreover, gets() has been deprecated (in C11). So the comparison with scanf() is no longer valid. Besides scanf() has its own problems when dealing with unformatted data.

So a better option would be fgets() and then process it as per your needs.

P.P
  • 117,907
  • 20
  • 175
  • 238
1

Because there is no way to prevent buffer overflow. fgets is safer as the maximum buffer length is specified.

suspectus
  • 16,548
  • 8
  • 49
  • 57
1

With gets it is not possible to prevent a buffer overflow in case of malformed input. scanf allows the control over amount of data read.

How to prevent scanf causing a buffer overflow in C?

Community
  • 1
  • 1
Valeri Atamaniouk
  • 5,125
  • 2
  • 16
  • 18
1

still encouraged to use scanf().

A quick Google search for "scanf security" turns up ~212k results. The first is Wikipedia, which states that

uses of %s placeholders without length specifiers are inherently insecure and exploitable for buffer overflows.

So there's enough info about scanf security on the web. The difference with gets is that scanf has secure uses, while using gets is practically always a bad idea.

Fred Foo
  • 355,277
  • 75
  • 744
  • 836
1

The nominal task of gets() is to read in a string from a stream. The caller tells it where to put the incoming characters. But gets() does not check the buffer space. If the caller provides a pointer to the stack, and more input than buffer space, gets() will overwrite the stack. Most systems are vulnerable to overwriting an existing entry in the middle of the stack with something bigger, that also overwrites neighboring entries. A malefactor can amend the return address in the procedure activation record on the stack by stashing the right binary patterns in the argument string. This will divert the flow of execution not back to where it came from, but to a special instruction sequence that calls execv() to replace the running image with a shell. This shell can issue commands to drag across a copy of the virus to the system. So gets() is not safe.

Deepu
  • 7,592
  • 4
  • 25
  • 47