【发布时间】:2018-01-08 21:26:21
【问题描述】:
更新:我创建了一个更多的 M,但仍然是 CVE,它可以重现崩溃。摘要:删除了Base 类中Bool* bools_ 字段的所有使用(但仍然必须定义它,否则不会发生崩溃)。还从Base 及其后代中删除了Base::Initialize() 和虚拟方法Rule。新的 MCVE 已附加。
我已经设法为此代码创建了一个 MCVE 并将其发布在下面。
一些描述性细节:代码使用虚拟基类和派生类,并且某些被实例化的派生类具有调用从“基”类(实际上是派生类,但在更高级别)继承的非虚拟方法的构造函数继承层次结构比我所谓的“派生”类)初始化“基”类数据。该方法调用在派生类中被覆盖的虚拟方法。我意识到这是一件危险的事情,但从我(可能有限)对 C++ 的理解来看,它似乎应该可以工作,因为派生类构造函数的主体在“基”类虚拟表建立之前不会执行.在任何情况下,在调用“基”类的初始化方法期间都不会发生段错误。
段错误发生在“基”类构造函数中,并且仅当构造函数的主体为空时。如果我在构造函数中添加调试行以在到达该点时打印出来,则打印出调试行并且代码正常运行。我的猜测是,由于某种原因,编译器正在优化应该在“基”类的构造函数的主体执行之前发生的初始化,包括 vtable 的设置。
正如主题行所说,此代码在使用 Apple 的 g++ 或 g++ 7.2.0 编译时运行良好,甚至在使用 g++ 7.2.0 编译 -O3 时也运行良好。只有在使用 Apple 的 g++ 的 LLVM 实现编译 -O2 或 -O3 时才会出现段错误。该编译器的g++ --version 的输出是:
% /usr/bin/g++ --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 9.0.0 (clang-900.0.39.2)
Target: x86_64-apple-darwin17.3.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Content
MCVE 紧随其后。
#include <iostream>
using namespace std;
class OriginalBaseClass {
public:
OriginalBaseClass(long double data1 = 1, long int data2 = 1) : data1_(data1), data2_(data2) { cout << "In OriginalBaseClass constructor\n"; }
private:
long double data1_;
long int data2_;
};
class Base : public virtual OriginalBaseClass {
public:
Base(long int data1 = 0, long int data2 = 0) : data1_(data1), data2_(data2) { cout << "In Base constructor\n"; }
virtual ~Base();
private:
bool* bools_;
long int data1_;
long int data2_;
};
Base::~Base()
{
cout << "In Base destructor\n";
}
class Derived_A : public virtual Base {
public:
Derived_A() { cout << "In Derived_A constructor\n"; }
};
class Derived_B : public Derived_A {
public:
Derived_B() : OriginalBaseClass(), Base(4, 1), Derived_A() { cout << "In Derived_B constructor\n"; }
};
int main()
{
Derived_B Derb;
}
错误报告链接:https://bugreport.apple.com/web/
参考号 36382481
【问题讨论】:
-
我建议您使用调试器来查明导致段错误的一般问题区域,然后自行调试或将其提取到成功崩溃并共享的较小程序中,以便我们帮助您调试
-
您好,谢谢。除了 Xcode 中的调试器之外,还有其他调试器可以处理使用 Apple 的 g++ 编译的代码吗?我试过在 Xcode 中使用它,它只是卡在“基”类构造函数中。它甚至不会介入——这就是我怀疑编译器本质上优化构造函数的原因之一。
-
尝试使用 -fsanitize=address 编译并运行您的程序。它在 clang 和 gcc 中都可用。这个工具非常擅长捕捉这类问题。很可能您的代码中有未定义的行为。
-
"源代码太长,无法发布,我无法用更简单的代码片段重现它。" 所以,尝试制造minimal reproducible example。如果您无法用较小的代码片段重现问题,则说明您删除了太多代码(可能问题是由于您认为不相关的代码造成的?)。此类问题的典型原因是代码中某处的未定义行为。至少,如果没有minimal reproducible example,就无法说出更多。
-
@PaulMcKenzie 嗯,这次好像是 Clang 的一个 bug。
标签: c++ clang llvm-clang virtual-inheritance