Rust: inline-asm immediate constraint with fn argument crashes LLVM

Created on 28 May 2018  路  15Comments  路  Source: rust-lang/rust

#![feature(asm)]
fn main() {
    unsafe { asm!("call $0" :: "i"(test) :: "intel"); }
}
extern fn test() {}

For some reason, this crashes rustc. However, the following test compiles properly in some cases:

#![feature(asm)]
fn main() {
    unsafe { asm!("call $0" :: "i"(test as *const u8) :: "intel"); }
}
extern fn test() {}

But, in a real world project, the exact same code I get errors such as error: invalid operand for inline asm constraint 'i' or compile-time segfaults.

A-inline-assembly C-bug I-crash T-compiler requires-nightly

All 15 comments

This example causes a segfault in rustc. Because this is very easy to reproduce, I think one can omit to post a full dump here, but nevertheless, here's the backtrace.

#gdb rustc 
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from rustc...done.
(gdb) r main.rs
Starting program: /home/op/.cargo/bin/rustc main.rs
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
process 15579 is executing new program: /home/op/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/rustc
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7fffe85ff700 (LWP 15584)]
[New Thread 0x7fffe7fff700 (LWP 15585)]
[New Thread 0x7fffe79ff700 (LWP 15586)]
[New Thread 0x7fffe77fe700 (LWP 15587)]
[New Thread 0x7fffe71ff700 (LWP 15588)]
[Thread 0x7fffe77fe700 (LWP 15587) exited]
[New Thread 0x7fffe77fe700 (LWP 15589)]
[Thread 0x7fffe79ff700 (LWP 15586) exited]
[New Thread 0x7fffe6bff700 (LWP 15590)]
[New Thread 0x7fffe79ff700 (LWP 15591)]
[Thread 0x7fffe77fe700 (LWP 15589) exited]
[Thread 0x7fffe6bff700 (LWP 15590) exited]
[Thread 0x7fffe71ff700 (LWP 15588) exited]
[New Thread 0x7fffe6bff700 (LWP 15592)]
[Thread 0x7fffe79ff700 (LWP 15591) exited]

Thread 10 "rustc" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7fffe6bff700 (LWP 15592)]
0x00007fffed67f404 in llvm::X86TargetLowering::LowerAsmOperandForConstraint(llvm::SDValue, std::string&, std::vector<llvm::SDValue, std::allocator<llvm::SDValue> >&, llvm::SelectionDAG&) const () from /home/op/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/codegen-backends/librustc_codegen_llvm-llvm.so
(gdb) bt
#0  0x00007fffed67f404 in llvm::X86TargetLowering::LowerAsmOperandForConstraint(llvm::SDValue, std::string&, std::vector<llvm::SDValue, std::allocator<llvm::SDValue> >&, llvm::SelectionDAG&) const () from /home/op/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/codegen-backends/librustc_codegen_llvm-llvm.so
#1  0x00007fffee19ea2f in llvm::SelectionDAGBuilder::visitInlineAsm(llvm::ImmutableCallSite) ()
   from /home/op/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/codegen-backends/librustc_codegen_llvm-llvm.so
#2  0x00007fffee182cb8 in llvm::SelectionDAGBuilder::visit(llvm::Instruction const&) ()
   from /home/op/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/codegen-backends/librustc_codegen_llvm-llvm.so
#3  0x00007fffee204d40 in llvm::SelectionDAGISel::SelectBasicBlock(llvm::ilist_iterator<llvm::ilist_detail::node_options<llvm::Instruction, false, false, void>, false, true>, llvm::ilist_iterator<llvm::ilist_detail::node_options<llvm::Instruction, false, false, void>, false, true>, bool&) ()
   from /home/op/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/codegen-backends/librustc_codegen_llvm-llvm.so
#4  0x00007fffee203a3e in llvm::SelectionDAGISel::SelectAllBasicBlocks(llvm::Function const&) ()
   from /home/op/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/codegen-backends/librustc_codegen_llvm-llvm.so
