From 47dd3543d36465496970406da03db5aecdc377ee Mon Sep 17 00:00:00 2001 From: Carlos O'Donell Date: Mon, 6 Jun 2016 14:20:58 -0400 Subject: Bug 20198: quick_exit should not call destructors. In C++11 18.5.12 says "Objects shall not be destroyed as a result of calling quick_exit." In C11 quick_exit is silent about thread object destruction. Therefore to make glibc C++ compliant we do not call any thread local destructors. A new regression test verifies the fix. I will note that C++11 18.5.3 makes it clear that C++ defines additional requirements for _Exit() to prevent it from executing destructors. Given that the point of _Exit() is to terminate the process immediately it makes sense the C and C++ should line up and avoid calling destructors. No failures. New regtest passes. --- stdlib/Makefile | 12 +++++++++- stdlib/Versions | 3 +++ stdlib/exit.c | 7 +++--- stdlib/exit.h | 5 +++-- stdlib/quick_exit.c | 23 +++++++++++++++++-- stdlib/tst-quick_exit.cc | 40 +++++++++++++++++++++++++++++++++ stdlib/tst-thread-quick_exit.cc | 50 +++++++++++++++++++++++++++++++++++++++++ 7 files changed, 132 insertions(+), 8 deletions(-) create mode 100644 stdlib/tst-quick_exit.cc create mode 100644 stdlib/tst-thread-quick_exit.cc (limited to 'stdlib') diff --git a/stdlib/Makefile b/stdlib/Makefile index e0eeada..fc6f23d 100644 --- a/stdlib/Makefile +++ b/stdlib/Makefile @@ -76,8 +76,18 @@ tests := tst-strtol tst-strtod testmb testrand testsort testdiv \ tst-secure-getenv tst-strtod-overflow tst-strtod-round \ tst-tininess tst-strtod-underflow tst-tls-atexit \ tst-setcontext3 tst-tls-atexit-nodelete \ - tst-strtol-locale tst-strtod-nan-locale tst-strfmon_l + tst-strtol-locale tst-strtod-nan-locale tst-strfmon_l \ + tst-quick_exit tst-thread-quick_exit tests-static := tst-secure-getenv +ifeq ($(have-cxx-thread_local),yes) +CFLAGS-tst-quick_exit.o = -std=c++11 +LDLIBS-tst-quick_exit = -lstdc++ +CFLAGS-tst-thread-quick_exit.o = -std=c++11 +LDLIBS-tst-thread-quick_exit = -lstdc++ +$(objpfx)tst-thread-quick_exit: $(shared-thread-library) +else +tests-unsupported += tst-quick_exit tst-thread-quick_exit +endif modules-names = tst-tls-atexit-lib extra-test-objs += $(addsuffix .os, $(modules-names)) diff --git a/stdlib/Versions b/stdlib/Versions index 60b628d..9c06b43 100644 --- a/stdlib/Versions +++ b/stdlib/Versions @@ -109,6 +109,9 @@ libc { GLIBC_2.18 { __cxa_thread_atexit_impl; } + GLIBC_2.24 { + quick_exit; + } GLIBC_PRIVATE { # functions which have an additional interface since they are # are cancelable. diff --git a/stdlib/exit.c b/stdlib/exit.c index 9d3c5f4..b50b178 100644 --- a/stdlib/exit.c +++ b/stdlib/exit.c @@ -31,13 +31,14 @@ DEFINE_HOOK (__libc_atexit, (void)) void attribute_hidden __run_exit_handlers (int status, struct exit_function_list **listp, - bool run_list_atexit) + bool run_list_atexit, bool run_dtors) { /* First, call the TLS destructors. */ #ifndef SHARED if (&__call_tls_dtors != NULL) #endif - __call_tls_dtors (); + if (run_dtors) + __call_tls_dtors (); /* We do it this way to handle recursive calls to exit () made by the functions registered with `atexit' and `on_exit'. We call @@ -101,6 +102,6 @@ __run_exit_handlers (int status, struct exit_function_list **listp, void exit (int status) { - __run_exit_handlers (status, &__exit_funcs, true); + __run_exit_handlers (status, &__exit_funcs, true, true); } libc_hidden_def (exit) diff --git a/stdlib/exit.h b/stdlib/exit.h index b28a4c9..b55e5d1 100644 --- a/stdlib/exit.h +++ b/stdlib/exit.h @@ -63,8 +63,9 @@ extern struct exit_function_list *__quick_exit_funcs attribute_hidden; extern struct exit_function *__new_exitfn (struct exit_function_list **listp); extern uint64_t __new_exitfn_called attribute_hidden; -extern void __run_exit_handlers (int status, struct exit_function_list **listp, - bool run_list_atexit) +extern void __run_exit_handlers (int status, + struct exit_function_list **listp, + bool run_list_atexit, bool run_dtors) attribute_hidden __attribute__ ((__noreturn__)); extern int __internal_atexit (void (*func) (void *), void *arg, void *d, diff --git a/stdlib/quick_exit.c b/stdlib/quick_exit.c index bb47472..c0ac4a9 100644 --- a/stdlib/quick_exit.c +++ b/stdlib/quick_exit.c @@ -19,11 +19,30 @@ #include #include #include +#include +#include +#include #include "exit.h" +void +__new_quick_exit (int status) +{ + /* The new quick_exit, following C++11 18.5.12, does not run object + destructors. While C11 says nothing about object destructors, + since it has none, the intent is to run the registered + at_quick_exit handlers and then run _Exit immediately without + disturbing the state of the process and threads. */ + __run_exit_handlers (status, &__quick_exit_funcs, false, false); +} +versioned_symbol (libc, __new_quick_exit, quick_exit, GLIBC_2_24); +#if SHLIB_COMPAT(libc, GLIBC_2_10, GLIBC_2_24) void -quick_exit (int status) +attribute_compat_text_section +__old_quick_exit (int status) { - __run_exit_handlers (status, &__quick_exit_funcs, false); + /* The old quick_exit runs thread_local destructors. */ + __run_exit_handlers (status, &__quick_exit_funcs, false, true); } +compat_symbol (libc, __old_quick_exit, quick_exit, GLIBC_2_10); +#endif diff --git a/stdlib/tst-quick_exit.cc b/stdlib/tst-quick_exit.cc new file mode 100644 index 0000000..c4a15a9 --- /dev/null +++ b/stdlib/tst-quick_exit.cc @@ -0,0 +1,40 @@ +/* Bug 20198: Do not call object destructors at exit. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +#include + +struct A +{ + ~A() { abort(); } +}; + +thread_local A a; + +static int +do_test() +{ + (void)a; + /* The C++11 standard in 18.5.12 says: + "Objects shall not be destroyed as a result of calling + quick_exit." + If quick_exit calls the destructors the test aborts. */ + std::quick_exit(0); + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/stdlib/tst-thread-quick_exit.cc b/stdlib/tst-thread-quick_exit.cc new file mode 100644 index 0000000..307d2a2 --- /dev/null +++ b/stdlib/tst-thread-quick_exit.cc @@ -0,0 +1,50 @@ +/* Bug 20198: Do not call object destructors at exit. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +#include +#include + +struct A +{ + ~A() { abort(); } +}; + +thread_local A a1; +thread_local A a2; + +/* Call std::quick_exit from a non-main thread. */ +void non_main_thread (void) +{ + (void)a1; + /* The C++11 standard in 18.5.12 says: + "Objects shall not be destroyed as a result of calling + quick_exit." + If quick_exit calls the destructors the test aborts. */ + std::quick_exit (0); +} + +static int +do_test() +{ + (void)a2; + std::thread th (non_main_thread); + th.join (); + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" -- cgit v1.1