-
Notifications
You must be signed in to change notification settings - Fork 12.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SIGSEGV in LLVM when linking to extern "Rust" { fn main(); }
#67946
Comments
We generally don't guarantee behavior with no_mangle, I think. I guess a segfault in llvm is unexpected though :) |
I think the |
I keep seeing this in my output when I play around with this on the playpen:
Here's a variant that does not use |
main
from #[no_mangle]
fnextern "Rust" { fn main(); }
triage: P-high. Leaving nominated in hopes that someone at triage meeting has a bright idea has to what's going on here (and what we might do about it). |
Hm, bad_alloc implies OOM to me, but maybe that's not always the case. |
Compiling with LLVM debug symbols + assertions, I get the same assertion failure for both:
Tracing the callstack with gdb, the assertion is triggered on the rust/src/rustllvm/RustWrapper.cpp Lines 311 to 315 in 19288dd
As the error suggests, this means that the downcast from llvm::Value to llvm::Function failed for Fn .
Printing out what type
That's strange -- it's reported as a function pointer, which is the same as what's reported for actual Usually, dumping an auto *mainTy = llvm::FunctionType::get(llvm::Type::getInt32Ty(theContext), { llvm::Type::getInt32Ty(theContext), llvm::Type::getInt8PtrTy(theContext)->getPointerTo() }, false);
auto *mainFn = llvm::Function::Create(mainTy, llvm::GlobalValue::LinkageTypes::ExternalLinkage, "main", module);
auto *entry = llvm::BasicBlock::Create(theContext, "entry", mainFn);
llvm::IRBuilder<> builder(theContext);
builder.SetInsertPoint(entry);
auto *inst = builder.CreateRet(llvm::ConstantInt::get(llvm::Type::getInt32Ty(theContext), 0)); gives us
But dumping
So it appears to be pointing to a I'll do a bit more digging. @rustbot claim |
After manually removing the LLVM build to force a complete rebuild with debug symbols, I was able to get a proper dump which makes far more sense:
Note that this is not a bitcast instruction but a constant expr bitcast -- ie, one generated at compile time. As it turns out, in the event that a function exists with athe same name but a different type in a module, llvm/lib/IR/Module.cpp:157-161 // If the function exists but has the wrong type, return a bitcast to the
// right type.
auto *PTy = PointerType::get(Ty, F->getAddressSpace());
if (F->getType() != PTy)
return {Ty, ConstantExpr::getBitCast(F, PTy)}; which is the overload called here rust/src/rustllvm/RustWrapper.cpp Lines 120 to 129 in 8ba3ca0
So, later, when we attempt to use any We run into this in both your cases because when codegen attempts to insert a declaration for This issue can be reproduced without causing a crash by forcing a name collision with a function that's not #[no_mangle]
pub fn bar(b: bool) {
// ...
}
pub fn foo() {
extern "Rust" {
fn bar();
}
unsafe { bar(); }
} Compiling with
we get this bitcode here: ...
; Function Attrs: nonlazybind uwtable
define void @bar(i1 zeroext %b) unnamed_addr #0 {
start:
ret void
}
; foo::foo
; Function Attrs: nonlazybind uwtable
define void @_ZN3foo3foo17he8a114b84f989db4E() unnamed_addr #0 {
start:
call void bitcast (void (i1)* @bar to void ()*)()
br label %bb1
bb1: ; preds = %start
ret void
}
... which I think exposes the problem more clearly: In an extern block which declares a function with the same name as some existing function within the module, we'll end up generating a call to the function in the module (potentially with an unsafe bitcast), instead of shadowing the module's function and generating a call to the external function (which, to me, appeared to be the intent of the example). You can see that this example shows that the At this point, I'm not sure how to proceed. Should we error out here because of the name collision to avoid generating crazy function pointer bitcasts? Or should we do some kind of trickery to rename the shadowing symbol so that it correctly calls the extern function? Or is it as @Mark-Simulacrum says -- is the current codegen into bitcast fine because we don't make any behaviour guarantees for |
Fail on multiple declarations of `main`. Closes rust-lang#67946. Previously, when inserting the entry function, we only checked for duplicate _definitions_ of `main`. However, it's possible to cause problems even only having a duplicate _declaration_. For example, shadowing `main` using an extern block isn't caught by the current check, and causes an assertion failure down the line in in LLVM code. r? @pnkfelix
This code crashes in LLVM during codegen on stable, beta, and nightly:
This originally happened in real-world code (a code base derived from cortex-m-rt).
This issue has been assigned to @jumbatm via this comment.
The text was updated successfully, but these errors were encountered: