Skip to content

Add uwtable annotation to modules when required#156973

Merged
rust-bors[bot] merged 3 commits into
rust-lang:mainfrom
Darksonn:unwind-tables-module
May 27, 2026
Merged

Add uwtable annotation to modules when required#156973
rust-bors[bot] merged 3 commits into
rust-lang:mainfrom
Darksonn:unwind-tables-module

Conversation

@Darksonn
Copy link
Copy Markdown
Member

@Darksonn Darksonn commented May 26, 2026

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

@rustbot rustbot added A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels May 26, 2026
@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented May 26, 2026

r? @nnethercote

rustbot has assigned @nnethercote.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: compiler
  • compiler expanded to 73 candidates
  • Random selection from 18 candidates

@Darksonn Darksonn added the A-rust-for-linux Relevant for the Rust-for-Linux project label May 26, 2026
@Darksonn
Copy link
Copy Markdown
Member Author

Darksonn commented May 26, 2026

Verified that passing -Zllvm_module_flag=uwtable:u32:2:max to the Linux kernel build fixes the boot failure that triggered this PR.

DllExport = 2, // Function to be accessible from DLL.
}

/// Must match the layout of `UWTableKind`.
Copy link
Copy Markdown
Contributor

@nnethercote nnethercote May 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This struct is UWTableKind. Did you mean to name a different type here?

View changes since the review

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm referring to the C++ enum of the same name on the LLVM side.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add that information to the comment? It wasn't clear to me. In nearby cases the LLVM type has a different name to the Rust type.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked a few other constants, and half of them just add an LLVM prefix even though it doesn't have that prefix in LLVM. The other half does have the prefix on the LLVM side. Anyways, I adjusted the comment.

@nnethercote
Copy link
Copy Markdown
Contributor

@bors r+ rollup

@rust-bors
Copy link
Copy Markdown
Contributor

rust-bors Bot commented May 27, 2026

📌 Commit 90fe8cc has been approved by nnethercote

It is now in the queue for this repository.

@rust-bors rust-bors Bot added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels May 27, 2026
GuillaumeGomez added a commit to GuillaumeGomez/rust that referenced this pull request May 27, 2026
…nethercote

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: rust-lang#130824
@bjorn3
Copy link
Copy Markdown
Member

bjorn3 commented May 27, 2026

If uwtable is emitted at the module level, is it still necessary to emit it at the function level too?

@Darksonn
Copy link
Copy Markdown
Member Author

Darksonn commented May 27, 2026

Yes I believe the only effect of setting it on the module level is to inherit it for compiler-generated functions such as asan.module_ctor. Ordinary functions do not inherit it.

Furthermore, this matches clang.

rust-bors Bot pushed a commit that referenced this pull request May 27, 2026
Rollup of 8 pull requests

Successful merges:

 - #156970 (coverage: Use original HIR info for synthetic by-move coroutine bodies)
 - #156390 (Constify Iterator-related methods and functions)
 - #156401 (rustdoc: deterministic sorting for `doc_cfg` badges)
 - #156845 (Clarify "infinite size" in cyclic-type diagnostic refers to the type name)
 - #156973 (Add uwtable annotation to modules when required)
 - #156985 (Limit the additional DLL to Windows)
 - #156988 (interpret/validity: properly treat zero-variant enums so that we do not have to check layout.is_uninhabited)
 - #157002 (std: Fix thread::available_parallelism on Redox targets)
rust-bors Bot pushed a commit that referenced this pull request May 27, 2026
Rollup of 10 pull requests

Successful merges:

 - #156970 (coverage: Use original HIR info for synthetic by-move coroutine bodies)
 - #157022 (MIR inlining: allow backends to opt-in to inlining intrinsics)
 - #157026 (miri subtree update)
 - #156390 (Constify Iterator-related methods and functions)
 - #156845 (Clarify "infinite size" in cyclic-type diagnostic refers to the type name)
 - #156955 (Fix const-eval of shared generic reborrows)
 - #156973 (Add uwtable annotation to modules when required)
 - #156985 (Limit the additional DLL to Windows)
 - #156988 (interpret/validity: properly treat zero-variant enums so that we do not have to check layout.is_uninhabited)
 - #157002 (std: Fix thread::available_parallelism on Redox targets)
@rust-bors rust-bors Bot merged commit 0846622 into rust-lang:main May 27, 2026
12 checks passed
@rustbot rustbot added this to the 1.98.0 milestone May 27, 2026
@Darksonn Darksonn deleted the unwind-tables-module branch May 28, 2026 05:53
@JonathanBrouwer
Copy link
Copy Markdown
Contributor

@rust-timer build c42badd

@rust-timer

This comment has been minimized.

pull Bot pushed a commit to xtqqczze/rust-lang-miri that referenced this pull request May 28, 2026
Rollup of 10 pull requests

Successful merges:

 - rust-lang/rust#156970 (coverage: Use original HIR info for synthetic by-move coroutine bodies)
 - rust-lang/rust#157022 (MIR inlining: allow backends to opt-in to inlining intrinsics)
 - rust-lang/rust#157026 (miri subtree update)
 - rust-lang/rust#156390 (Constify Iterator-related methods and functions)
 - rust-lang/rust#156845 (Clarify "infinite size" in cyclic-type diagnostic refers to the type name)
 - rust-lang/rust#156955 (Fix const-eval of shared generic reborrows)
 - rust-lang/rust#156973 (Add uwtable annotation to modules when required)
 - rust-lang/rust#156985 (Limit the additional DLL to Windows)
 - rust-lang/rust#156988 (interpret/validity: properly treat zero-variant enums so that we do not have to check layout.is_uninhabited)
 - rust-lang/rust#157002 (std: Fix thread::available_parallelism on Redox targets)
@rust-timer
Copy link
Copy Markdown
Collaborator

Finished benchmarking commit (c42badd): comparison URL.

Overall result: no relevant changes - no action needed

Benchmarking means the PR may be perf-sensitive. Consider adding rollup=never if this change is not fit for rolling up.

@rustbot label: -S-waiting-on-perf -perf-regression

Instruction count

This perf run didn't have relevant results for this metric.

Max RSS (memory usage)

Results (secondary 6.3%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
6.3% [5.3%, 7.3%] 2
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) - - 0

Cycles

Results (secondary 3.1%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
3.1% [2.4%, 3.8%] 2
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) - - 0

Binary size

This perf run didn't have relevant results for this metric.

Bootstrap: 511.088s -> 514.114s (0.59%)
Artifact size: 400.69 MiB -> 400.76 MiB (0.02%)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. A-rust-for-linux Relevant for the Rust-for-Linux project S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants