runStaticConstructorsDestructors not calling static destructors

Hi there,

I'm having trouble getting ExecutionEngine->runStaticConstructorsDestructors(module, true) to actually trigger static destructors in my code. The static constructors however do get called.

I don't know if this is an LLVM or Clang issue, from looking at the IR (see below) it looks like the destructor is being tied to cxa_atexit, and I wonder if that is not called by runStaticConstructorsDestructors(module, true);

Thanks in advance for any suggestions you can offer!

Graham

Using LLVM/Clang 2.9 release for OSX, on OSX 10.6.8, on a core i7 macbook pro.

I'm compiling from C++ using Clang, and passing the compiled module to an ExecutionEngine created as follows:

EE = llvm::EngineBuilder(globalModule)
      .setEngineKind(llvm::EngineKind::JIT)
      .setErrorStr(&err)
      .setOptLevel(llvm::CodeGenOpt::Default)
      .setAllocateGVsWithCode(false)
      //.setMAttrs("-avx")
      .setMCPU("core2")
      .create();
EE->DisableLazyCompilation();

After passing in the compiled module, I call:

EE->runStaticConstructorsDestructors(module, false);

Then to test the tear-down of the module, I call:

EE->runStaticConstructorsDestructors(mImpl->module, true);
EE->clearGlobalMappingsFromModule(mImpl->module);
EE->removeModule(mImpl->module);

The C++ code compiled:

#include <stdio.h>
class Foo {
public:
  Foo() { printf("Foo\n"); };
  ~Foo() { printf("~Foo\n"); };

  int x;
};

// a static variable:
Foo foo;

The constructor is being called (I see 'Foo' in my stdout), but the destructor is not.

The LLVM IR produced:

; ModuleID = 'mymodule'
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128-n8:16:32"
target triple = "i386-apple-darwin10"

%0 = type { i32, void ()* }
%class.Foo = type { i32 }

@foo = global %class.Foo zeroinitializer, align 4
@__dso_handle = external global i8*
@.str = private unnamed_addr constant [6 x i8] c"~Foo\0A\00"
@.str1 = private unnamed_addr constant [5 x i8] c"Foo\0A\00"
@llvm.global_ctors = appending global [1 x %0] [%0 { i32 65535, void ()* @_GLOBAL__I_a }]

define internal void @__cxx_global_var_init() nounwind section "__TEXT,__StaticInit,regular,pure_instructions" {
call void @_ZN3FooC1Ev(%class.Foo* @foo)
%1 = call i32 @__cxa_atexit(void (i8*)* bitcast (void (%class.Foo*)* @_ZN3FooD1Ev to void (i8*)*), i8* bitcast (%class.Foo* @foo to i8*), i8* bitcast (i8** @__dso_handle to i8*))
ret void
}

define linkonce_odr void @_ZN3FooC1Ev(%class.Foo* %this) unnamed_addr nounwind align 2 {
%1 = alloca %class.Foo*, align 4
store %class.Foo* %this, %class.Foo** %1, align 4
%2 = load %class.Foo** %1
call void @_ZN3FooC2Ev(%class.Foo* %2)
ret void
}

define linkonce_odr void @_ZN3FooD1Ev(%class.Foo* %this) unnamed_addr nounwind align 2 {
%1 = alloca %class.Foo*, align 4
store %class.Foo* %this, %class.Foo** %1, align 4
%2 = load %class.Foo** %1
call void @_ZN3FooD2Ev(%class.Foo* %2)
ret void
}

declare i32 @__cxa_atexit(void (i8*)*, i8*, i8*)

define linkonce_odr void @_ZN3FooD2Ev(%class.Foo* %this) unnamed_addr nounwind align 2 {
%1 = alloca %class.Foo*, align 4
store %class.Foo* %this, %class.Foo** %1, align 4
%2 = load %class.Foo** %1
%3 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([6 x i8]* @.str, i32 0, i32 0))
ret void
}

declare i32 @printf(i8*, ...)

define linkonce_odr void @_ZN3FooC2Ev(%class.Foo* %this) unnamed_addr nounwind align 2 {
%1 = alloca %class.Foo*, align 4
store %class.Foo* %this, %class.Foo** %1, align 4
%2 = load %class.Foo** %1
%3 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([5 x i8]* @.str1, i32 0, i32 0))
ret void
}

define internal void @_GLOBAL__I_a() nounwind section "__TEXT,__StaticInit,regular,pure_instructions" {
call void @__cxx_global_var_init()
ret void
}

I added a JITEventListener, which displays:

JIT emitted Function _GLOBAL__I_a at 0x1c00010, size 12
JIT emitted Function __cxx_global_var_init at 0x1c00020, size 47
JIT emitted Function _ZN3FooD1Ev at 0x1c00060, size 23
JIT emitted Function _ZN3FooD2Ev at 0x1c00080, size 27
JIT emitted Function _ZN3FooC1Ev at 0x1c000a0, size 23
JIT emitted Function _ZN3FooC2Ev at 0x1c000c0, size 27

JIT freed 0x1c00020
JIT freed 0x1c000a0
JIT freed 0x1c00060
JIT freed 0x1c00080
JIT freed 0x1c000c0
JIT freed 0x1c00010

Another data point - it looks like the destructors are called when the running program exits (which crashes because the machine code has been freed).

Is there a configuration to LLVM or Clang to tell it to put the destructors in a different location than __cxa_atexit ?

Thanks~

Hi there,

I'm having trouble getting ExecutionEngine->runStaticConstructorsDestructors(module, true) to actually trigger static destructors in my code. The static constructors however do get called.

I don't know if this is an LLVM or Clang issue, from looking at the IR (see below) it looks like the destructor is being tied to cxa_atexit, and I wonder if that is not called by runStaticConstructorsDestructors(module, true);

Thanks in advance for any suggestions you can offer!

Yes, that would do it... if you really need to be able to trigger
static destructors for C++ objects before calling exit(), you'll need
to mess with clang's IRGen. grep for cxa_atexit in
clang/lib/CodeGen/.

-Eli

Perfect - CodeGenOptions has the flag I needed!

CodeGenOptions.CGO;
CGO.CXAAtExit = 0;

Thanks for the fast reply!