Skip to content

Rust panics over FFI break std::exception_ptr on Windows #143623

Closed
@Fulgen301

Description

@Fulgen301

On Windows, Rust panics are implemented by assembling a C++ exception object and throwing it via _CxxThrowException.

fn _CxxThrowException(pExceptionObject: *mut c_void, pThrowInfo: *mut u8) -> !;

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.

// The exception_copy function is a bit special here: it is invoked by the MSVC
// runtime under a try/catch block and the panic that we generate here will be
// used as the result of the exception copy. This is used by the C++ runtime to
// support capturing exceptions with std::exception_ptr, which we can't support
// because Box<dyn Any> isn't clonable.

...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)

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-panicArea: Panicking machineryC-bugCategory: This is a bug.O-windowsOperating system: WindowsT-libsRelevant to the library team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions