rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
98.38k stars 12.72k forks source link

Permitting "foreign" languages to dispose of Rust panics #130369

Open BatmanAoD opened 1 month ago

BatmanAoD commented 1 month ago

It is currently undefined behavior for a "foreign" language (such as C++) to catch a Rust panic, regardless of what the "foreign" code then does with the exception. That is, either disposing of or rethrowing the panic are both unconditional undefined behavior.

Permitting other languages to rethrow the panic, and permitting them to dispose of the panic, are separate "features" Rust could provide. This issue is only for safe disposal.

Note that Rust can document a function that a different runtime must call in order to safely dispose of a Rust panic. Per @chorman0773, Itanium specifies this cross-language mechanism this way:

[the runtime catching the exception is] supposed to call the unwind_cleanup function stored in the _Unwind_Exception struct with _URC_FOREIGN_EXCEPTION_CAUGHT.

Currently, the main thing that the Rust runtime would need to do when notified that a panic has been disposed of by a foreign runtime is to decrement the panic count. @bjorn3, @nbdd0121, @workingjubilee, and @Amanieu may have additional context on what would be required for foreign languages to safely dispose of Rust panics.

Original discussion: https://github.com/rust-lang/reference/pull/1226#discussion_r1739926327

CC @rust-lang/libs-api ; CC @rust-lang/lang

RalfJung commented 1 month ago

Cc @rust-lang/opsem

Itanium specifies this cross-language mechanism this way:

(It's exception_cleanup, not unwind_cleanup.)

We currently set exception_cleanup to this function

https://github.com/rust-lang/rust/blob/ec0e16a66571458dc5c296ccfa5e4d8bdcc2a2a8/library/std/src/panicking.rs#L56-L58

So, we actually do something well-defined, though the error message one gets is probably a bit confusing.

RalfJung commented 1 month ago

In fact we even have a comment saying that this message is confusing :joy:

https://github.com/rust-lang/rust/blob/125b26acf6f3127ecdd344c372691cefe0e9243e/library/panic_unwind/src/gcc.rs#L97-L100

So we except "foreign Rust runtimes" from the confusion, but if the unwind gets caught by a foreign non-Rust runtime we continue to show the confusing error.

BatmanAoD commented 1 month ago

Okay, so we should document that we expect foreign runtimes to call this if they catch a panic, and that the effect is currently to abort but may change in the future?

Any suggestions for a less confusing panic message?

PatchMixolydic commented 1 month ago

Probably not great, but better than nothing: Rust panic caught by foreign runtime; cannot continue. aborting.

The message could also benefit from a short explanation of why the program cannot continue, even if it's just cannot continue safely/cannot continue soundly.

nbdd0121 commented 1 month ago

I think it's possible to implement it properly so a foreign runtime to catch Rust exception and resume normal execution, so I'd avoid "safely" or "soundly". It's just that it's not yet implemented.

RalfJung commented 1 month ago

"caught" is the wrong term here I think; this is called when a Rust panic is discarded by a foreign runtime.

discarding Rust panic in a foreign runtime is currently not supported; aborting

nbdd0121 commented 1 month ago

"Caught" is used in (Itanium ABI](https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html), e.g. _URC_FOREIGN_EXCEPTION_CAUGHT is the reason code given to cleanup function.

"Discarding" is also confusing IMO because it's not immediate clear how Rust panic is discarded when somebody writes try { ... } catch(...) {}.

Would Rust panics caught by a foreign runtime and not rethrown. This is not currently supported, aborting. be a more accurate way of describing? After all, only legal operations for a caught foreign exception is (1) rethrow (2) cleanup and (0) diverge.

RalfJung commented 1 month ago

"Caught" is used in (Itanium ABI](https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html), e.g. _URC_FOREIGN_EXCEPTION_CAUGHT is the reason code given to cleanup function.

Ah okay, I thought that term only applied in the "rethrow" case. Never mind then.

Amanieu commented 1 month ago

IMO we should just allow Rust panics to be caught and discarded by foreign code. The only thing we need to do is decrement the panic count in the cleanup function and everything should just work. Note that the panic count specifically only counts the number of active Rust panics (for the current Rust runtime, in case there are multiple in the address space).

Nothing needs to be done for foreign code re-throwing a Rust panic since that just acts like the catch never happened in the first place.