This is an archive of the discontinued LLVM Phabricator instance.

Use pthreads to manage thread-local storage on darwin for leak sanitizer
ClosedPublic

Authored by fjricci on Feb 9 2017, 1:19 PM.

Details

Summary

thread is supported on Darwin, but is implemented dynamically via
function calls to
tls_get_addr. This causes two issues when combined
with leak sanitizer, due to malloc() interception.

  • The dynamic loader calls malloc during the process of loading

the sanitizer dylib, while swapping a placeholder tlv_boostrap
function for __tls_get_addr. This will cause tlv_bootstrap to
be called in DisabledInThisThread() via the asan allocator.

  • The first time __tls_get_addr is called, it allocates memory

for the thread-local object, during which it calls malloc(). This
call will be intercepted, leading to an infinite loop in the asan
allocator, in which the allocator calls DisabledInThisThread,
which calls tls_get_addr, which calls into the allocator again.

Diff Detail

Repository
rL LLVM

Event Timeline

fjricci created this revision.Feb 9 2017, 1:19 PM
kubamracek added inline comments.Feb 10 2017, 2:56 PM
lib/lsan/lsan_common_mac.cc
29 ↗(On Diff #87866)

Check return value.

35 ↗(On Diff #87866)

clang-format please

53 ↗(On Diff #87866)

This should be called only once per thread, in get_tls_val above. No need to call it whenever we update the counter. Same below.

fjricci updated this revision to Diff 88202.Feb 13 2017, 7:44 AM
fjricci marked 3 inline comments as done.

Address comments

kubamracek added inline comments.Feb 13 2017, 8:36 AM
lib/lsan/lsan_common_mac.cc
28 ↗(On Diff #88202)

The declaration says the function returns "int", but the function body doesn't return anything.

35 ↗(On Diff #88202)

sizeof(int)

55–58 ↗(On Diff #88202)

I would prefer to replace the ! with an explicit == 0 (and change the lsan_common_linux.cc file as well) to improve readability.

Also, can we de-duplicate these 4 lines? Perhaps having just if (*disable_counter > 0) DisableCounterUnderflow(); and defining the new function in lsan_common.cc.

60 ↗(On Diff #88202)

Why not decrement unconditionally here? The Linux implementation does it unconditionally.

fjricci updated this revision to Diff 88231.Feb 13 2017, 11:30 AM
fjricci marked 3 inline comments as not done.

Deduplicate code and address style issues

lib/lsan/lsan_common_mac.cc
35 ↗(On Diff #88202)

Using sizeof(int) fails the check-sanitizer linter:

Using sizeof(type). Use sizeof(varname) instead if possible [runtime/sizeof] [1]

kubamracek added inline comments.Feb 13 2017, 11:45 AM
lib/lsan/lsan_common_mac.cc
35 ↗(On Diff #88231)

Oh. Then use sizeof(*ptr). It's completely non-obvious what sizeof(0) evaluates to (and I doubt it's guaranteed to equal sizeof(int).

Also, shouldn't this be InternalAlloc instead of malloc? But you probably know better than me here.

kubamracek edited edge metadata.Feb 13 2017, 11:46 AM

LGTM modulo my last comments about sizeof and InternalAlloc.

fjricci updated this revision to Diff 88242.Feb 13 2017, 12:23 PM

Fix up thread-specific data

fjricci added inline comments.Feb 13 2017, 12:25 PM
lib/lsan/lsan_common_mac.cc
35 ↗(On Diff #88231)

Yeah, it was tricky to figure out what the convention was here, as either way is pretty rare in the sanitizers. InternalAlloc does look more reasonable.

kubamracek accepted this revision.Feb 13 2017, 2:14 PM
This revision is now accepted and ready to land.Feb 13 2017, 2:14 PM
This revision was automatically updated to reflect the committed changes.