Merge branch 'fix/cxx-tls-destructors_v5.2' into 'release/v5.2'

fix(cxx): fix TLS classes destructor call (v5.2)

See merge request espressif/esp-idf!34210
This commit is contained in:
Jiang Jiang Jian
2025-07-11 13:57:48 +08:00
3 changed files with 42 additions and 3 deletions

View File

@@ -271,7 +271,9 @@ if(CMAKE_C_COMPILER_ID MATCHES "GNU")
endif() endif()
if(CMAKE_C_COMPILER_ID MATCHES "Clang") 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() endif()
if(COMPILER_RT_LIB_NAME) if(COMPILER_RT_LIB_NAME)

View File

@@ -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 * 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++. * 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 * This works via -u __cxa_guard_dummy flag in component.mk

View File

@@ -201,7 +201,7 @@ struct PriorityInitTest
int PriorityInitTest::order = 0; 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) // Default init_priority is always the lowest (highest priority number)
PriorityInitTest g_static_init_priority_test2; PriorityInitTest g_static_init_priority_test2;
PriorityInitTest g_static_init_priority_test1 __attribute__((init_priority(1000))); PriorityInitTest g_static_init_priority_test1 __attribute__((init_priority(1000)));
@@ -249,6 +249,36 @@ TEST_CASE("can use std::vector", "[misc]")
TEST_ASSERT_EQUAL(51, std::accumulate(std::begin(v), std::end(v), 0)); 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 /* These test cases pull a lot of code from libstdc++ and are disabled for now
*/ */
#if 0 #if 0
@@ -320,6 +350,7 @@ TEST_CASE("test std::this_thread::sleep_for basic functionality", "[misc]")
extern "C" void app_main(void) extern "C" void app_main(void)
{ {
s_testTLS.foo(); /* allocates memory that will be reused */
printf("CXX GENERAL TEST\n"); printf("CXX GENERAL TEST\n");
unity_run_menu(); unity_run_menu();
} }