Fix use-after-free when a C++ thread_local variable gets replaced (because its

type changes when the initializer is attached). Don't hold onto the
GlobalVariable*; recompute it from the VarDecl* instead.

llvm-svn: 254359
This commit is contained in:
Richard Smith 2015-12-01 01:10:48 +00:00
parent 21ed3b13bd
commit 5a99c49d2e
7 changed files with 34 additions and 32 deletions

View File

@ -538,11 +538,9 @@ public:
/// thread_local variables, a list of functions to perform the /// thread_local variables, a list of functions to perform the
/// initialization. /// initialization.
virtual void EmitThreadLocalInitFuncs( virtual void EmitThreadLocalInitFuncs(
CodeGenModule &CGM, CodeGenModule &CGM, ArrayRef<const VarDecl *> CXXThreadLocals,
ArrayRef<std::pair<const VarDecl *, llvm::GlobalVariable *>>
CXXThreadLocals,
ArrayRef<llvm::Function *> CXXThreadLocalInits, ArrayRef<llvm::Function *> CXXThreadLocalInits,
ArrayRef<llvm::GlobalVariable *> CXXThreadLocalInitVars) = 0; ArrayRef<const VarDecl *> CXXThreadLocalInitVars) = 0;
// Determine if references to thread_local global variables can be made // Determine if references to thread_local global variables can be made
// directly or require access through a thread wrapper function. // directly or require access through a thread wrapper function.

View File

