Update: I've created an even more M, but still CVE that reproduces the crash. Summary: removed all use of the Bool* bools_
field in Base
class (but it still must be defined or the crash does not happen). Also removed Base::Initialize()
and the virtual method Rule
from Base
and its descendants. New MCVE is attached.
I've managed to create an MCVE for this code and posted it below.
Some descriptive details: the code uses virtual base and derived classes, and certain derived classes that are instantiated have constructors that call a non-virtual method inherited from a "base" class (actually a derived class, but higher up in the inheritance hierarchy than what I am calling the "derived" classes) to initialize "base" class data. That method calls a virtual method that is overridden in the derived classes. I realize that that is a dangerous thing to do, but from my (possibly limited) understanding of C++, it seems like it should work because the body of the derived class constructor does not execute until the "base" class virtual tables are set up. In any case, the segfault does NOT occur during the call to the "base" class's initialization method.
The segfault occurs in the "base" class constructor, and ONLY when the body of the constructor is empty. If I add a debugging line to the constructor to print out when that point is reached, the debugging line is printed out and the code runs normally. My guess is that for some reason the compiler is optimizing away the initializations that should happen before the body of the "base" class's constructor is executed, including the setting up of the vtable.
As the subject line says, this code runs fine when compiled without optimization using either Apple's g++ or g++ 7.2.0, and it runs fine when compiled even -O3 using g++ 7.2.0. It ONLY segfault when compiled -O2
or -O3
with Apple's LLVM implementation of g++. The output of g++ --version
for that compiler is:
% /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
The MCVE follows.
#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;
}
Link to bug report: https://bugreport.apple.com/web/
Reference number 36382481
if (bools_) delete bools_;
-- 1) Wrong form ofdelete
. It should bedelete []
. 2) There is no need to check for null when issuing a call todelete[]
. – Etam