C++ code segfaults when compiled -O with Apple's LLVM compiler, but not with g++ -7.2.0

Can anyone help me figure out what is wrong with this code? It compiles and runs fine at any optimization level with g++ 7.2.0, and in debug mode with Apple's LLVM compiler, but not when compiled with -O2 or -O3 with Apple's compiler. The segfault apparently occurs during the call to Derived_A's constructor, but I cannot tell when running inside the Xcode debugger as it simply gets stuck at the function call and will not step into the constructor - maybe because line number information is lost in optimization.

If either the OriginalBaseClass constructor's argument list or that of the Base class's constructor is reduced from two arguments to one, or even if the values passed by Derived_B are changed, the crash does not happen and the code reaches the Base destructor.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <iostream>

using namespace std;
    
class OriginalBaseClass {
public:
  OriginalBaseClass(long double data1 = 1, long int data2 = 1) : data1_(data1), data2_(data2) {}
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), bools_(0) {}
  virtual ~Base();
  void Initialize(long int anchor, long int ypc, long int lypc);
  bool* bools_;
protected:
  virtual bool Rule(long int year, long int anchor, long int ypc, long int lypc) { return false; }
private:
  long int data1_;
  long int data2_;
};
    
Base::~Base()
{
  cout << "In Base destructor\n";
  if ( bools_ ) delete bools_;
}
    
void Base::Initialize(long int anchor, long int ypc, long int lypc)
{
  bools_ = new bool[ypc];
  for ( short int i = 0 ; i < ypc ; i++ )
    bools_[i] = this->Rule(anchor + i, anchor, ypc, lypc);
}
    
class Derived_A : public virtual Base {
public:
  Derived_A() {}
};
    
class Derived_B : public Derived_A {
public:
  Derived_B() : OriginalBaseClass(), Base(4, 1) { Initialize(1, 4, 1); }
protected:
  virtual bool Rule(long int year, long int anchor, long int ypc, long int lypc);
};
    
bool Derived_B::Rule(long int yr, long int a, long int ypc, long int lypc)
{
  return false;
}

int main()
{
  Derived_B Derb;
}
Last edited on
> I cannot tell when running inside the Xcode debugger as it will not step into the constructor

Try placing a break point in the constructor.

Or debug using the command line debugger. See 'Using LLDB as a Standalone Debugger':
https://developer.apple.com/library/content/documentation/IDEs/Conceptual/gdb_to_lldb_transition_guide/document/lldb-terminal-workflow-tutorial.html#//apple_ref/doc/uid/TP40012917-CH4-SW1
Thanks, but a break point inside the constructor is never reached. I tried un-inlining all of the constructors to insert print statements to see where it gets stuck. In particular, in the Base constructor I put the line "cout << "In Base constructor\n"; ", and found that Xcode gets stuck right at the Base constructor header, where the data1_, data2_, and bools_ members are initialized and the OriginalBaseClass constructor is (implicitly) called. The corresponding line in OriginalBaseClass's constructor does execute, but the line in the body of the Base constructor is never reached.

Some additional info that may be helpful: Xcode reports Thread 1: EXC_BAD_ACCESS (code=EXC_I386_GPFLT) at that point.
Last edited on
One problem I see in your code is that use bools_ = new bool[ypc]; but call if ( bools_ ) delete bools_;
I guess this is undefined behaviour, so it might work on some compiler but not others.

In modern C++ you should not use new and delete anyway.
Much better to use a vector<bool>
Last edited on
I am not able to reproduce this error with these two versions of clang++:
clang++ 3.8 (linux and freebsd) or clang++ 5.0 ( x86_64-w64-windows-gnu)

clang version 3.8.0 (tags/RELEASE_380/final 263969) Target: x86_64-unknown-linux-gnu on coliru:
Original code: http://coliru.stacked-crooked.com/a/547051efb5be1a2f
Noisy version: http://coliru.stacked-crooked.com/a/ef1f23c79ef1a4f6

Also: there is no error with clang++ front-end and Microsoft CodeGen.


What is the version of clang++ that you are using?
Is it the latest version of the compiler on Apple?

