Skip to content

Commit f176803

Browse files
committed
Revert "[sanitizer] Simplify GetTls with dl_iterate_phdr"
This reverts commit 9be8f8b. This breaks tsan on Ubuntu 16.04: $ cat tiny_race.c #include <pthread.h> int Global; void *Thread1(void *x) { Global = 42; return x; } int main() { pthread_t t; pthread_create(&t, NULL, Thread1, NULL); Global = 43; pthread_join(t, NULL); return Global; } $ out/gn/bin/clang -fsanitize=thread -g -O1 tiny_race.c --sysroot ~/src/chrome/src/build/linux/debian_sid_amd64-sysroot/ $ docker run -v $PWD:/foo ubuntu:xenial /foo/a.out FATAL: ThreadSanitizer CHECK failed: ../../compiler-rt/lib/tsan/rtl/tsan_platform_linux.cpp:447 "((thr_beg)) >= ((tls_addr))" (0x7fddd76beb80, 0xfffffffffffff980) #0 <null> <null> (a.out+0x4960b6) #1 <null> <null> (a.out+0x4b677f) rust-lang#2 <null> <null> (a.out+0x49cf94) rust-lang#3 <null> <null> (a.out+0x499bd2) rust-lang#4 <null> <null> (a.out+0x42aaf1) rust-lang#5 <null> <null> (libpthread.so.0+0x76b9) rust-lang#6 <null> <null> (libc.so.6+0x1074dc) (Get the sysroot from here: https://commondatastorage.googleapis.com/chrome-linux-sysroot/toolchain/500976182686961e34974ea7bdc0a21fca32be06/debian_sid_amd64_sysroot.tar.xz) Also reverts follow-on commits: This reverts commit 58c62fd. This reverts commit 31e541e.
1 parent 1d54aa2 commit f176803

16 files changed

+184
-111
lines changed

compiler-rt/lib/asan/asan_rtl.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,9 @@ static void AsanInitInternal() {
490490
if (flags()->start_deactivated)
491491
AsanDeactivate();
492492

493+
// interceptors
494+
InitTlsSize();
495+
493496
// Create main thread.
494497
AsanThread *main_thread = CreateMainThread();
495498
CHECK_EQ(0, main_thread->tid());
@@ -565,7 +568,7 @@ void UnpoisonStack(uptr bottom, uptr top, const char *type) {
565568
type, top, bottom, top - bottom, top - bottom);
566569
return;
567570
}
568-
PoisonShadow(bottom, RoundUpTo(top - bottom, SHADOW_GRANULARITY), 0);
571+
PoisonShadow(bottom, top - bottom, 0);
569572
}
570573

