Skip to content

Using some libstdc++ concurrency support (e.g. std::mutex) with libctru thread API can be broken #5

@alvinhochun

Description

@alvinhochun

Bug Report

What's the issue you encountered?

When a program uses the libctru thread API (e.g. threadCreate) to manage threads, without using pthread or std::thread, theoretically it should still be possible to use synchronization primitives from pthread or the C++ concurrency support library.

However, if something in said program uses std::mutex for example, by default it actually does not do any synchronization. That is because libstdc++ has an intermediate abstraction called "gthread" which tries to do something "smart".
If you look into its functions, like __gthread_mutex_trylock, they check the return value of __gthread_active_p():

gcc/libgcc/gthr-posix.h

Lines 767 to 774 in 2eb98d6

static inline int
__gthread_mutex_trylock (__gthread_mutex_t *__mutex)
{
if (__gthread_active_p ())
return __gthrw_(pthread_mutex_trylock) (__mutex);
else
return 0;
}

gcc/libgcc/gthr-posix.h

Lines 260 to 266 in 2eb98d6

static inline int
__gthread_active_p (void)
{
static void *const __gthread_active_ptr
= __extension__ (void *) &GTHR_ACTIVE_PROXY;
return __gthread_active_ptr != 0;
}

Basically what it does is: reference all pthread functions with weak symbols, if a pthread function is 0 (undefined, which means pthread isn't linked into the binary) then it basically skips actually doing the synchronization the functions are supposed to be doing.

Remember that the program is using the libctru thread API directly? This means not calling pthread_create, which means no strong reference to pthread, which means pthread isn't linked into the binary. Which means std::mutex is effectively broken in this setup.

How can the issue be reproduced?

Test a program which uses libctru's threadCreate to create threads and uses std::mutex and do something that will fail if the mutex doesn't work. (Sorry, don't have time to make a self contained reproducer yet.)

Environment?

  • Arch Linux
  • devkitARM r65-1

Additional context?

  • It's not me who wants to intentionally mix libctru thread with pthread stuff, but a third-party library that uses std::mutex. This issue took me many hours to track down.
  • I tried adding -pthread to the compile and link flags, but that doesn't force the pthread weak symbols to be linked.
  • I did find a workaround to fix this issue, which is to define _GLIBCXX_GTHREAD_USE_WEAK=0. This disables all the shenanigans involving weak symbols and causes __gthread_active_p() to always return 1, so the synchronization primitives actually works.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions