diff --git a/CMakeLists.txt b/CMakeLists.txt index 20ef5b9689..b4dbce1bc2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -251,7 +251,9 @@ if(CMAKE_C_COMPILER_ID MATCHES "GNU") endif() if(CMAKE_C_COMPILER_ID MATCHES "Clang") - list(APPEND compile_options "-fno-use-cxa-atexit") + list(APPEND compile_options "-fno-use-cxa-atexit") # TODO IDF-10934 +else() + list(APPEND cxx_compile_options "-fuse-cxa-atexit") endif() if(COMPILER_RT_LIB_NAME) diff --git a/components/cxx/cxx_guards.cpp b/components/cxx/cxx_guards.cpp index 0a76173769..e4f9f905a6 100644 --- a/components/cxx/cxx_guards.cpp +++ b/components/cxx/cxx_guards.cpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -210,6 +210,12 @@ extern "C" void __cxa_guard_abort(__guard* pg) throw() } } +/* Originally, this should come with crtbegin.o from the toolchain (if GCC is configured with --enable-__cxa_atexit). + Since we do not link with crtbegin.o and have not configured GCC with --enable-__cxa_atexit, it is declared here. + Note: It should have a unique value in every shared object; in the main program its value is zero. */ +extern "C" void *__dso_handle __attribute__((__visibility__("hidden"))); +void *__dso_handle = 0; + /** * Dummy function used to force linking this file instead of the same one in libstdc++. * This works via -u __cxa_guard_dummy flag in component.mk diff --git a/components/cxx/test_apps/general/main/test_cxx_general.cpp b/components/cxx/test_apps/general/main/test_cxx_general.cpp index 0e483ab655..858b16bc16 100644 --- a/components/cxx/test_apps/general/main/test_cxx_general.cpp +++ b/components/cxx/test_apps/general/main/test_cxx_general.cpp @@ -197,7 +197,7 @@ struct PriorityInitTest { int PriorityInitTest::order = 0; -// init_priority objects are initialized from the lowest to the heighest priority number +// init_priority objects are initialized from the lowest to the highest priority number // Default init_priority is always the lowest (highest priority number) PriorityInitTest g_static_init_priority_test2; PriorityInitTest g_static_init_priority_test1 __attribute__((init_priority(1000))); @@ -243,6 +243,36 @@ TEST_CASE("can use std::vector", "[misc]") TEST_ASSERT_EQUAL(51, std::accumulate(std::begin(v), std::end(v), 0)); } +static volatile bool is_tls_class_destructor_called; +struct TestTLS { + TestTLS() { } + ~TestTLS() + { + is_tls_class_destructor_called = true; + } + void foo() { } +}; + +thread_local TestTLS s_testTLS; + +void test_thread_local_destructors(void * arg) +{ + s_testTLS.foo(); + xSemaphoreGive(s_slow_init_sem); + vTaskDelete(NULL); +} + +TEST_CASE("call destructors for thread_local classes CXX", "[misc]") +{ + is_tls_class_destructor_called = false; + s_slow_init_sem = xSemaphoreCreateCounting(1, 0); + xTaskCreate(test_thread_local_destructors, "test_thread_local_destructors", 2048, NULL, 10, NULL); + vTaskDelay(1); /* Triggers IDLE task to call prvCheckTasksWaitingTermination() which cleans task-specific data */ + TEST_ASSERT_TRUE(xSemaphoreTake(s_slow_init_sem, 500 / portTICK_PERIOD_MS)); + vSemaphoreDelete(s_slow_init_sem); + TEST_ASSERT_TRUE(is_tls_class_destructor_called); +} + /* These test cases pull a lot of code from libstdc++ and are disabled for now */ #if 0 @@ -291,6 +321,7 @@ TEST_CASE("stack smashing protection CXX", "[stack_smash]") extern "C" void app_main(void) { + s_testTLS.foo(); /* allocates memory that will be reused */ printf("CXX GENERAL TEST\n"); unity_run_menu(); }