m3t*_*n0b 16 c++ crash visual-studio-2010 compiler-optimization visual-c++
我遇到了奇怪的崩溃.我想知道它是否是我的代码或编译器中的错误.当我使用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;
}
Run Code Online (Sandbox Code Playgroud)
查看反汇编,很明显它必须崩溃:
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
Run Code Online (Sandbox Code Playgroud)
在偏移00CE1008处,它将0写入x.
在偏移00CE100B处,它将x(0)读入ecx
在偏移00CE1017时,它取消引用0指针.
我看到两个可能的原因:
在我的代码中有一些微妙的(或不那么微妙的)未定义行为的情况,并且编译器将这个未定义的行为"优化"为崩溃.
或者有一个编译器错误
有谁看到可能导致问题的原因?
谢谢,
乔纳斯
编辑:解决有关"指向无效位置的指针"的评论
如果我v1改为be struct tup v1[10];并设置c.p = &v1[0];,那么将没有指向无效位置的指针.但我仍然可以观察到同样的行为.反汇编看起来略有不同,但仍然存在崩溃,仍然是由于将0加载到ecx并取消引用它.
编辑:结论
所以,可能是一个bug.我发现如果我改变,崩溃就会消失
struct tup* operator--() { return --p; }
Run Code Online (Sandbox Code Playgroud)
至
struct tup* operator--() { --p; return p; }
Run Code Online (Sandbox Code Playgroud)
正如bames53告诉我们的那样,VS2011中没有发生崩溃,并得出结论它必须已经修复.
尽管如此,我决定提交该bug有两个原因:
该错误可能仍然存在于VS2011中.也许优化器只是改变了我的代码不再触发错误的方式.(这个bug似乎非常微妙,当我删除volative或者它时不会发生virtual void Reset())
我想知道我的解决方法是否是排除崩溃的可靠方法,或者其他地方的代码更改是否可以重新引入错误.
链接在这里:
https://connect.microsoft.com/VisualStudio/feedback/details/741628/error-in-code-generation-for-x86
R. *_*des 17
代码很好.这是一个编译器错误.
代码*(c++) = v2将后递增,c.p产生原始值.该值在前一行中分配,并且是&v1.所以,实际上,确实v1 = v2;很好.
c.p现在表现为仅v1按照标准的§5.7p4 保存的单元素数组的一个结尾:
出于这些运算符[
+和-] 的目的,指向非阵列对象的指针与指向长度为1的数组的第一个元素的指针的行为相同,其中对象的类型为其元素类型.
然后*(--c)将指针移回&v1并取消引用它,这也没关系.
| 归档时间: |
|
| 查看次数: |
714 次 |
| 最近记录: |