3
#include <stdio.h>
int main()
{
    unsigned char y;
    scanf("%hhu", &y);
    printf("%hhu", y);
    return 0;
}

This code work's fine with g++ (Dev C++), but causes stack corruption in Visual Studio (2010), is this VS bug or there is any other way to input unsigned char in VS using scanf(); ?

Binary Mind
  • 309
  • 3
  • 13

2 Answers2

5

Sounds like VS doesn't handle %hhu: https://stackoverflow.com/a/15825386/1715829

The important detail is that you're using Windows, and presumably an outdated or non-conforming C environment (compiler and standard library). MSVCRT only supports C89 (and even then, not entirely correctly); in particular, there was no "hh" modifier in C89, and it's probably interpreting "hh" the same as "h" (i.e. short).

Community
  • 1
  • 1
Buddy
  • 10,874
  • 5
  • 41
  • 58
  • `Sounds like VS doesn't handle %hhu correctly` More like "doesn't handle it at all", rather than "not correctly". Handling it "not correctly" implies it *is* handled, but has bugs. – PaulMcKenzie Jun 22 '15 at 21:06
  • The linked question and answer show that MSVS treats `%hhu` like `%u`, that is, handles it incorrectly. You can say that it doesn't handle `hh` at all. – anatolyg Jun 22 '15 at 21:20
  • 3
    From the [MSDN](https://msdn.microsoft.com/en-us/library/tcxf1dw6%28v=vs.140%29.aspx): `The hh, j, z, and t length prefixes are not supported.`. – Grzegorz Szpetkowski Jun 22 '15 at 23:28
1

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."

Ian
  • 11
  • 2