Skip to content
This repository was archived by the owner on Apr 23, 2020. It is now read-only.

Commit 722b6f3

Browse files
committed
[ASAN] Fix crash on i?86-linux (32-bit) against glibc 2.27 and later
Summary: Running sanitized 32-bit x86 programs on glibc 2.27 crashes at startup, with: ERROR: AddressSanitizer: SEGV on unknown address 0xf7a8a250 (pc 0xf7f807f4 bp 0xff969fc8 sp 0xff969f7c T16777215) The signal is caused by a WRITE memory access. #0 0xf7f807f3 in _dl_get_tls_static_info (/lib/ld-linux.so.2+0x127f3) #1 0xf7a92599 (/lib/libasan.so.5+0x112599) #2 0xf7a80737 (/lib/libasan.so.5+0x100737) #3 0xf7f7e14f in _dl_init (/lib/ld-linux.so.2+0x1014f) #4 0xf7f6eb49 (/lib/ld-linux.so.2+0xb49) The problem is that glibc changed the calling convention for the GLIBC_PRIVATE symbol that sanitizer uses (even when it should not, GLIBC_PRIVATE is exactly for symbols that can change at any time, be removed etc.), see https://sourceware.org/ml/libc-alpha/2017-08/msg00497.html Fixes google/sanitizers#954 Patch By: Jakub Jelinek Reviewed By: vitalybuka, Lekensteyn Differential Revison: https://reviews.llvm.org/D44623 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@334363 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent edbb972 commit 722b6f3

File tree

1 file changed

+38
-7
lines changed

1 file changed

+38
-7
lines changed

lib/sanitizer_common/sanitizer_linux_libcdep.cc

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -162,24 +162,55 @@ bool SetEnv(const char *name, const char *value) {
162162
static uptr g_tls_size;
163163

164164
#ifdef __i386__
165+
# ifndef __GLIBC_PREREQ
166+
# define CHECK_GET_TLS_STATIC_INFO_VERSION 1
167+
# else
168+
# define CHECK_GET_TLS_STATIC_INFO_VERSION (!__GLIBC_PREREQ(2, 27))
169+
# endif
170+
#else
171+
# define CHECK_GET_TLS_STATIC_INFO_VERSION 0
172+
#endif
173+
174+
#if CHECK_GET_TLS_STATIC_INFO_VERSION
165175
# define DL_INTERNAL_FUNCTION __attribute__((regparm(3), stdcall))
166176
#else
167177
# define DL_INTERNAL_FUNCTION
168178
#endif
169179

180+
namespace {
181+
struct GetTlsStaticInfoCall {
182+
typedef void (*get_tls_func)(size_t*, size_t*);
183+
};
184+
struct GetTlsStaticInfoRegparmCall {
185+
typedef void (*get_tls_func)(size_t*, size_t*) DL_INTERNAL_FUNCTION;
186+
};
187+
188+
template <typename T>
189+
void CallGetTls(void* ptr, size_t* size, size_t* align) {
190+
typename T::get_tls_func get_tls;
191+
CHECK_EQ(sizeof(get_tls), sizeof(ptr));
192+
internal_memcpy(&get_tls, &ptr, sizeof(ptr));
193+
CHECK_NE(get_tls, 0);
194+
get_tls(size, align);
195+
}
196+
} // namespace
197+
170198
void InitTlsSize() {
171199
// all current supported platforms have 16 bytes stack alignment
172200
const size_t kStackAlign = 16;
173-
typedef void (*get_tls_func)(size_t*, size_t*) DL_INTERNAL_FUNCTION;
174-
get_tls_func get_tls;
175201
void *get_tls_static_info_ptr = dlsym(RTLD_NEXT, "_dl_get_tls_static_info");
176-
CHECK_EQ(sizeof(get_tls), sizeof(get_tls_static_info_ptr));
177-
internal_memcpy(&get_tls, &get_tls_static_info_ptr,
178-
sizeof(get_tls_static_info_ptr));
179-
CHECK_NE(get_tls, 0);
180202
size_t tls_size = 0;
181203
size_t tls_align = 0;
182-
get_tls(&tls_size, &tls_align);
204+
// On i?86, _dl_get_tls_static_info used to be internal_function, i.e.
205+
// __attribute__((regparm(3), stdcall)) before glibc 2.27 and is normal
206+
// function in 2.27 and later.
207+
if (CHECK_GET_TLS_STATIC_INFO_VERSION &&
208+
!dlvsym(RTLD_NEXT, "glob", "GLIBC_2.27"))
209+
CallGetTls<GetTlsStaticInfoRegparmCall>(get_tls_static_info_ptr,
210+
&tls_size, &tls_align);
211+
else
212+
CallGetTls<GetTlsStaticInfoCall>(get_tls_static_info_ptr,
213+
&tls_size, &tls_align);
183214
if (tls_align < kStackAlign)
184215
tls_align = kStackAlign;
185216
g_tls_size = RoundUpTo(tls_size, tls_align);

0 commit comments

Comments
 (0)