This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of NAD status.

### 1265. `longjmp` and destructors

Section: 17.13 [support.runtime] Status: NAD Submitter: Sean Hunt Opened: 2009-11-16 Last modified: 2016-01-28

Priority: Not Prioritized

View all other issues in [support.runtime].

View all issues with NAD status.

Discussion:

17.13 [support.runtime]/4 says that `longjmp` is undefined if unwinding by the mechanism used by catch and throw would invoke any nontrivial destructors. However, the text as written is rather vague, in particular when dealing with `catch(...)`:

>     void foo() {
>       jump_buf buf;
>       non_trivial_dtor n1; // 1
>       if (!setjmp(buf)) {
>         non_trivial_dtor n2; // 2
>         try {
>           longjmp(buf, 1);
>         } catch (...) {
>         }
>       }
>     }

My interpretation of the meaning of 17.13 [support.runtime]/4 is that declaration 2, but not 1, would cause the `longjmp` to be undefined behavior. However, it's not entirely clear from the text. Arguably, replacing the `setjmp` and `longjmp` with `catch` would still cause the destructor for `n1` to be called after the unwinding, which would lead to undefined behavior. This is clearly not an intended consequence of the wording. However, it is probably still UB, as `n1` now has "indeterminate" value, and running its destructor on `foo`'s exit will cause Bad Things.

Declarations 2 has a more interesting issue. The `catch(...)` muddles up the definition that uses `throw` and `catch` - if `longjmp()` were indeed a `throw`, control would never return to the `setjmp`. As such, `n2`'s destructor wouldn't be called (except by the argument for `n1`, which is that the destructor would be called later as the frame was left in the normal control flow).

I suggest that paragraph 4 of 17.13 [support.runtime] should be replaced with the following, or something that reads better but has the same effect:

> The function signature `longjmp(jmp_buf jbuf, int val)` has more restricted behavior in this International Standard. A call to `longjmp` has undefined behavior if any non-trivial destructors would be called were the `longjmp` call replaced with a throw-expression whose nearest matching handler were a (possibly imaginary) function-try-block on the function containing the corresponding `setjmp` call.

[ 2009-11-17 Moved to Tentatively NAD after 5 positive votes on c++std-lib. Rationale added below. ]

Proposed resolution:

Change 17.13 [support.runtime]/4:

> The function signature `longjmp(jmp_buf jbuf, int val)` has more restricted behavior in this International Standard. A `setjmp`/`longjmp` call pair has undefined behavior if replacing the `setjmp` and `longjmp` by `catch` and `throw` would invoke any non-trivial destructors for any automatic objects. A call to `longjmp` has undefined behavior if any non-trivial destructors would be called were the `longjmp` call replaced with a throw-expression whose nearest matching handler were a (possibly imaginary) function-try-block on the function containing the corresponding `setjmp` call.

Rationale:

In the given example, it is clear that it is only `n2` and not `n1` that is destroyed by the `longjmp`.

At this late stage in the standards process, we are focusing on issues that impact users or implementers. Trying to rewrite complex wording just for the sake of improved clarity is likely to do more harm than good.