@@ -188,8 +188,80 @@ __attribute__((unused)) static bool GetLibcVersion(int *major, int *minor,
188
188
#endif
189
189
}
190
190
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
+
193
265
#if (defined(__x86_64__) || defined(__i386__) || defined(__mips__) || \
194
266
defined (__aarch64__) || defined(__powerpc64__) || defined(__s390__) || \
195
267
defined(__arm__) || SANITIZER_RISCV64) && \
@@ -262,6 +334,13 @@ uptr ThreadDescriptorSize() {
262
334
return val;
263
335
}
264
336
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
+
265
344
#if defined(__mips__) || defined(__powerpc64__) || SANITIZER_RISCV64
266
345
// TlsPreTcbSize includes size of struct pthread_descr and size of tcb
267
346
// head structure. It lies before the static tls blocks.
@@ -280,63 +359,48 @@ static uptr TlsPreTcbSize() {
280
359
}
281
360
#endif
282
361
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;
305
402
}
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
340
404
341
405
#if SANITIZER_FREEBSD
342
406
static void **ThreadSelfSegbase () {
@@ -408,54 +472,18 @@ static void GetTls(uptr *addr, uptr *size) {
408
472
*size = 0 ;
409
473
}
410
474
#elif SANITIZER_LINUX
411
- uptr align;
412
- GetStaticTlsRange (addr, size, &align);
413
475
#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 ();
451
484
#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 ;
459
487
#endif
460
488
#elif SANITIZER_FREEBSD
461
489
void ** segbase = ThreadSelfSegbase ();
@@ -496,11 +524,17 @@ static void GetTls(uptr *addr, uptr *size) {
496
524
497
525
#if !SANITIZER_GO
498
526
uptr GetTlsSize () {
499
- #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
527
+ #if SANITIZER_FREEBSD || SANITIZER_ANDROID || SANITIZER_NETBSD || \
500
528
SANITIZER_SOLARIS
501
529
uptr addr, size;
502
530
GetTls (&addr, &size);
503
531
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
504
538
#else
505
539
return 0 ;
506
540
#endif
@@ -523,9 +557,10 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
523
557
if (!main) {
524
558
// If stack and tls intersect, make them non-intersecting.
525
559
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;
529
564
}
530
565
}
531
566
#endif
0 commit comments