[Beignet] [Patch V2] GBE: remove static context to fix Segmentation fault.

Yang Rong rong.r.yang at intel.com
Tue Aug 22 04:33:55 UTC 2017


If application has static clProgram, when application exit, the static
context has been deleted before delete static clProgram will cause
segmentation fault.
As the global static context is just for link, use the individual context
of each llvm module, when link the llvm module, generate the new llvm
module from src.

V2: fix llvm 3.8 build error and CleanLlvmResource delete bug.
Signed-off-by: Yang Rong <rong.r.yang at intel.com>
---
 backend/src/backend/gen_program.cpp | 46 ++++++++++++++++++++++++++-----------
 backend/src/backend/program.cpp     | 15 ++++++------
 backend/src/llvm/llvm_to_gen.cpp    |  7 ------
 backend/src/llvm/llvm_to_gen.hpp    |  4 ----
 4 files changed, 40 insertions(+), 32 deletions(-)

diff --git a/backend/src/backend/gen_program.cpp b/backend/src/backend/gen_program.cpp
index 6ba2e54..245b844 100644
--- a/backend/src/backend/gen_program.cpp
+++ b/backend/src/backend/gen_program.cpp
@@ -28,6 +28,8 @@
 #include "llvm/IR/Module.h"
 #include "llvm/IR/DataLayout.h"
 #include "llvm-c/Linker.h"
+#include "llvm-c/BitReader.h"
+#include "llvm-c/BitWriter.h"
 #include "llvm/Transforms/Utils/Cloning.h"
 #if LLVM_VERSION_MAJOR * 10 + LLVM_VERSION_MINOR >= 40
 #include "llvm/Bitcode/BitcodeWriter.h"
