Visual Studio 2013 C++项目具有/GS
开关,可在运行时启用缓冲区安全检查验证。自从升级到VS 2013以来,我们遇到了更多的STATUS_STACK_BUFFER_OVERRUN错误,并且怀疑这与新编译器中改进的缓冲区溢出检查有关。我一直在尝试验证这一点,并更好地理解如何检测缓冲区溢出。令我困惑的是,即使一个语句更新的内存只会更改同一作用域中堆栈上另一个局部变量的内容,缓冲区溢出也会报告!因此,它必须检查不仅更改不会破坏非本地变量所“拥有”的内存,而且更改也不会影响除分配给单个更新语句的那个变量之外的任何本地变量。这是如何工作的?自VS 2010以来是否有所改变?
编辑: 以下是一个示例,说明Mysticial的解释无法涵盖的情况:
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';
}
输出为4
,表示即将被覆盖的内存位于buffer1
的范围内(紧接在buffer2
之后),但随后程序以缓冲区溢出而终止。严格来说,它应该被视为缓冲区溢出,但我不知道它是如何被检测出来的,因为它仍然在局部变量的存储范围内,实际上并没有破坏任何局部变量之外的东西。这个内存布局的屏幕截图证明了它。经过一行代码的单步操作后,程序因缓冲区溢出错误而中止。
![Debugger screenshot with memory layout](https://istack.dev59.com/Bmm9i.webp)
/GS
开关的行为。
编辑2:
我成功地通过了甚至是VS 2013的范围检查,使用了这段代码,它仍然没有检测到更新一个局部变量实际上更新了另一个局部变量: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);
}