public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug c++/97720] New: Sometimes std::current_exception does not work properly in the terminate handler
@ 2020-11-04 20:54 m101010a at gmail dot com
2020-11-04 21:20 ` [Bug c++/97720] " redi at gcc dot gnu.org
` (9 more replies)
0 siblings, 10 replies; 11+ messages in thread
From: m101010a at gmail dot com @ 2020-11-04 20:54 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97720
Bug ID: 97720
Summary: Sometimes std::current_exception does not work
properly in the terminate handler
Product: gcc
Version: 10.2.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c++
Assignee: unassigned at gcc dot gnu.org
Reporter: m101010a at gmail dot com
Target Milestone: ---
$ g++ -v
Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: /build/gcc/src/gcc/configure --prefix=/usr --libdir=/usr/lib
--libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info
--with-bugurl=https://bugs.archlinux.org/
--enable-languages=c,c++,ada,fortran,go,lto,objc,obj-c++,d --with-isl
--with-linker-hash-style=gnu --with-system-zlib --enable-__cxa_atexit
--enable-cet=auto --enable-checking=release --enable-clocale=gnu
--enable-default-pie --enable-default-ssp --enable-gnu-indirect-function
--enable-gnu-unique-object --enable-install-libiberty --enable-linker-build-id
--enable-lto --enable-multilib --enable-plugin --enable-shared
--enable-threads=posix --disable-libssp --disable-libstdcxx-pch
--disable-libunwind-exceptions --disable-werror
gdc_include_dir=/usr/include/dlang/gdc
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 10.2.0 (GCC)
$ cat x.cpp
#include <iostream>
struct has_destructor {
~has_destructor();
};
void do_nothing();
inline int throwing_function() {
#ifdef DESTRUCTOR
has_destructor hd;
#endif
throw "";
}
class C {
public:
C() noexcept;
~C();
};
C::C() noexcept {throwing_function();}
inline C::~C() { do_nothing(); }
static void term_handler() {
const char *f = "Died without exception\n";
auto e = std::current_exception();
if (e)
f = "Died with exception\n";
std::cout << f << std::flush;
quick_exit(0);
}
int main() {
std::set_terminate(&term_handler);
C{};
}
$ cat y.cpp
struct has_destructor {
~has_destructor();
};
void do_nothing();
has_destructor::~has_destructor() = default;
void do_nothing() {}
$ g++ x.cpp y.cpp -O1
$ ./a.out
Died with exception
$ g++ -DDESTRUCTOR x.cpp y.cpp -O1
$ ./a.out
Died without exception
$
This bug is very sensitive to small changes. For example, it will correctly
get the exception_ptr when compiling with -O0 or -O2, or if C's constructor is
inline, or if C's destructor is not inline. This is probably the underlying
cause of bug 97339.
^ permalink raw reply [flat|nested] 11+ messages in thread
* [Bug c++/97720] Sometimes std::current_exception does not work properly in the terminate handler
2020-11-04 20:54 [Bug c++/97720] New: Sometimes std::current_exception does not work properly in the terminate handler m101010a at gmail dot com
@ 2020-11-04 21:20 ` redi at gcc dot gnu.org
2020-11-05 2:02 ` m101010a at gmail dot com
` (8 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: redi at gcc dot gnu.org @ 2020-11-04 21:20 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97720
Jonathan Wakely <redi at gcc dot gnu.org> changed:
What |Removed |Added
----------------------------------------------------------------------------
See Also| |https://gcc.gnu.org/bugzill
| |a/show_bug.cgi?id=97339
--- Comment #1 from Jonathan Wakely <redi at gcc dot gnu.org> ---
I'm not sure if this is a bug. I think when the compiler can see there is no
matching handler for the exception, it doesn't perform stack unwinding, it just
calls std::terminate without throwing anything.
When the destructor is there, it unwinds (because that destructor might have
important side effects that the user relies on) by throwing an exception.
^ permalink raw reply [flat|nested] 11+ messages in thread
* [Bug c++/97720] Sometimes std::current_exception does not work properly in the terminate handler
2020-11-04 20:54 [Bug c++/97720] New: Sometimes std::current_exception does not work properly in the terminate handler m101010a at gmail dot com
2020-11-04 21:20 ` [Bug c++/97720] " redi at gcc dot gnu.org
@ 2020-11-05 2:02 ` m101010a at gmail dot com
2022-12-16 16:52 ` m101010a at gmail dot com
` (7 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: m101010a at gmail dot com @ 2020-11-05 2:02 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97720
--- Comment #2 from m101010a at gmail dot com ---
> when the compiler can see there is no matching handler for the exception,
> it doesn't perform stack unwinding
This is fine, it's implementation-defined whether the stack is unwound.
> it just calls std::terminate without throwing anything.
This is not fine. According to N4868 there is an implicit exception handler
active when std::terminate is called due to a throw (14.4/7), and
std::current_exception returns the currently handled exception (17.9.7/8). So
even if the compiler is going to optimize the throw to a call to terminate it
still needs to behave as if something is being thrown. This interpretation is
corroborated by comments from MSVC devs in a similar bug: see
https://developercommunity.visualstudio.com/comments/305900/view.html and
https://developercommunity.visualstudio.com/comments/579784/view.html
Also I just looked at the assembly, and it still calls __cxa_throw, even in
cases where it warns that the throw will always terminate:
https://godbolt.org/z/9hja8r . Between that and how very small changes cause
the test program to report the exception in the terminate handler, this doesn't
look like intentional behavior.
^ permalink raw reply [flat|nested] 11+ messages in thread
* [Bug c++/97720] Sometimes std::current_exception does not work properly in the terminate handler
2020-11-04 20:54 [Bug c++/97720] New: Sometimes std::current_exception does not work properly in the terminate handler m101010a at gmail dot com
2020-11-04 21:20 ` [Bug c++/97720] " redi at gcc dot gnu.org
2020-11-05 2:02 ` m101010a at gmail dot com
@ 2022-12-16 16:52 ` m101010a at gmail dot com
2023-05-22 21:34 ` [Bug c++/97720] throw in try in noexcept fn calls terminate without handling the exception jason at gcc dot gnu.org
` (6 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: m101010a at gmail dot com @ 2022-12-16 16:52 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97720
--- Comment #3 from m101010a at gmail dot com ---
After looking into this more, I have confirmed that this is definitely the
cause of bug 97339, and found a simpler reproduction in bug 55918 comment #4:
#include <iostream>
class Foo
{
public:
Foo() { std::cout << "Foo::Foo()\n"; }
~Foo() { std::cout << "Foo::~Foo()\n"; }
};
void bad_guy() noexcept {
try {
Foo foo;
throw 0;
} catch (float) {
// Don't catch int.
}
}
void level1() {
bad_guy();
throw "dead code";
}
int main() {
try {
level1();
} catch (int) {
}
}
^ permalink raw reply [flat|nested] 11+ messages in thread
* [Bug c++/97720] throw in try in noexcept fn calls terminate without handling the exception
2020-11-04 20:54 [Bug c++/97720] New: Sometimes std::current_exception does not work properly in the terminate handler m101010a at gmail dot com
` (2 preceding siblings ...)
2022-12-16 16:52 ` m101010a at gmail dot com
@ 2023-05-22 21:34 ` jason at gcc dot gnu.org
2023-05-23 3:52 ` jason at gcc dot gnu.org
` (5 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: jason at gcc dot gnu.org @ 2023-05-22 21:34 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97720
Jason Merrill <jason at gcc dot gnu.org> changed:
What |Removed |Added
----------------------------------------------------------------------------
Ever confirmed|0 |1
Last reconfirmed| |2023-05-22
Summary|Sometimes |throw in try in noexcept fn
|std::current_exception does |calls terminate without
|not work properly in the |handling the exception
|terminate handler |
Status|UNCONFIRMED |NEW
CC| |jason at gcc dot gnu.org
--- Comment #4 from Jason Merrill <jason at gcc dot gnu.org> ---
Yes. https://eel.is/c++draft/except#handle-7 : "Also, an implicit handler is
considered active when the function std::terminate is entered due to a
throw."
This is handled properly for the case where there is no possible catch clause
between the call and the noexcept: in that case the call site has no EH landing
pad, so the personality function calls __cxa_call_terminate, which properly
handles the exception.
In the comment #3 case where there are catch clauses, we represent the noexcept
region around the catch as a cleanup. This also means that the phase 1 search
for a handler looks past it rather than properly recognizing that we found a
(terminating) handler. And we call std::terminate directly rather than through
__cxa_call_terminate, so indeed std::current_exception is wrong.
I assume the optimization sensitivity the original testcase is seeing is due to
inlining changing whether a particular call falls into the first or second case
above.
It looks like Clang represents the second case roughly as catch (...) {
std::terminate(); }
It seems to me that it would be superior to represent the second case in the
action table as an empty exception specification like C++98 throw(), but in the
generated code hand off to __cxa_call_terminate rather than
__cxa_call_unexpected. Representing it that way rather than catch(...) would
work better for PR88218 and PR55918.
^ permalink raw reply [flat|nested] 11+ messages in thread
* [Bug c++/97720] throw in try in noexcept fn calls terminate without handling the exception
2020-11-04 20:54 [Bug c++/97720] New: Sometimes std::current_exception does not work properly in the terminate handler m101010a at gmail dot com
` (3 preceding siblings ...)
2023-05-22 21:34 ` [Bug c++/97720] throw in try in noexcept fn calls terminate without handling the exception jason at gcc dot gnu.org
@ 2023-05-23 3:52 ` jason at gcc dot gnu.org
2023-05-23 17:20 ` m101010a at gmail dot com
` (4 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: jason at gcc dot gnu.org @ 2023-05-23 3:52 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97720
--- Comment #5 from Jason Merrill <jason at gcc dot gnu.org> ---
Note that Foo is unneeded, this shows the same behavior:
void bad_guy() throw() {
try { throw 0; }
catch (float) { }
// Don't catch int.
}
void level1() {
bad_guy();
throw "dead code";
}
int main() {
try { level1(); }
catch (int) { }
}
// terminate called without an active exception
Without the throw "dead code" the compiler optimizes away the catch in main, so
the handler search finds nothing, so __cxa_throw calls __cxa_call_terminate and
std::current_exception is set properly.
But of course the catch in main shouldn't make a difference, the search should
never leave bad_guy.
^ permalink raw reply [flat|nested] 11+ messages in thread
* [Bug c++/97720] throw in try in noexcept fn calls terminate without handling the exception
2020-11-04 20:54 [Bug c++/97720] New: Sometimes std::current_exception does not work properly in the terminate handler m101010a at gmail dot com
` (4 preceding siblings ...)
2023-05-23 3:52 ` jason at gcc dot gnu.org
@ 2023-05-23 17:20 ` m101010a at gmail dot com
2023-06-04 1:49 ` cvs-commit at gcc dot gnu.org
` (3 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: m101010a at gmail dot com @ 2023-05-23 17:20 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97720
--- Comment #6 from m101010a at gmail dot com ---
> represent the second case in the action table as an empty exception specification like C++98 throw()
That will deal with this issue and PR88218, but won't solve PR55918 since using
throw() causes the stack to unwind. I don't believe there's a way to solve
PR55918 without modifying the personality function in some way; if terminate is
called in the handler then we're already in phase 2, which means the stack has
already been unwound.
^ permalink raw reply [flat|nested] 11+ messages in thread
* [Bug c++/97720] throw in try in noexcept fn calls terminate without handling the exception
2020-11-04 20:54 [Bug c++/97720] New: Sometimes std::current_exception does not work properly in the terminate handler m101010a at gmail dot com
` (5 preceding siblings ...)
2023-05-23 17:20 ` m101010a at gmail dot com
@ 2023-06-04 1:49 ` cvs-commit at gcc dot gnu.org
2023-06-04 2:08 ` jason at gcc dot gnu.org
` (2 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: cvs-commit at gcc dot gnu.org @ 2023-06-04 1:49 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97720
--- Comment #7 from CVS Commits <cvs-commit at gcc dot gnu.org> ---
The trunk branch has been updated by Jason Merrill <jason@gcc.gnu.org>:
https://gcc.gnu.org/g:2415024e0f81f8c09bf08f947c790b43de9d0bbc
commit r14-1527-g2415024e0f81f8c09bf08f947c790b43de9d0bbc
Author: Jason Merrill <jason@redhat.com>
Date: Tue May 23 12:25:15 2023 -0400
c++: use __cxa_call_terminate for MUST_NOT_THROW [PR97720]
[except.handle]/7 says that when we enter std::terminate due to a throw,
that is considered an active handler. We already implemented that properly
for the case of not finding a handler (__cxa_throw calls __cxa_begin_catch
before std::terminate) and the case of finding a callsite with no landing
pad (the personality function calls __cxa_call_terminate which calls
__cxa_begin_catch), but for the case of a throw in a try/catch in a
noexcept
function, we were emitting a cleanup that calls std::terminate directly
without ever calling __cxa_begin_catch to handle the exception.
A straightforward way to fix this seems to be calling __cxa_call_terminate
instead. However, that requires exporting it from libstdc++, which we have
not previously done. Despite the name, it isn't actually part of the ABI
standard. Nor is __cxa_call_unexpected, as far as I can tell, but that one
is also used by clang. For this case they use __clang_call_terminate; it
seems reasonable to me for us to stick with __cxa_call_terminate.
I also change __cxa_call_terminate to take void* for simplicity in the
front
end (and consistency with __cxa_call_unexpected) but that isn't necessary
if
it's undesirable for some reason.
This patch does not fix the issue that representing the noexcept as a
cleanup is wrong, and confuses the handler search; since it looks like a
cleanup in the EH tables, the unwinder keeps looking until it finds the
catch in main(), which it should never have gotten to. Without the
try/catch in main, the unwinder would reach the end of the stack and say no
handler was found. The noexcept is a handler, and should be treated as
one,
as it is when the landing pad is omitted.
The best fix for that issue seems to me to be to represent an
ERT_MUST_NOT_THROW after an ERT_TRY in an action list as though it were an
ERT_ALLOWED_EXCEPTIONS (since indeed it is an exception-specification).
The
actual code generation shouldn't need to change (apart from the change made
by this patch), only the action table entry.
PR c++/97720
gcc/cp/ChangeLog:
* cp-tree.h (enum cp_tree_index): Add CPTI_CALL_TERMINATE_FN.
(call_terminate_fn): New macro.
* cp-gimplify.cc (gimplify_must_not_throw_expr): Use it.
* except.cc (init_exception_processing): Set it.
(cp_protect_cleanup_actions): Return it.
gcc/ChangeLog:
* tree-eh.cc (lower_resx): Pass the exception pointer to the
failure_decl.
* except.h: Tweak comment.
libstdc++-v3/ChangeLog:
* libsupc++/eh_call.cc (__cxa_call_terminate): Take void*.
* config/abi/pre/gnu.ver: Add it.
gcc/testsuite/ChangeLog:
* g++.dg/eh/terminate2.C: New test.
^ permalink raw reply [flat|nested] 11+ messages in thread
* [Bug c++/97720] throw in try in noexcept fn calls terminate without handling the exception
2020-11-04 20:54 [Bug c++/97720] New: Sometimes std::current_exception does not work properly in the terminate handler m101010a at gmail dot com
` (6 preceding siblings ...)
2023-06-04 1:49 ` cvs-commit at gcc dot gnu.org
@ 2023-06-04 2:08 ` jason at gcc dot gnu.org
2023-06-04 2:11 ` jason at gcc dot gnu.org
2024-05-07 7:39 ` rguenth at gcc dot gnu.org
9 siblings, 0 replies; 11+ messages in thread
From: jason at gcc dot gnu.org @ 2023-06-04 2:08 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97720
--- Comment #8 from Jason Merrill <jason at gcc dot gnu.org> ---
*** Bug 97339 has been marked as a duplicate of this bug. ***
^ permalink raw reply [flat|nested] 11+ messages in thread
* [Bug c++/97720] throw in try in noexcept fn calls terminate without handling the exception
2020-11-04 20:54 [Bug c++/97720] New: Sometimes std::current_exception does not work properly in the terminate handler m101010a at gmail dot com
` (7 preceding siblings ...)
2023-06-04 2:08 ` jason at gcc dot gnu.org
@ 2023-06-04 2:11 ` jason at gcc dot gnu.org
2024-05-07 7:39 ` rguenth at gcc dot gnu.org
9 siblings, 0 replies; 11+ messages in thread
From: jason at gcc dot gnu.org @ 2023-06-04 2:11 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97720
Jason Merrill <jason at gcc dot gnu.org> changed:
What |Removed |Added
----------------------------------------------------------------------------
Depends on|95741 |
Status|NEW |ASSIGNED
Target Milestone|--- |14.0
Assignee|unassigned at gcc dot gnu.org |jason at gcc dot gnu.org
See Also| |https://gcc.gnu.org/bugzill
| |a/show_bug.cgi?id=95741
--- Comment #9 from Jason Merrill <jason at gcc dot gnu.org> ---
(In reply to m101010a from comment #6)
> I don't believe there's a way to solve PR55918 without modifying the
> personality function in some way
I agree; for C++17 (when dynamic exception specifications were removed) and
later we could use an alternate personality function that knows that an
exception-specification is noexcept, so we can just call terminate.
Referenced Bugs:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95741
[Bug 95741] Optimization skips destructor and calls terminate directly
^ permalink raw reply [flat|nested] 11+ messages in thread
* [Bug c++/97720] throw in try in noexcept fn calls terminate without handling the exception
2020-11-04 20:54 [Bug c++/97720] New: Sometimes std::current_exception does not work properly in the terminate handler m101010a at gmail dot com
` (8 preceding siblings ...)
2023-06-04 2:11 ` jason at gcc dot gnu.org
@ 2024-05-07 7:39 ` rguenth at gcc dot gnu.org
9 siblings, 0 replies; 11+ messages in thread
From: rguenth at gcc dot gnu.org @ 2024-05-07 7:39 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97720
Richard Biener <rguenth at gcc dot gnu.org> changed:
What |Removed |Added
----------------------------------------------------------------------------
Target Milestone|14.0 |14.2
--- Comment #10 from Richard Biener <rguenth at gcc dot gnu.org> ---
GCC 14.1 is being released, retargeting bugs to GCC 14.2.
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2024-05-07 7:39 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-11-04 20:54 [Bug c++/97720] New: Sometimes std::current_exception does not work properly in the terminate handler m101010a at gmail dot com
2020-11-04 21:20 ` [Bug c++/97720] " redi at gcc dot gnu.org
2020-11-05 2:02 ` m101010a at gmail dot com
2022-12-16 16:52 ` m101010a at gmail dot com
2023-05-22 21:34 ` [Bug c++/97720] throw in try in noexcept fn calls terminate without handling the exception jason at gcc dot gnu.org
2023-05-23 3:52 ` jason at gcc dot gnu.org
2023-05-23 17:20 ` m101010a at gmail dot com
2023-06-04 1:49 ` cvs-commit at gcc dot gnu.org
2023-06-04 2:08 ` jason at gcc dot gnu.org
2023-06-04 2:11 ` jason at gcc dot gnu.org
2024-05-07 7:39 ` rguenth at gcc dot gnu.org
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).