Skip to content

llvm::Module::getOrInsertGlobal returns a Constant*, not always GlobalValue* #91050

Closed
@cuviper

Description

@cuviper

xref: https://bugzilla.redhat.com/show_bug.cgi?id=1990657

In Fedora, one particular crate has been seeing non-deterministic errors or crashes in the compiler, and I was able to reproduce it with a rustup-installed compiler as well. Valgrind gave the following error report, even on runs that otherwise appeared to succeed.

Valgrind error

==325== Invalid read of size 1
==325==    at 0x93E6CF4: getVisibility (GlobalValue.h:229)
==325==    by 0x93E6CF4: LLVMGetVisibility (Core.cpp:1992)
==325==    by 0x4F6D05C: LLVMRustGetVisibility (RustWrapper.cpp:1602)
==325==    by 0x51AE144: rustc_codegen_llvm::mono_item::<impl rustc_codegen_llvm::context::CodegenCx>::should_assume_dso_local (mono_item.rs:106)
==325==    by 0x51A41DF: rustc_codegen_llvm::consts::<impl rustc_codegen_llvm::context::CodegenCx>::get_static (consts.rs:289)
==325==    by 0x51A1E05: rustc_codegen_llvm::common::<impl rustc_codegen_ssa::traits::consts::ConstMethods for rustc_codegen_llvm::context::CodegenCx>::scalar_to_backend (common.rs:267)
==325==    by 0x521D477: rustc_codegen_ssa::mir::operand::OperandRef<V>::from_const (operand.rs:85)
==325==    by 0x523D07A: eval_mir_constant_to_operand<rustc_codegen_llvm::builder::Builder> (constant.rs:20)
==325==    by 0x523D07A: rustc_codegen_ssa::mir::operand::<impl rustc_codegen_ssa::mir::FunctionCx<Bx>>::codegen_operand (operand.rs:450)
==325==    by 0x5238B33: rustc_codegen_ssa::mir::rvalue::<impl rustc_codegen_ssa::mir::FunctionCx<Bx>>::codegen_rvalue_operand (rvalue.rs:546)
==325==    by 0x522DB68: codegen_statement<rustc_codegen_llvm::builder::Builder> (statement.rs:24)
==325==    by 0x522DB68: codegen_block<rustc_codegen_llvm::builder::Builder> (block.rs:901)
==325==    by 0x522DB68: rustc_codegen_ssa::mir::codegen_mir (mod.rs:258)
==325==    by 0x51B6E09: rustc_codegen_ssa::base::codegen_instance (base.rs:342)
==325==    by 0x51E249C: <rustc_middle::mir::mono::MonoItem as rustc_codegen_ssa::mono_item::MonoItemExt>::define (mono_item.rs:70)
==325==    by 0x51F713E: rustc_codegen_llvm::base::compile_codegen_unit::module_codegen (base.rs:141)
==325==  Address 0x1734a400 is 8 bytes after a block of size 56 alloc'd
==325==    at 0x4840FF5: operator new(unsigned long) (vg_replace_malloc.c:417)
==325==    by 0x94DDFE4: allocateFixedOperandUser (User.cpp:127)
==325==    by 0x94DDFE4: llvm::User::operator new(unsigned long, unsigned int) (User.cpp:146)
==325==    by 0x93CE0C6: operator new (ConstantsContext.h:55)
==325==    by 0x93CE0C6: llvm::ConstantExprKeyType::create(llvm::Type*) const (ConstantsContext.h:612)
==325==    by 0x93DA482: create (ConstantsContext.h:715)
==325==    by 0x93DA482: llvm::ConstantUniqueMap<llvm::ConstantExpr>::getOrCreate(llvm::Type*, llvm::ConstantExprKeyType) (ConstantsContext.h:734)
==325==    by 0x93E02F2: getFoldedCast (Constants.cpp:1937)
==325==    by 0x93E02F2: getBitCast (Constants.cpp:2194)
==325==    by 0x93E02F2: llvm::ConstantExpr::getBitCast(llvm::Constant*, llvm::Type*, bool) (Constants.cpp:2185)
==325==    by 0x94AA7E0: llvm::Module::getOrInsertGlobal(llvm::StringRef, llvm::Type*) (Module.cpp:226)
==325==    by 0x51C67D5: declare_global (declare.rs:60)
==325==    by 0x51C67D5: rustc_codegen_llvm::consts::check_and_apply_linkage (consts.rs:157)
==325==    by 0x51A34BC: rustc_codegen_llvm::consts::<impl rustc_codegen_llvm::context::CodegenCx>::get_static (consts.rs:234)
==325==    by 0x51A1E05: rustc_codegen_llvm::common::<impl rustc_codegen_ssa::traits::consts::ConstMethods for rustc_codegen_llvm::context::CodegenCx>::scalar_to_backend (common.rs:267)
==325==    by 0x521D477: rustc_codegen_ssa::mir::operand::OperandRef<V>::from_const (operand.rs:85)
==325==    by 0x523D07A: eval_mir_constant_to_operand<rustc_codegen_llvm::builder::Builder> (constant.rs:20)
==325==    by 0x523D07A: rustc_codegen_ssa::mir::operand::<impl rustc_codegen_ssa::mir::FunctionCx<Bx>>::codegen_operand (operand.rs:450)
==325==    by 0x5238B33: rustc_codegen_ssa::mir::rvalue::<impl rustc_codegen_ssa::mir::FunctionCx<Bx>>::codegen_rvalue_operand (rvalue.rs:546)

