Make LLVMRustGetOrInsertGlobal
always return a GlobalVariable
`Module::getOrInsertGlobal` returns a `Constant*`, which is a super class of `GlobalVariable`, but if the given type doesn't match an existing declaration, it returns a bitcast of that global instead. This causes UB when we pass that to `LLVMGetVisibility` which unconditionally casts the opaque argument to a `GlobalValue*`. Instead, we can do our own get-or-insert without worrying whether existing types match exactly. It's not relevant when we're just trying to get/set the linkage and visibility, and if types are needed we can bitcast or error nicely from `rustc_codegen_llvm` instead.
This commit is contained in:
parent
a77da2d454
commit
023cc968e1
2 changed files with 45 additions and 1 deletions
|
@ -124,8 +124,18 @@ extern "C" LLVMValueRef LLVMRustGetOrInsertFunction(LLVMModuleRef M,
|
|||
|
||||
extern "C" LLVMValueRef
|
||||
LLVMRustGetOrInsertGlobal(LLVMModuleRef M, const char *Name, size_t NameLen, LLVMTypeRef Ty) {
|
||||
Module *Mod = unwrap(M);
|
||||
StringRef NameRef(Name, NameLen);
|
||||
return wrap(unwrap(M)->getOrInsertGlobal(NameRef, unwrap(Ty)));
|
||||
|
||||
// We don't use Module::getOrInsertGlobal because that returns a Constant*,
|
||||
// which may either be the real GlobalVariable*, or a constant bitcast of it
|
||||
// if our type doesn't match the original declaration. We always want the
|
||||
// GlobalVariable* so we can access linkage, visibility, etc.
|
||||
GlobalVariable *GV = Mod->getGlobalVariable(NameRef, true);
|
||||
if (!GV)
|
||||
GV = new GlobalVariable(*Mod, unwrap(Ty), false,
|
||||
GlobalValue::ExternalLinkage, nullptr, NameRef);
|
||||
return wrap(GV);
|
||||
}
|
||||
|
||||
extern "C" LLVMValueRef
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue