Skip to content
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

Rules for nesting foreign exceptions are unclear #145

Open
CAD97 opened this issue Jul 16, 2022 · 0 comments
Open

Rules for nesting foreign exceptions are unclear #145

CAD97 opened this issue Jul 16, 2022 · 0 comments

Comments

@CAD97
Copy link

CAD97 commented Jul 16, 2022

Concerning just the level 1 base [ABI-EH]. I haven't consulted the [psABI] directly, and perhaps it offers clarifications when interpreted together with [ABI-EH], but [ABI-EH] should ideally be sufficient on its own to use the unwinding runtime.

§1.2 Data Structures; Exception Header; exception_cleanup

_URC_FOREIGN_EXCEPTION_CAUGHT = 1: This indicates that a different runtime caught this exception. Nested foreign exceptions, or rethrowing a foreign exception, result in undefined behaviour. [source; emphasis mine]

§1.6.4 Rules for Correct Inter-Language Operation

The behavior is undefined in the following cases:

  • A __foreign_exception is active at the same time as another exception (either there is a nested exception while catching the foreign exception, or the foreign exception was itself nested). [source; emphasis mine]

This is unfortunately insufficiently clear at defining when an exception is considered nested, and at which operation behavior becomes undefined. There are at least three different scenarios:

  1. A personality routine is running for an exception of class $A$ and an exception of class $B$ is raised.
  2. A _URC_CONTINUE_UNWIND frame landing pad is running for an exception of class $A$ and an exception of class $B$ is raised.
  3. A _URC_HANDLER_FOUND frame landing pad is running for an exception of class $A$ and an exception of class $B$ is raised.

All three cases have the additional variable of if any intervening frame would register a handler for the newly raised exception, as well as if that handler is native or foreign to exception class $B$.

Case (1) of a personality routine raising an exception itself is likely problematic for other reasons.
In C++, case (2) results from a throw within a destructor where that destructor is run by a cleanup landing pad for the prior exception, and case (3) results from a throw within a catch clause where $A$ is foreign to the C++ runtime (and thus not yet handled).
In Rust, case (2) results from a panic! within a Drop::drop run by a cleanup landing pad where $A$ is not a Rust panic (that case would abort). Case (3) is impossible by construction; the catch equivalent does not run user code inside the handler landing pad.

I have one concrete ask for the specification: directly define when _Unwind_RaiseException is sound to call. By my reading, I think the answer is that _Unwind_RaiseException causes undefined behavior when

  • some exception $e$ of class $E$ has previously been raised; where
  • $e$ has not been passed to e->exception_cleanup or otherwise cleaned up by the defining runtime; and
  • the newly raised exception is not of class $E$.

_Unwind_RaiseException is sound to call when

  • The _Unwind_Exception fields have been initialized as described; and
  • the above is not the case.

This operationally defines the nesting of foreign exceptions which produces undefined behavior in a way such that the undefined behavior can be prevented.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant