[Libcxx/TizenRT]: Memory leak in std::thread

Hello Everyone,

We are using LLVM libc++ in TizenRT IoT OS( https://github.com/Samsung/TizenRT). We observed memory leak while using std::thread

About TizenRT:

LLVM libc++ source has been integrated to TizenRT and the whole platform(OS + libc + libcpp + App) is built into a single elf executable.

TizenRT uses a FLAT memory model(physical memory), there is no virtual memory support and hence we cant run application executables (elf) directly.

First time when we create a thread using std::thread , there is no memory leak after thread exits.

But next time onwards, if we create a thread using std::thread and after thread exits there is a memory leak.

First time__thread_specific_ptr<__thread_struct> is constructed in __thread_local_data() and hence the pthread_key_create() and during exit key is destroyed.

But second time onwards, __thread_specific_ptr<__thread_struct> is not getting constructed in __thread_local_data().

__thread_local_data()
{
static __thread_specific_ptr<__thread_struct> __p;
return __p;
}

We suspect that the problem is with __thread_local_data(), and __thread_specific_ptr is getting constructed only once.

Because of this we feel "__thread_struct and __thread_struct_impl " which are allocated earlier during thread create are not getting freed and there is a leak.

Please guide us with, how can we deallocate these objects after or during thread exit.

Also what is the expected behavior of thread_local_data instance?

  1. One thread_local_data instance for a process/task and all of its threads(pthreads) share the same thread_local_data instance?

OR
2. Each thread(pthread) should have a separate thread_local_data instance?

Thanks,

Manohar

Hello Everyone,

We are using *LLVM libc++ *in TizenRT IoT OS( https://github.com/Samsung/
TizenRT). We observed *memory leak while using std::thread*

About TizenRT:

LLVM libc++ source has been integrated to TizenRT and the whole
platform(OS + libc + libcpp + App) is built into a single elf executable.

TizenRT uses a FLAT memory model(physical memory), there is no virtual
memory support and hence we cant run application executables (elf) directly.

First time when we create a thread using std::thread , there is no memory
leak after thread exits.

But next time onwards, if we create a thread using std::thread and after
thread exits there is a memory leak.

First time__thread_specific_ptr<__thread_struct> is constructed in
__thread_local_data() and hence the pthread_key_create() and during exit
key is destroyed.

But second time onwards, __thread_specific_ptr<__thread_struct> is not
getting constructed in __thread_local_data().

__thread_local_data()

{

    static __thread_specific_ptr<__thread_struct>
__p;
    return __p;

}

We suspect that the problem is with __thread_local_data(), and
__thread_specific_ptr is getting constructed only once.

Because of this we feel "__thread_struct and __thread_struct_impl " which
are allocated earlier during thread create are not getting freed and there
is a leak.

__thread_specific_ptr intentionally leaks. See
https://github.com/llvm-mirror/libcxx/blob/master/include/thread#L189

Hello Eric,

Thank you for the reply.

If it is intentionally leaked, Is it freed at any later stage and who is responsible for cleanup?

In our case, below is the call sequence.

======================First Time(No Memory Leak) ==============================

  1. malloc() // ALLOC1

  2. malloc() // ALLOC2

  3. malloc() // ALLOC3

  4. pthread_create() // pthread_create by std::thread

5. pthread_key_create() // Key created

6. _aeabi_atexit() // static storage destructor register to atexit

  1. free() //ALLOC3 freed

  2. pthread_exit()

9. std::__thread_specific_ptrstd::__thread_struct::__at_thread_exit()
//Key destructor called

10. free() //ALLOC2 freed

11. free() //ALOOC1 freed

  1. std::__thread_specific_ptrstd::__thread_struct::~__thread_specific_ptr
    //thread_specific_ptr static storage destructor called

======================Second Time Onwards (Memory Leak) =======================

  1. malloc() // ALLOC1

  2. malloc() // ALLOC2

  3. malloc() // ALLOC3

  4. pthread_create() // pthread_create by std::thread

  5. free() //ALLOC3 free’d

  6. pthread_exit()

// ALLOC1 & ALLOC2 are not freed

// No call to __thread_specific_ptr destructor

201805211700708_LCGFY2AH.gif

201602111742151_N3WZA6X7.png

Hello Eric,

Thank you for the reply.

If it is intentionally leaked, Is it freed at any later stage and who is responsible for cleanup?

Nothing; it’s leaked under the assumption that normal memory allocations will be returned to the OS at exit. This is a common technique used in language libraries and runtimes. It’s even considered good practice, at it allows the process to exit faster and eliminates a source of crashes during user-provided atexit() teardown. If Tizen doesn’t return process memory automatically, you will need to change the code when compiling for Tizen.

John.