Yes, there is UB (pointed out by Thomas1965); does the error go away if that is fixed?
Last edited on
Yes, another user pointed out that I should be using delete [] bools_ instead. Fixing this changes nothing. Even if the calls to new and delete are removed and indeed, even if Base::Initialize and Base::~Base do nothing but print out a line to cout, the code still crashes. (If the bool *bools_ field is removed entirely from class Base, however, the code does not crash.)

I had thought that the cause was the call to this->Rule, a virtual method, indirectly from the Derived_B constructor. However this is not the case; first of all, that call is never reached during execution. Moreover, making Base::Rule non-virtual changes nothing. Indeed, removing it (from both Base and Derived_B) changes nothing. Even removing Base::Initialize altogether changes nothing.

@JLBorges, thank you for trying to reproduce the crash. Did you use -O2 or -O3? Without optimization it doesn't crash for me either. Here is my version of clang; I do believe that it is the latest (MacOS 10.3.2, Xcode 9.2).

% clang --version
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/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

Attached is an even shorter example code that crashes:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#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;
}
Last edited on
It crashed (with a SEGFAULT) in
http://rextester.com/l/cpp_online_compiler_clang
with -O2 or -O3 optimisation.

Doing any one of the following stopped the crash;
- removing the optimisation;
- changing long double to long int;
- removing the base destructor;
- commenting out bool* bools_;
- moving bool* bools_; to after the declarations of data1_ and data2_;
- declaring an object of class Base in main, rather than Derived_A or Derived_B.


The following, slightly smaller, code does exactly the same with that version of clang. Everything works fine with other compilers.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#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 = 1, long int data2 = 1) : data1_(data1), data2_(data2) { cout << "In Base constructor\n"; }
   virtual ~Base(){ cout << "In Base destructor\n"; }
private:
   bool* bools_;
   long int data1_;
   long int data2_;
};


class Derived_A : public virtual Base {
public:
   Derived_A() { cout << "In Derived_A constructor\n"; }
};

int main()
{
   Derived_A x;    // Fails at http://rextester.com/l/cpp_online_compiler_clang  with default optimisation (-O2)
// Base x;         // Works OK at above site
}
Last edited on
@lastchance - Thanks for reproducing my crash. I confirm that your smaller example also crashes. Interesting that removing the one level of inheritance does not "fix" the problem - I had tried that with a previous, but slightly more complicated, example code and it did not crash for me - so apparently the two levels of inheritance may, or may not, be necessary to make it crash depending on what else is in the code.

Any idea of what the problem is? Compiler bug or bug in the code? (The fact that it works fine with other compilers is no guarantee that the code is okay!)

I am tempted to send a bug report to Apple but I want to be sure my code is okay first.

Question: how do you post formatted code on this forum?
fizzixgal wrote:
Question: how do you post formatted code on this forum?

Use code tags - either by manually writing [code] and [/code], or by selecting your code and applying the first format tag from the box on the RHS; i.e. the <> button. The latter doesn't seem to work on first posting, so either edit your post immediately or manually put the code tags in.
Thanks.
Well, the clang version on rextester is 3.8.0 (tags/RELEASE_380/final)

It would appear that the code generated by the compiler for placing the sub-object of type Base violates the alignment requirements of the type.

It reports this: std::alignment_of<Base>::value: 16

However, with -fsanitize=undefined, this is the crash diagnostic:
runtime error: constructor call on misaligned address 0x7ffeae23dd68 for type 'Base', which requires 16 byte alignment
0x7ffeae23dd68: note: pointer points here
 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ff 00 00 00
              ^ 

http://rextester.com/VACW20259


If the code is modified with an explicit class alignas(16) Base : public virtual OriginalBaseClass { // ...
the error goes away.
http://rextester.com/CPGYGA9582


AFAIK, this appears to be a compiler bug. However, note that the same version of the compiler does not have this problem on all platforms; for instance, on coliru, there is no crash:
http://coliru.stacked-crooked.com/a/042e92096df8c479

Using LLDB directly (from the command line) might have saved a lot of time; it should immediately point out the error (presence of misaligned data).
Last edited on
@JLBorges: thanks. Actually I had tried running it with command-line lldb, but I compiled with -fsanitize=address, not undefined. With address it only gives the reason (EXC_BAD_ACCESS) and the line where it occurs. So I was completely stumoed.
Topic archived. No new replies allowed.