【问题标题】:Compiler optimization makes program crash编译器优化使程序崩溃
【发布时间】:2012-07-10 13:12:00
【问题描述】:

我正在用 C++/Qt 编写一个包含图形文件解析器的程序。我使用g++ 编译项目。

在开发过程中,我不断比较不同编译器标志与优化和调试信息以及 Qt 的调试标志(打开/关闭 qDebug() 和 Q_ASSERT())之间的低级解析器层的性能。

现在我面临一个问题,唯一正常运行的构建是没有任何优化的构建。所有其他版本,即使是-O1,似乎都以另一种方式工作。它们由于不满足的断言而崩溃,在没有-O... 标志的情况下编译时满足。该代码不会产生任何编译器警告,即使使用 -Wall

我非常确定我的程序中存在错误,这似乎只有在启用优化后才会有害。问题是:即使在调试程序时也找不到它。解析器似乎从文件中读取了错误的数据。当我运行一些简单的测试用例时,它们运行良好。当我运行一个更大的测试用例(直接从文件读取的图表上的路线计算)时,文件中存在我无法解释的错误读取。

我应该从哪里开始追踪这种未定义行为的问题? 这种不同的行为可能涉及哪些优化方法?(我可以一个接一个地启用所有标志,但我不知道那么多编译器标志,但-O... 我知道有一个很多,所以这需要很长时间。)一旦我知道错误的类型,我相信我迟早会找到它。

如果您能告诉我哪些编译器优化方法可能适合此类问题,您可以帮我很多。

【问题讨论】:

  • 在某处听起来像是未定义的行为。
  • @R.MartinhoFernandes 是的,但我怎样才能找到它?也许使用 valgrind?
  • 是的,valgrind 会警告你未初始化的值。
  • 请注意,-Wall 实际上并不是所有警告,而是很多警告。你需要-Wextra 来添加更多,但它仍然不会是所有可用的警告。

标签: c++ qt g++ compiler-optimization


【解决方案1】:

您可以从优化版本中禁用一些优化,以帮助更轻松地调试优化版本。

-g -O1 -fno-inline -fno-loop-optimize -fno-if-conversion -fno-if-conversion2 \
  -fno-delayed-branch

这应该会使在调试器中单步执行代码更容易一些。

另一个建议是,如果您的断言没有为您提供有关导致问题的足够信息,您应该考虑添加更多断言。如果您担心性能问题或断言混乱,您可以将它们包装在宏中。这使您可以将调试断言与您最初添加的断言区分开来,以便以后可以从您的代码中禁用或删除它们。

【讨论】:

  • 谢谢。 Q_ASSERT 就是这样一个宏,取决于#define 的存在。宏在发布构建模式下被禁用(对编译器使用 -D 标志)。
  • @leemes:明白了。我的意思是你要添加的新的和已经存在的。问候
【解决方案2】:

在优化构建中通常会出现几类错误,而在调试构建中通常不会出现。

  1. 未初始化的变量。编译器可以捕获一些但不是全部。查看所有构造函数,查看全局变量。等等。特别是寻找未初始化的指针。在调试版本中,内存被重置为零,但在发布版本中不是。

  2. 使用超出范围的临时对象。例如,当您在函数中返回对本地临时的引用时。这些通常在调试版本中起作用,因为堆栈被填充得更多。临时人员往往会在堆栈中存活更长时间。

  3. 数组超出了临时变量的写入。例如,如果您在函数中创建一个临时数组,然后在末尾写入一个元素。同样,堆栈在调试中将有额外的空间(用于调试信息)并且您的溢出不会影响程序数据。

【讨论】:

  • 非常感谢。这是一个完美的清单,不仅适用于这种情况,而且适用于我再次遇到此类问题的未来情况!
【解决方案3】:

1) 在损坏的版本上使用 valgrind。 (就此而言,在工作版本上尝试 valgrind,也许你会很幸运。)

2) 使用“-O1 -g”构建系统并使用 gdb 逐步执行您的程序。崩溃时,哪个变量的值不正确?重新运行您的程序并注意何时写入该变量(或何时未写入且应该写入)。

【讨论】:

    猜你喜欢
    • 2014-09-08
    • 1970-01-01
    • 2011-01-04
    • 2021-08-22
    • 2013-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-07
    相关资源
    最近更新 更多