- the pthread_key_specific approach does not work well on FreeBSD, at AsanTSDInit it gets stuck.
- Instead storing the data in a thread local storage variable.
Details
- Reviewers
emaste vitalybuka eugenis dim krytarowski
Diff Detail
Event Timeline
Do we know why pthread_{get,set}specific fails now? And would it make sense to use tls more broadly (not just on FreeBSD)?
I seem to remember that it sometimes (but not always) returns ENOSYS and fails. This is when libthr is not completely initialized yet, and it appears to depend on the order in which the DT_NEEDED entries are loaded. I know that I could never figure it out completely, that's why D39254 ("add -pthread to the flags for dynamic ASan tests") stalled. That was a workaround to make the tests succeed more often...
In fact I ve noticed it stopped to be workable since around end of February/beginning March but things got in the way and I lost track but just to say it s not a so new issue. I m half surprised by @dim comment then. But in fact this PR it s more a way to trigger thoughts I knew it would not be accepted just like that ... Ideally I would go more with a common solution indeed.
This is now needed on NetBSD too. Do we know what change caused this regression?
In the NetBSD case we are now configuring main thread on the first interceptor, that is premature to get pthread specific functions.
"context->destructor_iterations > 1" trick is needed to make sure that this destructor is called after other thread_local destructors
E.g. This descructor will remove thread form thread registry making it invisible to leak sanitizer causing false leak reports on thread_locals not yet destroyed.
lib/asan/asan_posix.cc | ||
---|---|---|
67 | it's not the same |
lib/asan/asan_posix.cc | ||
---|---|---|
67 | There might be need to rework the code, and add support for calling a destructor in this fashion:
Alternatively follow TSan for NetBSD, extend it for FreeBSD. In TSan we are intercepting _lwp_exit() on NetBSD as the thread termination routine. FreeBSD shall have something similar. There is also an option for: __cxa_thread_atexit but perhaps the worst one. Some hybrid solution.. get/set specific for !main thread. |
lib/asan/asan_posix.cc | ||
---|---|---|
65 | pthread_setspecific() works together with destructor_iterations. With TsdKey Tsd[4] pthread does not guaranty that it not going to destroy all 4 of them before the rest. btw it's not always 4. On FreeBSD, is the bug is the problem of the main thread? |
BTW. Does FreeBSD/i386 work? The NetBSD 32-bit code broke due to shadow granularity assert in:
void PoisonShadow(uptr addr, uptr size, u8 value) { if (!CanPoisonMemory()) return; CHECK(AddrIsAlignedByGranularity(addr)); // <- here, addr=0xxxxxxxx4 CHECK(AddrIsInMem(addr)); CHECK(AddrIsAlignedByGranularity(addr + size)); CHECK(AddrIsInMem(addr + size - SHADOW_GRANULARITY)); CHECK(REAL(memset)); FastPoisonShadow(addr, size, value); }
I don't see related changes in the code base.. debugging.
lib/asan/asan_posix.cc | ||
---|---|---|
65 | On FreeBSD, is the bug is the problem of the main thread? Could we just store tsd of the main thread in the static and other threads keep as is with pthread_getspecific? Not sure, but also maybe we don't need to call TSDDtor of the main thread. This is the case for NetBSD. Alternatively we could defer of setup of this main thread later. In TSan we are starting extra g/c thread for the first pthread_create(3) interceptor. |
BTW. Does FreeBSD/i386 work? The NetBSD 32-bit code broke due to shadow granularity assert in:
void PoisonShadow(uptr addr, uptr size, u8 value) {
if (!CanPoisonMemory()) return; CHECK(AddrIsAlignedByGranularity(addr)); // <- here, addr=0xxxxxxxx4 CHECK(AddrIsInMem(addr)); CHECK(AddrIsAlignedByGranularity(addr + size)); CHECK(AddrIsInMem(addr + size - SHADOW_GRANULARITY)); CHECK(REAL(memset)); FastPoisonShadow(addr, size, value);}
I've fixed this and I will submit a patch in a separate review.
pthread_setspecific() works together with destructor_iterations.
pthreads will continue to call the destructor if we call pthread_setspecific from it up to GetPthreadDestructorIterations() times. And we hope that all other thread_locals are gone after few first iteration and we are the last when destructor_iterations is 0.
With TsdKey Tsd[4] pthread does not guaranty that it not going to destroy all 4 of them before the rest. btw it's not always 4.
On FreeBSD, is the bug is the problem of the main thread?
Could we just store tsd of the main thread in the static and other threads keep as is with pthread_getspecific?
Not sure, but also maybe we don't need to call TSDDtor of the main thread.