【发布时间】:2012-05-19 07:53:42
【问题描述】:
我遇到了奇怪的崩溃。我想知道这是否是我的代码或编译器中的错误。 当我使用 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 指针。
我看到两个可能的原因:
在我的代码中是否存在一些微妙(或不那么微妙?)未定义行为的情况 并且编译器将这种未定义的行为“优化”为崩溃。
或存在编译器错误
有谁知道可能导致问题的原因吗?
谢谢,
乔纳斯
编辑:解决有关“指向无效位置的指针”的 cmets
如果我将v1 更改为struct tup v1[10]; 并设置c.p = &v1[0];,则不会有指向无效位置的指针。但我仍然可以观察到相同的行为。反汇编看起来略有不同,但仍然存在崩溃,它仍然是由将 0 加载到 ecx 并取消引用它造成的。
编辑:结论
所以,这可能是一个错误。我发现如果我改变,崩溃就会消失
struct tup* operator--() { return --p; }
到
struct tup* operator--() { --p; return p; }
正如 bames53 告诉我们的那样,崩溃并没有发生在 VS2011 中,并得出结论认为它必须已修复。
尽管如此,我还是出于两个原因决定提交该错误:
该错误可能仍然存在于 VS2011 中。也许优化器只是改变了我的代码不再触发错误的方式。 (这个bug似乎很微妙,当我删除
volative或virtual void Reset()时不会出现)我想知道我的解决方法是否是排除崩溃的可靠方法,或者其他地方的代码更改是否会重新引入错误。
这是链接:
https://connect.microsoft.com/VisualStudio/feedback/details/741628/error-in-code-generation-for-x86
【问题讨论】:
-
你让很多人感到困惑。在我看来,它确实像一个编译器错误。应该通过 Microsoft Connect 联系他们。
-
@将
v2更改为{0, 0};并删除volatile int x表现出相同的行为,因此不相关。 -
@ildjarn: bames53 确认它已经在 vs11 中修复。
-
@Mooing Duck:不,这是必要的。
virtual Reset()也是必要的。删除这两个中的一个,崩溃就会消失。我认为两者都需要以欺骗优化器,使其无法优化得很好。因为明显的优化是只返回 0。 -
@m3tikn0b:在我的机器上,当我删除
virtual int x时问题仍然存在,但我调整了优化设置。所以要么(A)这些设置是相关的,要么(B)我们中的一个人搞砸了我们的测试。 (我承认可能是我)
标签: c++ visual-studio-2010 visual-c++ crash compiler-optimization