Skip to content

Commit 0846622

Browse files
Rollup merge of #156973 - Darksonn:unwind-tables-module, r=nnethercote
Add uwtable annotation to modules when required When unwind tables are enabled with `-Cforce-unwind-tables=y`, Rust will annotate all functions with the `uwtable` annotation. However, this annotation is missing on modules, which leads to incorrect unwind tables being generated by LLVM for constructors (such as `asan.module_ctor`). This was discovered because it leads to a crash in Linux when KASAN and dynamic shadow call stack are both enabled. In this scenario, the kernel uses the unwind tables to locate the `paciasp` and `autiasp` instructions in each function and patches the machine code at boot to use the shadow call stack instructions instead. However, LLVM's AArch64PointerAuth pass emits DWARF info for `paciasp` whenever `-g` is passed, but only emits DWARF info for `autiasp` when the `uwtable` attribute is present. Since the `uwtable` annotation is missing for modules, the relevant directives are generated for only the `autiasp` instruction in `asan.module_ctor`, and not for the `paciasp` instruction. This causes the kernel's dynamic SCS logic to patch the prolouge of `asan.module_ctor`, but not the epilogue. This leads to a crash as the shadow call stack becomes unbalanced. The fact that LLVM doesn't use the same condition for whether to emit DWARF information for both instructions may be a separate bug in LLVM. Relevant issue: llvm/llvm-project#188234 AI assistance was used to determine the root cause of this crash from the observed symptoms, and to write the tests. Also thanks to @samitolvanen and @maurer for debugging this issue. Similar to this previous PR of mine: #130824
2 parents 3e15f82 + 90fe8cc commit 0846622

5 files changed

Lines changed: 37 additions & 0 deletions

File tree

compiler/rustc_codegen_llvm/src/attributes.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,8 @@ pub(crate) fn uwtable_attr(llcx: &llvm::Context, use_sync_unwind: Option<bool>)
165165
// NOTE: We should determine if we even need async unwind tables, as they
166166
// take have more overhead and if we can use sync unwind tables we
167167
// probably should.
168+
//
169+
// Similar logic exists for the per-module uwtable annotation in `context.rs`.
168170
let async_unwind = !use_sync_unwind.unwrap_or(false);
169171
llvm::CreateUWTableAttr(llcx, async_unwind)
170172
}

compiler/rustc_codegen_llvm/src/context.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,25 @@ pub(crate) unsafe fn create_module<'ll>(
311311
);
312312
}
313313

314+
if sess.must_emit_unwind_tables() {
315+
// This assertion checks that Max is the correct merge behavior.
316+
// Async unwind tables are strictly more useful than sync uwtables.
317+
const {
318+
assert!((llvm::UWTableKind::None as u32) < (llvm::UWTableKind::Sync as u32));
319+
assert!((llvm::UWTableKind::Sync as u32) < (llvm::UWTableKind::Async as u32));
320+
}
321+
322+
llvm::add_module_flag_u32(
323+
llmod,
324+
llvm::ModuleFlagMergeBehavior::Max,
325+
"uwtable",
326+
match sess.opts.unstable_opts.use_sync_unwind {
327+
Some(true) => llvm::UWTableKind::Sync as u32,
328+
Some(false) | None => llvm::UWTableKind::Async as u32,
329+
},
330+
);
331+
}
332+
314333
// Add "kcfi" module flag if KCFI is enabled. (See https://reviews.llvm.org/D119296.)
315334
if sess.is_sanitizer_kcfi_enabled() {
316335
llvm::add_module_flag_u32(llmod, llvm::ModuleFlagMergeBehavior::Override, "kcfi", 1);

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,18 @@ pub(crate) enum DLLStorageClass {
240240
DllExport = 2, // Function to be accessible from DLL.
241241
}
242242

243+
/// Must match the layout of `llvm::UWTableKind`.
244+
#[derive(Copy, Clone)]
245+
#[repr(C)]
246+
pub(crate) enum UWTableKind {
247+
/// No unwind table requested
248+
None = 0,
249+
/// "Synchronous" unwind tables
250+
Sync = 1,
251+
/// "Asynchronous" unwind tables (instr precise)
252+
Async = 2,
253+
}
254+
243255
/// Must match the layout of `LLVMRustAttributeKind`.
244256
/// Semantically a subset of the C++ enum llvm::Attribute::AttrKind,
245257
/// though it is not ABI compatible (since it's a C++ enum)

tests/codegen-llvm/force-no-unwind-tables.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,5 @@
99
fn foo() {
1010
panic!();
1111
}
12+
13+
// CHECK-NOT: !"uwtable"

tests/codegen-llvm/force-unwind-tables.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,5 @@
44

55
// CHECK: attributes #{{.*}} uwtable
66
pub fn foo() {}
7+
8+
// CHECK: !{{[0-9]+}} = !{i32 7, !"uwtable", i32 2}

0 commit comments

Comments
 (0)