Index: lib/sanitizer_common/sanitizer_linux_libcdep.cc =================================================================== --- lib/sanitizer_common/sanitizer_linux_libcdep.cc +++ lib/sanitizer_common/sanitizer_linux_libcdep.cc @@ -157,29 +157,70 @@ } #endif +#if !SANITIZER_ANDROID +void GetGlibcVersion(int *minor, int *patch) { + *minor = *patch = 0; + typedef const char *(*glibc_version_fn)(); + glibc_version_fn get_glibc_version = + (glibc_version_fn)dlsym(RTLD_NEXT, "gnu_get_libc_version"); + if (!get_glibc_version) + return; + + const char *version = get_glibc_version(); + if (version[0] == '2' && version[1] == '.') { + char *end; + *minor = internal_simple_strtoll(version + 2, &end, 10); + if (end != version + 2 && (*end == '\0' || *end == '.' || *end == '-')) { + if (*end == '.') + // strtoll will return 0 if no valid conversion could be performed + *patch = internal_simple_strtoll(end + 1, nullptr, 10); + } else { + *minor = 0; + } + } +} +#endif // !SANITIZER_ANDROID + #if !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO && \ !SANITIZER_NETBSD && !SANITIZER_OPENBSD && !SANITIZER_SOLARIS static uptr g_tls_size; #ifdef __i386__ # define DL_INTERNAL_FUNCTION __attribute__((regparm(3), stdcall)) +# define CHECK_GET_TLS_STATIC_INFO_VERSION 1 #else # define DL_INTERNAL_FUNCTION +# define CHECK_GET_TLS_STATIC_INFO_VERSION 0 #endif void InitTlsSize() { // all current supported platforms have 16 bytes stack alignment const size_t kStackAlign = 16; - typedef void (*get_tls_func)(size_t*, size_t*) DL_INTERNAL_FUNCTION; - get_tls_func get_tls; - void *get_tls_static_info_ptr = dlsym(RTLD_NEXT, "_dl_get_tls_static_info"); - CHECK_EQ(sizeof(get_tls), sizeof(get_tls_static_info_ptr)); - internal_memcpy(&get_tls, &get_tls_static_info_ptr, - sizeof(get_tls_static_info_ptr)); - CHECK_NE(get_tls, 0); size_t tls_size = 0; size_t tls_align = 0; - get_tls(&tls_size, &tls_align); + int minor, patch; + GetGlibcVersion(&minor, &patch); + // Glibc before 2.27 used a different calling convention for + // _dl_get_tls_static_info on __i386__. + if (CHECK_GET_TLS_STATIC_INFO_VERSION && minor && minor < 27) { + typedef void (*get_tls_func)(size_t*, size_t*) DL_INTERNAL_FUNCTION; + get_tls_func get_tls; + void *get_tls_static_info_ptr = dlsym(RTLD_NEXT, "_dl_get_tls_static_info"); + CHECK_EQ(sizeof(get_tls), sizeof(get_tls_static_info_ptr)); + internal_memcpy(&get_tls, &get_tls_static_info_ptr, + sizeof(get_tls_static_info_ptr)); + CHECK_NE(get_tls, 0); + get_tls(&tls_size, &tls_align); + } else { + typedef void (*get_tls_func)(size_t*, size_t*); + get_tls_func get_tls; + void *get_tls_static_info_ptr = dlsym(RTLD_NEXT, "_dl_get_tls_static_info"); + CHECK_EQ(sizeof(get_tls), sizeof(get_tls_static_info_ptr)); + internal_memcpy(&get_tls, &get_tls_static_info_ptr, + sizeof(get_tls_static_info_ptr)); + CHECK_NE(get_tls, 0); + get_tls(&tls_size, &tls_align); + } if (tls_align < kStackAlign) tls_align = kStackAlign; g_tls_size = RoundUpTo(tls_size, tls_align); @@ -202,17 +243,9 @@ return val; #if defined(__x86_64__) || defined(__i386__) || defined(__arm__) #ifdef _CS_GNU_LIBC_VERSION - char buf[64]; - uptr len = confstr(_CS_GNU_LIBC_VERSION, buf, sizeof(buf)); - if (len < sizeof(buf) && internal_strncmp(buf, "glibc 2.", 8) == 0) { - char *end; - int minor = internal_simple_strtoll(buf + 8, &end, 10); - if (end != buf + 8 && (*end == '\0' || *end == '.' || *end == '-')) { - int patch = 0; - if (*end == '.') - // strtoll will return 0 if no valid conversion could be performed - patch = internal_simple_strtoll(end + 1, nullptr, 10); - + int minor, patch; + GetGlibcVersion(&minor, &patch); + if (minor) { /* sizeof(struct pthread) values from various glibc versions. */ if (SANITIZER_X32) val = 1728; // Assume only one particular version for x32. @@ -235,7 +268,6 @@ val = FIRST_32_SECOND_64(1168, 2304); else val = FIRST_32_SECOND_64(1216, 2304); - } } #endif #elif defined(__mips__)