@ -337,7 +337,7 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
// FIXME: We only need to register one __cxa_thread_atexit function for the // FIXME: We only need to register one __cxa_thread_atexit function for the
// entire TU. // entire TU.
CXXThreadLocalInits.push_back(Fn); CXXThreadLocalInits.push_back(Fn);
CXXThreadLocalInitVars.push_back(Addr); CXXThreadLocalInitVars.push_back(D);
} else if (PerformInit && ISA) { } else if (PerformInit && ISA) {
EmitPointerToInitFunc(D, Addr, Fn, ISA); EmitPointerToInitFunc(D, Addr, Fn, ISA);
} else if (auto *IPA = D->getAttr<InitPriorityAttr>()) { } else if (auto *IPA = D->getAttr<InitPriorityAttr>()) {

View File

@ -1986,7 +1986,7 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName,
if (D->getTLSKind()) { if (D->getTLSKind()) {
if (D->getTLSKind() == VarDecl::TLS_Dynamic) if (D->getTLSKind() == VarDecl::TLS_Dynamic)
CXXThreadLocals.push_back(std::make_pair(D, GV)); CXXThreadLocals.push_back(D);
setTLSMode(GV, *D); setTLSMode(GV, *D);
} }
@ -2379,7 +2379,7 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D,
if (D->getTLSKind() && !GV->isThreadLocal()) { if (D->getTLSKind() && !GV->isThreadLocal()) {
if (D->getTLSKind() == VarDecl::TLS_Dynamic) if (D->getTLSKind() == VarDecl::TLS_Dynamic)
CXXThreadLocals.push_back(std::make_pair(D, GV)); CXXThreadLocals.push_back(D);
setTLSMode(GV, *D); setTLSMode(GV, *D);
} }

View File

@ -378,13 +378,12 @@ private:
StaticExternCMap StaticExternCValues; StaticExternCMap StaticExternCValues;
/// \brief thread_local variables defined or used in this TU. /// \brief thread_local variables defined or used in this TU.
std::vector<std::pair<const VarDecl *, llvm::GlobalVariable *> > std::vector<const VarDecl *> CXXThreadLocals;
CXXThreadLocals;
/// \brief thread_local variables with initializers that need to run /// \brief thread_local variables with initializers that need to run
/// before any thread_local variable in this TU is odr-used. /// before any thread_local variable in this TU is odr-used.
std::vector<llvm::Function *> CXXThreadLocalInits; std::vector<llvm::Function *> CXXThreadLocalInits;
std::vector<llvm::GlobalVariable *> CXXThreadLocalInitVars; std::vector<const VarDecl *> CXXThreadLocalInitVars;
/// Global variables with initializers that need to run before main. /// Global variables with initializers that need to run before main.
std::vector<llvm::Function *> CXXGlobalInits; std::vector<llvm::Function *> CXXGlobalInits;

View File

@ -327,10 +327,9 @@ public:
llvm::Value *Val); llvm::Value *Val);
void EmitThreadLocalInitFuncs( void EmitThreadLocalInitFuncs(
CodeGenModule &CGM, CodeGenModule &CGM,
ArrayRef<std::pair<const VarDecl *, llvm::GlobalVariable *>> ArrayRef<const VarDecl *> CXXThreadLocals,
CXXThreadLocals,
ArrayRef<llvm::Function *> CXXThreadLocalInits, ArrayRef<llvm::Function *> CXXThreadLocalInits,
ArrayRef<llvm::GlobalVariable *> CXXThreadLocalInitVars) override; ArrayRef<const VarDecl *> CXXThreadLocalInitVars) override;
bool usesThreadWrapperFunction() const override { return true; } bool usesThreadWrapperFunction() const override { return true; }
LValue EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF, const VarDecl *VD, LValue EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF, const VarDecl *VD,
@ -2200,10 +2199,9 @@ ItaniumCXXABI::getOrCreateThreadLocalWrapper(const VarDecl *VD,
} }
void ItaniumCXXABI::EmitThreadLocalInitFuncs( void ItaniumCXXABI::EmitThreadLocalInitFuncs(
CodeGenModule &CGM, CodeGenModule &CGM, ArrayRef<const VarDecl *> CXXThreadLocals,
ArrayRef<std::pair<const VarDecl *, llvm::GlobalVariable *>> ArrayRef<llvm::Function *> CXXThreadLocalInits,
CXXThreadLocals, ArrayRef<llvm::Function *> CXXThreadLocalInits, ArrayRef<const VarDecl *> CXXThreadLocalInitVars) {
ArrayRef<llvm::GlobalVariable *> CXXThreadLocalInitVars) {
llvm::Function *InitFunc = nullptr; llvm::Function *InitFunc = nullptr;
if (!CXXThreadLocalInits.empty()) { if (!CXXThreadLocalInits.empty()) {
// Generate a guarded initialization function. // Generate a guarded initialization function.
@ -2226,9 +2224,9 @@ void ItaniumCXXABI::EmitThreadLocalInitFuncs(
.GenerateCXXGlobalInitFunc(InitFunc, CXXThreadLocalInits, .GenerateCXXGlobalInitFunc(InitFunc, CXXThreadLocalInits,
Address(Guard, GuardAlign)); Address(Guard, GuardAlign));
} }
for (auto &I : CXXThreadLocals) { for (const VarDecl *VD : CXXThreadLocals) {
const VarDecl *VD = I.first; llvm::GlobalVariable *Var =
llvm::GlobalVariable *Var = I.second; cast<llvm::GlobalVariable>(CGM.GetGlobalValue(CGM.getMangledName(VD)));
// Some targets require that all access to thread local variables go through // Some targets require that all access to thread local variables go through
// the thread wrapper. This means that we cannot attempt to create a thread // the thread wrapper. This means that we cannot attempt to create a thread
@ -2305,9 +2303,7 @@ void ItaniumCXXABI::EmitThreadLocalInitFuncs(
LValue ItaniumCXXABI::EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF, LValue ItaniumCXXABI::EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF,
const VarDecl *VD, const VarDecl *VD,
QualType LValType) { QualType LValType) {
QualType T = VD->getType(); llvm::Value *Val = CGF.CGM.GetAddrOfGlobalVar(VD);
llvm::Type *Ty = CGF.getTypes().ConvertTypeForMem(T);
llvm::Value *Val = CGF.CGM.GetAddrOfGlobalVar(VD, Ty);
llvm::Function *Wrapper = getOrCreateThreadLocalWrapper(VD, Val); llvm::Function *Wrapper = getOrCreateThreadLocalWrapper(VD, Val);
Val = CGF.Builder.CreateCall(Wrapper); Val = CGF.Builder.CreateCall(Wrapper);

View File

@ -377,11 +377,9 @@ public:
const ReturnAdjustment &RA) override; const ReturnAdjustment &RA) override;
void EmitThreadLocalInitFuncs( void EmitThreadLocalInitFuncs(
CodeGenModule &CGM, CodeGenModule &CGM, ArrayRef<const VarDecl *> CXXThreadLocals,
ArrayRef<std::pair<const VarDecl *, llvm::GlobalVariable *>>
CXXThreadLocals,
ArrayRef<llvm::Function *> CXXThreadLocalInits, ArrayRef<llvm::Function *> CXXThreadLocalInits,
ArrayRef<llvm::GlobalVariable *> CXXThreadLocalInitVars) override; ArrayRef<const VarDecl *> CXXThreadLocalInitVars) override;
bool usesThreadWrapperFunction() const override { return false; } bool usesThreadWrapperFunction() const override { return false; }
LValue EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF, const VarDecl *VD, LValue EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF, const VarDecl *VD,
@ -2197,11 +2195,9 @@ void MicrosoftCXXABI::registerGlobalDtor(CodeGenFunction &CGF, const VarDecl &D,
} }
void MicrosoftCXXABI::EmitThreadLocalInitFuncs( void MicrosoftCXXABI::EmitThreadLocalInitFuncs(
CodeGenModule &CGM, CodeGenModule &CGM, ArrayRef<const VarDecl *> CXXThreadLocals,
ArrayRef<std::pair<const VarDecl *, llvm::GlobalVariable *>>
CXXThreadLocals,
ArrayRef<llvm::Function *> CXXThreadLocalInits, ArrayRef<llvm::Function *> CXXThreadLocalInits,
ArrayRef<llvm::GlobalVariable *> CXXThreadLocalInitVars) { ArrayRef<const VarDecl *> CXXThreadLocalInitVars) {
// This will create a GV in the .CRT$XDU section. It will point to our // This will create a GV in the .CRT$XDU section. It will point to our
// initialization function. The CRT will call all of these function // initialization function. The CRT will call all of these function
// pointers at start-up time and, eventually, at thread-creation time. // pointers at start-up time and, eventually, at thread-creation time.
@ -2219,7 +2215,8 @@ void MicrosoftCXXABI::EmitThreadLocalInitFuncs(
std::vector<llvm::Function *> NonComdatInits; std::vector<llvm::Function *> NonComdatInits;
for (size_t I = 0, E = CXXThreadLocalInitVars.size(); I != E; ++I) { for (size_t I = 0, E = CXXThreadLocalInitVars.size(); I != E; ++I) {
llvm::GlobalVariable *GV = CXXThreadLocalInitVars[I]; llvm::GlobalVariable *GV = cast<llvm::GlobalVariable>(
CGM.GetGlobalValue(CGM.getMangledName(CXXThreadLocalInitVars[I])));
llvm::Function *F = CXXThreadLocalInits[I]; llvm::Function *F = CXXThreadLocalInits[I];
// If the GV is already in a comdat group, then we have to join it. // If the GV is already in a comdat group, then we have to join it.

View File

@ -20,6 +20,18 @@ struct U { static thread_local int m; };
// DARWIN: @_ZN1U1mE = internal thread_local global i32 0 // DARWIN: @_ZN1U1mE = internal thread_local global i32 0
thread_local int U::m = f(); thread_local int U::m = f();
namespace MismatchedInitType {
// Check that we don't crash here when we're forced to create a new global
// variable (with a different type) when we add the initializer.
union U {
int a;
float f;
constexpr U() : f(0.0) {}
};
static thread_local U u;
void *p = &u;
}
template<typename T> struct V { static thread_local int m; }; template<typename T> struct V { static thread_local int m; };
template<typename T> thread_local int V<T>::m = g(); template<typename T> thread_local int V<T>::m = g();