571574
static void UnpoisonDefaultStack() {

compiler-rt/lib/asan/asan_thread.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ void AsanThread::SetThreadStackAndTls(const InitOptions *options) {
307307
uptr stack_size = 0;
308308
GetThreadStackAndTls(tid() == 0, &stack_bottom_, &stack_size, &tls_begin_,
309309
&tls_size);
310-
stack_top_ = RoundDownTo(stack_bottom_ + stack_size, SHADOW_GRANULARITY);
310+
stack_top_ = stack_bottom_ + stack_size;
311311
tls_end_ = tls_begin_ + tls_size;
312312
dtls_ = DTLS_Get();
313313

compiler-rt/lib/hwasan/hwasan.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,8 @@ void __hwasan_init() {
265265
hwasan_init_is_running = 1;
266266
SanitizerToolName = "HWAddressSanitizer";
267267

268+
InitTlsSize();
269+
268270
CacheBinaryName();
269271
InitializeFlags();
270272

compiler-rt/lib/lsan/lsan.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ extern "C" void __lsan_init() {
9898
InitCommonLsan();
9999
InitializeAllocator();
100100
ReplaceSystemMalloc();
101+
InitTlsSize();
101102
InitializeInterceptors();
102103
InitializeThreadRegistry();
103104
InstallDeadlySignalHandlers(LsanOnDeadlySignal);

compiler-rt/lib/memprof/memprof_rtl.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,9 @@ static void MemprofInitInternal() {
214214

215215
InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir);
216216

217+
// interceptors
218+
InitTlsSize();
219+
217220
// Create main thread.
218221
MemprofThread *main_thread = CreateMainThread();
219222
CHECK_EQ(0, main_thread->tid());

compiler-rt/lib/msan/msan.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,7 @@ void __msan_init() {
436436

437437
InitializeInterceptors();
438438
CheckASLR();
439+
InitTlsSize();
439440
InstallDeadlySignalHandlers(MsanOnDeadlySignal);
440441
InstallAtExitHandler(); // Needs __cxa_atexit interceptor.
441442

compiler-rt/lib/sanitizer_common/sanitizer_common.h

+1
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,7 @@ void SetSandboxingCallback(void (*f)());
284284

285285
void InitializeCoverage(bool enabled, const char *coverage_dir);
286286

287+
void InitTlsSize();
287288
uptr GetTlsSize();
288289

289290
// Other

compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ void DisableCoreDumperIfNecessary() {}
103103
void InstallDeadlySignalHandlers(SignalHandlerType handler) {}
104104
void SetAlternateSignalStack() {}
105105
void UnsetAlternateSignalStack() {}
106+
void InitTlsSize() {}
106107

107108
bool SignalContext::IsStackOverflow() const { return false; }
108109
void SignalContext::DumpAllRegisters(void *context) { UNIMPLEMENTED(); }

compiler-rt/lib/sanitizer_common/sanitizer_linux.h

+1
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ class ThreadLister {
9898
// Exposed for testing.
9999
uptr ThreadDescriptorSize();
100100
uptr ThreadSelf();
101+
uptr ThreadSelfOffset();
101102

102103
// Matches a library's file name against a base name (stripping path and version
103104
// information).

compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp

+143-108
Original file line numberDiff line numberDiff line change
@@ -188,8 +188,80 @@ __attribute__((unused)) static bool GetLibcVersion(int *major, int *minor,
188188
#endif
189189
}
190190

191-
// ThreadDescriptorSize() is only used by lsan to get the pointer to
192-
// thread-specific data keys in the thread control block.
191+
#if SANITIZER_GLIBC && !SANITIZER_GO
192+
static uptr g_tls_size;
193+
194+
#ifdef __i386__
195+
#define CHECK_GET_TLS_STATIC_INFO_VERSION (!__GLIBC_PREREQ(2, 27))
196+
#else
197+
#define CHECK_GET_TLS_STATIC_INFO_VERSION 0
198+
#endif
199+
200+
#if CHECK_GET_TLS_STATIC_INFO_VERSION
201+
#define DL_INTERNAL_FUNCTION __attribute__((regparm(3), stdcall))
202+
#else
203+
#define DL_INTERNAL_FUNCTION
204+
#endif
205+
206+
namespace {
207+
struct GetTlsStaticInfoCall {
208+
typedef void (*get_tls_func)(size_t*, size_t*);
209+
};
210+
struct GetTlsStaticInfoRegparmCall {
211+
typedef void (*get_tls_func)(size_t*, size_t*) DL_INTERNAL_FUNCTION;
212+
};
213+
214+
template <typename T>
215+
void CallGetTls(void* ptr, size_t* size, size_t* align) {
216+
typename T::get_tls_func get_tls;
217+
CHECK_EQ(sizeof(get_tls), sizeof(ptr));
218+
internal_memcpy(&get_tls, &ptr, sizeof(ptr));
219+
CHECK_NE(get_tls, 0);
220+
get_tls(size, align);
221+
}
222+
223+
bool CmpLibcVersion(int major, int minor, int patch) {
224+
int ma;
225+
int mi;
226+
int pa;
227+
if (!GetLibcVersion(&ma, &mi, &pa))
228+
return false;
229+
if (ma > major)
230+
return true;
231+
if (ma < major)
232+
return false;
233+
if (mi > minor)
234+
return true;
235+
if (mi < minor)
236+
return false;
237+
return pa >= patch;
238+
}
239+
240+
} // namespace
241+
242+
void InitTlsSize() {
243+
// all current supported platforms have 16 bytes stack alignment
244+
const size_t kStackAlign = 16;
245+
void *get_tls_static_info_ptr = dlsym(RTLD_NEXT, "_dl_get_tls_static_info");
246+
size_t tls_size = 0;
247+
size_t tls_align = 0;
248+
// On i?86, _dl_get_tls_static_info used to be internal_function, i.e.
249+
// __attribute__((regparm(3), stdcall)) before glibc 2.27 and is normal
250+
// function in 2.27 and later.
251+
if (CHECK_GET_TLS_STATIC_INFO_VERSION && !CmpLibcVersion(2, 27, 0))
252+
CallGetTls<GetTlsStaticInfoRegparmCall>(get_tls_static_info_ptr,
253+
&tls_size, &tls_align);
254+
else
255+
CallGetTls<GetTlsStaticInfoCall>(get_tls_static_info_ptr,
256+
&tls_size, &tls_align);
257+
if (tls_align < kStackAlign)
258+
tls_align = kStackAlign;
259+
g_tls_size = RoundUpTo(tls_size, tls_align);
260+
}
261+
#else
262+
void InitTlsSize() { }
263+
#endif // SANITIZER_GLIBC && !SANITIZER_GO
264+
193265
#if (defined(__x86_64__) || defined(__i386__) || defined(__mips__) || \
194266
defined(__aarch64__) || defined(__powerpc64__) || defined(__s390__) || \
195267
defined(__arm__) || SANITIZER_RISCV64) && \
@@ -262,6 +334,13 @@ uptr ThreadDescriptorSize() {
262334
return val;
263335
}
264336

337+
// The offset at which pointer to self is located in the thread descriptor.
338+
const uptr kThreadSelfOffset = FIRST_32_SECOND_64(8, 16);
339+
340+
uptr ThreadSelfOffset() {
341+
return kThreadSelfOffset;
342+
}
343+
265344
#if defined(__mips__) || defined(__powerpc64__) || SANITIZER_RISCV64
266345
// TlsPreTcbSize includes size of struct pthread_descr and size of tcb
267346
// head structure. It lies before the static tls blocks.
@@ -280,63 +359,48 @@ static uptr TlsPreTcbSize() {
280359
}
281360
#endif
282361

283-
#if !SANITIZER_GO
284-
namespace {
285-
struct TlsRange {
286-
uptr begin, end, align;
287-
size_t tls_modid;
288-
bool operator<(const TlsRange &rhs) const { return begin < rhs.begin; }
289-
};
290-
} // namespace
291-
292-
static int CollectStaticTlsRanges(struct dl_phdr_info *info, size_t size,
293-
void *data) {
294-
if (!info->dlpi_tls_data)
295-
return 0;
296-
const uptr begin = (uptr)info->dlpi_tls_data;
297-
for (unsigned i = 0; i != info->dlpi_phnum; ++i)
298-
if (info->dlpi_phdr[i].p_type == PT_TLS) {
299-
static_cast<InternalMmapVector<TlsRange> *>(data)->push_back(
300-
TlsRange{begin, begin + info->dlpi_phdr[i].p_memsz,
301-
info->dlpi_phdr[i].p_align, info->dlpi_tls_modid});
302-
break;
303-
}
304-
return 0;
362+
uptr ThreadSelf() {
363+
uptr descr_addr;
364+
#if defined(__i386__)
365+
asm("mov %%gs:%c1,%0" : "=r"(descr_addr) : "i"(kThreadSelfOffset));
366+
#elif defined(__x86_64__)
367+
asm("mov %%fs:%c1,%0" : "=r"(descr_addr) : "i"(kThreadSelfOffset));
368+
#elif defined(__mips__)
369+
// MIPS uses TLS variant I. The thread pointer (in hardware register $29)
370+
// points to the end of the TCB + 0x7000. The pthread_descr structure is
371+
// immediately in front of the TCB. TlsPreTcbSize() includes the size of the
372+
// TCB and the size of pthread_descr.
373+
const uptr kTlsTcbOffset = 0x7000;
374+
uptr thread_pointer;
375+
asm volatile(".set push;\
376+
.set mips64r2;\
377+
rdhwr %0,$29;\
378+
.set pop" : "=r" (thread_pointer));
379+
descr_addr = thread_pointer - kTlsTcbOffset - TlsPreTcbSize();
380+
#elif defined(__aarch64__) || defined(__arm__)
381+
descr_addr = reinterpret_cast<uptr>(__builtin_thread_pointer()) -
382+
ThreadDescriptorSize();
383+
#elif SANITIZER_RISCV64
384+
// https://github.com/riscv/riscv-elf-psabi-doc/issues/53
385+
uptr thread_pointer = reinterpret_cast<uptr>(__builtin_thread_pointer());
386+
descr_addr = thread_pointer - TlsPreTcbSize();
387+
#elif defined(__s390__)
388+
descr_addr = reinterpret_cast<uptr>(__builtin_thread_pointer());
389+
#elif defined(__powerpc64__)
390+
// PPC64LE uses TLS variant I. The thread pointer (in GPR 13)
391+
// points to the end of the TCB + 0x7000. The pthread_descr structure is
392+
// immediately in front of the TCB. TlsPreTcbSize() includes the size of the
393+
// TCB and the size of pthread_descr.
394+
const uptr kTlsTcbOffset = 0x7000;
395+
uptr thread_pointer;
396+
asm("addi %0,13,%1" : "=r"(thread_pointer) : "I"(-kTlsTcbOffset));
397+
descr_addr = thread_pointer - TlsPreTcbSize();
398+
#else
399+
#error "unsupported CPU arch"
400+
#endif
401+
return descr_addr;
305402
}
306-
307-
static void GetStaticTlsRange(uptr *addr, uptr *size, uptr *align) {
308-
InternalMmapVector<TlsRange> ranges;
309-
dl_iterate_phdr(CollectStaticTlsRanges, &ranges);
310-
uptr len = ranges.size();
311-
Sort(ranges.begin(), len);
312-
// Find the range with tls_modid=1. For glibc, because libc.so uses PT_TLS,
313-
// this module is guaranteed to exist and is one of the initially loaded
314-
// modules.
315-
uptr one = 0;
316-
while (one != len && ranges[one].tls_modid != 1) ++one;
317-
if (one == len) {
318-
// This may happen with musl if no module uses PT_TLS.
319-
*addr = 0;
320-
*size = 0;
321-
*align = 1;
322-
return;
323-
}
324-
// Find the maximum consecutive ranges. We consider two modules consecutive if
325-
// the gap is smaller than the alignment. The dynamic loader places static TLS
326-
// blocks this way not to waste space.
327-
uptr l = one;
328-
*align = ranges[l].align;
329-
while (l != 0 && ranges[l].begin < ranges[l - 1].end + ranges[l - 1].align)
330-
*align = Max(*align, ranges[--l].align);
331-
uptr r = one + 1;
332-
while (r != len && ranges[r].begin < ranges[r - 1].end + ranges[r - 1].align)
333-
*align = Max(*align, ranges[r++].align);
334-
*addr = ranges[l].begin;
335-
*size = ranges[r - 1].end - ranges[l].begin;
336-
}
337-
#endif // !SANITIZER_GO
338-
#endif // (x86_64 || i386 || mips || ...) && SANITIZER_LINUX &&
339-
// !SANITIZER_ANDROID
403+
#endif // (x86_64 || i386 || MIPS) && SANITIZER_LINUX
340404

341405
#if SANITIZER_FREEBSD
342406
static void **ThreadSelfSegbase() {
@@ -408,54 +472,18 @@ static void GetTls(uptr *addr, uptr *size) {
408472
*size = 0;
409473
}
410474
#elif SANITIZER_LINUX
411-
uptr align;
412-
GetStaticTlsRange(addr, size, &align);
413475
#if defined(__x86_64__) || defined(__i386__) || defined(__s390__)
414-
if (SANITIZER_GLIBC) {
415-
#if defined(__s390__)
416-
align = Max<uptr>(align, 16);
417-
#else
418-
align = Max<uptr>(align, 64);
419-
#endif
420-
}
421-
const uptr tp = RoundUpTo(*addr + *size, align);
422-
423-
// lsan requires the range to additionally cover the static TLS surplus
424-
// (elf/dl-tls.c defines 1664). Otherwise there may be false positives for
425-
// allocations only referenced by tls in dynamically loaded modules.
426-
if (SANITIZER_GLIBC)
427-
*size += 1644;
428-
429-
// Extend the range to include the thread control block. On glibc, lsan needs
430-
// the range to include pthread::{specific_1stblock,specific} so that
431-
// allocations only referenced by pthread_setspecific can be scanned. This may
432-
// underestimate by at most TLS_TCB_ALIGN-1 bytes but it should be fine
433-
// because the number of bytes after pthread::specific is larger.
434-
*addr = tp - RoundUpTo(*size, align);
435-
*size = tp - *addr + ThreadDescriptorSize();
436-
#else
437-
if (SANITIZER_GLIBC)
438-
*size += 1664;
439-
#if defined(__powerpc64__)
440-
// TODO Figure out why *addr may be zero and use TlsPreTcbSize.
441-
void *ptr = dlsym(RTLD_NEXT, "_dl_get_tls_static_info");
442-
uptr tls_size, tls_align;
443-
((void (*)(size_t *, size_t *))ptr)(&tls_size, &tls_align);
444-
asm("addi %0,13,-0x7000" : "=r"(*addr));
445-
*addr -= TlsPreTcbSize();
446-
*size = RoundUpTo(tls_size + TlsPreTcbSize(), 16);
447-
#elif defined(__mips__) || SANITIZER_RISCV64
448-
const uptr pre_tcb_size = TlsPreTcbSize();
449-
*addr -= pre_tcb_size;
450-
*size += pre_tcb_size;
476+
*addr = ThreadSelf();
477+
*size = GetTlsSize();
478+
*addr -= *size;
479+
*addr += ThreadDescriptorSize();
480+
#elif defined(__mips__) || defined(__aarch64__) || defined(__powerpc64__) || \
481+
defined(__arm__) || SANITIZER_RISCV64
482+
*addr = ThreadSelf();
483+
*size = GetTlsSize();
451484
#else
452-
// arm and aarch64 reserve two words at TP, so this underestimates the range.
453-
// However, this is sufficient for the purpose of finding the pointers to
454-
// thread-specific data keys.
455-
const uptr tcb_size = ThreadDescriptorSize();
456-
*addr -= tcb_size;
457-
*size += tcb_size;
458-
#endif
485+
*addr = 0;
486+
*size = 0;
459487
#endif
460488
#elif SANITIZER_FREEBSD
461489
void** segbase = ThreadSelfSegbase();
@@ -496,11 +524,17 @@ static void GetTls(uptr *addr, uptr *size) {
496524

497525
#if !SANITIZER_GO
498526
uptr GetTlsSize() {
499-
#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
527+
#if SANITIZER_FREEBSD || SANITIZER_ANDROID || SANITIZER_NETBSD || \
500528
SANITIZER_SOLARIS
501529
uptr addr, size;
502530
GetTls(&addr, &size);
503531
return size;
532+
#elif SANITIZER_GLIBC
533+
#if defined(__mips__) || defined(__powerpc64__) || SANITIZER_RISCV64
534+
return RoundUpTo(g_tls_size + TlsPreTcbSize(), 16);
535+
#else
536+
return g_tls_size;
537+
#endif
504538
#else
505539
return 0;
506540
#endif
@@ -523,9 +557,10 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
523557
if (!main) {
524558
// If stack and tls intersect, make them non-intersecting.
525559
if (*tls_addr > *stk_addr && *tls_addr < *stk_addr + *stk_size) {
526-
if (*stk_addr + *stk_size < *tls_addr + *tls_size)
527-
*tls_size = *stk_addr + *stk_size - *tls_addr;
528-
*stk_size = *tls_addr - *stk_addr;
560+
CHECK_GT(*tls_addr + *tls_size, *stk_addr);
561+
CHECK_LE(*tls_addr + *tls_size, *stk_addr + *stk_size);
562+
*stk_size -= *tls_size;
563+
*tls_addr = *stk_addr + *stk_size;
529564
}
530565
}
531566
#endif

compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -548,6 +548,9 @@ uptr GetTlsSize() {
548548
return 0;
549549
}
550550

551+
void InitTlsSize() {
552+
}
553+
551554
uptr TlsBaseAddr() {
552555
uptr segbase = 0;
553556
#if defined(__x86_64__)

0 commit comments

Comments
 (0)