espressif / esp-idf

Espressif IoT Development Framework. Official development framework for Espressif SoCs.
Apache License 2.0
13.33k stars 7.2k forks source link

Destructors of C++11 thread_local object are not called after task returned (IDFGH-13456) #14360

Open andylinpersonal opened 1 month ago

andylinpersonal commented 1 month ago

IDF version.

v5.2, master

Espressif SoC revision.

ESP32-C3, ESP32-C6, ESP32-S3

Operating System used.

Linux

How did you build your project?

Command line with idf.py

Development Kit.

esp32-c6 devkit-c

What is the expected behavior?

TLS finalizers of C++ thread_local variables seems to be missing from the current implementation of toolchain.

MWE on other platform (linux,x64): https://godbolt.org/z/vfWWdh7qe

TestTLS
foo
~TestTLS

The TLS wrapper function registered the destructor of thread_local object to __cxa_thread_atexit and get called after main returned. But there are no such ABI function found in ESP-IDF.

What is the actual behavior?

Destructor of thread local variables are not called after the task died.

Logging messages excerpted from my C6

I (80) sleep: Configure to isolate all GPIO pins in sleep state
I (81) sleep: Enable automatic switching of GPIO sleep configuration
I (81) coexist: coex firmware version: 8da3f50af
I (82) coexist: coexist rom version 5b8dcfa
I (82) main_task: Started on CPU0
I (82) main_task: Calling app_main()
TestTLS
test
I (82) main_task: Returned from app_main()

Steps to reproduce.

  1. Build the aforementioned code https://godbolt.org/z/vfWWdh7qe.
  2. See the output and disassembled code.

More Information.

Relevant crosstool-NG config files here: RISC-V: https://github.com/espressif/crosstool-NG/blob/esp-13.2.0_20240530/samples/riscv32-esp-elf/crosstool.config ESP32-S3: https://github.com/espressif/crosstool-NG/blob/esp-13.2.0_20240530/samples/xtensa-esp32s3-elf/crosstool.config TLS finalizers in libsupc++: https://github.com/espressif/gcc/blob/esp-13.2.0_20240530/libstdc%2B%2B-v3/libsupc%2B%2B/atexit_thread.cc

0xjakob commented 1 month ago

@andylinpersonal Thanks for pointing this out! We'll take a look at this.

0xjakob commented 3 weeks ago

We need to find and discuss some implementation (of __cxa_thread_atexit_impl, etc.), and it appears to me that we would also need to change the toolchain, so solving this problem might take a while. But we'll keep you updated here.

Lapshin commented 3 weeks ago

@andylinpersonal , for now, you can workaround it with these steps:

After these steps I have the output:

I (285) main_task: Calling app_main()
TestTLS
foo
I (285) main_task: Returned from app_main()
~TestTLS

Done

I also tested it with multiple tasks created with xTaskCreate(test, "test", 2048, NULL, 10, NULL); and seems all works fine.

@andylinpersonal , could you please test this fix and leave feedback?

andylinpersonal commented 3 weeks ago

image Ok, it works now! Thanks for your suggestion @Lapshin!