Inlined `asm!` block with `may_unwind` is missing LSDA call site info
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 119k
- Forks
- 16.1k
- PR merge metrics
- PR metrics pending
Description
(I apologize if some info is incorrect, since this is the first time I'm dealing with LSDA, LLVM's IR, and unwinding.)
(There's a smaller reproducer in the next comment; you can ignore the coroutine-specific stuff in this description.)
Consider the following function:
#![feature(asm_unwind)]
#[repr(C)]
struct Control {
stack_ptr: NonNull<()>,
// ...
}
#[inline(never)]
pub unsafe fn suspend_coro(active: &mut Control) {
unsafe {
asm!(
// ...
"ret",
"2:",
// ...
in("rdi") active,
in("rsi") active.stack_ptr.as_ptr(),
clobber_abi("sysv64"),
lateout("r12") _, lateout("r13") _, lateout("r14") _, lateout("r15") _,
sp_off = const offset_of!(Control, stack_ptr),
options(may_unwind),
)
};
}
When a coroutine is "suspended," the Control structure contains (among other things) a pointer to local label 2.
I've been implementing coroutine stack unwinding via the unstable asm_unwind feature,
and everything works smoothly. (Inspired by corosensei, a force_unwind
function switches to the coroutine stack, and manually creates a frame on top of the one for suspend_coro for
a function that immediately calls _Unwind_RaiseException/std::panic::resume_unwind.)
However, unwinding breaks when I replace #[inline(never)] by #[inline(always)] in suspend_coro.
The reason, I think, is that suspend_coro gets inlined into a function with a cleanup function (and
the rust_eh_personality personality), and Rust/LLVM does not produce the necessary LSDA info for the
unwinder to locate the cleanup function when the frame points to the local label 2 (or more generally,
to any instruction within the asm! block).
To make sure that this is what's happening, I modified Rust (specifically function find_eh_action in
src/sys/personality/dwarf/eh.rs; here's the patch) and libunwind to output all relevant info during unwinding.
The frame pointing to the function with the partly missing LSDA info (and the inlined assembly) leads
the personality function to return _URC_FATAL_PHASE1_ERROR, because it cannot find any landing pad
for the instruction at 2: within the inlined asm! block:
reading dwarf code at lsda=0x591a69ad3e38, func_start=0x591a69afae10
start encoding: ff
ttype encoding: ff
call site encoding: 1
action table start: 0x591a69ad3e57, ip=0x591a69afaed3
cs_start=37
cs_len=5
cs_lpad=309
cs_action_entry=0
cs_start=239
cs_len=6
cs_lpad=325
cs_action_entry=0
passed ip, not present
thread 'resume_from_different_coros' (355403) panicked at src/unwind/itanium.rs:83:5:
_Unwind_RaiseException failed: _URC_FATAL_PHASE1_ERROR
For reference, here's the IR for suspend_coro with #[inline(never)]. As expected, the asm call
contains the unwind attribute. This function requires no cleanup, so no personality nor landing pad
are created. Unwinding proceeds normally through its corresponding stack frame.
; coro::arch::imp::suspend_coro
; Function Attrs: noinline nonlazybind uwtable
define void @_RNvNtNtCscfDV7XxA4Im_4coro4arch3imp12suspend_coro(ptr noundef nonnull align 8 %active) unnamed_addr #5 !guid !81 {
start:
%_4 = load ptr, ptr %active, align 8, !nonnull !64, !noundef !64
%0 = tail call { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, float, float, float, float, float, float, float, float, float, float, float, float, float, float, float, float } asm sideeffect alignstack inteldialect unwind "push rbx\0Apush rbp\0Alea rax, [rip + 2f]\0Apush rax\0Amov [rdi + 0], rsp\0Amov rsp, rsi\0Apop rbp\0A.cfi_escape 0x2e, 0\0Aret\0A2:\0Apush rbp\0Amov [rdi + 0], rsp\0Alea rsp, [rsi + 8]\0Apop rbp\0Apop rbx", "={r12},={r13},={r14},={r15},={ax},={cx},={dx},={si},={di},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},{di},{si},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k0},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{tmm0},~{tmm1},~{tmm2},~{tmm3},~{tmm4},~{tmm5},~{tmm6},~{tmm7},~{dirflag},~{fpsr},~{flags},~{memory}"(ptr nonnull %active, ptr nonnull %_4), !srcloc !82
ret void
}
But when #[inline(always)], the IR for the inlinee function control_transfers::resume_from_different_coros::{closure#1} is:
; control_transfers::resume_from_different_coros::{closure#1}
; Function Attrs: inlinehint nonlazybind uwtable
define internal fastcc void @_RNCNvCshisOEaq0iZN_17control_transferss_27resume_from_different_coross_0B3_(ptr nofree noundef nonnull align 8 captures(none) %_1) unnamed_addr #6 personality ptr @rust_eh_personality !guid !586 {
start:
%_3 = alloca [8 x i8], align 4
call void @llvm.lifetime.start.p0(ptr nonnull %_3)
%_18 = load i64, ptr %_1, align 8, !noundef !132
%0 = icmp eq i64 %_18, 0
br i1 %0, label %bb14, label %bb13, !prof !560
bb14: ; preds = %start
store i64 -1, ptr %_1, align 8
%_24 = getelementptr inbounds nuw i8, ptr %_1, i64 8
; invoke <coro::Coro<i32, control_transfers::resume_after_move::{closure#0}>>::resume
%1 = invoke fastcc { i32, i32 } @_RNvMs0_CscfDV7XxA4Im_4coroINtB5_4CorolNCNvCshisOEaq0iZN_17control_transferss_17resume_after_move0E6resumeBE_(ptr noalias nofree noundef align 8 dereferenceable(24) %_24)
to label %bb1 unwind label %cleanup
bb13: ; preds = %start
; call core::cell::panic_already_borrowed
tail call void @_RNvNtCsdN1ZzDs28Vk_4core4cell22panic_already_borrowed(ptr noalias nofree noundef readonly align 8 captures(address, read_provenance) dereferenceable(24) @alloc_f92ec3a5190f40a4f61d46926f400512) #25
unreachable
cleanup: ; preds = %bb4, %bb14
%2 = landingpad { ptr, i32 }
cleanup
br label %bb12
bb1: ; preds = %bb14
%3 = extractvalue { i32, i32 } %1, 0
%4 = extractvalue { i32, i32 } %1, 1
store i32 %3, ptr %_3, align 4
%5 = getelementptr inbounds nuw i8, ptr %_3, i64 4
store i32 %4, ptr %5, align 4
%_5.i = icmp eq i32 %3, 0
br i1 %_5.i, label %bb3, label %bb4, !prof !487
bb4: ; preds = %bb1
; invoke core::panicking::assert_failed::<core::ops::coroutine::CoroutineState<(), i32>, core::ops::coroutine::CoroutineState<(), i32>>
invoke fastcc void @_RINvNtCsdN1ZzDs28Vk_4core9panicking13assert_failedINtNtNtB4_3ops9coroutine14CoroutineStateulEBM_ECshisOEaq0iZN_17control_transfers(ptr noalias nofree noundef readonly align 4 captures(address, read_provenance) dereferenceable(8) %_3, ptr noalias nofree noundef readonly align 4 captures(address, read_provenance) dereferenceable(8) @alloc_bd30ae0d503613008a9049c05daf1744, ptr noalias nofree noundef readonly align 8 captures(address, read_provenance) dereferenceable(24) @alloc_84d20907cd6dbcb746b7b2abf3c753d9) #27
to label %unreachable unwind label %cleanup
bb3: ; preds = %bb1
%_2.i.i.i7 = load i64, ptr %_1, align 8, !noundef !132
%_3.i.i.i8 = add i64 %_2.i.i.i7, 1
store i64 %_3.i.i.i8, ptr %_1, align 8
call void @llvm.lifetime.end.p0(ptr nonnull %_3)
%_11.i = icmp ult i64 %_3.i.i.i8, 9223372036854775807
br i1 %_11.i, label %_RNvMst_NtCsdN1ZzDs28Vk_4core4cellINtB5_7RefCellINtCscfDV7XxA4Im_4coro4CorolNCNvCshisOEaq0iZN_17control_transferss_27resume_from_different_coros0EE6borrowB1f_.exit, label %bb2.i9, !prof !560
bb2.i9: ; preds = %bb3
; call core::cell::panic_already_mutably_borrowed
tail call void @_RNvNtCsdN1ZzDs28Vk_4core4cell30panic_already_mutably_borrowed(ptr noalias nofree noundef nonnull readonly align 8 captures(address, read_provenance) dereferenceable(24) @alloc_178b316d1232c191ec98be2b6cd5cb4e) #25
unreachable
_RNvMst_NtCsdN1ZzDs28Vk_4core4cellINtB5_7RefCellINtCscfDV7XxA4Im_4coro4CorolNCNvCshisOEaq0iZN_17control_transferss_27resume_from_different_coros0EE6borrowB1f_.exit: ; preds = %bb3
%b.i = add nsw i64 %_2.i.i.i7, 2
store i64 %b.i, ptr %_1, align 8, !noalias !587
tail call void @llvm.experimental.noalias.scope.decl(metadata !590)
tail call void @llvm.experimental.noalias.scope.decl(metadata !593)
%_8.i.i = load ptr, ptr %_24, align 8, !alias.scope !596, !nonnull !132, !noundef !132
%_6.i.i = load ptr, ptr %_8.i.i, align 16, !noalias !596, !nonnull !132, !noundef !132
%6 = ptrtoint ptr %_6.i.i to i64
%7 = getelementptr inbounds nuw i8, ptr %_1, i64 16
%_14.i.i = load ptr, ptr %7, align 8, !alias.scope !596, !nonnull !132, !noundef !132
%8 = ptrtoint ptr %_14.i.i to i64
%_9.i.i = sub i64 %6, %8
%9 = getelementptr inbounds nuw i8, ptr %_1, i64 24
%_16.i.i = load i64, ptr %9, align 8, !range !159, !alias.scope !596, !noundef !132
%_5.not.i.i = icmp ult i64 %_9.i.i, %_16.i.i
br i1 %_5.not.i.i, label %_RNvMs0_CscfDV7XxA4Im_4coroINtB5_4CorolNCNvCshisOEaq0iZN_17control_transferss_27resume_from_different_coros0E11has_startedBE_.exit.i, label %bb6.i.invoke
_RNvMs0_CscfDV7XxA4Im_4coroINtB5_4CorolNCNvCshisOEaq0iZN_17control_transferss_27resume_from_different_coros0E11has_startedBE_.exit.i: ; preds = %_RNvMst_NtCsdN1ZzDs28Vk_4core4cellINtB5_7RefCellINtCscfDV7XxA4Im_4coro4CorolNCNvCshisOEaq0iZN_17control_transferss_27resume_from_different_coros0EE6borrowB1f_.exit
%_3.i.i = load ptr, ptr %_6.i.i, align 8, !noalias !596, !noundef !132
%.not.i = icmp eq ptr %_3.i.i, getelementptr inbounds nuw (i8, ptr @_RINvNtNtCscfDV7XxA4Im_4coro4arch3imp11first_tramplNCNvCshisOEaq0iZN_17control_transferss_27resume_from_different_coros0EBQ_, i64 1)
br i1 %.not.i, label %bb6.i.invoke, label %bb2.i11, !prof !160
bb2.i11: ; preds = %_RNvMs0_CscfDV7XxA4Im_4coroINtB5_4CorolNCNvCshisOEaq0iZN_17control_transferss_27resume_from_different_coros0E11has_startedBE_.exit.i
%10 = getelementptr inbounds nuw i8, ptr %_8.i.i, i64 24
%_4.i.i = load ptr, ptr %10, align 8, !noalias !597, !noundef !132
%_3.i3.i = icmp eq ptr %_4.i.i, null
br i1 %_3.i3.i, label %bb7, label %bb6.i.invoke, !prof !487
bb6.i.invoke: ; preds = %_RNvMst_NtCsdN1ZzDs28Vk_4core4cellINtB5_7RefCellINtCscfDV7XxA4Im_4coro4CorolNCNvCshisOEaq0iZN_17control_transferss_27resume_from_different_coros0EE6borrowB1f_.exit, %bb2.i11, %_RNvMs0_CscfDV7XxA4Im_4coroINtB5_4CorolNCNvCshisOEaq0iZN_17control_transferss_27resume_from_different_coros0E11has_startedBE_.exit.i
%11 = phi ptr [ @alloc_a90b2cdc5510238b0390717c26dbfd52, %_RNvMs0_CscfDV7XxA4Im_4coroINtB5_4CorolNCNvCshisOEaq0iZN_17control_transferss_27resume_from_different_coros0E11has_startedBE_.exit.i ], [ @alloc_fa70cf512e51213f6e93f0d251b72a17, %bb2.i11 ], [ @alloc_fa70cf512e51213f6e93f0d251b72a17, %_RNvMst_NtCsdN1ZzDs28Vk_4core4cellINtB5_7RefCellINtCscfDV7XxA4Im_4coro4CorolNCNvCshisOEaq0iZN_17control_transferss_27resume_from_different_coros0EE6borrowB1f_.exit ]
%12 = phi i64 [ 36, %_RNvMs0_CscfDV7XxA4Im_4coroINtB5_4CorolNCNvCshisOEaq0iZN_17control_transferss_27resume_from_different_coros0E11has_startedBE_.exit.i ], [ 34, %bb2.i11 ], [ 34, %_RNvMst_NtCsdN1ZzDs28Vk_4core4cellINtB5_7RefCellINtCscfDV7XxA4Im_4coro4CorolNCNvCshisOEaq0iZN_17control_transferss_27resume_from_different_coros0EE6borrowB1f_.exit ]
%13 = phi ptr [ @alloc_d8aa9af72d2367601b2f42a76ca5794b, %_RNvMs0_CscfDV7XxA4Im_4coroINtB5_4CorolNCNvCshisOEaq0iZN_17control_transferss_27resume_from_different_coros0E11has_startedBE_.exit.i ], [ @alloc_99d67c30cdcd95a0cea586fa7474d0f1, %bb2.i11 ], [ @alloc_99d67c30cdcd95a0cea586fa7474d0f1, %_RNvMst_NtCsdN1ZzDs28Vk_4core4cellINtB5_7RefCellINtCscfDV7XxA4Im_4coro4CorolNCNvCshisOEaq0iZN_17control_transferss_27resume_from_different_coros0EE6borrowB1f_.exit ]
; invoke core::panicking::panic
invoke void @_RNvNtCsdN1ZzDs28Vk_4core9panicking5panic(ptr noalias nofree noundef nonnull readonly captures(address, read_provenance) %11, i64 noundef %12, ptr noalias nofree noundef readonly align 8 captures(address, read_provenance) dereferenceable(24) %13) #25
to label %bb6.i.cont unwind label %cleanup1
bb6.i.cont: ; preds = %bb6.i.invoke
unreachable
unreachable: ; preds = %bb4
unreachable
cleanup1: ; preds = %bb6.i.invoke
%14 = landingpad { ptr, i32 }
cleanup
br label %bb12
bb7: ; preds = %bb2.i11
store i64 %_3.i.i.i8, ptr %_1, align 8
%_3.i = tail call align 8 ptr @llvm.threadlocal.address.p0(ptr @_RNvCscfDV7XxA4Im_4coro6ACTIVE)
%_2.i = load ptr, ptr %_3.i, align 8, !noundef !132
%_9.i = icmp eq ptr %_2.i, null
br i1 %_9.i, label %bb2.i, label %_RNvCscfDV7XxA4Im_4coro7suspend.exit, !prof !440
bb2.i: ; preds = %bb7
; call coro::suspend_from_outside
tail call void @_RNvCscfDV7XxA4Im_4coro20suspend_from_outside() #27
unreachable
_RNvCscfDV7XxA4Im_4coro7suspend.exit: ; preds = %bb7
%_14.i = load ptr, ptr %_2.i, align 8, !nonnull !132, !noundef !132
%15 = tail call { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, float, float, float, float, float, float, float, float, float, float, float, float, float, float, float, float } asm sideeffect alignstack inteldialect unwind "push rbx\0Apush rbp\0Alea rax, [rip + 2f]\0Apush rax\0Amov [rdi + 0], rsp\0Amov rsp, rsi\0Apop rbp\0A.cfi_escape 0x2e, 0\0Aret\0A2:\0Apush rbp\0Amov [rdi + 0], rsp\0Alea rsp, [rsi + 8]\0Apop rbp\0Apop rbx", "={r12},={r13},={r14},={r15},={ax},={cx},={dx},={si},={di},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},{di},{si},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k0},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{tmm0},~{tmm1},~{tmm2},~{tmm3},~{tmm4},~{tmm5},~{tmm6},~{tmm7},~{dirflag},~{fpsr},~{flags},~{memory}"(ptr nonnull %_2.i, ptr nonnull %_14.i), !srcloc !478
ret void
bb12: ; preds = %cleanup1, %cleanup
%.sink = phi i64 [ -1, %cleanup1 ], [ 1, %cleanup ]
%.pn = phi { ptr, i32 } [ %14, %cleanup1 ], [ %2, %cleanup ]
%_2.i.i.i13 = load i64, ptr %_1, align 8, !noundef !132
%_3.i.i.i14 = add i64 %_2.i.i.i13, %.sink
store i64 %_3.i.i.i14, ptr %_1, align 8
resume { ptr, i32 } %.pn
}
The relevant asm call appears right at the end, after label _RNvCscfDV7XxA4Im_4coro7suspend.exit.
The complete .ll file appears in this Godbolt.
LLVM produces the following assembly (when passing -O2 --exception-model=dwarf -mtriple=x86_64-unknown-linux-gnu) for this function:
.text
.prefalign 4, .Lfunc_end55, nop # -- Begin function control_transfers[c97a7856c43022a1]::resume_from_different_coros::{closure#1}
.type control_transfers[c97a7856c43022a1]::resume_from_different_coros::{closure#1},@function
control_transfers[c97a7856c43022a1]::resume_from_different_coros::{closure#1}: # @control_transfers[c97a7856c43022a1]::resume_from_different_coros::{closure#1}
.Lfunc_begin21:
.cfi_startproc
.cfi_personality 3, rust_eh_personality
.cfi_lsda 3, .Lexception21
# %bb.0: # %start
push r15
.cfi_def_cfa_offset 16
push r14
.cfi_def_cfa_offset 24
push r13
.cfi_def_cfa_offset 32
push r12
.cfi_def_cfa_offset 40
push rbx
.cfi_def_cfa_offset 48
sub rsp, 16
.cfi_def_cfa_offset 64
.cfi_offset rbx, -48
.cfi_offset r12, -40
.cfi_offset r13, -32
.cfi_offset r14, -24
.cfi_offset r15, -16
cmp qword ptr [rdi], 0
jne .LBB55_4
# %bb.1: # %bb14
mov rbx, rdi
mov qword ptr [rdi], -1
add rdi, 8
.Ltmp189: # EH_LABEL
call <coro[8eb5da1bc166bea0]::Coro<i32, control_transfers[c97a7856c43022a1]::resume_after_move::{closure#0}>>::resume
.Ltmp190: # EH_LABEL
# %bb.2: # %bb1
mov dword ptr [rsp + 8], eax
mov dword ptr [rsp + 12], edx
test eax, eax
jne .LBB55_3
# %bb.5: # %bb3
mov rcx, qword ptr [rbx]
lea rax, [rcx + 1]
mov qword ptr [rbx], rax
movabs rdx, 9223372036854775807
cmp rax, rdx
jae .LBB55_18
# %bb.6: # %_RNvMst_NtCsdN1ZzDs28Vk_4core4cellINtB5_7RefCellINtCscfDV7XxA4Im_4coro4CorolNCNvCshisOEaq0iZN_17control_transferss_27resume_from_different_coros0EE6borrowB1f_.exit
add rcx, 2
mov qword ptr [rbx], rcx
mov rcx, qword ptr [rbx + 8]
mov r8, qword ptr [rcx]
mov r9, r8
sub r9, qword ptr [rbx + 16]
mov edx, offset .Lalloc_99d67c30cdcd95a0cea586fa7474d0f1
mov esi, 34
mov edi, offset .Lalloc_fa70cf512e51213f6e93f0d251b72a17
cmp r9, qword ptr [rbx + 24]
jae .LBB55_10
# %bb.7: # %_RNvMs0_CscfDV7XxA4Im_4coroINtB5_4CorolNCNvCshisOEaq0iZN_17control_transferss_27resume_from_different_coros0E11has_startedBE_.exit.i
cmp qword ptr [r8], offset coro[8eb5da1bc166bea0]::arch::imp::first_tramp::<i32, control_transfers[c97a7856c43022a1]::resume_from_different_coros::{closure#0}>+1
je .LBB55_8
# %bb.9: # %bb2.i11
cmp qword ptr [rcx + 24], 0
jne .LBB55_10
# %bb.14: # %bb7
mov qword ptr [rbx], rax
mov rax, qword ptr [rip + coro[8eb5da1bc166bea0]::ACTIVE@GOTTPOFF]
mov rdi, qword ptr fs:[rax]
test rdi, rdi
je .LBB55_19
# %bb.15: # %_RNvCscfDV7XxA4Im_4coro7suspend.exit
mov rsi, qword ptr [rdi]
#APP
push rbx
push rbp
lea rax, [rip + .Ltmp197]
push rax
mov qword ptr [rdi], rsp
mov rsp, rsi
pop rbp
.cfi_escape 0x2e, 0x00
ret
.Ltmp197:
push rbp
mov qword ptr [rdi], rsp
lea rsp, [rsi + 8]
pop rbp
pop rbx
#NO_APP
add rsp, 16
.cfi_def_cfa_offset 48
pop rbx
.cfi_def_cfa_offset 40
pop r12
.cfi_def_cfa_offset 32
pop r13
.cfi_def_cfa_offset 24
pop r14
.cfi_def_cfa_offset 16
pop r15
.cfi_def_cfa_offset 8
ret
.LBB55_8:
.cfi_def_cfa_offset 64
mov edx, offset .Lalloc_d8aa9af72d2367601b2f42a76ca5794b
mov esi, 36
mov edi, offset .Lalloc_a90b2cdc5510238b0390717c26dbfd52
.LBB55_10: # %bb6.i.invoke
.Ltmp194: # EH_LABEL
call qword ptr [rip + core[a0a1658e72bc1214]::panicking::panic@GOTPCREL]
.Ltmp195: # EH_LABEL
# %bb.11: # %bb6.i.cont
.LBB55_4: # %bb13
mov edi, offset .Lalloc_f92ec3a5190f40a4f61d46926f400512
call qword ptr [rip + core[a0a1658e72bc1214]::cell::panic_already_borrowed@GOTPCREL]
.LBB55_3: # %bb4
.Ltmp191: # EH_LABEL
lea rdi, [rsp + 8]
mov esi, offset .Lalloc_bd30ae0d503613008a9049c05daf1744
mov edx, offset .Lalloc_84d20907cd6dbcb746b7b2abf3c753d9
call core[a0a1658e72bc1214]::panicking::assert_failed::<core[a0a1658e72bc1214]::ops::coroutine::CoroutineState<(), i32>, core[a0a1658e72bc1214]::ops::coroutine::CoroutineState<(), i32>>
.Ltmp192: # EH_LABEL
# %bb.12: # %unreachable
.LBB55_18: # %bb2.i9
mov edi, offset .Lalloc_178b316d1232c191ec98be2b6cd5cb4e
call qword ptr [rip + core[a0a1658e72bc1214]::cell::panic_already_mutably_borrowed@GOTPCREL]
.LBB55_19: # %bb2.i
call qword ptr [rip + coro[8eb5da1bc166bea0]::suspend_from_outside@GOTPCREL]
.LBB55_16: # %cleanup
.Ltmp193: # EH_LABEL
mov ecx, 1
jmp .LBB55_17
.LBB55_13: # %cleanup1
.Ltmp196: # EH_LABEL
mov rcx, -1
.LBB55_17: # %bb12
add qword ptr [rbx], rcx
mov rdi, rax
call _Unwind_Resume@PLT
.Lfunc_end55:
.size control_transfers[c97a7856c43022a1]::resume_from_different_coros::{closure#1}, .Lfunc_end55-control_transfers[c97a7856c43022a1]::resume_from_different_coros::{closure#1}
.cfi_endproc
.section .gcc_except_table,"a",@progbits
.p2align 2, 0x0
GCC_except_table55:
.Lexception21:
.byte 255 # @LPStart Encoding = omit
.byte 255 # @TType Encoding = omit
.byte 1 # Call site Encoding = uleb128
.uleb128 .Lcst_end21-.Lcst_begin21
.Lcst_begin21:
.uleb128 .Ltmp189-.Lfunc_begin21 # >> Call Site 1 <<
.uleb128 .Ltmp190-.Ltmp189 # Call between .Ltmp189 and .Ltmp190
.uleb128 .Ltmp193-.Lfunc_begin21 # jumps to .Ltmp193
.byte 0 # On action: cleanup
.uleb128 .Ltmp194-.Lfunc_begin21 # >> Call Site 2 <<
.uleb128 .Ltmp195-.Ltmp194 # Call between .Ltmp194 and .Ltmp195
.uleb128 .Ltmp196-.Lfunc_begin21 # jumps to .Ltmp196
.byte 0 # On action: cleanup
.uleb128 .Ltmp195-.Lfunc_begin21 # >> Call Site 3 <<
.uleb128 .Ltmp191-.Ltmp195 # Call between .Ltmp195 and .Ltmp191
.byte 0 # has no landing pad
.byte 0 # On action: cleanup
.uleb128 .Ltmp191-.Lfunc_begin21 # >> Call Site 4 <<
.uleb128 .Ltmp192-.Ltmp191 # Call between .Ltmp191 and .Ltmp192
.uleb128 .Ltmp193-.Lfunc_begin21 # jumps to .Ltmp193
.byte 0 # On action: cleanup
.uleb128 .Ltmp192-.Lfunc_begin21 # >> Call Site 5 <<
.uleb128 .Lfunc_end55-.Ltmp192 # Call between .Ltmp192 and .Lfunc_end55
.byte 0 # has no landing pad
.byte 0 # On action: cleanup
.Lcst_end21:
.p2align 2, 0x0
# -- End function
Notice in particular that there's no call site info for the asm! instructions in between
the #APP and #NO_APP comments, i.e. no call site entry between .Ltmp197 and .Ltmp194.
Ideally I'd have liked to provide a small reproducer, but I've been unable to hit all the See the next comment. Ultimately I don't know if this is a Rust or a LLVM codegen issue, so I decided to
necessary conditions with only a few lines of code. In fact, I'm not sure if inlining even
plays a role in the actual issue. I can keep working on it during the next few days if it
would facilitate things. I can also make the coroutine crate repo public so you can inspect
it.
open the issue here first. Also, I'm not 100% sure whether unwinding in this way is allowed.
@Amanieu do you think this issue could be related to the crashes you observed here?
Meta
rustc --version --verbose:
rustc 1.100.0-nightly (8fa1c96cf 2026-08-17)
binary: rustc
commit-hash: 8fa1c96cfd489e4c27654c144ae871ce2c4db6c6
commit-date: 2026-08-17
host: x86_64-unknown-linux-gnu
release: 1.100.0-nightly
LLVM version: 23.1.0
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in src/sys/personality/dwarf/eh.rs, especially find_eh_action, and compare the provided inline(never) and inline(always) LLVM IR for asm! with may_unwind. Use the smaller reproducer from the issue and inspect the emitted LSDA call-site information. Done means unwinding can locate the cleanup for an instruction inside an inlined asm! block.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100