#5  0x00007fffee200f73 in llvm::SelectionDAGISel::runOnMachineFunction(llvm::MachineFunction&) ()
   from /home/op/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/codegen-backends/librustc_codegen_llvm-llvm.so
#6  0x00007fffed5ded51 in (anonymous namespace)::X86DAGToDAGISel::runOnMachineFunction(llvm::MachineFunction&) ()
   from /home/op/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/codegen-backends/librustc_codegen_llvm-llvm.so
#7  0x00007fffee3dc7ca in llvm::MachineFunctionPass::runOnFunction(llvm::Function&) ()
   from /home/op/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/codegen-backends/librustc_codegen_llvm-llvm.so
#8  0x00007fffeebc235b in llvm::FPPassManager::runOnFunction(llvm::Function&) ()
   from /home/op/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/codegen-backends/librustc_codegen_llvm-llvm.so
#9  0x00007fffeebc25c3 in llvm::FPPassManager::runOnModule(llvm::Module&) ()
   from /home/op/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/codegen-backends/librustc_codegen_llvm-llvm.so
#10 0x00007fffeebc29c5 in llvm::legacy::PassManagerImpl::run(llvm::Module&) ()
   from /home/op/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/codegen-backends/librustc_codegen_llvm-llvm.so
#11 0x00007fffed546e2a in LLVMRustWriteOutputFile ()
   from /home/op/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/codegen-backends/librustc_codegen_llvm-llvm.so
#12 0x00007fffed431d7a in rustc_codegen_llvm::back::write::write_output_file::hf698d82f9c58fbc6 ()
   from /home/op/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/codegen-backends/librustc_codegen_llvm-llvm.so
#13 0x00007fffed3eb767 in rustc_codegen_llvm::back::write::codegen::_$u7b$$u7b$closure$u7d$$u7d$::h747b8ab31c2b9bcd ()
   from /home/op/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/codegen-backends/librustc_codegen_llvm-llvm.so
#14 0x00007fffed3e556a in rustc::util::common::time_ext::h235dac2bffa5e147 ()
   from /home/op/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/codegen-backends/librustc_codegen_llvm-llvm.so
#15 0x00007fffed434065 in rustc_codegen_llvm::back::write::codegen::h6094f17d63c01077 ()
   from /home/op/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/codegen-backends/librustc_codegen_llvm-llvm.so
#16 0x00007fffed423a42 in std::sys_common::backtrace::__rust_begin_short_backtrace::h133fe52b0e7d804a ()
   from /home/op/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/codegen-backends/librustc_codegen_llvm-llvm.so
#17 0x00007fffed449548 in std::panicking::try::do_call::h79f44434ae03a417 ()
   from /home/op/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/codegen-backends/librustc_codegen_llvm-llvm.so
#18 0x00007ffff768d94a in __rust_maybe_catch_panic () at libpanic_unwind/lib.rs:105
#19 0x00007fffed3e24d1 in _$LT$F$u20$as$u20$alloc..boxed..FnBox$LT$A$GT$$GT$::call_box::h287fbe6d24a16a97 ()
   from /home/op/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/codegen-backends/librustc_codegen_llvm-llvm.so
#20 0x00007ffff768107b in _$LT$alloc..boxed..Box$LT$alloc..boxed..FnBox$LT$A$C$$u20$Output$u3d$R$GT$$u20$$u2b$$u20$$u27$a$GT$$u20$as$u20$core..ops..function..FnOnce$LT$A$GT$$GT$::call_once::h4d3c38b88e082d2c () at /checkout/src/liballoc/boxed.rs:648
#21 std::sys_common::thread::start_thread::haf82b92357fb7f56 () at libstd/sys_common/thread.rs:24
#22 0x00007ffff764a7f6 in std::sys::unix::thread::Thread::new::thread_start::h184d9993e322d77a () at libstd/sys/unix/thread.rs:90
#23 0x00007ffff18e27fc in start_thread (arg=0x7fffe6bff700) at pthread_create.c:465
#24 0x00007ffff7325b0f in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95
(gdb) 

