我正在经历奇怪的崩溃。我想知道这是否是我的代码或编译器中的错误。当我使用 Microsoft Visual Studio 2010 编译以下 C++ 代码作为优化版本构建时,它在标记的行中崩溃:
struct tup { int x; int y; };
class C
{
public:
struct tup* p;
struct tup* operator--() { return --p; }
struct tup* operator++(int) { return p++; }
virtual void Reset() { p = 0;}
};
int main ()
{
C c;
volatile int x = 0;
struct tup v1;
struct tup v2 = {0, x};
c.p = &v1;
(*(c++)) = v2;
struct tup i = (*(--c)); // crash! (dereferencing a NULL-pointer)
return i.x;
}
查看反汇编,很明显它必须崩溃:
int _tmain(int argc, _TCHAR* argv[])
{
00CE1000 push ebp
00CE1001 mov ebp,esp
00CE1003 sub esp,0Ch
C c;
volatile int x = 0;
00CE1006 xor eax,eax
00CE1008 mov dword ptr [x],eax
struct tup v1;
struct tup v2 = {0, x};
00CE100B mov ecx,dword ptr [x]
c.p = &v1;
(*(c++)) = v2;
00CE100E mov dword ptr [ebp-8],ecx
struct tup i = (*(--c));
00CE1011 mov ecx,dword ptr [x]
00CE1014 mov dword ptr [v1],eax
00CE1017 mov eax,dword ptr [ecx]
00CE1019 mov ecx,dword ptr [ecx+4]
00CE101C mov dword ptr [ebp-8],ecx
return i.x;
}
00CE101F mov esp,ebp
00CE1021 pop ebp
00CE1022 ret
在偏移量 00CE1008 处,它将 0 写入 x。
在偏移量 00CE100B 处,它将 x(0)读入 ecx
在偏移量 00CE1017 处,它取消引用该 0 指针。
我看到两个可能的原因:
在我的代码中存在一些微妙的(或不那么微妙的?)未定义行为的情况,编译器将这种未定义的行为“优化”为崩溃。
或者存在编译器错误
有谁看到可能导致问题的原因?
谢谢,
乔纳斯
编辑:解决有关“指向无效位置的指针”的评论
如果我更改v1
为 bestruct tup v1[10];
和 set c.p = &v1[0];
,那么将没有指向无效位置的指针。但我仍然可以观察到相同的行为。反汇编看起来略有不同,但仍然存在崩溃,它仍然是由将 0 加载到 ecx 并取消引用它引起的。
编辑:结论
所以,这可能是一个错误。我发现如果我改变,崩溃就会消失
struct tup* operator--() { return --p; }
到
struct tup* operator--() { --p; return p; }
正如 bames53 告诉我们的那样,在 VS2011 中不会发生崩溃,并得出结论认为它必须已修复。
尽管如此,我还是出于两个原因决定提交该错误:
该错误可能仍然存在于 VS2011 中。也许优化器只是改变了我的代码不再触发错误的方式。(该错误似乎非常微妙,当我删除
volative
或时不会发生virtual void Reset()
)我想知道我的解决方法是否是排除崩溃的可靠方法,或者其他地方的代码更改是否可以重新引入错误。
链接在这里:
https://connect.microsoft.com/VisualStudio/feedback/details/741628/error-in-code-generation-for-x86