From 1c19e0ab4a039c83821d10169c5f0c1877c89ba4 Mon Sep 17 00:00:00 2001
From: Frederich Munch <marsupial@users.noreply.github.com>
Date: Thu, 1 Dec 2016 11:04:20 -0500
Subject: [PATCH] Fix atexit function declarations for gcc and add test. Fix
 mangling issues for at_quick_exit and g++ headers.

---
 .../cling/lib/Interpreter/Interpreter.cpp     | 24 ++++++--
 interpreter/cling/test/CodeUnloading/AtExit.C | 60 +++++++++++++++++++
 2 files changed, 79 insertions(+), 5 deletions(-)
 create mode 100644 interpreter/cling/test/CodeUnloading/AtExit.C

diff --git a/interpreter/cling/lib/Interpreter/Interpreter.cpp b/interpreter/cling/lib/Interpreter/Interpreter.cpp
index bfafb83e679..f3d5c053dce 100644
--- a/interpreter/cling/lib/Interpreter/Interpreter.cpp
+++ b/interpreter/cling/lib/Interpreter/Interpreter.cpp
@@ -208,7 +208,13 @@ namespace cling {
     if (const Transaction* T = getLastTransaction()) {
       if (llvm::Module* M = T->getModule()) {
         for (const llvm::StringRef& Sym : Syms) {
-          if (const llvm::GlobalValue* GV = M->getNamedValue(Sym)) {
+          const llvm::GlobalValue* GV = M->getNamedValue(Sym);
+#if defined(__GLIBCXX__) && !defined(__APPLE__)
+          // libstdc++ mangles at_quick_exit on Linux when headers from g++ < 5
+          if (!GV && Sym.equals("at_quick_exit"))
+            GV = M->getNamedValue("_Z13at_quick_exitPFvvE");
+#endif
+          if (GV) {
             if (void* Addr = m_Executor->getPointerToGlobalFromJIT(*GV))
               m_Executor->addSymbol(Sym.str().c_str(), Addr, true);
             else
@@ -326,6 +332,14 @@ namespace cling {
     // Intercept all atexit calls, as the Interpreter and functions will be long
     // gone when the -native- versions invoke them.
     if (!SyntaxOnly) {
+#if defined(__GLIBCXX__) && !defined(__APPLE__)
+      const char* LinkageCxx = "extern \"C++\"";
+      const char* Attr = LangOpts.CPlusPlus ? " throw () " : "";
+#else
+      const char* LinkageCxx = Linkage;
+      const char* Attr = "";
+#endif
+
       // While __dso_handle is still overriden in the JIT below,
       // #define __dso_handle is used to mitigate the following problems:
       //  1. Type of __dso_handle is void* making assignemnt to it legal
@@ -346,14 +360,14 @@ namespace cling {
       Strm << Linkage << " int __cxa_atexit(void (*f)(void*), void*, void*);\n";
 
       // C atexit, std::atexit
-      Strm << Linkage << " int atexit(void(*f)()) { "
-           "return __cxa_atexit((void(*)(void*))f, 0, __dso_handle); }\n";
+      Strm << Linkage << " int atexit(void(*f)()) " << Attr << " { return "
+                        "__cxa_atexit((void(*)(void*))f, 0, __dso_handle); }\n";
       Globals.push_back("atexit");
 
       // C++ 11 at_quick_exit, std::at_quick_exit
       if (LangOpts.CPlusPlus && LangOpts.CPlusPlus11) {
-          Strm << Linkage << " int at_quick_exit(void(*f)()) { "
-           "return __cxa_atexit((void(*)(void*))f, 0, __dso_handle); }\n";
+        Strm << LinkageCxx << " int at_quick_exit(void(*f)()) " << Attr <<
+              " { return __cxa_atexit((void(*)(void*))f, 0, __dso_handle); }\n";
         Globals.push_back("at_quick_exit");
       }
 
diff --git a/interpreter/cling/test/CodeUnloading/AtExit.C b/interpreter/cling/test/CodeUnloading/AtExit.C
new file mode 100644
index 00000000000..8b89740e313
--- /dev/null
+++ b/interpreter/cling/test/CodeUnloading/AtExit.C
@@ -0,0 +1,60 @@
+//------------------------------------------------------------------------------
+// CLING - the C++ LLVM-based InterpreterG :)
+//
+// This file is dual-licensed: you can choose to license it under the University
+// of Illinois Open Source License or the GNU Lesser General Public License. See
+// LICENSE.TXT for details.
+//------------------------------------------------------------------------------
+
+// RUN: cat %s | %cling -Xclang -verify 2>&1 | FileCheck %s
+
+// Test to check functions registered via atexit are intercepted, and __dso_handle
+// is properly overridden in for child interpreters.
+#include <cstdlib>
+#include "cling/Interpreter/Interpreter.h"
+
+
+static void atexit_1() {
+  printf("atexit_1\n");
+}
+static void atexit_2() {
+  printf("atexit_2\n");
+}
+static void atexit_3() {
+  printf("atexit_3\n");
+}
+
+atexit(atexit_1);
+.undo
+// Undoing the registration should call the function
+// CHECK: atexit_1
+
+at_quick_exit(atexit_2);
+.undo
+// Make sure at_quick_exit is resolved correctly (mangling issues on gcc < 5)
+// CHECK-NEXT: atexit_2
+
+atexit(atexit_3);
+
+cling::Interpreter * gChild = 0;
+{
+  const char* kArgV[1] = {"cling"};
+  cling::Interpreter ChildInterp(*gCling, 1, kArgV);
+  gChild = &ChildInterp;
+  ChildInterp.declare("static void atexit_c() { printf(\"atexit_c %d\\n\", gChild==__dso_handle); }");
+  ChildInterp.execute("atexit(atexit_c);");
+}
+// ChildInterp
+// CHECK-NEXT: atexit_c 1
+
+static void atexit_f() {
+  printf("atexit_f %s\n", gCling==__dso_handle ? "true" : "false");
+}
+at_quick_exit(atexit_f);
+
+// expected-no-diagnostics
+.q
+
+// Reversed registration order
+// CHECK-NEXT: atexit_f true
+// CHECK-NEXT: atexit_3
-- 
GitLab