nbdd0121 / unwinding

Stack unwinding library in Rust
Apache License 2.0
100 stars 18 forks source link

Build failure on aarch64 and riscv64 with recent nightlies #34

Open bjorn3 opened 3 weeks ago

bjorn3 commented 3 weeks ago

This is blocking https://github.com/sunfishcode/c-ward/pull/139.

$ rustc -vV
rustc 1.82.0-nightly (6de928dce 2024-08-18)
binary: rustc
commit-hash: 6de928dce9472b864f4e5d590dd7aa2075cb7551
commit-date: 2024-08-18
host: aarch64-unknown-linux-gnu
release: 1.82.0-nightly
LLVM version: 19.1.0
$ CARGO_INCREMENTAL=0 cargo build --no-default-features --features "unwinder dwarf-expr fde-phdr-dl"
   Compiling unwinding v0.2.2 (/home/gh-bjorn3/c-ward/unwinding)
inlinable function call in a function with debug info must have a !dbg location
  call void @_Unwind_Resume(ptr %202) #16
rustc-LLVM ERROR: Broken module found, compilation aborted!
error: could not compile `unwinding` (lib)
sunfishcode commented 3 weeks ago

The error message is from the LLVM IR verifier rule that "each inlinable callsite of a debug-info-bearing function in a debug-info-bearing function has a debug location attached to it". The compiler may be emitting a call to _Unwind_Resume without a debug location somewhere, which would normally work because _Unwind_Resume is normally not defined and thus not inlinable. In the unwinding crate though, _Unwind_Resume is defined, so it's inlinable, and it can have debug info, so the call with no debug info hits this rule.

A workaround is to add this to Cargo.toml:

[profile.dev]
debug = false

because then the function containing the callsite isn't debug-info-bearing and the rule doesn't apply.

bjorn3 commented 3 weeks ago

Unwinding marks _Unwind_Resume as #[inline(never)].

sunfishcode commented 3 weeks ago

The code in LLVM doesn't check any inlining attributes.

My current theory is that the bug happens here where it creates a _Unwind_Resume call that doesn't seem to get a debug location. It's suspicious because a different _Unwind_Resume call here does have code to add a debug location, and even has a comment about how the verifier requires calls of debug-info-bearing functions from debug-info-bearing functions to have a debug location. However, I haven't yet confirmed that this is the problem.

nbdd0121 commented 3 weeks ago

I guess I could check the IR to see where resume calls are generated, and try to tweak the code to not generate them... This will be fragile though

bjorn3 commented 3 weeks ago

Another option would be to put the _Unwind_Resume definition in a separate crate which doesn't contain anything else, right? That would force it to be generated in a different codegen unit. You did still have LTO to worry about, but I don't think there is anything that can be done against that other than fixing LLVM as _Unwind_Resume calls will be coming from other crates than unwinding anyway.

bjorn3 commented 3 weeks ago

Or defining _Unwind_Resume using inline asm, but rust currently doesn't have a way to then ensure the function gets exported from dylibs.

sunfishcode commented 3 weeks ago

I've now confirmed my theory above, and posted https://github.com/llvm/llvm-project/pull/105513 to fix the bug in LLVM.

nbdd0121 commented 3 weeks ago

BTW I tried to reproduce this on my x64 machine with rustc cross-compiling to aarch64 and riscv64 but can't reproduce it. Maybe Rustc's LLVM is compiled with different flags on x64/aarch64?

sunfishcode commented 3 weeks ago

I can reproduce it on an x86_64 host in a clean unwinding checkout with the command CARGO_INCREMENTAL=0 cargo build --no-default-features --features "unwinder dwarf-expr fde-phdr-dl" --target=aarch64-unknown-linux-gnu.

nbdd0121 commented 3 weeks ago

Ah I can produce it by downloading the prebuilt standard library, but not with -Zbuild-std, weird.

nbdd0121 commented 3 weeks ago

It looks like things work with a non-zero opt-level even with debug info enabled. @sunfishcode maybe you workaround on c-ward side by something like this while waiting for LLVM fix to be merged?

[profile.dev.package.unwinding]
opt-level = 1
sunfishcode commented 2 weeks ago

The LLVM fix is now merged, and the backport to the release/19.x branch is now merged. It'll be some time before that's in a Rust builid, so thanks for the [profile.dev.package.unwinding] workaround idea, c-ward is now using until it's ready.

sunfishcode commented 1 week ago

The LLVM fix is now in LLVM 19.1.0-rc4.