Description
On Windows, Rust panics are implemented by assembling a C++ exception object and throwing it via _CxxThrowException
.
rust/library/panic_unwind/src/seh.rs
Line 351 in a2d45f7
This exception is treated like any other regular C++ exceptions, can be caught in catch
blocks, and can be retrieved via std::current_exception()
. Furthermore, exceptions are mandated to be copyable by the C++ standard, and std::current_exception
is permitted to copy the exception objects which is necessary on Windows as exceptions are stored on the stack and only copied to the heap when an std::exception_ptr
is constructed. Thus the Rust exception panics in the copy constructor, which count as throwing a C++ exception, for which the C++ standard mandates that a std::bad_exception
object is stored inside the exception pointer.
rust/library/panic_unwind/src/seh.rs
Lines 263 to 267 in a2d45f7
...except that that panic is also a Rust panic, which will be caught by std::current_exception
and dropped, and abort.
Consider the following example:
unsafe extern "C-unwind" {
safe fn cpp_exception_foo(throws: extern "C-unwind" fn());
}
extern "C-unwind" fn do_panic() {
panic!("hi");
}
fn main() {
_ = std::panic::catch_unwind(|| cpp_exception_foo(do_panic));
}
#include <exception>
#include <print>
extern "C" void cpp_exception_foo(void(*callback)())
{
try
{
callback();
}
catch(...)
{
std::current_exception();
throw;
}
}
Not only does this cause two Rust panics cannot be copied
panics to be dumped to stderr, the process aborts with
fatal runtime error: Rust panics must be rethrown, aborting
Without the call std::current_exception()
, it succeeds - but the copy constructor throws / panics, so the exception pointer should only have contained an std::bad_exception
object in the first place! (Which too is ergonomically unpleasant, but something C++ code already has to deal with, and making Rust exceptions reference counted so that they can be stored and rethrown at a later point in time is its own can of worms.)
This breaks any sort of unwinding over FFI where the C++ side wants to create an exception pointer, even if the C++ side isn't even aware of Rust code. One might argue that Rust panics aren't exceptions and shouldn't be treated as such, but they are - they literally are implemented as throwing C++ exceptions, and the C++ language and ecosystem will treat them accordingly.
Meta
rustc --version --verbose
:
rustc 1.90.0-nightly (a84ab0ce6 2025-07-06)
binary: rustc
commit-hash: a84ab0ce6c4557a2f01a3a6c3fdb0f92098db78d
commit-date: 2025-07-06
host: x86_64-pc-windows-msvc
release: 1.90.0-nightly
LLVM version: 20.1.7
Backtrace
thread 'main' panicked at src\main.rs:6:5:
hi
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
thread 'main' panicked at library\panic_unwind\src\seh.rs:289:8:
Rust panics cannot be copied
stack backtrace:
0: 0x7ff71a9f6762 - std::backtrace_rs::backtrace::win64::trace
at /rustc/6b00bc3880198600130e1cf62b8f8a93494488cc/library\std\src\..\..\backtrace\src\backtrace\win64.rs:85
1: 0x7ff71a9f6762 - std::backtrace_rs::backtrace::trace_unsynchronized
at /rustc/6b00bc3880198600130e1cf62b8f8a93494488cc/library\std\src\..\..\backtrace\src\backtrace\mod.rs:66
2: 0x7ff71a9f6762 - std::sys::backtrace::_print_fmt
at /rustc/6b00bc3880198600130e1cf62b8f8a93494488cc/library\std\src\sys\backtrace.rs:66
3: 0x7ff71a9f6762 - std::sys::backtrace::impl$0::print::impl$0::fmt
at /rustc/6b00bc3880198600130e1cf62b8f8a93494488cc/library\std\src\sys\backtrace.rs:39
4: 0x7ff71aa016cb - core::fmt::rt::Argument::fmt
at /rustc/6b00bc3880198600130e1cf62b8f8a93494488cc/library\core\src\fmt\rt.rs:181
5: 0x7ff71aa016cb - core::fmt::write
at /rustc/6b00bc3880198600130e1cf62b8f8a93494488cc/library\core\src\fmt\mod.rs:1446
6: 0x7ff71a9f4e57 - std::io::default_write_fmt
at /rustc/6b00bc3880198600130e1cf62b8f8a93494488cc/library\std\src\io\mod.rs:639
7: 0x7ff71a9f4e57 - std::io::Write::write_fmt<std::sys::stdio::windows::Stderr>
at /rustc/6b00bc3880198600130e1cf62b8f8a93494488cc/library\std\src\io\mod.rs:1914
8: 0x7ff71a9f65a5 - std::sys::backtrace::BacktraceLock::print
at /rustc/6b00bc3880198600130e1cf62b8f8a93494488cc/library\std\src\sys\backtrace.rs:42
9: 0x7ff71a9f7a2c - std::panicking::default_hook::closure$0
at /rustc/6b00bc3880198600130e1cf62b8f8a93494488cc/library\std\src\panicking.rs:300
10: 0x7ff71a9f77c2 - std::panicking::default_hook
at /rustc/6b00bc3880198600130e1cf62b8f8a93494488cc/library\std\src\panicking.rs:327
11: 0x7ff71a9f851f - std::panicking::rust_panic_with_hook
at /rustc/6b00bc3880198600130e1cf62b8f8a93494488cc/library\std\src\panicking.rs:833
12: 0x7ff71a9f8372 - std::panicking::begin_panic_handler::closure$0
at /rustc/6b00bc3880198600130e1cf62b8f8a93494488cc/library\std\src\panicking.rs:699
13: 0x7ff71a9f6e5f - std::sys::backtrace::__rust_end_short_backtrace<std::panicking::begin_panic_handler::closure_env$0,never$>
at /rustc/6b00bc3880198600130e1cf62b8f8a93494488cc/library\std\src\sys\backtrace.rs:168
14: 0x7ff71a9f7fae - std::panicking::begin_panic_handler
at /rustc/6b00bc3880198600130e1cf62b8f8a93494488cc/library\std\src\panicking.rs:697
15: 0x7ff71aa06161 - core::panicking::panic_fmt
at /rustc/6b00bc3880198600130e1cf62b8f8a93494488cc/library\core\src\panicking.rs:75
16: 0x7ff71aa0604c - panic_unwind::imp::exception_copy
at /rustc/6b00bc3880198600130e1cf62b8f8a93494488cc/library\panic_unwind\src\seh.rs:281
17: 0x7ffe1f55228e - <unknown>
18: 0x7ffe1f55200c - <unknown>
19: 0x7ffe1f552511 - __ExceptionPtrCurrentException
20: 0x7ff71aa04842 - std::current_exception
at C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\include\exception:318
21: 0x7ff71aa066a6 - cpp_exception_foo$catch$0
at C:\Users\tokgeo\source\repos\uncaught_exceptions\src\main.cpp:12
22: 0x7ffe4cd541d0 - _CxxFrameHandler4
23: 0x7ffe4cd5258f - <unknown>
24: 0x7ffe63646c56 - RtlCaptureContext2
25: 0x7ff71aa047ad - cpp_exception_foo
at C:\Users\tokgeo\source\repos\uncaught_exceptions\src\main.cpp:8
26: 0x7ff71a9f11a0 - uncaught_exceptions::main::closure$0
at C:\Users\tokgeo\source\repos\uncaught_exceptions\src\main.rs:10
27: 0x7ff71a9f1318 - std::panicking::try::do_call<uncaught_exceptions::main::closure_env$0,tuple$<> >
at C:\Users\tokgeo\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\std\src\panicking.rs:589
28: 0x7ff71a9f10b3 - std::panic::catch_unwind<uncaught_exceptions::main::closure_env$0,tuple$<> >
29: 0x7ff71a9f1046 - std::panicking::try
at C:\Users\tokgeo\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\std\src\panicking.rs:552
30: 0x7ff71a9f1046 - std::panic::catch_unwind<uncaught_exceptions::main::closure_env$0,tuple$<> >
at C:\Users\tokgeo\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\std\src\panic.rs:359
31: 0x7ff71a9f13d9 - uncaught_exceptions::main
at C:\Users\tokgeo\source\repos\uncaught_exceptions\src\main.rs:10
32: 0x7ff71a9f144b - core::ops::function::FnOnce::call_once<void (*)(),tuple$<> >
at C:\Users\tokgeo\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\core\src\ops\function.rs:250
33: 0x7ff71a9f100e - core::hint::black_box
at C:\Users\tokgeo\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\core\src\hint.rs:482
34: 0x7ff71a9f100e - std::sys::backtrace::__rust_begin_short_backtrace<void (*)(),tuple$<> >
at C:\Users\tokgeo\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\std\src\sys\backtrace.rs:152
35: 0x7ff71a9f1181 - std::rt::lang_start::closure$0<tuple$<> >
at C:\Users\tokgeo\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\std\src\rt.rs:199
36: 0x7ff71a9f315c - std::rt::lang_start_internal::closure$0
at /rustc/6b00bc3880198600130e1cf62b8f8a93494488cc/library\std\src\rt.rs:168
37: 0x7ff71a9f315c - std::panicking::try::do_call
at /rustc/6b00bc3880198600130e1cf62b8f8a93494488cc/library\std\src\panicking.rs:589
38: 0x7ff71a9f315c - std::panicking::try
at /rustc/6b00bc3880198600130e1cf62b8f8a93494488cc/library\std\src\panicking.rs:552
39: 0x7ff71a9f315c - std::panic::catch_unwind
at /rustc/6b00bc3880198600130e1cf62b8f8a93494488cc/library\std\src\panic.rs:359
40: 0x7ff71a9f315c - std::rt::lang_start_internal
at /rustc/6b00bc3880198600130e1cf62b8f8a93494488cc/library\std\src\rt.rs:164
41: 0x7ff71a9f116a - std::rt::lang_start<tuple$<> >
at C:\Users\tokgeo\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\std\src\rt.rs:198
42: 0x7ff71a9f1419 - main
43: 0x7ff71aa04a68 - invoke_main
at D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:78
44: 0x7ff71aa04a68 - __scrt_common_main_seh
at D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288
45: 0x7ffe6296e8d7 - BaseThreadInitThunk
46: 0x7ffe635bc5dc - RtlUserThreadStart
thread 'main' panicked at library\panic_unwind\src\seh.rs:289:8:
Rust panics cannot be copied
stack backtrace:
0: 0x7ff71a9f6762 - std::backtrace_rs::backtrace::win64::trace
at /rustc/6b00bc3880198600130e1cf62b8f8a93494488cc/library\std\src\..\..\backtrace\src\backtrace\win64.rs:85
1: 0x7ff71a9f6762 - std::backtrace_rs::backtrace::trace_unsynchronized
at /rustc/6b00bc3880198600130e1cf62b8f8a93494488cc/library\std\src\..\..\backtrace\src\backtrace\mod.rs:66
2: 0x7ff71a9f6762 - std::sys::backtrace::_print_fmt
at /rustc/6b00bc3880198600130e1cf62b8f8a93494488cc/library\std\src\sys\backtrace.rs:66
3: 0x7ff71a9f6762 - std::sys::backtrace::impl$0::print::impl$0::fmt
at /rustc/6b00bc3880198600130e1cf62b8f8a93494488cc/library\std\src\sys\backtrace.rs:39
4: 0x7ff71aa016cb - core::fmt::rt::Argument::fmt
at /rustc/6b00bc3880198600130e1cf62b8f8a93494488cc/library\core\src\fmt\rt.rs:181
5: 0x7ff71aa016cb - core::fmt::write
at /rustc/6b00bc3880198600130e1cf62b8f8a93494488cc/library\core\src\fmt\mod.rs:1446
6: 0x7ff71a9f4e57 - std::io::default_write_fmt
at /rustc/6b00bc3880198600130e1cf62b8f8a93494488cc/library\std\src\io\mod.rs:639
7: 0x7ff71a9f4e57 - std::io::Write::write_fmt<std::sys::stdio::windows::Stderr>
at /rustc/6b00bc3880198600130e1cf62b8f8a93494488cc/library\std\src\io\mod.rs:1914
8: 0x7ff71a9f65a5 - std::sys::backtrace::BacktraceLock::print
at /rustc/6b00bc3880198600130e1cf62b8f8a93494488cc/library\std\src\sys\backtrace.rs:42
9: 0x7ff71a9f7a2c - std::panicking::default_hook::closure$0
at /rustc/6b00bc3880198600130e1cf62b8f8a93494488cc/library\std\src\panicking.rs:300
10: 0x7ff71a9f77c2 - std::panicking::default_hook
at /rustc/6b00bc3880198600130e1cf62b8f8a93494488cc/library\std\src\panicking.rs:327
11: 0x7ff71a9f851f - std::panicking::rust_panic_with_hook
at /rustc/6b00bc3880198600130e1cf62b8f8a93494488cc/library\std\src\panicking.rs:833
12: 0x7ff71a9f8372 - std::panicking::begin_panic_handler::closure$0
at /rustc/6b00bc3880198600130e1cf62b8f8a93494488cc/library\std\src\panicking.rs:699
13: 0x7ff71a9f6e5f - std::sys::backtrace::__rust_end_short_backtrace<std::panicking::begin_panic_handler::closure_env$0,never$>
at /rustc/6b00bc3880198600130e1cf62b8f8a93494488cc/library\std\src\sys\backtrace.rs:168
14: 0x7ff71a9f7fae - std::panicking::begin_panic_handler
at /rustc/6b00bc3880198600130e1cf62b8f8a93494488cc/library\std\src\panicking.rs:697
15: 0x7ff71aa06161 - core::panicking::panic_fmt
at /rustc/6b00bc3880198600130e1cf62b8f8a93494488cc/library\core\src\panicking.rs:75
16: 0x7ff71aa0604c - panic_unwind::imp::exception_copy
at /rustc/6b00bc3880198600130e1cf62b8f8a93494488cc/library\panic_unwind\src\seh.rs:281
17: 0x7ffe1f55228e - <unknown>
18: 0x7ffe1f59e651 - std::basic_ostream<wchar_t,std::char_traits<wchar_t> >::write
19: 0x7ffe4cd541d0 - _CxxFrameHandler4
20: 0x7ffe4cd5258f - <unknown>
21: 0x7ffe63646c56 - RtlCaptureContext2
22: 0x7ffe1f55200c - <unknown>
23: 0x7ffe1f552511 - __ExceptionPtrCurrentException
24: 0x7ff71aa04842 - std::current_exception
at C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\include\exception:318
25: 0x7ff71aa066a6 - cpp_exception_foo$catch$0
at C:\Users\tokgeo\source\repos\uncaught_exceptions\src\main.cpp:12
26: 0x7ffe4cd541d0 - _CxxFrameHandler4
27: 0x7ffe4cd5258f - <unknown>
28: 0x7ffe63646c56 - RtlCaptureContext2
29: 0x7ff71aa047ad - cpp_exception_foo
at C:\Users\tokgeo\source\repos\uncaught_exceptions\src\main.cpp:8
30: 0x7ff71a9f11a0 - uncaught_exceptions::main::closure$0
at C:\Users\tokgeo\source\repos\uncaught_exceptions\src\main.rs:10
31: 0x7ff71a9f1318 - std::panicking::try::do_call<uncaught_exceptions::main::closure_env$0,tuple$<> >
at C:\Users\tokgeo\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\std\src\panicking.rs:589
32: 0x7ff71a9f10b3 - std::panic::catch_unwind<uncaught_exceptions::main::closure_env$0,tuple$<> >
33: 0x7ff71a9f1046 - std::panicking::try
at C:\Users\tokgeo\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\std\src\panicking.rs:552
34: 0x7ff71a9f1046 - std::panic::catch_unwind<uncaught_exceptions::main::closure_env$0,tuple$<> >
at C:\Users\tokgeo\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\std\src\panic.rs:359
35: 0x7ff71a9f13d9 - uncaught_exceptions::main
at C:\Users\tokgeo\source\repos\uncaught_exceptions\src\main.rs:10
36: 0x7ff71a9f144b - core::ops::function::FnOnce::call_once<void (*)(),tuple$<> >
at C:\Users\tokgeo\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\core\src\ops\function.rs:250
37: 0x7ff71a9f100e - core::hint::black_box
at C:\Users\tokgeo\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\core\src\hint.rs:482
38: 0x7ff71a9f100e - std::sys::backtrace::__rust_begin_short_backtrace<void (*)(),tuple$<> >
at C:\Users\tokgeo\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\std\src\sys\backtrace.rs:152
39: 0x7ff71a9f1181 - std::rt::lang_start::closure$0<tuple$<> >
at C:\Users\tokgeo\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\std\src\rt.rs:199
40: 0x7ff71a9f315c - std::rt::lang_start_internal::closure$0
at /rustc/6b00bc3880198600130e1cf62b8f8a93494488cc/library\std\src\rt.rs:168
41: 0x7ff71a9f315c - std::panicking::try::do_call
at /rustc/6b00bc3880198600130e1cf62b8f8a93494488cc/library\std\src\panicking.rs:589
42: 0x7ff71a9f315c - std::panicking::try
at /rustc/6b00bc3880198600130e1cf62b8f8a93494488cc/library\std\src\panicking.rs:552
43: 0x7ff71a9f315c - std::panic::catch_unwind
at /rustc/6b00bc3880198600130e1cf62b8f8a93494488cc/library\std\src\panic.rs:359
44: 0x7ff71a9f315c - std::rt::lang_start_internal
at /rustc/6b00bc3880198600130e1cf62b8f8a93494488cc/library\std\src\rt.rs:164
45: 0x7ff71a9f116a - std::rt::lang_start<tuple$<> >
at C:\Users\tokgeo\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\std\src\rt.rs:198
46: 0x7ff71a9f1419 - main
47: 0x7ff71aa04a68 - invoke_main
at D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:78
48: 0x7ff71aa04a68 - __scrt_common_main_seh
at D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288
49: 0x7ffe6296e8d7 - BaseThreadInitThunk
50: 0x7ffe635bc5dc - RtlUserThreadStart
fatal runtime error: Rust panics must be rethrown, aborting
error: process didn't exit successfully: `target\debug\uncaught_exceptions.exe` (exit code: 0xc0000409, STATUS_STACK_BUFFER_OVERRUN)