@@ -184,80 +184,8 @@ __attribute__((unused)) static bool GetLibcVersion(int *major, int *minor,
184
184
#endif
185
185
}
186
186
187
- #if SANITIZER_GLIBC && !SANITIZER_GO
188
- static uptr g_tls_size;
189
-
190
- #ifdef __i386__
191
- #define CHECK_GET_TLS_STATIC_INFO_VERSION (!__GLIBC_PREREQ(2 , 27 ))
192
- #else
193
- #define CHECK_GET_TLS_STATIC_INFO_VERSION 0
194
- #endif
195
-
196
- #if CHECK_GET_TLS_STATIC_INFO_VERSION
197
- #define DL_INTERNAL_FUNCTION __attribute__ ((regparm(3 ), stdcall))
198
- #else
199
- #define DL_INTERNAL_FUNCTION
200
- #endif
201
-
202
- namespace {
203
- struct GetTlsStaticInfoCall {
204
- typedef void (*get_tls_func)(size_t *, size_t *);
205
- };
206
- struct GetTlsStaticInfoRegparmCall {
207
- typedef void (*get_tls_func)(size_t *, size_t *) DL_INTERNAL_FUNCTION;
208
- };
209
-
210
- template <typename T>
211
- void CallGetTls (void * ptr, size_t * size, size_t * align) {
212
- typename T::get_tls_func get_tls;
213
- CHECK_EQ (sizeof (get_tls), sizeof (ptr));
214
- internal_memcpy (&get_tls, &ptr, sizeof (ptr));
215
- CHECK_NE (get_tls, 0 );
216
- get_tls (size, align);
217
- }
218
-
219
- bool CmpLibcVersion (int major, int minor, int patch) {
220
- int ma;
221
- int mi;
222
- int pa;
223
- if (!GetLibcVersion (&ma, &mi, &pa))
224
- return false ;
225
- if (ma > major)
226
- return true ;
227
- if (ma < major)
228
- return false ;
229
- if (mi > minor)
230
- return true ;
231
- if (mi < minor)
232
- return false ;
233
- return pa >= patch;
234
- }
235
-
236
- } // namespace
237
-
238
- void InitTlsSize () {
239
- // all current supported platforms have 16 bytes stack alignment
240
- const size_t kStackAlign = 16 ;
241
- void *get_tls_static_info_ptr = dlsym (RTLD_NEXT, " _dl_get_tls_static_info" );
242
- size_t tls_size = 0 ;
243
- size_t tls_align = 0 ;
244
- // On i?86, _dl_get_tls_static_info used to be internal_function, i.e.
245
- // __attribute__((regparm(3), stdcall)) before glibc 2.27 and is normal
246
- // function in 2.27 and later.
247
- if (CHECK_GET_TLS_STATIC_INFO_VERSION && !CmpLibcVersion (2 , 27 , 0 ))
248
- CallGetTls<GetTlsStaticInfoRegparmCall>(get_tls_static_info_ptr,
249
- &tls_size, &tls_align);
250
- else
251
- CallGetTls<GetTlsStaticInfoCall>(get_tls_static_info_ptr,
252
- &tls_size, &tls_align);
253
- if (tls_align < kStackAlign )
254
- tls_align = kStackAlign ;
255
- g_tls_size = RoundUpTo (tls_size, tls_align);
256
- }
257
- #else
258
- void InitTlsSize () { }
259
- #endif // SANITIZER_GLIBC && !SANITIZER_GO
260
-
187
+ // ThreadDescriptorSize() is only used by lsan to get the pointer to
188
+ // thread-specific data keys in the thread control block.
261
189
#if (defined(__x86_64__) || defined(__i386__) || defined(__mips__) || \
262
190
defined (__aarch64__) || defined(__powerpc64__) || defined(__s390__) || \
263
191
defined(__arm__) || SANITIZER_RISCV64) && \
@@ -330,13 +258,6 @@ uptr ThreadDescriptorSize() {
330
258
return val;
331
259
}
332
260
333
- // The offset at which pointer to self is located in the thread descriptor.
334
- const uptr kThreadSelfOffset = FIRST_32_SECOND_64(8 , 16 );
335
-
336
- uptr ThreadSelfOffset () {
337
- return kThreadSelfOffset ;
338
- }
339
-
340
261
#if defined(__mips__) || defined(__powerpc64__) || SANITIZER_RISCV64
341
262
// TlsPreTcbSize includes size of struct pthread_descr and size of tcb
342
263
// head structure. It lies before the static tls blocks.
@@ -355,48 +276,61 @@ static uptr TlsPreTcbSize() {
355
276
}
356
277
#endif
357
278
358
- uptr ThreadSelf () {
359
- uptr descr_addr;
360
- #if defined(__i386__)
361
- asm (" mov %%gs:%c1,%0" : " =r" (descr_addr) : " i" (kThreadSelfOffset ));
362
- #elif defined(__x86_64__)
363
- asm (" mov %%fs:%c1,%0" : " =r" (descr_addr) : " i" (kThreadSelfOffset ));
364
- #elif defined(__mips__)
365
- // MIPS uses TLS variant I. The thread pointer (in hardware register $29)
366
- // points to the end of the TCB + 0x7000. The pthread_descr structure is
367
- // immediately in front of the TCB. TlsPreTcbSize() includes the size of the
368
- // TCB and the size of pthread_descr.
369
- const uptr kTlsTcbOffset = 0x7000 ;
370
- uptr thread_pointer;
371
- asm volatile (" .set push;\
372
- .set mips64r2;\
373
- rdhwr %0,$29;\
374
- .set pop" : " =r" (thread_pointer));
375
- descr_addr = thread_pointer - kTlsTcbOffset - TlsPreTcbSize ();
376
- #elif defined(__aarch64__) || defined(__arm__)
377
- descr_addr = reinterpret_cast <uptr>(__builtin_thread_pointer ()) -
378
- ThreadDescriptorSize ();
379
- #elif SANITIZER_RISCV64
380
- // https://github.com/riscv/riscv-elf-psabi-doc/issues/53
381
- uptr thread_pointer = reinterpret_cast <uptr>(__builtin_thread_pointer ());
382
- descr_addr = thread_pointer - TlsPreTcbSize ();
383
- #elif defined(__s390__)
384
- descr_addr = reinterpret_cast <uptr>(__builtin_thread_pointer ());
385
- #elif defined(__powerpc64__)
386
- // PPC64LE uses TLS variant I. The thread pointer (in GPR 13)
387
- // points to the end of the TCB + 0x7000. The pthread_descr structure is
388
- // immediately in front of the TCB. TlsPreTcbSize() includes the size of the
389
- // TCB and the size of pthread_descr.
390
- const uptr kTlsTcbOffset = 0x7000 ;
391
- uptr thread_pointer;
392
- asm (" addi %0,13,%1" : " =r" (thread_pointer) : " I" (-kTlsTcbOffset ));
393
- descr_addr = thread_pointer - TlsPreTcbSize ();
394
- #else
395
- #error "unsupported CPU arch"
396
- #endif
397
- return descr_addr;
279
+ #if !SANITIZER_GO
280
+ namespace {
281
+ struct TlsRange {
282
+ uptr begin, end, align;
283
+ size_t tls_modid;
284
+ bool operator <(const TlsRange &rhs) const { return begin < rhs.begin ; }
285
+ };
286
+ } // namespace
287
+
288
+ static int CollectStaticTlsRanges (struct dl_phdr_info *info, size_t size,
289
+ void *data) {
290
+ if (!info->dlpi_tls_data )
291
+ return 0 ;
292
+ const uptr begin = (uptr)info->dlpi_tls_data ;
293
+ for (unsigned i = 0 ; i != info->dlpi_phnum ; ++i)
294
+ if (info->dlpi_phdr [i].p_type == PT_TLS) {
295
+ static_cast <InternalMmapVector<TlsRange> *>(data)->push_back (
296
+ TlsRange{begin, begin + info->dlpi_phdr [i].p_memsz ,
297
+ info->dlpi_phdr [i].p_align , info->dlpi_tls_modid });
298
+ break ;
299
+ }
300
+ return 0 ;
398
301
}
399
- #endif // (x86_64 || i386 || MIPS) && SANITIZER_LINUX
302
+
303
+ static void GetStaticTlsRange (uptr *addr, uptr *size) {
304
+ InternalMmapVector<TlsRange> ranges;
305
+ dl_iterate_phdr (CollectStaticTlsRanges, &ranges);
306
+ uptr len = ranges.size ();
307
+ Sort (ranges.begin (), len);
308
+ // Find the range with tls_modid=1. For glibc, because libc.so uses PT_TLS,
309
+ // this module is guaranteed to exist and is one of the initially loaded
310
+ // modules.
311
+ uptr one = 0 ;
312
+ while (one != len && ranges[one].tls_modid != 1 ) ++one;
313
+ if (one == len) {
314
+ // This may happen with musl if no module uses PT_TLS.
315
+ *addr = 0 ;
316
+ *size = 0 ;
317
+ return ;
318
+ }
319
+ // Find the maximum consecutive ranges. We consider two modules consecutive if
320
+ // the gap is smaller than the alignment. The dynamic loader places static TLS
321
+ // blocks this way not to waste space.
322
+ uptr l = one;
323
+ while (l != 0 && ranges[l].begin < ranges[l - 1 ].end + ranges[l - 1 ].align )
324
+ --l;
325
+ uptr r = one + 1 ;
326
+ while (r != len && ranges[r].begin < ranges[r - 1 ].end + ranges[r - 1 ].align )
327
+ ++r;
328
+ *addr = ranges[l].begin ;
329
+ *size = ranges[r - 1 ].end - ranges[l].begin ;
330
+ }
331
+ #endif // !SANITIZER_GO
332
+ #endif // (x86_64 || i386 || mips || ...) && SANITIZER_LINUX &&
333
+ // !SANITIZER_ANDROID
400
334
401
335
#if SANITIZER_FREEBSD
402
336
static void **ThreadSelfSegbase () {
@@ -468,18 +402,36 @@ static void GetTls(uptr *addr, uptr *size) {
468
402
*size = 0 ;
469
403
}
470
404
#elif SANITIZER_LINUX
405
+ GetStaticTlsRange (addr, size);
471
406
#if defined(__x86_64__) || defined(__i386__) || defined(__s390__)
472
- *addr = ThreadSelf ();
473
- *size = GetTlsSize ();
474
- *addr -= *size;
475
- *addr += ThreadDescriptorSize ();
476
- #elif defined(__mips__) || defined(__aarch64__) || defined(__powerpc64__) || \
477
- defined (__arm__) || SANITIZER_RISCV64
478
- *addr = ThreadSelf ();
479
- *size = GetTlsSize ();
407
+ // lsan requires the range to additionally cover the static TLS surplus
408
+ // (elf/dl-tls.c defines 1664). Otherwise there may be false positives for
409
+ // allocations only referenced by tls in dynamically loaded modules.
410
+ if (SANITIZER_GLIBC) {
411
+ *addr -= 1664 ;
412
+ *size += 1664 ;
413
+ }
414
+ // Extend the range to include the thread control block. On glibc, lsan needs
415
+ // the range to include pthread::{specific_1stblock,specific} so that
416
+ // allocations only referenced by pthread_setspecific can be scanned. This may
417
+ // underestimate by at most TLS_TCB_ALIGN-1 bytes but it should be fine
418
+ // because the number of bytes after pthread::specific is larger.
419
+ *size += ThreadDescriptorSize ();
480
420
#else
481
- *addr = 0 ;
482
- *size = 0 ;
421
+ if (SANITIZER_GLIBC)
422
+ *size += 1664 ;
423
+ #if defined(__mips__) || defined(__powerpc64__) || SANITIZER_RISCV64
424
+ const uptr pre_tcb_size = TlsPreTcbSize ();
425
+ *addr -= pre_tcb_size;
426
+ *size += pre_tcb_size;
427
+ #else
428
+ // arm and aarch64 reserve two words at TP, so this underestimates the range.
429
+ // However, this is sufficient for the purpose of finding the pointers to
430
+ // thread-specific data keys.
431
+ const uptr tcb_size = ThreadDescriptorSize ();
432
+ *addr -= tcb_size;
433
+ *size += tcb_size;
434
+ #endif
483
435
#endif
484
436
#elif SANITIZER_FREEBSD
485
437
void ** segbase = ThreadSelfSegbase ();
@@ -520,17 +472,11 @@ static void GetTls(uptr *addr, uptr *size) {
520
472
521
473
#if !SANITIZER_GO
522
474
uptr GetTlsSize () {
523
- #if SANITIZER_FREEBSD || SANITIZER_ANDROID || SANITIZER_NETBSD || \
475
+ #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
524
476
SANITIZER_SOLARIS
525
477
uptr addr, size;
526
478
GetTls (&addr, &size);
527
479
return size;
528
- #elif SANITIZER_GLIBC
529
- #if defined(__mips__) || defined(__powerpc64__) || SANITIZER_RISCV64
530
- return RoundUpTo (g_tls_size + TlsPreTcbSize (), 16 );
531
- #else
532
- return g_tls_size;
533
- #endif
534
480
#else
535
481
return 0 ;
536
482
#endif
@@ -553,10 +499,9 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
553
499
if (!main) {
554
500
// If stack and tls intersect, make them non-intersecting.
555
501
if (*tls_addr > *stk_addr && *tls_addr < *stk_addr + *stk_size) {
556
- CHECK_GT (*tls_addr + *tls_size, *stk_addr);
557
- CHECK_LE (*tls_addr + *tls_size, *stk_addr + *stk_size);
558
- *stk_size -= *tls_size;
559
- *tls_addr = *stk_addr + *stk_size;
502
+ if (*stk_addr + *stk_size < *tls_addr + *tls_size)
503
+ *tls_size = *stk_addr + *stk_size - *tls_addr;
504
+ *stk_size = *tls_addr - *stk_addr;
560
505
}
561
506
}
562
507
#endif
0 commit comments