Visual Studio 2013 C++ projects have a /GS
switch to enable buffer security check validation at runtime. We are encountering many more STATUS_STACK_BUFFER_OVERRUN errors since upgrading to VS 2013, and suspect it has something to do with improved checking of buffer overrun in the new compiler. I've been trying to verify this and better understand how buffer overrun is detected. I'm befuddled by the fact that buffer overrun is reported even when the memory updated by a statement only changes the contents of another local variable on the stack in the same scope! So it must be checking not only that the change doesn't corrupt memory not "owned" by a local variable, but that the change doesn't affect any local variable other than that allocated to the one referenced by the individual update statement. How does this work? Has it changed since VS 2010?
Edit: Here's an example illustrating a case that Mysticial's explanation doesn't cover:
void TestFunc1();
int _tmain(int argc, _TCHAR* argv[])
{
TestFunc1();
return 0;
}
void TestFunc1()
{
char buffer1[4] = ("123");
char buffer2[4] = ("456");
int diff = buffer1 - buffer2;
printf("%d\n", diff);
getchar();
buffer2[4] = '\0';
}
The output is 4
indicating that the memory about to be overwritten is within the bounds of buffer1
(immediately after buffer2
), but then the program terminates with a buffer overrun. Technically it should be considered a buffer overrun, but I don't know how it's being detected since it's still within the local variables' storage and not really corrupting anything outside local variables.
This screenshot with memory layout proves it. After stepping one line the program aborted with the buffer overrun error.
I just tried the same code in VS 2010, and although debug mode caught the buffer overrun (with a buffer offset of 12), in release mode it did not catch it (with a buffer offset of 8). So I think VS 2013 tightened the behavior of the /GS
switch.
Edit 2: I managed to sneak past even VS 2013 range checking with this code. It still did not detect that an attempt to update one local variable actually updated another:
void TestFunc()
{
char buffer1[4] = "123";
char buffer2[4] = "456";
int diff;
if (buffer1 < buffer2)
{
puts("Sequence 1,2");
diff = buffer2 - buffer1;
}
else
{
puts("Sequence 2,1");
diff = buffer1 - buffer2;
}
printf("Offset: %d\n", diff);
switch (getchar())
{
case '1':
puts("Updating buffer 1");
buffer1[diff] = '!';
break;
case '2':
puts("Updating buffer 2");
buffer2[diff] = '!';
break;
}
getchar(); // Eat enter keypress
printf("%s,%s\n", buffer1, buffer2);
}