Gear Gear - 28 days ago 14
C Question

Difference between scanf's width specification and scanf_s

scanf_s("%s", a, 10);


This code will protect our program from buffer overflow exploit.

But without scanf_s, we can write:

scanf("%9s", a);


I think this code will also block buffer overflow. Is this true?

So what is basically different between two ways?

And if scanf's width specification is blocking buffer overflow, why do we call original scanf "unsafe"?

Answer

scanf_s() is not described by the C99 Standard (or previous ones).

If you want to use a compiler that targets C99 (or previous) use scanf(). For C11 Standard, scanf_s() is much harder to use than scanf() for improved security against buffer overflows.

So what is basically different between two ways?

scanf_s() is a more secure version of scanf(). After the argument specifying the destination, the size of the destination must be provided. The program checks that the buffer is of the specified size before copying it to ensure that that there are no overwrites and malicious code isn't run. The argument has to be passed in case of scanf_s().

And if scanf's width specification is blocking buffer overflow, why do we call original scanf "unsafe"?

The format specifiers that can be used with scanf functions support explicit field width setting, which limit the maximum size of the input and prevent buffer overflow. But scanf() features are difficult to use, since the field width has to be embedded into format string (there's no way to pass it through a variadic argument, as it can be done in printf). scanf is indeed rather poorly designed in that regard. But nevertheless any claims that scanf is somehow hopelessly broken with regard to string-buffer-overflow safety are completely bogus and usually made by lazy programmers.

The real problem with scanf() has a completely different nature, even though it is also about overflow. When scanf function is used for converting decimal representations of numbers into values of arithmetic types, it provides no protection from arithmetic overflow. If overflow happens, scanf produces undefined behavior. For this reason, the only proper way to perform the conversion in C standard library is functions from strto family.

So, to summarize the above, the problem with scanf is that it is difficult to use properly and safely with string buffers. And it is impossible to use safely for arithmetic input. The latter is the real problem. The former is just an inconvenience.

scanf_s solves the problem of buffer-overflow in case of character array by passing field width through a variadic argument, as it can be done in printf (in scanf() field width has to be embedded into format string). Also, field width is mandatory in scanf_s but is optional in scanf.

Comments