-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
Add __CxxFrameHandler3
in panic_abort
#83607
Conversation
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @dtolnay (or someone else) soon. If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes. Please see the contribution instructions for more information. |
How to test for MSVC? |
You should add a test case under |
__CxxFrameHandler3
in panic_abort
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ping to @danielframpton for awareness. It seems like #54137 is no longer an issue. The tests added in this PR all already pass even without the change adding the It also looks like this issue was introduced relatively recently. The code here does not reproduce the issue on nightlies older than 2021-03-11. I did a cargo bisect run and found that #76570 seems to be the culprit - perhaps LLVM can no longer prove that unwinding won't happen. Pinging @cratelyn for awareness as she was the author of that PR. Additionally, it seems like the linker is expecting the So with this in mind, I believe the following is what needs to be done:
|
I agree with most of @rylev 's points, but I don't think the requirement of rust/compiler/rustc_codegen_llvm/src/context.rs Lines 383 to 387 in 6e17a5c
LLVM distinguishes exception type with name, so hard coding __CxxFrameHandler3 is the only way to use SEH with MSVC toolchains.
|
It seems that there's no test for |
@Berrysoft |
I added to tests for |
__CxxFrameHandler3
in panic_abort
no_std
panic with MSVC toolchain
|
||
#[no_mangle] | ||
pub extern "C" fn mainCRTStartup() -> ! { | ||
main() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a call to a function that may panic, drops a value on panic and is not inlined from a crate that is compiled with -Cpanic=unwind
? In that case the personality function should be referenced.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A crate compiled with panic=abort
can't import a crate compiled with panic=unwind
.
Oh, I see. They could be statically linked.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But what's the expected result? When both crates use std
, it wouldn't be a problem, and the executable will run normally without any error; but when both use no_std
, there's no unwind runtime. Should the executable pass or abort?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The called function should not actually panic when running the executable. It should be added merely to check that there is no linking error when trying to call such a function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, you're right. __CxxFrameHandler3
is required in that case. Should I add back the empty implementation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think so.
no_std
panic with MSVC toolchain__CxxFrameHandler3
in panic_abort
The three |
Perfectly fine to keep this as r=me after the commits are squashed. |
@nagisa squashed. |
@bors r+ |
📌 Commit 48acdb7 has been approved by |
Add `__CxxFrameHandler3` in `panic_abort` Fix rust-lang#54137 <del>I initially tried to forward to `__CxxFrameHandler3` from `rust_eh_personality`, but later I found that LLVM uses handler names to distinguish exception type. Therefore I choose to add `__CxxFrameHandler3` in `panic_abort`. Anyway it solves the link problem, and this function will never be called.</del> It seems that the original issue was solved, but still adding these tests.
Failed in rollup: #83897 (comment) |
Seems caused by i686-msvc, and I'll check later. Why there're so many CRT symbols required even in |
There are 3 more symbols needed for x86 msvc target: The first two could be resolved by link against rust/compiler/rustc_target/src/spec/i686_pc_windows_msvc.rs Lines 12 to 15 in 505ed7f
As we just abort when panicking, do we really need safe exception handlers? And note that if |
@Berrysoft @nagisa I'm a bit confused and unsure if this is the right thing to do. Presumably, while this fixes the linker error, the resulting binary won't work properly right? Shouldn't we either be forcing the user to link to the MSVC runtime for exception handling, or providing an error and saying that it's not possible to unwind on MSVC targets without linking to the runtime? The proposed change seems like a hack to just make the linker happy, but it doesn't actually produce working binaries. |
#[global_allocator] | ||
static ALLOC: DummyAllocator = DummyAllocator; | ||
|
||
#[alloc_error_handler] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the reason for bringing in alloc?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
panic_unwind
needs that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason we're using the panic_unwind
feature and not #[panic_handler]
with an eh_personality
item? This would remove the need for the panic_unwind
and alloc_error_handler
features. I believe that's the more common and less verbose way to handle panics in a custom way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm only testing a no_std
crate with panic_unwind
feature. Do you mean that panic_unwind
doesn't need a panic_handler
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess I'm asking if testing the panic_unwind
feature is the right test here. We want to test custom panic handling, and the panic_unwind
feature is one way to do that. Another is simply adding a panic_handler
and eh_personality
. Perhaps we should add another test for that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thoughts here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mean adding a test with panic=unwind
feature and a custom panic handler? It seems somehow complicated to write a robust unwind panic handler...
@rylev Yes, linking a crate with After all these attempts, I'm agree with either of these solutions:
|
@rylev my reasoning in approving this is that the change should not make anything worse. And it might help somebody to produce a working binary if they are careful enough. I'm glad that you brought a different viewpoint to this though.
Hm, you already can't mix |
I might be missing something, but it seems to me that I'm still not sure what should happen in the case of statically linking a crate compiled with Are we stuck with just a linker errors or is there a way to provide the user with better error messages? |
// only-msvc | ||
// Test that `no_std` with `panic=abort` under MSVC toolchain | ||
// doesn't cause error when linking to libcmt. | ||
// We don't run this executable because it will hang in `rust_begin_unwind` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we expect that this should actually run successfully? If the MSCRT is linked in statically, then we should be able to handle linking another crate which is compiled with -Cpanic=unwind
, no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At first, I expect it fail because panic!
is in a panic=abort
crate, and unwind won't occur; but it hangs in rust_begin_unwind
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I solved this problem now. It should be able to run and fail.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment should be changed then.
// compile-flags: -C panic=abort | ||
// aux-build:exit-success-if-unwind-msvc-no-std.rs | ||
// only-msvc | ||
// Test that `no_std` with `panic=abort` under MSVC toolchain |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we also expect this to run successfully (even though it doesn't currently)? Since MSCRT is linked in?
Btw, current rustc requires msvc 2019 to build (at least i can't build it with 2017 version, in the past), that have Checked currently build exe file, it uses |
|
r? @rylev (but see my observations above) |
looks like this is ready to review |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess we can merge this since it shouldn't cause any issues, but this is definitely still not in a complete steady state.
There are a few tests that don't seem minimal in that they're testing multiple things at once. It would be good to break them up. For instance, there is one test that tests panic=unwind with a panic_unwind
feature. We also need to test without using the panic_unwind
feature and just using a custom panic_handler
.
// only-msvc | ||
// Test that `no_std` with `panic=abort` under MSVC toolchain | ||
// doesn't cause error when linking to libcmt. | ||
// We don't run this executable because it will hang in `rust_begin_unwind` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment should be changed then.
@@ -0,0 +1,32 @@ | |||
// compile-flags:-C panic=unwind |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be good to add a comment explaining what this helper crate does at a high level.
@@ -0,0 +1,25 @@ | |||
// run-fail | |||
// compile-flags: -C panic=abort -C target-feature=+crt-static |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm slightly confused about -C target-feature=+crt-static
. We're statically linking the crt but also dynamically linking libcmt
. Shouldn't we be testing on or the other.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
libcmt
is the static C runtime library. It is a static library, though it should be linked dynamically. I just cannot tell why it needs dynamic linking. It should make no difference between dynamic linking and static linking.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+crt-static
will already link libcmt
so there should be no reason to declare it manually.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's right when using libc
crate, but here we need to test under no_std
.
// aux-build:exit-success-if-unwind-msvc-no-std.rs | ||
// no-prefer-dynamic | ||
// only-msvc | ||
// We don't run this executable because it will hang in `rust_begin_unwind` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment is wrong now
#[global_allocator] | ||
static ALLOC: DummyAllocator = DummyAllocator; | ||
|
||
#[alloc_error_handler] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thoughts here?
@Berrysoft I think what's missing is a good overview of what each test is supposed to be covering. For instance, I wonder if it's better for us to close this PR, and open individual ones for each type of test we're adding explaining what the test is for. Right now it's hard for me to get an overview of what use cases we're trying to cover, especially when the linked issue is actually not being addressed here (because it's no longer an issue). |
I do think this PR is somehow miscellaneous. Anyway the issue I originally wanted to address had been solved, and we found so many different problems here, which made me a little bit tired. I'd like to close this PR, and will consider to open individual ones for each type of test in the future. |
Fix #54137
I initially tried to forward to__CxxFrameHandler3
fromrust_eh_personality
, but later I found that LLVM uses handler names to distinguish exception type. Therefore I choose to add__CxxFrameHandler3
inpanic_abort
. Anyway it solves the link problem, and this function will never be called.It seems that the original issue was solved, but still adding these tests.