I am currently, writing a code for string manipulation.
As part of this, I am using vsnprintf()
.
However, compiler flashes below error message:
dont_call: vsnprintf(). Invokation of a potentially dangerous function
that could introduce a vulnerability. remediation:
Recommendation: Use vsprintf_s() instead!
The results with vsprintf_s()
is as not expected.
What is the difference between vsnprintf()
and vsprintf_s()
?
vsnprintf()
is a perfectly fine standard function that has no security issues if used properly, especially if the format string is a string literal compatible with the arguments passed.Microsoft deprecated this function because an attacker could take advantage of sloppy code that uses user supplied text as the format specification: carefully crafted user supplied strings could use the
%n
format to try and corrupt the program's data and make the program execute arbitrary code.Using a variable format string is error prone as it is difficult to verify that the types of the arguments are compatible with this dynamically generated format string. Sensible coding conventions do not permit such code. Passing a user supplied string as a format string is completely inappropriate as it is a trivial source of undefined behavior. Disabling useful and standard functions because they could be misused and create security flaws is laudable, but in this particular case, the proposed alternatives have shortcomings.
There are 2 alternatives for
vsnprintf()
, standardized in Annex K, but with optional support and thus non portable across environments:and
These functions behave differently from
vsnprintf
in subtile ways:%n
specifier.n
to have a0
value.s
target array to be a null pointer, whichsnprintf()
allows if then
size is0
.vsprintf_s
differs fromvsnprintf_s
when the output string is longer thann-1
: it sets the destination to the empty string, invokes the error handler and returns0
or a negative number instead of the length of the formatted string, as bothvsnprintf
andvsnprintf_s
do.As commented by A T, to make matters worse, Microsoft implements different semantics in their own version of this standard functions: even the prototype for
vsnprintf_s
is different (as documented in the Visual Studio documentation):As a result of the numerous deviations from the specification the Microsoft implementation cannot be considered conforming or portable.
You did not post the code where you want a replacement for
snprintf()
, but a classic use case is this:In the above code,
vnsprintf
cannot be replaced withvsprintf_s
becausevsprintf_s
cannot be used to compute the required size: it always considers a short size as an error.vsnprintf_s
cannot be used as a direct replacement because it considers aNULL
pointer as the target to be an error too.The solution is simple: you can prevent Visual Studio from emitting this warning by defining a macro before including
<stdio.h>
in the source file:This prevents the warning for all deprecated library functions.
Note also that it is very useful to increase the warning level and let the compiler warn about potential bugs, such as inconsistent arguments for a given format string. With
gcc
andclang
, you can pass-Wall
and other command line options to enable such behavior. For Visual Studio, you can add more warnings with/W4
.