swprintf_s()
and sprintf_s()
are additions to VC++8, and were supposedly written to tolerate formatting errors and to avoid buffer overruns. They differ from their corresponding non-safe cousins swprintf()
and sprintf()
by taking an extra argument (the 2nd parameter), which is the size of the buffer passed as the first argument. The prototype for swprintf_s()
is:
int swprintf_s(wchar_t *Buf, size_t sizeOfBuf, const wchar_t *format [, argument]...)
The following use of
swprintf_s()
would seem to be in keeping with the prototype declaration.
wchar_t buf[12];
...
swprintf_s(buf, sizeof buf, "%s%d", L"result", 2);
However, this code is likely to cause a crash in the next few statements following it, but not always.
If you change the code to
swprintf_s(buf, 12, "%s%d", L"result", 2);
it will correctly execute.
A close examination of the documentation reveals that the 2nd parameter is not a size, in spite of its type, but instead the number of characters in the buffer. The reason the first example crashes is because sizeof(wchar_t)
is greater than 1. If we assume sizeof(wchar_t) == 2
, then sizeof buf == 24
, but since the 2nd argument is taken as the number of characters swprintf_s()
thinks that it has a 48 byte memory area. So what? The format request only generates 8 characters. However, if you watch the memory area (with VS8) passed as the 1st parameter while swprintf_s()
executes, you will see the Debug version clear to uninitialized all the bytes in the buffer beyond those in which it writes the formatted information. So if you pass the wrong size to swprintf_s()
, it will spank you by overwriting your data.
The poor aspect of this design is avoidance of sizeof
, which is the standard C/C++ operator for compile-time determination of memory sizes. Even though the type of the 2nd parameter would imply a sizeof
value, this is not what the function expects. sizeof
is the language's way of keeping byte counts out of a program, but swprintf_s()
's design forces character counts back into the program. Consider what would happen if the buffer size is changed. Is the programmer going to realize that all the character count arguments to swprintf_s()
calls also need to be changed?
In order to be truly safe, the 2nd parameter needs to be coded as:
(sizeof buf)/(sizeof buf[0])
We divide the size of an array by the size of an array element, which provides the number of array elements. This is the expression that is needed as the 2nd parameter to
swprintf_s()
in order to keep your code independent of changes to the size of the buffer. Microsoft has incorporated this definition in the
_countof()
macro, which is not standard C, but is available in VS8
stdlib.hAs to why the function spends CPU time clearing the remaining buffer, I guess that it is an attempt to generate a quick failure if the wrong the size passed. I hope that this undocumented feature is only in the Debug version of the function.