@@ -126,10 +128,21 @@ namespace gbe {
 
   void GenProgram::CleanLlvmResource(void){
 #ifdef GBE_COMPILER_AVAILABLE
+    llvm::LLVMContext* ctx = NULL;
     if(module){
+      ctx = &((llvm::Module*)module)->getContext();
+      (void)ctx;
       delete (llvm::Module*)module;
       module = NULL;
     }
+//llvm's version < 3.9, ctx is global ctx, can't be deleted.
+#if LLVM_VERSION_MAJOR * 10 + LLVM_VERSION_MINOR >= 39
+    if (ctx != NULL) {
+      if (llvm_ctx == ctx)
+        llvm_ctx = NULL; //avoid delete twice.
+      delete ctx;
+    }
+#endif
 
     if(llvm_ctx){
       delete (llvm::LLVMContext*)llvm_ctx;
@@ -353,19 +366,19 @@ namespace gbe {
     binary_content.assign(binary+1, size-1);
     llvm::StringRef llvm_bin_str(binary_content);
 #if LLVM_VERSION_MAJOR * 10 + LLVM_VERSION_MINOR >= 39
-    llvm::LLVMContext& c = GBEGetLLVMContext();
+    llvm::LLVMContext *c = new llvm::LLVMContext;
 #else
-    llvm::LLVMContext& c = llvm::getGlobalContext();
+    llvm::LLVMContext *c = &llvm::getGlobalContext();
 #endif
     llvm::SMDiagnostic Err;
 #if LLVM_VERSION_MAJOR * 10 + LLVM_VERSION_MINOR >= 36
     std::unique_ptr<llvm::MemoryBuffer> memory_buffer = llvm::MemoryBuffer::getMemBuffer(llvm_bin_str, "llvm_bin_str");
     acquireLLVMContextLock();
-    llvm::Module* module = llvm::parseIR(memory_buffer->getMemBufferRef(), Err, c).release();
+    llvm::Module* module = llvm::parseIR(memory_buffer->getMemBufferRef(), Err, *c).release();
 #else
     llvm::MemoryBuffer* memory_buffer = llvm::MemoryBuffer::getMemBuffer(llvm_bin_str, "llvm_bin_str");
     acquireLLVMContextLock();
-    llvm::Module* module = llvm::ParseIR(memory_buffer, Err, c);
+    llvm::Module* module = llvm::ParseIR(memory_buffer, Err, *c);
 #endif
     // if load 32 bit spir binary, the triple should be spir-unknown-unknown.
     llvm::Triple triple(module->getTargetTriple());
@@ -506,23 +519,31 @@ namespace gbe {
     using namespace gbe;
     char* errMsg = NULL;
     if(((GenProgram*)dst_program)->module == NULL){
-#if LLVM_VERSION_MAJOR * 10 + LLVM_VERSION_MINOR >= 38
+#if LLVM_VERSION_MAJOR * 10 + LLVM_VERSION_MINOR >= 39
+      LLVMModuleRef modRef;
+      LLVMParseBitcodeInContext2(wrap(new llvm::LLVMContext()),
+                                 LLVMWriteBitcodeToMemoryBuffer(wrap((llvm::Module*)((GenProgram*)src_program)->module)),
+                                 &modRef);
+      ((GenProgram*)dst_program)->module = llvm::unwrap(modRef);
+#elif LLVM_VERSION_MAJOR * 10 + LLVM_VERSION_MINOR >= 38
       ((GenProgram*)dst_program)->module = llvm::CloneModule((llvm::Module*)((GenProgram*)src_program)->module).release();
 #else
       ((GenProgram*)dst_program)->module = llvm::CloneModule((llvm::Module*)((GenProgram*)src_program)->module);
 #endif
       errSize = 0;
     } else {
-#if LLVM_VERSION_MAJOR * 10 + LLVM_VERSION_MINOR >= 39
-      // Src now will be removed automatically. So clone it.
-      llvm::Module* src = llvm::CloneModule((llvm::Module*)((GenProgram*)src_program)->module).release();
-#else
       llvm::Module* src = (llvm::Module*)((GenProgram*)src_program)->module;
-#endif
       llvm::Module* dst = (llvm::Module*)((GenProgram*)dst_program)->module;
-
 #if LLVM_VERSION_MAJOR * 10 + LLVM_VERSION_MINOR >= 39
-      if (LLVMLinkModules2(wrap(dst), wrap(src))) {
+      if (&src->getContext() != &dst->getContext()) {
+        LLVMModuleRef modRef;
+        LLVMParseBitcodeInContext2(wrap(&dst->getContext()),
+                                    LLVMWriteBitcodeToMemoryBuffer(wrap(src)),
+                                    &modRef);
+        src = llvm::unwrap(modRef);
+      }
+      llvm::Module* clone = llvm::CloneModule(src).release();
+      if (LLVMLinkModules2(wrap(dst), wrap(clone))) {
 #elif LLVM_VERSION_MAJOR * 10 + LLVM_VERSION_MINOR >= 37
       if (LLVMLinkModules(wrap(dst), wrap(src), LLVMLinkerPreserveSource_Removed, &errMsg)) {
 #else
@@ -536,7 +557,6 @@ namespace gbe {
         return true;
       }
     }
-    // Everything run fine
 #endif
     return false;
   }
diff --git a/backend/src/backend/program.cpp b/backend/src/backend/program.cpp
index c06ae5a..c37c595 100644
--- a/backend/src/backend/program.cpp
+++ b/backend/src/backend/program.cpp
@@ -1104,22 +1104,22 @@ EXTEND_QUOTE:
       return NULL;
 
 #if LLVM_VERSION_MAJOR * 10 + LLVM_VERSION_MINOR >= 39
-    llvm::LLVMContext& c = GBEGetLLVMContext();
+    llvm::LLVMContext *c = new llvm::LLVMContext;
 #else
-    llvm::LLVMContext& c = llvm::getGlobalContext();
+    llvm::LLVMContext *c = &llvm::getGlobalContext();
 #endif
     // Get the module from its file
     llvm::SMDiagnostic errDiag;
 #if LLVM_VERSION_MAJOR * 10 + LLVM_VERSION_MINOR >= 36
-    llvm::Module *module = parseIRFile(fileName, errDiag, c).release();
+    llvm::Module *module = parseIRFile(fileName, errDiag, *c).release();
 #else
-    llvm::Module *module = ParseIRFile(fileName, errDiag, c);
+    llvm::Module *module = ParseIRFile(fileName, errDiag, *c);
 #endif
 
     int optLevel = 1;
 
     //module will be delete in programCleanLlvmResource
-    p = gbe_program_new_from_llvm(deviceID, module, &c, NULL,
+    p = gbe_program_new_from_llvm(deviceID, module, c, NULL,
                                   string_size, err, err_size, optLevel, NULL);
     if (OCL_OUTPUT_BUILD_LOG && err && *err_size)
       llvm::errs() << err << "\n";
@@ -1152,11 +1152,10 @@ EXTEND_QUOTE:
 
     gbe_program p;
     acquireLLVMContextLock();
-    //FIXME: if use new allocated context to link two modules there would be context mismatch
-    //for some functions, so we use global context now, need switch to new context later.
+
     llvm::Module * out_module;
 #if LLVM_VERSION_MAJOR * 10 + LLVM_VERSION_MINOR >= 39
-    llvm::LLVMContext* llvm_ctx = &GBEGetLLVMContext();
+    llvm::LLVMContext* llvm_ctx = new llvm::LLVMContext;
 #else
     llvm::LLVMContext* llvm_ctx = &llvm::getGlobalContext();
 #endif
diff --git a/backend/src/llvm/llvm_to_gen.cpp b/backend/src/llvm/llvm_to_gen.cpp
index 8546f73..7f7deff 100644
--- a/backend/src/llvm/llvm_to_gen.cpp
+++ b/backend/src/llvm/llvm_to_gen.cpp
@@ -46,13 +46,6 @@ namespace gbe
   BVAR(OCL_OUTPUT_CFG_GEN_IR, false);
   using namespace llvm;
 
-#if LLVM_VERSION_MAJOR * 10 + LLVM_VERSION_MINOR >= 39
-  llvm::LLVMContext& GBEGetLLVMContext() {
-    static llvm::LLVMContext GBEContext;
-    return GBEContext;
-  }
-#endif
-
 #if LLVM_VERSION_MAJOR * 10 + LLVM_VERSION_MINOR >= 37
   #define TARGETLIBRARY  TargetLibraryInfoImpl
 #else
diff --git a/backend/src/llvm/llvm_to_gen.hpp b/backend/src/llvm/llvm_to_gen.hpp
index 73e8819..d2247bb 100644
--- a/backend/src/llvm/llvm_to_gen.hpp
+++ b/backend/src/llvm/llvm_to_gen.hpp
@@ -37,10 +37,6 @@ namespace gbe {
 		  optLevel 0 equal to clang -O1 and 1 equal to clang -O2*/
   bool llvmToGen(ir::Unit &unit, const void* module,
                  int optLevel, bool strictMath, int profiling, std::string &errors);
-#if LLVM_VERSION_MAJOR * 10 + LLVM_VERSION_MINOR >= 39
-  extern llvm::LLVMContext& GBEGetLLVMContext();
-#endif
-
 } /* namespace gbe */
 
 #endif /* __GBE_IR_LLVM_TO_GEN_HPP__ */
-- 
2.7.4



More information about the Beignet mailing list