mirror of
https://github.com/rust-lang/rust.git
synced 2026-05-28 20:16:58 +03:00
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: https://github.com/llvm/llvm-project/issues/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: rust-lang/rust#130824
This commit is contained in:
@@ -165,6 +165,8 @@ pub(crate) fn uwtable_attr(llcx: &llvm::Context, use_sync_unwind: Option<bool>)
|
||||
// NOTE: We should determine if we even need async unwind tables, as they
|
||||
// take have more overhead and if we can use sync unwind tables we
|
||||
// probably should.
|
||||
//
|
||||
// Similar logic exists for the per-module uwtable annotation in `context.rs`.
|
||||
let async_unwind = !use_sync_unwind.unwrap_or(false);
|
||||
llvm::CreateUWTableAttr(llcx, async_unwind)
|
||||
}
|
||||
|
||||
@@ -311,6 +311,25 @@ pub(crate) unsafe fn create_module<'ll>(
|
||||
);
|
||||
}
|
||||
|
||||
if sess.must_emit_unwind_tables() {
|
||||
// This assertion checks that Max is the correct merge behavior.
|
||||
// Async unwind tables are strictly more useful than sync uwtables.
|
||||
const {
|
||||
assert!((llvm::UWTableKind::None as u32) < (llvm::UWTableKind::Sync as u32));
|
||||
assert!((llvm::UWTableKind::Sync as u32) < (llvm::UWTableKind::Async as u32));
|
||||
}
|
||||
|
||||
llvm::add_module_flag_u32(
|
||||
llmod,
|
||||
llvm::ModuleFlagMergeBehavior::Max,
|
||||
"uwtable",
|
||||
match sess.opts.unstable_opts.use_sync_unwind {
|
||||
Some(true) => llvm::UWTableKind::Sync as u32,
|
||||
Some(false) | None => llvm::UWTableKind::Async as u32,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// Add "kcfi" module flag if KCFI is enabled. (See https://reviews.llvm.org/D119296.)
|
||||
if sess.is_sanitizer_kcfi_enabled() {
|
||||
llvm::add_module_flag_u32(llmod, llvm::ModuleFlagMergeBehavior::Override, "kcfi", 1);
|
||||
|
||||
@@ -240,6 +240,18 @@ pub(crate) enum DLLStorageClass {
|
||||
DllExport = 2, // Function to be accessible from DLL.
|
||||
}
|
||||
|
||||
/// Must match the layout of `llvm::UWTableKind`.
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub(crate) enum UWTableKind {
|
||||
/// No unwind table requested
|
||||
None = 0,
|
||||
/// "Synchronous" unwind tables
|
||||
Sync = 1,
|
||||
/// "Asynchronous" unwind tables (instr precise)
|
||||
Async = 2,
|
||||
}
|
||||
|
||||
/// Must match the layout of `LLVMRustAttributeKind`.
|
||||
/// Semantically a subset of the C++ enum llvm::Attribute::AttrKind,
|
||||
/// though it is not ABI compatible (since it's a C++ enum)
|
||||
|
||||
@@ -9,3 +9,5 @@
|
||||
fn foo() {
|
||||
panic!();
|
||||
}
|
||||
|
||||
// CHECK-NOT: !"uwtable"
|
||||
|
||||
@@ -4,3 +4,5 @@
|
||||
|
||||
// CHECK: attributes #{{.*}} uwtable
|
||||
pub fn foo() {}
|
||||
|
||||
// CHECK: !{{[0-9]+}} = !{i32 7, !"uwtable", i32 2}
|
||||
|
||||
Reference in New Issue
Block a user