-
Notifications
You must be signed in to change notification settings - Fork 12.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
LLVM 17 regression: tests/ui/backtrace.rs can't double-panic anymore #109672
Comments
tests/ui/abi/stack-protector.rs: rust-lang/rust#109671 the test is being optimized in newer LLVM which breaks its expectations. tests/ui/backtrace.rs: rust-lang/rust#109672 the second panic in a double-panic is being optimized out (reasonably correctly) by newer LLVM. Bug: b/274802621, 1401042 Change-Id: I2be621f38dd1630c13eaf9128c76e0d17d684367 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4375277 Reviewed-by: Hans Wennborg <hans@chromium.org> Commit-Queue: danakj <danakj@chromium.org> Cr-Commit-Position: refs/heads/main@{#1122545}
@rustbot label +A-llvm |
this seems like a bug in LLVM itself? why did you file it against rust-lang/rust? |
It certainly sounds like one, but the IR from the Rust test case is big enough that I feel bad just whining upstream, when I don't really understand what's going on. Maybe @nikic has an idea, given they reviewed the upstream change? |
Hm, the IR looks fine to me -- double() still has the check for double panics. Not sure why it doesn't work. |
Looks like error code 3 is _URC_FATAL_PHASE1_ERROR. |
rust_eh_personality returns _URC_CONTINUE_UNWIND for the I think the problem here is that LLVM now realizes that This seems correct from an LLVM perspective, but not sure who/what is actually at fault here. Maybe @Amanieu knows. |
Based on my reading of the personality function ( Note that this is not something that LLVM should assume on its own: throwing an exception from a landing pad is well-defined and should propagate that exception up to the caller. If we (or LLVM) are something incorrectly marking a call as Does this still reproduce if the test case is reduced to just the |
Hrm, just reducing it to use std::env;
use std::process::Command;
#[inline(never)]
fn double() {
struct Double;
impl Drop for Double {
fn drop(&mut self) { panic!("twice") }
}
let _d = Double;
panic!("once");
}
fn main() {
let args: Vec<String> = env::args().collect();
if args.len() >= 2 && args[1] == "fail" {
} else if args.len() >= 2 && args[1] == "double-fail" {
double();
} else {
Command::new(&args[0]);
}
} The IR/asm for that file looks like this: https://gist.github.com/nikic/a3a4322442c8f63b507cbe5a4a32b0db |
As I understand the problem, this is what happens. The call site is noexcept because the function is known to ultimately abort due to double panic. Cleanup handlers get skipped during the phase 1 walk. Normally, we will always hit a catch handler eventually (in lang_start_internal if nothing else). In this case this doesn't happen because it is known that no exception can unwind that far up (once cleanup handlers have been executed). |
Clang uses a I remember we had a good reason for using cc @nbdd0121 |
We just don't have a reliable way to tell whether we'll be aborting or not, because |
@nikic what will happen if you change the If so, then we have a bigger problem then just |
I don't think that changing how we handle the double panic abort will fully fix, because we get the same behavior if we just explicitly abort inside the cleanup: #[inline(never)]
fn double() {
struct Double;
impl Drop for Double {
fn drop(&mut self) {
std::process::abort();
}
}
let _d = Double;
panic!("once");
} This wouldn't be affected by the proposed changes, right? |
Hah, a race condition there :) |
I think we should just return EDIT: Actually this isn't quite right because we won't be able to resume if we returned |
One possible approach is to return |
Hm, it looks like this also affects C++. For the following snippet: #include <cstdlib>
#include <iostream>
struct Abort {
~Abort() {
abort();
}
};
__attribute__((noinline))
static void abort_in_dtor() {
Abort abort;
throw "test";
}
int main() {
try {
abort_in_dtor();
} catch (...) {
std::cout << "caught" << std::endl;
}
} I get:
Rather than just an abort. So this does also affect the |
I've filed llvm/llvm-project#61945 on the LLVM side with the Clang reproducer. |
@durin42 This should be fixed now, can you please try re-enabling the test? |
Would we still have issue for the abort case (the double-panic case should be fixed)? |
test.rs: #[no_mangle]
extern "C" fn d() {
struct Double;
impl Drop for Double {
fn drop(&mut self) {
std::process::abort();
}
}
let _d = Double;
panic!("once");
} test.c: void d();
int main(void) {
d();
} compile with: rustc -O test.rs --crate-type staticlib
gcc test.c libtest.a
./a.out and I get:
|
@nbdd0121 Is that with LLVM 17? The abort case should be fixed as well. We consider all cleanup landingpads as unwinding now, including those that just abort. |
I tested this on LLVM 15 and 16 and it could be reproduced in both cases. I'll file a new issue. |
LLVM change 0d4a709 (https://reviews.llvm.org/D145210) caused LLVM to have enough smarts to figure out that double panics "can't" happen - we already adjusted some tests for this (eg e4a4064 where we fixed tests/codegen/vec-shrink-panik.rs) but this seems to be a bit of an actual regression, as the code asserts the double-panic happens, but instead the double panic fails like:
so it seems like maybe LLVM is incorrect about this double-panic not being reachable or something.
Filing this bug and disabling the test in our Rust/LLVM HEADs CI for now so we see other (more urgent) breakage reliably.
The text was updated successfully, but these errors were encountered: