我有一个程序在调试时提示我 VS2010 中的错误:
Error: Stack around the variable 'x' was corrupted
这给了我可能发生堆栈溢出的函数,但我无法直观地看到问题出在哪里。
有没有用VS2010调试这个错误的通用方法?是否有可能确定哪个写操作覆盖了不正确的堆栈内存?谢谢
我有一个程序在调试时提示我 VS2010 中的错误:
Error: Stack around the variable 'x' was corrupted
这给了我可能发生堆栈溢出的函数,但我无法直观地看到问题出在哪里。
有没有用VS2010调试这个错误的通用方法?是否有可能确定哪个写操作覆盖了不正确的堆栈内存?谢谢
有没有用VS2010调试这个错误的通用方法?
不,没有。您所做的是以某种方式调用未定义的行为。这些行为未定义的原因是一般情况很难检测/诊断。有时证明是不可能的。
但是,通常会导致您的问题的事情很少:
free
对于分配有的东西new
等),这可能是由几个通常很难看到的问题引起的:
delete
分配有的变量new[]
或delete[]
分配有的变量new
delete
分配给的东西malloc
delete
自动存储变量如果不是很清楚,我会使用内存调试器(我可以想到 Rational Purify for windows)。
此消息也可能是由于数组边界违规。确保您的函数(以及它调用的每个函数,尤其是基于堆栈的对象的成员函数)遵守可能使用的任何数组的边界。
实际上,您所看到的信息量很大,您应该在 x 变量位置附近检查可能导致此错误的任何活动。
以下是如何重现此类异常:
int main() {
char buffer1[10];
char buffer2[20];
memset(buffer1, 0, sizeof(buffer1) + 1);
return 0;
}
将生成(VS2010):
运行时检查失败 #2 - 变量“buffer1”周围的堆栈已损坏。
显然 memset 比它应该写的多 1 个字符。带有选项 \GS 的 VS 允许检测此类缓冲区溢出(您已启用),有关更多信息,请在此处阅读:http: //msdn.microsoft.com/en-us/library/Aa290051。
例如,您可以使用调试器并逐步执行代码,每次查看变量的内容,它们如何变化。你也可以试试数据断点的运气,当一些内存位置改变并且调试器在那一刻停止时设置断点,可能会向你显示问题所在的调用堆栈。但这实际上可能不适用于 \GS 标志。
要检测堆溢出,您可以使用 gflags 工具。
我对这个错误困惑了好几个小时,我知道可能的原因,并且在前面的答案中已经提到过,但是我不分配内存,不访问数组元素,不返回指向局部变量的指针.. .
然后终于找到了问题的根源:
*x++;
目的是增加指向的值。但是由于优先级++
是第一位的,向前移动x
指针然后*
什么都不做,*x
如果参数来自堆栈,那么写入将破坏堆栈金丝雀,使 VS 抱怨。
改变它来(*x)++
解决问题。
希望这可以帮助。
这是我在这种情况下所做的:
在可以看到相关变量的(正确)值但在错误发生之前的位置设置断点。您将需要堆栈被破坏的变量的内存地址。有时我必须添加一行代码才能让调试器轻松地给我地址 (int *x = &y)
此时可以设置内存断点(Debug->New Breakpoint->New Data Breakpoint)
点击播放,当内存被写入时调试器应该停止。查找堆栈(我的通常会在一些汇编代码中中断)以查看被调用的内容。
我通常在抱怨变量之前跟踪变量,这通常可以帮助我解决问题。但这有时可能非常复杂,没有任何线索,正如您所见。您可以启用“调试”菜单>>“异常”并勾选“Win32 异常”以捕获所有异常。这仍然不会捕获此异常,但它可以捕获可能间接指向问题的其他内容。
就我而言,这是由我正在使用的库引起的。结果是我在项目中包含的头文件与该库中的实际头文件不完全匹配(一行)。
还有一个不同的错误也相关:
0xC015000F:被停用的激活上下文不是最近激活的。
当我厌倦了在没有调试信息的情况下在我的计算机上收到神秘的堆栈损坏消息时,我在另一台计算机上尝试了我的项目,它给了我上面的消息。有了新的例外,我能够解决问题。
当我创建一个包含 13 个项目的指针数组,然后尝试设置第 14 个项目时,我遇到了这个问题。将数组更改为 14 个项目解决了这个问题。希望这可以帮助一些人^_^
“围绕变量'x'的堆栈已损坏”问题的一个相对常见的来源是错误转换。有时很难发现。这是发生此类问题的功能示例和修复方法。在函数中assignValue
,我想为变量分配一些值。该变量位于作为参数传递给函数的内存地址:
using namespace std;
template<typename T>
void assignValue(uint64_t address, T value)
{
int8_t* begin_object = reinterpret_cast<int8_t*>(std::addressof(value));
// wrongly casted to (int*), produces the error (sizeof(int) == 4)
//std::copy(begin_object, begin_object + sizeof(T), (int*)address);
// correct cast to (int8_t*), assignment byte by byte, (sizeof(int8_t) == 1)
std::copy(begin_object, begin_object + sizeof(T), (int8_t*)address);
}
int main()
{
int x = 1;
int x2 = 22;
assignValue<int>((uint64_t)&x, x2);
assert(x == x2);
}