Just to add a bit more detail...
The corruption occurs around line 1111 in input.c.
if ( integer64 )
*(__int64 UNALIGNED *)pointer = (unsigned __int64)num64;
else
if (longone)
*(long UNALIGNED *)pointer = (unsigned long)number;
else
*(short UNALIGNED *)pointer = (unsigned short)number;
You can see that there is no case where only 8 bits will be written.
While parsing the format string the counter longone
initially has the value 1, and is decremented each time a 'h' character is encountered. Later on (at the above snippet) longone
is used as a flag to determine if the parsed integer is 32 bits or not.
This behaviour is ok if "%hu"
is used, as longone
will be 0 and so the parsed value will be treated as 16 bits. If however "%hhu"
is used, longone
will be -1 and so the parsed value will be treated as 32 bits.
In either case (32 or 16 bit value) your supplied char pointer will have more than the expected 1 byte written, thus causing stack corruption.
This behaviour affects all scanf()
related functions as Visual Studio implements things like swscanf_s()
internally by making the input string look like a file handle. In this way everything ends up in the _tinput_s_l()
function (line 368 in input.c) where the above problem manifests.
The MSDN documentation for Visual Studio 2010 shows the %h
prefix but not the %hh
prefix.
What's new for Visual C++ in Visual Studio 2015 states that:
C99 Conformance Visual Studio 2015 fully implements the C99 Standard
Library, with the exception of any library features that depend on
compiler features not yet supported by the Visual C++ compiler (for
example, <tgmath.h>
is not implemented).
Which I read as "we've implemented everything, except the bits we haven't, which we won't tell you about."