Note that llvm::Module::getOrInsertGlobal returns a Constant*, but LLVMGetVisibility casts its argument to a GlobalValue*, which is a subclass. Most of the time you do get a GlobalVariable* (a further subclass), except when getOrInsertGlobal is given different types it instead returns a constant bitcast expression, as you can see in the error backtrace with getBitCast.

I ran a new rustc with LLVM assertions, and it does fail there trying to cast GlobalValue*:

rustc: /checkout/src/llvm-project/llvm/include/llvm/Support/Casting.h:269: typename cast_retty<X, Y *>::ret_type llvm::cast(Y *) [X = llvm::GlobalValue, Y = llvm::Value]: Assertion `isa<X>(Val) && "cast<Ty>() argument of incompatible type!"' failed.

So, casting the wrong pointer type is Undefined Behavior, and the non-reproducible aspect of this bug is just "luck" of whatever happens to be in memory there.

I'm not yet sure why rustc would have a type mismatch in what it's feeding getOrInsertGlobal, but my first suspicion is this real_name indirection in check_and_apply_linkage.

// Declare a symbol `foo` with the desired linkage.
let g1 = cx.declare_global(sym, llty2);
llvm::LLVMRustSetLinkage(g1, base::linkage_to_llvm(linkage));
// Declare an internal global `extern_with_linkage_foo` which
// is initialized with the address of `foo`. If `foo` is
// discarded during linking (for example, if `foo` has weak
// linkage and there are no definitions), then
// `extern_with_linkage_foo` will instead be initialized to
// zero.
let mut real_name = "_rust_extern_with_linkage_".to_string();
real_name.push_str(sym);
let g2 = cx.define_global(&real_name, llty).unwrap_or_else(|| {
cx.sess().span_fatal(
cx.tcx.def_span(span_def_id),
&format!("symbol `{}` is already defined", &sym),
)
});
llvm::LLVMRustSetLinkage(g2, llvm::Linkage::InternalLinkage);
llvm::LLVMSetInitializer(g2, g1);
g2

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-LLVMArea: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.A-codegenArea: Code generationC-bugCategory: This is a bug.I-crashIssue: The compiler crashes (SIGSEGV, SIGABRT, etc). Use I-ICE instead when the compiler panics.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions