|
21 | 21 | #include "sanitizer_placement_new.h"
|
22 | 22 | #include "sanitizer_procmaps.h"
|
23 | 23 | #include "sanitizer_stacktrace.h"
|
| 24 | +#include "sanitizer_atomic.h" |
24 | 25 |
|
25 | 26 | #include <dlfcn.h>
|
26 | 27 | #include <pthread.h>
|
|
32 | 33 | #if !SANITIZER_ANDROID
|
33 | 34 | #include <elf.h>
|
34 | 35 | #include <link.h>
|
| 36 | +#include <unistd.h> |
35 | 37 | #endif
|
36 | 38 |
|
37 | 39 | #ifndef SANITIZER_GO
|
@@ -226,16 +228,41 @@ uptr GetTlsSize() {
|
226 | 228 |
|
227 | 229 | #if defined(__x86_64__) || defined(__i386__)
|
228 | 230 | // sizeof(struct thread) from glibc.
|
229 |
| -// There has been a report of this being different on glibc 2.11 and 2.13. We |
230 |
| -// don't know when this change happened, so 2.14 is a conservative estimate. |
231 |
| -#if __GLIBC_PREREQ(2, 14) |
232 |
| -const uptr kThreadDescriptorSize = FIRST_32_SECOND_64(1216, 2304); |
233 |
| -#else |
234 |
| -const uptr kThreadDescriptorSize = FIRST_32_SECOND_64(1168, 2304); |
235 |
| -#endif |
| 231 | +static atomic_uintptr_t kThreadDescriptorSize; |
236 | 232 |
|
237 | 233 | uptr ThreadDescriptorSize() {
|
238 |
| - return kThreadDescriptorSize; |
| 234 | + char buf[64]; |
| 235 | + uptr val = atomic_load(&kThreadDescriptorSize, memory_order_relaxed); |
| 236 | + if (val) |
| 237 | + return val; |
| 238 | +#ifdef _CS_GNU_LIBC_VERSION |
| 239 | + uptr len = confstr(_CS_GNU_LIBC_VERSION, buf, sizeof(buf)); |
| 240 | + if (len < sizeof(buf) && internal_strncmp(buf, "glibc 2.", 8) == 0) { |
| 241 | + char *end; |
| 242 | + int minor = internal_simple_strtoll(buf + 8, &end, 10); |
| 243 | + if (end != buf + 8 && (*end == '\0' || *end == '.')) { |
| 244 | + /* sizeof(struct thread) values from various glibc versions. */ |
| 245 | + if (minor <= 3) |
| 246 | + val = FIRST_32_SECOND_64(1104, 1696); |
| 247 | + else if (minor == 4) |
| 248 | + val = FIRST_32_SECOND_64(1120, 1728); |
| 249 | + else if (minor == 5) |
| 250 | + val = FIRST_32_SECOND_64(1136, 1728); |
| 251 | + else if (minor <= 9) |
| 252 | + val = FIRST_32_SECOND_64(1136, 1712); |
| 253 | + else if (minor == 10) |
| 254 | + val = FIRST_32_SECOND_64(1168, 1776); |
| 255 | + else if (minor <= 12) |
| 256 | + val = FIRST_32_SECOND_64(1168, 2288); |
| 257 | + else |
| 258 | + val = FIRST_32_SECOND_64(1216, 2304); |
| 259 | + } |
| 260 | + if (val) |
| 261 | + atomic_store(&kThreadDescriptorSize, val, memory_order_relaxed); |
| 262 | + return val; |
| 263 | + } |
| 264 | +#endif |
| 265 | + return 0; |
239 | 266 | }
|
240 | 267 |
|
241 | 268 | // The offset at which pointer to self is located in the thread descriptor.
|
@@ -263,7 +290,7 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
|
263 | 290 | *tls_addr = ThreadSelf();
|
264 | 291 | *tls_size = GetTlsSize();
|
265 | 292 | *tls_addr -= *tls_size;
|
266 |
| - *tls_addr += kThreadDescriptorSize; |
| 293 | + *tls_addr += ThreadDescriptorSize(); |
267 | 294 | #else
|
268 | 295 | *tls_addr = 0;
|
269 | 296 | *tls_size = 0;
|
|
0 commit comments