使用o2标志进行编译会使程序抛出访问冲突

时间:2011-05-26 21:11:37

标签: c++ visual-studio-2010 optimization assembly access-violation

我知道这可能是一生一次的问题,但我坚持使用它,我不能想到任何可能的问题,这是一个很好的问题,我已经用c ++编写了一个代码(单独约500行代码)类和文件)使用visual studio,而我编译它没有优化标志(/ od)它工作正常,但当我尝试使用发布配置(/ o2标志进行优化)编译它时,程序提供访问冲突和崩溃。经过一些调试后我发现有一个this值正在改变其中一个成员函数,但我看不到在调用堆栈中指针的任何直接使用是指针改变了,任何人都可以给出任何建议只有在启用优化时才会发生?

不知道这是否对您有所帮助,但是当我使用优化进行编译时,我可以看到在我的第一个函数调用pop ebp结束时添加了一个汇编实例,不知道是什么这个,但它是什么,这是这个指针改变的地方。

我在尝试使用反汇编程序进行调试时发现了一些新内容,在函数中有13个push指令和只有10个pop指令导致问题(问题是由上一次弹出引起的)就在ret指令之前)是否可以? (我正在计算所调用函数中的所有push,pop指令。)

2 个答案:

答案 0 :(得分:3)

因为你说这个指针突然改变了值导致我认为这与堆损坏有关。另一方面,既然你说这与优化代码有关,那么它也可能与堆栈有关。优化器所做的一件事就是它删除了堆栈中未使用的变量,这些变量从未被访问过。

这实际上意味着当你没有在优化模式下编译时,堆栈上会有更多的变量,从而使内存布局有所不同,从某种意义上说,为堆栈增加了更多的内存空间,影响软件对堆栈溢出的反应。

如果存在从未使用的局部变量,则程序不关心是否损坏了未使用的局部变量的内存。只有当你破坏了实际使用的内存时才会出现问题。

您可以告诉编译器使用不同的警告级别(如果我没有记错,则为4级)。如果使用最高的警告将被视为编译器错误,这将停止编译过程。这样,您可以注意到在优化代码时将删除的局部变量,并且可以使您更接近真正的问题。开始搜索代码的这些区域。

我还建议您删除代码并进行测试,只是为了排除有问题的代码所在的位置,然后逐步挖掘出问题所在。当您没有信息时,您必须从头开始(程序的主循环)并尝试隔离并排除部分正常工作的代码。 “如果我注释掉这个函数调用,那么它不会崩溃”可能会给你一个提示:)

答案 1 :(得分:3)

您在使用和不使用优化时看到不同行为的原因是您的代码(无意中)依赖于未定义的行为。如果编译器以一种方式布局数据就会发生这种情况,如果编译器以不同的方式布局,则会中断。

换句话说,你有一个错误。

它可能在您已经测试过的代码中,也可能在您使用代码的方式中。无论如何,正如@Nim在评论中所说,检查你分配的位置和释放内存。检查您的课程是否遵循三级规则。验证您的某处没有缓冲区溢出。也许,尝试使用不同的编译器进行编译。使用静态分析工具(MSVC有/ analyze,Clang有--analyze。在Linux上Valgrind可能是一个不错的选择)。

但不要以为它是编译器错误。确实发生了这些事情,但它们通常不是这种错误的根源。几乎在每种情况下,它都是开发人员自己代码中的潜在错误。仅仅因为它不会每次触发,每个编译器标志并不意味着它不存在,或者它是编译器的错误。