pthread_self() problem in DRD

Konstantin Belousov kostikbel at
Sat Dec 19 12:20:59 UTC 2020

On Sat, Dec 19, 2020 at 01:02:46PM +0100, Paul Floyd wrote:
> Hi
> I'm trying to debug an issue in DRD (a thread hazard detection tool, part of
> Valgrind). There is an issue when using shared libraries.
> A detailed description is here
> In short, the flow of events is
> 1. [guest] The DRD init function gets called (as it is marked
>    __attribute__((constructor))
> 2. [guest] DRD init sets the current thread id, calling pthread_self()
>    and using a client request.
> 3. [host] DRD_(thread_set_pthreadid)() gets called, and it is passed
>    the DRD tid and the value obtained from pthread_self().
> 4. [guest] The testcase does a dlopen() and then calls a function in
>    the shared library
> 5. [guest] the shard lib function calls pthread_create
> 6. [host] pthread_create gets intercepted and performs another call to
>    DRD_(set_pthread_id)()
> I've marked thinks as guest/host, in reality there is only one process
> executing.
> The problem is that the thread id obtained in step 3 is not the same as the
> one obtained in step 6. The result is an assert.
> Two questions
> 1. Is there any reason why pthread_self() should return different
>    values when executed from a constructor and then from a dlopen()'d
>    function?
> 2. Is there any initialization code that affects the value returned by
>    pthread_self()? It's possible that something is missing.
It is impossible to say anything definitive without minimal self-contained
example, but it is possible to make some guess.

In FreeBSD, libc exports pthread stubs which main purpose is to satisfy
linkage requirements of the shared objects that can work in multithreaded
environment but do not require it.  For instance, pthread_self() is exported
from libc, and it returns a pointer to some internal non-sensical memory
when called, until libthr is loaded and initialized.  At the moment libthr
is initialized, pthread_self() starts returning 'real' pthread_t.

In your case, my guess is that one of two things happen:
1. you have first pthread_self() call from the process that does not have
   libthr loaded, then later dlopen(3) loads dso which is linked with libhtr.
   Second call to pthread_self() returns real pthread_t for main thread.
2. (less likely but possible to arrange) You process has libthr linked in,
   but your first call to pthread_self() from constructor occurs before
   constructors for libthr are run.  Visible outcome is same.

More information about the freebsd-hackers mailing list