[英]Compiler optimization makes program crash
我正在用C ++ / Qt编写一个包含图形文件解析器的程序。 我使用g++
编译项目。
在开发过程中,我不断比较不同编译器标志之间关于优化和调试信息的低级解析器层的性能,以及Qt的调试标志(打开/关闭qDebug()和Q_ASSERT())。
现在我遇到的问题是,唯一正常运行的构建是没有任何优化的构建 。 所有其他版本,即使使用-O1
,似乎也以另一种方式工作。 它们由于不满意的断言而崩溃,这些断言在没有-O...
标志的情况下编译时会得到满足。 即使使用-Wall
,代码也不会产生任何编译器警告。
我非常确定我的程序中存在一个错误,这似乎只对启用优化有害。 问题是:即使在调试程序时我也找不到它。 解析器似乎从文件中读取错误的数据。 当我运行一些简单的测试用例时,它们运行得很好。 当我运行一个更大的测试用例(直接从文件读取的图形上的路由计算)时,文件中的读取不正确,我无法解释。
我应该从哪里开始追踪这种未定义行为的问题? 这种不同的行为可能涉及哪些优化方法? (我可以一个接一个地启用所有标志,但是我不知道那么多的编译器标志但-O...
我知道它们有很多,所以这需要很长时间。)尽快因为我知道这个类型的类型,我相信我迟早会发现它。
如果你能告诉我哪些编译器优化方法可能成为这些问题的候选者,你可以帮助我很多。
在优化的构建中通常会出现一些类错误,这些错误通常不会出现在调试版本中。
未初始化的变量。 编译器可以捕获一些但不是全部。 查看所有构造函数,查看全局变量。 特别是寻找未初始化的指针。 在调试中,构建内存重置为零,但在发布版本中则不是。
使用超出范围的临时工。 例如,当您在函数中返回对本地临时的引用时。 这些通常在调试版本中工作,因为堆栈被填充更多。 临时者倾向于在堆叠上存活一段时间。
阵列覆盖临时写作。 例如,如果在函数中创建一个数组作为临时数,然后在结尾之外写入一个元素。 同样,堆栈将在调试中有额外的空间(用于调试信息),并且您的溢出将不会命中程序数据。
您可以从优化的构建中禁用优化,以帮助简化调试优化版本。
-g -O1 -fno-inline -fno-loop-optimize -fno-if-conversion -fno-if-conversion2 \
-fno-delayed-branch
这应该使调试器中的代码更容易理解。
另一个建议是,如果您所拥有的断言没有提供有关导致问题的原因的足够信息,则应考虑添加更多断言。 如果您害怕性能问题或断言混乱,可以将它们包装在宏中。 这允许您区分调试断言与最初添加的断言,因此可以在以后禁用它们或从代码中删除它们。
1)在破碎版本上使用valgrind。 (就此而言,在工作版本上尝试valgrind,也许你会很幸运。)
2)使用“-O1 -g”构建系统,并使用gdb逐步执行程序。 在崩溃时,哪个变量的值不正确? 重新运行您的程序并记下该变量的写入时间(或者当它不存在且应该存在时)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.