On Sat, Nov 7, 2026 at 5:41 AM Rich Felker via Gcc-bugs
<[email protected]> wrote:
>
> On Sat, Nov 07, 2026 at 01:09:03PM +0100, Pepper Gray wrote:
> > According to POSIX, self-joining a thread is undefined behavior:
> >
> > > The behavior is undefined if the value specified by the thread argument to
> > > pthread_join() refers to the calling thread.
> >
> > ```C
> > #include <pthread.h>
> > #include <stdio.h>
> > #include <string.h>
> >
> > int main(void) {
> > int err = pthread_join(pthread_self(), NULL); // glibc: EDEADLK,
> > musl: never returns
> > printf("returned: %s\n", strerror(err));
> > }
> > ```
> >
> > but the rationale recommends detecting it:
> >
> > > If an implementation detects that the value specified by the thread
> > > argument
> > > to pthread_join() refers to the calling thread, it is recommended that the
> > > function should fail and report an [EDEADLK] error.
> >
> > This is the case in `glibc`, which reports `EDEADLK` while musl just hangs.
> >
> > While hanging is technically correct, the behavior is undesirable in
> > practice,
> > and a behavior like returning `EDEADLK` or even crashing would make it
> > easier to
> > deal with such an app than when it just hangs.
>
> It's very intentional that we do not facilitate forward progress when
> a program has invoked undefined behavior. There is no good reason to
> expect that a programmer has ignored the fact that the operation is UB
> will have taken the effort to check the return value, so just
> returning an error is likely to result in the flow of execution
> continuing to run in an inconsistent and possibly dangerous state.
>
> Self-join suggests a confusion about who owns resources, so this may
> involve data races, etc. But this is a pretty broad principle in musl,
> not specific to pthread_join. At one point my write-up of the
> principle was included in some glibc guidelines too; I can't find the
> link to that at the moment, but FWIW there was consensus that "return
> an error on UB" is bad behavior.
>
> > In C++ this case is defined for `std::thread::join()`
> > ([thread.thread.member](https://eel.is/c++draft/thread.thread.member)):
> >
> > > *Throws:* `system_error` when an exception is required
> > > ([thread.req.exception]).
> > >
> > > *Error conditions:*
> > > - `resource_deadlock_would_occur` — if deadlock is detected or `get_id()
> > > == this_thread::get_id()`.
> >
> > However this doesn't work on `libstdc++` nor `libc++` because they both wrap
> > `pthread_join`, which just hangs on musl.
>
> If the C++ std::thread::join has a contract to throw on self-join then
> it needs to call pthread_equal before pthread_join to check that
> condition.
libstdc++ works correctly:
```
void
thread::join()
{
int __e = EINVAL;
if (_M_id != id()) //<< check here
__e = __gthread_join(_M_id._M_thread, 0);
if (__e)
__throw_system_error(__e);
_M_id = id();
}
```