asavonic created this revision. asavonic requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits.
This fixes PR49198: Wrong usage of __dso_handle in user code leads to a compiler crash. `__dso_handle` variable is now created with a prefix to avoid a conflict with the user-defined one which can be emitted later. Once all globals are emitted, it is renamed back or replaced with a user-defined `__dso_handle`. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D101156 Files: clang/lib/CodeGen/ItaniumCXXABI.cpp clang/test/CodeGenCXX/dso-handle-custom.cpp Index: clang/test/CodeGenCXX/dso-handle-custom.cpp =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/dso-handle-custom.cpp @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -fexceptions %s -o - | FileCheck %s + +class A { +public: + ~A(); +} a; + +// CHECK: @__dso_handle = hidden global i8* bitcast (i8** @__dso_handle to i8*), align 8 +// CHECK: define internal void @__cxx_global_var_init() +// CHECK: call i32 @__cxa_atexit({{.*}}, {{.*}}, i8* bitcast (i8** @__dso_handle to i8*)) + +void *__dso_handle = &__dso_handle; + +void use(void *); +void use_dso_handle() { + use(__dso_handle); +} Index: clang/lib/CodeGen/ItaniumCXXABI.cpp =================================================================== --- clang/lib/CodeGen/ItaniumCXXABI.cpp +++ clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -2531,7 +2531,7 @@ // Create a variable that binds the atexit to this shared object. llvm::Constant *handle = - CGF.CGM.CreateRuntimeVariable(CGF.Int8Ty, "__dso_handle"); + CGF.CGM.CreateRuntimeVariable(CGF.Int8Ty, "$__dso_handle"); auto *GV = cast<llvm::GlobalValue>(handle->stripPointerCasts()); GV->setVisibility(llvm::GlobalValue::HiddenVisibility); @@ -2685,6 +2685,26 @@ if (getCXXABI().useSinitAndSterm()) unregisterGlobalDtorsWithUnAtExit(); + + // Prefer user-defined __dso_handle over the compiler generated one + if (llvm::GlobalValue *GeneratedDSOHandle = GetGlobalValue("$__dso_handle")) { + llvm::GlobalValue *CustomDSOHandle = GetGlobalValue("__dso_handle"); + if (!CustomDSOHandle) { + GeneratedDSOHandle->setName("__dso_handle"); + } else { + if (!isa<llvm::GlobalVariable>(CustomDSOHandle)) + llvm_unreachable("__dso_handle must be a global variable"); + + setDSOLocal(CustomDSOHandle); + CustomDSOHandle->setLinkage(llvm::GlobalValue::ExternalLinkage); + CustomDSOHandle->setVisibility(llvm::GlobalValue::HiddenVisibility); + + llvm::Constant *DSOHandle = llvm::ConstantExpr::getBitCast( + CustomDSOHandle, GeneratedDSOHandle->getType()); + GeneratedDSOHandle->replaceAllUsesWith(DSOHandle); + GeneratedDSOHandle->eraseFromParent(); + } + } } /// Register a global destructor as best as we know how.
Index: clang/test/CodeGenCXX/dso-handle-custom.cpp =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/dso-handle-custom.cpp @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -fexceptions %s -o - | FileCheck %s + +class A { +public: + ~A(); +} a; + +// CHECK: @__dso_handle = hidden global i8* bitcast (i8** @__dso_handle to i8*), align 8 +// CHECK: define internal void @__cxx_global_var_init() +// CHECK: call i32 @__cxa_atexit({{.*}}, {{.*}}, i8* bitcast (i8** @__dso_handle to i8*)) + +void *__dso_handle = &__dso_handle; + +void use(void *); +void use_dso_handle() { + use(__dso_handle); +} Index: clang/lib/CodeGen/ItaniumCXXABI.cpp =================================================================== --- clang/lib/CodeGen/ItaniumCXXABI.cpp +++ clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -2531,7 +2531,7 @@ // Create a variable that binds the atexit to this shared object. llvm::Constant *handle = - CGF.CGM.CreateRuntimeVariable(CGF.Int8Ty, "__dso_handle"); + CGF.CGM.CreateRuntimeVariable(CGF.Int8Ty, "$__dso_handle"); auto *GV = cast<llvm::GlobalValue>(handle->stripPointerCasts()); GV->setVisibility(llvm::GlobalValue::HiddenVisibility); @@ -2685,6 +2685,26 @@ if (getCXXABI().useSinitAndSterm()) unregisterGlobalDtorsWithUnAtExit(); + + // Prefer user-defined __dso_handle over the compiler generated one + if (llvm::GlobalValue *GeneratedDSOHandle = GetGlobalValue("$__dso_handle")) { + llvm::GlobalValue *CustomDSOHandle = GetGlobalValue("__dso_handle"); + if (!CustomDSOHandle) { + GeneratedDSOHandle->setName("__dso_handle"); + } else { + if (!isa<llvm::GlobalVariable>(CustomDSOHandle)) + llvm_unreachable("__dso_handle must be a global variable"); + + setDSOLocal(CustomDSOHandle); + CustomDSOHandle->setLinkage(llvm::GlobalValue::ExternalLinkage); + CustomDSOHandle->setVisibility(llvm::GlobalValue::HiddenVisibility); + + llvm::Constant *DSOHandle = llvm::ConstantExpr::getBitCast( + CustomDSOHandle, GeneratedDSOHandle->getType()); + GeneratedDSOHandle->replaceAllUsesWith(DSOHandle); + GeneratedDSOHandle->eraseFromParent(); + } + } } /// Register a global destructor as best as we know how.
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits