Defect report - std::terminate

392 views
Skip to first unread message

Andrzej Krzemieński

unread,
Sep 25, 2011, 11:29:00 AM9/25/11
to
Hi,
In N3290,which is to become the official standard, in 18.8.3.4,
paragraph 1 reads

Remarks: Called by the implementation when exception handling must
be abandoned for any of several reasons (15.5.1), in effect
immediately after evaluating the throw-expression (18.8.3.1).
May also be called directly by the program.

It is not clear what is "in effect". It was clear in previous drafts
where paragraphs 1 and 2 read:

Called by the implementation when exception handling must be
abandoned
for any of several reasons (15.5.1). May also be called directly
by the
program.

Effects: Calls the terminate_handler function in effect
immediately
after evaluating the throw-expression (18.8.3.1), if called by the
implementation, or calls the current terminate_handler function,
if
called by the program.

It was changed by N3189. The same applies to function unexpected (D.
11.4, paragraph 1).

Assuming the previous wording is still intended, the wording can be
read
"unless std::terminate is called bythe program, we will use the
handler
that was in effect immediately after evaluating the throw-
expression"

This assumes that there is some throw-expression connected to every
situation that triggers the call to std::terminate. But this is not
the case:

In case std::thread is assigned to or destroyed while being joinable
there is no throw-expression involved.

In case std::uexpected is called by the program, std::terminate is
triggered by the implementation - no throw-expression involved.

In case a destructor throws during stack unwinding we have two throw-
expressions involved. Which one is referred to?

In case std::nested_exception::rethrow_nested is called for an object
that has captured no exception, there is no throw-expression involved
directly (and may no trow be involved even indirectly).

Next, 18.8.3.1, paragraph 2 says
"Required behavior: A terminate_handler shall terminate execution
of the
program without returning to the caller."

This seems to allow that the function may exit by throwing an
exception (because word "return" implies a normal return). One could
argue that words "terminate execution of the program" are sufficient,
but then why "without returning to the caller" would be mentioned. In
case such handler throws, noexcept specification in function
std::terminate is violated, and std::terminate would be called
recursively - should std::abort not be called in case of recursive
std::terminate call? On the other hand some controlled recursion could
be useful, like in the following technique:

http://cplusplus.co.il/2010/03/21/catching-uncaught-exceptions-within-terminate/

Regards,
&rzej


--
[ comp.std.c++ is moderated. To submit articles, try posting with your ]
[ newsreader. If that fails, use mailto:std-cpp...@vandevoorde.com ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]

Daniel Krügler

unread,
Sep 26, 2011, 11:59:32 AM9/26/11
to
Am 25.09.2011 17:29, schrieb Andrzej Krzemieński:
> Hi,
> In N3290,which is to become the official standard, in 18.8.3.4,
> paragraph 1 reads
>
> Remarks: Called by the implementation when exception handling must
> be abandoned for any of several reasons (15.5.1), in effect
> immediately after evaluating the throw-expression (18.8.3.1).
> May also be called directly by the program.
>
> It is not clear what is "in effect". It was clear in previous drafts
> where paragraphs 1 and 2 read:
>
> Called by the implementation when exception handling must be
> abandoned
> for any of several reasons (15.5.1). May also be called directly
> by the
> program.
>
> Effects: Calls the terminate_handler function in effect
> immediately
> after evaluating the throw-expression (18.8.3.1), if called by the
> implementation, or calls the current terminate_handler function,
> if
> called by the program.
>
> It was changed by N3189. The same applies to function unexpected (D.
> 11.4, paragraph 1).

The here mentioned wording changes by N3189 were done for a better
separation of effects (Effects element) and additional normative wording
explanations (Remarks element), there was no meaning change intended.

> Assuming the previous wording is still intended, the wording can be
> read
> "unless std::terminate is called bythe program, we will use the
> handler
> that was in effect immediately after evaluating the throw-
> expression"

Yes, I believe this is a defect already existing in the previous
wording, which was not updated when further situations where defined,
when std::terminate where supposed to be called by the implementation. I
just recognize that the quoted reference (18.8.3.1) was incorrectly
moved and need to be part of the effects element where it refers to the
current terminate_handler function.

> This assumes that there is some throw-expression connected to every
> situation that triggers the call to std::terminate. But this is not
> the case:
>
> In case std::thread is assigned to or destroyed while being joinable
> there is no throw-expression involved.
>
> In case std::uexpected is called by the program, std::terminate is
> triggered by the implementation - no throw-expression involved.
>
> In case a destructor throws during stack unwinding we have two throw-
> expressions involved. Which one is referred to?
>
> In case std::nested_exception::rethrow_nested is called for an object
> that has captured no exception, there is no throw-expression involved
> directly (and may no trow be involved even indirectly).

I agree that the wording state should be changed to honor the other
situations as well. My current impression is that the part

"in effect immediately after evaluating the throw-expression"

should be removed and the reference to (18.8.3.1) should be moved just after

"Effects: Calls the current terminate_handler function."

> Next, 18.8.3.1, paragraph 2 says
> "Required behavior: A terminate_handler shall terminate execution
> of the
> program without returning to the caller."
>
> This seems to allow that the function may exit by throwing an
> exception (because word "return" implies a normal return).

It wouldn't harm to clarify that the function shall not exit via an
exception, but I think the current wording is pretty clear as it is.

> One could
> argue that words "terminate execution of the program" are sufficient,
> but then why "without returning to the caller" would be mentioned. In
> case such handler throws, noexcept specification in function
> std::terminate is violated, and std::terminate would be called
> recursively - should std::abort not be called in case of recursive
> std::terminate call? On the other hand some controlled recursion could
> be useful, like in the following technique:
>
> http://cplusplus.co.il/2010/03/21/catching-uncaught-exceptions-within-terminate/

I don't consider this a good idiom, IMO you should simply use
std::current_exception() within the terminate handler for this purpose
(15.3 p7 seems to provide the necessary guarantees for this):

void our_terminate (void) {
std::exception_ptr p = std::current_exception();
if (p) {
... // OK to rethrow and to determine it's nature
} else {
... // Do something else
}
}

HTH& Greetings from Bremen,

Daniel Krügler

Daniel Krügler

unread,
Sep 27, 2011, 2:16:14 PM9/27/11
to
Am 26.09.2011 17:59, schrieb Daniel Krügler:
> Am 25.09.2011 17:29, schrieb Andrzej Krzemieński:
>> Next, 18.8.3.1, paragraph 2 says
>> "Required behavior: A terminate_handler shall terminate execution
>> of the
>> program without returning to the caller."
>>
>> This seems to allow that the function may exit by throwing an
>> exception (because word "return" implies a normal return).
>
> It wouldn't harm to clarify that the function shall not exit via an
> exception, but I think the current wording is pretty clear as it is.

I withdraw this interpretation, I would say that the wording allows an
exception to leave the terminate handler and it is OK this way. I still
think that your suggested idiom is not so reasonable given the less
fragile idiom based on std::exception_ptr() evaluation without any
further roundtrip to terminate again.

Reply all
Reply to author
Forward
0 new messages