LLVM assertion failure:

rustc: /home/nikic/rust/src/llvm/include/llvm/Support/Casting.h:92: static bool llvm::isa_impl_cl<To, From*>::doit(const From*) [with To = llvm::ConstantSDNode; From = llvm::SDNode]: Assertion `Val && "isa<> used on a null pointer"' failed.

Assertion backtrace:

#3  0x00007ffff729dc82 in __GI___assert_fail (
    assertion=0x7fffee147b98 "Val && \"isa<> used on a null pointer\"", 
    file=0x7fffee147b58 "/home/nikic/rust/src/llvm/include/llvm/Support/Casting.h", line=92, 
    function=0x7fffee463e00 <llvm::isa_impl_cl<llvm::ConstantSDNode, llvm::SDNode*>::doit(llvm::SDNode const*)::__PRETTY_FUNCTION__> "static bool llvm::isa_impl_cl<To, From*>::doit(const From*) [with To = llvm::ConstantSDNode; From = llvm::SDNode]") at assert.c:101
#4  0x00007fffec3b61a4 in llvm::cast_retty<llvm::ConstantSDNode, llvm::SDValue>::ret_type llvm::dyn_cast<llvm::ConstantSDNode, llvm::SDValue>(llvm::SDValue&) ()
   from /home/nikic/rust/build/x86_64-unknown-linux-gnu/stage1/lib/rustlib/x86_64-unknown-linux-gnu/codegen-backends/librustc_codegen_llvm-llvm.so
#5  0x00007fffec44762a in llvm::X86TargetLowering::LowerAsmOperandForConstraint(llvm::SDValue, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, std::vector<llvm::SDValue, std::allocator<llvm::SDValue> >&, llvm::SelectionDAG&) const ()
   from /home/nikic/rust/build/x86_64-unknown-linux-gnu/stage1/lib/rustlib/x86_64-unknown-linux-gnu/codegen-backends/librustc_codegen_llvm-llvm.so
#6  0x00007fffed237f08 in llvm::SelectionDAGBuilder::visitInlineAsm(llvm::ImmutableCallSite) ()
   from /home/nikic/rust/build/x86_64-unknown-linux-gnu/stage1/lib/rustlib/x86_64-unknown-linux-gnu/codegen-backends/librustc_codegen_llvm-llvm.so
#7  0x00007fffed2451d7 in llvm::SelectionDAGBuilder::visitCall(llvm::CallInst const&) ()
   from /home/nikic/rust/build/x86_64-unknown-linux-gnu/stage1/lib/rustlib/x86_64-unknown-linux-gnu/codegen-backends/librustc_codegen_llvm-llvm.so
#8  0x00007fffed24c723 in llvm::SelectionDAGBuilder::visit(llvm::Instruction const&) ()
   from /home/nikic/rust/build/x86_64-unknown-linux-gnu/stage1/lib/rustlib/x86_64-unknown-linux-gnu/codegen-backends/librustc_codegen_llvm-llvm.so
#9  0x00007fffed28fd69 in llvm::SelectionDAGISel::SelectBasicBlock(llvm::ilist_iterator<llvm::ilist_detail::node_options<llvm::Instruction, true, false, void>, false, true>, llvm::ilist_iterator<llvm::ilist_detail::node_options<llvm::Instruction, true, false, void>, false, true>, bool&) ()
   from /home/nikic/rust/build/x86_64-unknown-linux-gnu/stage1/lib/rustlib/x86_64-unknown-linux-gnu/codegen-backends/librustc_codegen_llvm-llvm.so
#10 0x00007fffed2956d1 in llvm::SelectionDAGISel::SelectAllBasicBlocks(llvm::Function const&) ()
   from /home/nikic/rust/build/x86_64-unknown-linux-gnu/stage1/lib/rustlib/x86_64-unknown-linux-gnu/codegen-backends/librustc_codegen_llvm-llvm.so
#11 0x00007fffed2973e2 in llvm::SelectionDAGISel::runOnMachineFunction(llvm::MachineFunction&) [clone .part.876] [clone .constprop.902] ()
   from /home/nikic/rust/build/x86_64-unknown-linux-gnu/stage1/lib/rustlib/x86_64-unknown-linux-gnu/codegen-backends/librustc_codegen_llvm-llvm.so
#12 0x00007fffec3c07c4 in (anonymous namespace)::X86DAGToDAGISel::runOnMachineFunction(llvm::MachineFunction&) ()
   from /home/nikic/rust/build/x86_64-unknown-linux-gnu/stage1/lib/rustlib/x86_64-unknown-linux-gnu/codegen-backends/librustc_codegen_llvm-llvm.so
#13 0x00007fffed510775 in llvm::MachineFunctionPass::runOnFunction(llvm::Function&) ()
   from /home/nikic/rust/build/x86_64-unknown-linux-gnu/stage1/lib/rustlib/x86_64-unknown-linux-gnu/codegen-backends/librustc_codegen_llvm-llvm.so
#14 0x00007fffedecc2c3 in llvm::FPPassManager::runOnFunction(llvm::Function&) ()

LLVM IR:

define void @test() {
  call void asm sideeffect inteldialect "call $0", "i"({} undef)
  ret void
}

Causes assertion failure under llc.

I've reported this issue upstream: https://bugs.llvm.org/show_bug.cgi?id=37624

However, there is also a rustc issue here in that it shouldn't be generating an undef operand in the first place.

I've looked a bit closer at what is going on here on the Rust side. The issue seems to be that we're directly using an fn item as an inline asm operand (which is treated as a ZST scalar, yielding an undef), where usually such a use should go through a ReifyFnPointer.

This is because in https://github.com/rust-lang/rust/blob/master/src/librustc_typeck/check/mod.rs#L3946 we do not impose any type restrictions on inline asm input operands. We should be introducing a ReifyFnPointer adjustment somehow here, though I'm not sure how to actually do it (we don't really have an expected type here).

For variadic (FFI) calls, we error saying you should cast:
https://github.com/rust-lang/rust/blob/3d28ee3e34d100534062d0bc690779ed9b6927fe/src/librustc_typeck/check/mod.rs#L2915-L2916

We should maybe do something similar about inline asm!.
cc @nagisa @rkruppe @nikomatsakis

We should validate lots and lots of things about the values passed to inline asm, and we currently don't do any of them. That's no reason to not fix it, but it will be a drop in the bucket.

Would it be possible to produce such a list and make a tracking issue for it?

This particular issue seems to be somewhat common. #36907 is another instance.

@mark-i-m I鈥檝e been writing such a list (and fixing some of them) for a while now, so I guess I can make a tracking issue sometime soon.

That said, we are eventually gonna get rid of the current semantics in favor of something new. There鈥檚 already a Pre-RFC on internals, and I鈥檇 hope that we could soon write the actual RFC.

Triage: there hasn't really been any direct changes here, but there has been movement towards entirely re-doing inline assembly; with the current implementation moving to llvm_asm and a brand new inline asm design/implementation.

The equivalent version in the new asm syntax (as implemented by https://github.com/rust-lang/rust/pull/69171) is:

#![feature(asm)]
fn main() {
    unsafe { asm!("call {}", sym test); }
}
extern fn test() {}

This issue does not apply to the new asm! (RFC 2850).

The legacy llvm_asm! is deprecated and is no longer maintained.

@Amanieu The obvious equivalent in the new asm,

#![feature(asm)]
fn main() {
    unsafe { asm!("call {}", sym test); }
}
extern fn test() {}

Fails with a linking error. See https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=4c66087def8876f1661239ca3b06c976 . Should I open a new issue?

Yes, please open a new issue for this.

Was this page helpful?
0 / 5 - 0 ratings