From 81ce2e4cbc5b2dcbe44e58bcf68be49434085ea8 Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Mon, 8 Jan 2024 11:45:02 -0800 Subject: [PATCH] Call thread finalizers on exit() While we don't call POSIX thread key destructors from exit(), we do need to call these, since C++ uses it for TLS object destructors. See #1076 --- libc/runtime/exit.c | 14 ++++++++++++- test/libc/thread/BUILD.mk | 22 ++++++++++---------- test/libc/thread/pthread_exit_test.c | 7 ------- test/libc/thread/tls_dtor_test.cc | 30 ++++++++++++++++++++++++++++ third_party/libcxxabi/test/BUILD.mk | 5 +---- 5 files changed, 56 insertions(+), 22 deletions(-) create mode 100644 test/libc/thread/tls_dtor_test.cc diff --git a/libc/runtime/exit.c b/libc/runtime/exit.c index 4f8599b79..4a299f05b 100644 --- a/libc/runtime/exit.c +++ b/libc/runtime/exit.c @@ -17,6 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/cxxabi.h" +#include "libc/intrin/cxaatexit.internal.h" #include "libc/intrin/strace.internal.h" #include "libc/intrin/weaken.h" #include "libc/runtime/internal.h" @@ -36,13 +37,24 @@ * @noreturn */ wontreturn void exit(int exitcode) { - const uintptr_t *p; STRACE("exit(%d)", exitcode); + + // call thread local c++ object destructors + if (_weaken(__cxa_thread_finalize)) { + _weaken(__cxa_thread_finalize)(); + } + + // call atexit() and __cxa_atexit() destructors if (_weaken(__cxa_finalize)) { _weaken(__cxa_finalize)(NULL); } + + // call __destructor__ and finiarray destructors + const uintptr_t *p; for (p = __fini_array_end; p > __fini_array_start;) { ((void (*)(void))(*--p))(); } + + // terminate process _Exit(exitcode); } diff --git a/test/libc/thread/BUILD.mk b/test/libc/thread/BUILD.mk index 5cadbff27..15bc7232a 100644 --- a/test/libc/thread/BUILD.mk +++ b/test/libc/thread/BUILD.mk @@ -3,24 +3,30 @@ PKGS += TEST_LIBC_THREAD -TEST_LIBC_THREAD_SRCS := $(wildcard test/libc/thread/*.c) -TEST_LIBC_THREAD_SRCS_TEST = $(filter %_test.c,$(TEST_LIBC_THREAD_SRCS)) +TEST_LIBC_THREAD_FILES := $(wildcard test/libc/thread/*) +TEST_LIBC_THREAD_SRCS_C = $(filter %_test.c,$(TEST_LIBC_THREAD_FILES)) +TEST_LIBC_THREAD_SRCS_CC = $(filter %_test.cc,$(TEST_LIBC_THREAD_FILES)) + +TEST_LIBC_THREAD_SRCS = \ + $(TEST_LIBC_THREAD_SRCS_C) \ + $(TEST_LIBC_THREAD_SRCS_CC) TEST_LIBC_THREAD_OBJS = \ - $(TEST_LIBC_THREAD_SRCS:%.c=o/$(MODE)/%.o) + $(TEST_LIBC_THREAD_SRCS_C:%.c=o/$(MODE)/%.o) \ + $(TEST_LIBC_THREAD_SRCS_CC:%.cc=o/$(MODE)/%.o) TEST_LIBC_THREAD_COMS = \ - $(TEST_LIBC_THREAD_SRCS:%.c=o/$(MODE)/%.com) + $(TEST_LIBC_THREAD_OBJS:%.o=%.com) TEST_LIBC_THREAD_BINS = \ $(TEST_LIBC_THREAD_COMS) \ $(TEST_LIBC_THREAD_COMS:%=%.dbg) TEST_LIBC_THREAD_TESTS = \ - $(TEST_LIBC_THREAD_SRCS_TEST:%.c=o/$(MODE)/%.com.ok) + $(TEST_LIBC_THREAD_OBJS:%.o=%.com.ok) TEST_LIBC_THREAD_CHECKS = \ - $(TEST_LIBC_THREAD_SRCS_TEST:%.c=o/$(MODE)/%.com.runs) + $(TEST_LIBC_THREAD_OBJS:%.o=%.com.runs) TEST_LIBC_THREAD_DIRECTDEPS = \ LIBC_CALLS \ @@ -61,10 +67,6 @@ o/$(MODE)/test/libc/thread/%.com.dbg: \ $(APE_NO_MODIFY_SELF) @$(APELINK) -o/$(MODE)/test/libc/thread/pthread_create_test.o: \ - private CPPFLAGS += \ - -DSTACK_FRAME_UNLIMITED - o/$(MODE)/test/libc/thread/pthread_kill_test.com.runs: \ private .PLEDGE = stdio rpath wpath cpath fattr proc inet diff --git a/test/libc/thread/pthread_exit_test.c b/test/libc/thread/pthread_exit_test.c index 1fcecb891..2855702ae 100644 --- a/test/libc/thread/pthread_exit_test.c +++ b/test/libc/thread/pthread_exit_test.c @@ -73,13 +73,6 @@ void OnMainThreadExit(void *arg) { _Exit((long)arg); } -TEST(__cxa_thread_atexit, exit_wontInvokeThreadDestructors) { - SPAWN(fork); - __cxa_thread_atexit(OnMainThreadExit, (void *)123L, 0); - exit(0); - EXITS(0); -} - TEST(__cxa_thread_atexit, pthread_exit_willInvokeThreadDestructors) { SPAWN(fork); __cxa_thread_atexit(OnMainThreadExit, (void *)123L, 0); diff --git a/test/libc/thread/tls_dtor_test.cc b/test/libc/thread/tls_dtor_test.cc new file mode 100644 index 000000000..d27a38936 --- /dev/null +++ b/test/libc/thread/tls_dtor_test.cc @@ -0,0 +1,30 @@ +/*-*-mode:c++;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8-*-│ +│ vi: set et ft=c++ ts=2 sts=2 sw=2 fenc=utf-8 :vi │ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2024 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/runtime/runtime.h" + +struct Foo { + ~Foo() { + exit(0); + } +}; + +int main() { + thread_local Foo foo; + exit(1); +} diff --git a/third_party/libcxxabi/test/BUILD.mk b/third_party/libcxxabi/test/BUILD.mk index 42c58e6f8..010e5526c 100644 --- a/third_party/libcxxabi/test/BUILD.mk +++ b/third_party/libcxxabi/test/BUILD.mk @@ -52,6 +52,7 @@ THIRD_PARTY_LIBCXXABI_TEST_SRCS = \ third_party/libcxxabi/test/test_guard.pass.cc \ third_party/libcxxabi/test/test_vector1.pass.cc \ third_party/libcxxabi/test/test_vector2.pass.cc \ + third_party/libcxxabi/test/thread_local_destruction_order.pass.cc \ third_party/libcxxabi/test/test_vector3.pass.cc \ third_party/libcxxabi/test/uncaught_exception.pass.cc \ third_party/libcxxabi/test/uncaught_exceptions.pass.cc \ @@ -67,10 +68,6 @@ THIRD_PARTY_LIBCXXABI_TEST_SRCS = \ THIRD_PARTY_LIBCXXABI_TEST_SRCS_TOOSLOW_COSMO = \ third_party/libcxxabi/test/guard_threaded_test.pass.cc \ -# TODO: Add this test when #1073 is fixed -THIRD_PARTY_LIBCXXABI_TEST_SRCS_FAILING_COSMO = \ - third_party/libcxxabi/test/thread_local_destruction_order.pass.cc - THIRD_PARTY_LIBCXXABI_TEST_SRCS_FAILING_GCC = \ third_party/libcxxabi/test/catch_array_01.pass.cc \ third_party/libcxxabi/test/catch_function_01.pass.cc \