[PATCH] D22474: [CodeGen] Suppress C++ static destructor registration

Bruno Cardoso Lopes via cfe-commits cfe-commits at lists.llvm.org
Mon Jul 18 13:39:25 PDT 2016


bruno created this revision.
bruno added reviewers: rsmith, doug.gregor.
bruno added subscribers: cfe-commits, dexonsmith.

C++ static destructors can be problematic in multi-threaded environment. Some of the issues users often complain about include:

1. Teardown ordering: crashes when one thread is exiting the process and calling destructors while another thread is still running and accessing the destructing variables
2. Shared code that is compiled both as an application and as a library. When library mode is chosen, goto (1).
3. Some projects currently override __cxa_atexit to avoid the behavior in question.

To get around that, I propose we add the compiler flag -fno-cxx-static-destructors, which allows clang to suppress static destructor registration (suppress emitting __cxa_atexit, atexit, etc).

https://reviews.llvm.org/D22474

Files:
  include/clang/Driver/Options.td
  include/clang/Frontend/CodeGenOptions.def
  lib/CodeGen/ItaniumCXXABI.cpp
  lib/Driver/Tools.cpp
  lib/Frontend/CompilerInvocation.cpp
  test/CodeGenCXX/static-destructor.cpp

Index: test/CodeGenCXX/static-destructor.cpp
===================================================================
--- test/CodeGenCXX/static-destructor.cpp
+++ test/CodeGenCXX/static-destructor.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 %s -triple=x86_64-pc-linux -emit-llvm -o - | FileCheck --check-prefix=X86 %s
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin -emit-llvm -fno-cxx-static-destructors -o - | FileCheck --check-prefix=X86-NOATEXIT %s
 // RUN: %clang_cc1 %s -triple=wasm32 -emit-llvm -o - | FileCheck --check-prefix=WASM %s
 // RUN: %clang_cc1 %s -triple=armv7-apple-darwin9 -emit-llvm -o - | FileCheck --check-prefix=ARM %s
 
@@ -19,6 +20,11 @@
 // X86: define internal void @__cxx_global_var_init()
 // X86:   call i32 @__cxa_atexit(void (i8*)* bitcast (void (%class.Foo*)* @_ZN3FooD1Ev to void (i8*)*), i8* getelementptr inbounds (%class.Foo, %class.Foo* @global, i32 0, i32 0), i8* @__dso_handle)
 
+// X86 destructors have void return, and are registered directly with __cxa_atexit.
+// X86-NOATEXIT: define internal void @__cxx_global_var_init()
+// X86-NOATEXIT-NOT:   call i32 @__cxa_atexit(void (i8*)* bitcast (void (%class.Foo*)* @_ZN3FooD1Ev to void (i8*)*), i8* getelementptr inbounds (%class.Foo, %class.Foo* @global, i32 0, i32 0), i8* @__dso_handle)
+// X86-NOATEXIT-NOT:   declare i32 @__cxa_atexit(void (i8*)*, i8*, i8*)
+
 // ARM destructors return this, but can be registered directly with __cxa_atexit
 // because the calling conventions tolerate the mismatch.
 // ARM: define internal void @__cxx_global_var_init()
Index: lib/Frontend/CompilerInvocation.cpp
===================================================================
--- lib/Frontend/CompilerInvocation.cpp
+++ lib/Frontend/CompilerInvocation.cpp
@@ -546,6 +546,7 @@
   Opts.AssumeSaneOperatorNew = !Args.hasArg(OPT_fno_assume_sane_operator_new);
   Opts.ObjCAutoRefCountExceptions = Args.hasArg(OPT_fobjc_arc_exceptions);
   Opts.CXAAtExit = !Args.hasArg(OPT_fno_use_cxa_atexit);
+  Opts.CXXNoExitTimeDtor = Args.hasArg(OPT_fno_cxx_static_destructors);
   Opts.CXXCtorDtorAliases = Args.hasArg(OPT_mconstructor_aliases);
   Opts.CodeModel = getCodeModel(Args, Diags);
   Opts.DebugPass = Args.getLastArgValue(OPT_mdebug_pass);
Index: lib/Driver/Tools.cpp
===================================================================
--- lib/Driver/Tools.cpp
+++ lib/Driver/Tools.cpp
@@ -5963,6 +5963,9 @@
     CmdArgs.push_back("-fwhole-program-vtables");
   }
 
+  if (Args.hasArg(options::OPT_fno_cxx_static_destructors))
+    CmdArgs.push_back("-fno-cxx-static-destructors");
+
   // Finally add the compile command to the compilation.
   if (Args.hasArg(options::OPT__SLASH_fallback) &&
       Output.getType() == types::TY_Object &&
Index: lib/CodeGen/ItaniumCXXABI.cpp
===================================================================
--- lib/CodeGen/ItaniumCXXABI.cpp
+++ lib/CodeGen/ItaniumCXXABI.cpp
@@ -2132,6 +2132,10 @@
                                        const VarDecl &D,
                                        llvm::Constant *dtor,
                                        llvm::Constant *addr) {
+  // Do not register global dtor at all
+  if (CGM.getCodeGenOpts().CXXNoExitTimeDtor)
+    return;
+
   // Use __cxa_atexit if available.
   if (CGM.getCodeGenOpts().CXAAtExit)
     return emitGlobalDtorWithCXAAtExit(CGF, dtor, addr, D.getTLSKind());
Index: include/clang/Frontend/CodeGenOptions.def
===================================================================
--- include/clang/Frontend/CodeGenOptions.def
+++ include/clang/Frontend/CodeGenOptions.def
@@ -40,6 +40,7 @@
 CODEGENOPT(CoverageNoFunctionNamesInData, 1, 0) ///< Do not include function names in GCDA files.
 CODEGENOPT(CoverageExitBlockBeforeBody, 1, 0) ///< Whether to emit the exit block before the body blocks in GCNO files.
 CODEGENOPT(CXAAtExit         , 1, 1) ///< Use __cxa_atexit for calling destructors.
+CODEGENOPT(CXXNoExitTimeDtor , 1, 0) ///< Do not register exit time destructors (skip calls to __cxa_atexit or atexit).
 CODEGENOPT(CXXCtorDtorAliases, 1, 0) ///< Emit complete ctors/dtors as linker
                                      ///< aliases to base ctors when possible.
 CODEGENOPT(DataSections      , 1, 0) ///< Set when -fdata-sections is enabled.
Index: include/clang/Driver/Options.td
===================================================================
--- include/clang/Driver/Options.td
+++ include/clang/Driver/Options.td
@@ -982,6 +982,8 @@
   Flags<[CC1Option]>, HelpText<"Do not emit code to make initialization of local statics thread safe">;
 def fno_use_cxa_atexit : Flag<["-"], "fno-use-cxa-atexit">, Group<f_Group>, Flags<[CC1Option]>,
   HelpText<"Don't use __cxa_atexit for calling destructors">;
+def fno_cxx_static_destructors : Flag<["-"], "fno-cxx-static-destructors">, Group<f_clang_Group>,
+  Flags<[CC1Option]>, HelpText<"Don't register c++ exit time destructors">;
 def fno_use_init_array : Flag<["-"], "fno-use-init-array">, Group<f_Group>, Flags<[CC1Option]>,
   HelpText<"Don't use .init_array instead of .ctors">;
 def fno_unit_at_a_time : Flag<["-"], "fno-unit-at-a-time">, Group<f_Group>;


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D22474.64217.patch
Type: text/x-patch
Size: 5117 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20160718/88366882/attachment.bin>


More information about the cfe-commits mailing list