From fff9c28d48167d0a34e8a750b94f6f663798e5ca Mon Sep 17 00:00:00 2001 From: Chris Cotter Date: Wed, 31 Jul 2024 21:34:47 -0400 Subject: [PATCH] Attempting to use heap instead of tls for large arrays Workaround issue where older glibc cannot allocate large TLS blocks after the program has started running ("cannot allocate memory in static TLS block"). ref: https://github.com/microsoft/LightGBM/issues/6509 https://bugzilla.redhat.com/show_bug.cgi?id=1722181 --- compiler-rt/lib/msan/msan.cpp | 39 +++++++++++++++---- compiler-rt/lib/msan/msan.h | 2 + compiler-rt/lib/msan/msan_interceptors.cpp | 1 + .../Instrumentation/MemorySanitizer.cpp | 10 ++--- 4 files changed, 40 insertions(+), 12 deletions(-) diff --git a/compiler-rt/lib/msan/msan.cpp b/compiler-rt/lib/msan/msan.cpp index 2ee05f43ec5e568..67b79ddf5ce62f7 100644 --- a/compiler-rt/lib/msan/msan.cpp +++ b/compiler-rt/lib/msan/msan.cpp @@ -31,6 +31,8 @@ #include "ubsan/ubsan_flags.h" #include "ubsan/ubsan_init.h" +#include + // ACHTUNG! No system header includes in this file. using namespace __sanitizer; @@ -42,25 +44,27 @@ static THREADLOCAL int msan_expected_umr_found = 0; // Function argument shadow. Each argument starts at the next available 8-byte // aligned address. SANITIZER_INTERFACE_ATTRIBUTE -THREADLOCAL u64 __msan_param_tls[kMsanParamTlsSize / sizeof(u64)]; +THREADLOCAL u64* __msan_param_tls; // Function argument origin. Each argument starts at the same offset as the // corresponding shadow in (__msan_param_tls). Slightly weird, but changing this // would break compatibility with older prebuilt binaries. SANITIZER_INTERFACE_ATTRIBUTE -THREADLOCAL u32 __msan_param_origin_tls[kMsanParamTlsSize / sizeof(u32)]; +THREADLOCAL u32* __msan_param_origin_tls; + + SANITIZER_INTERFACE_ATTRIBUTE -THREADLOCAL u64 __msan_retval_tls[kMsanRetvalTlsSize / sizeof(u64)]; +THREADLOCAL u64* __msan_retval_tls; SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL u32 __msan_retval_origin_tls; -alignas(16) SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL u64 - __msan_va_arg_tls[kMsanParamTlsSize / sizeof(u64)]; +alignas(16) SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL u64* + __msan_va_arg_tls; -alignas(16) SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL u32 - __msan_va_arg_origin_tls[kMsanParamTlsSize / sizeof(u32)]; +alignas(16) SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL u32* + __msan_va_arg_origin_tls; SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL u64 __msan_va_arg_overflow_size_tls; @@ -274,6 +278,14 @@ void ScopedThreadLocalStateBackup::Restore() { // A lame implementation that only keeps essential state and resets the rest. __msan_va_arg_overflow_size_tls = va_arg_overflow_size_tls; +#if 0 +u64 __msan_param_tls[kMsanParamTlsSize / sizeof(u64)]; +u32 __msan_param_origin_tls[kMsanParamTlsSize / sizeof(u32)]; +u64 __msan_retval_tls[kMsanRetvalTlsSize / sizeof(u64)]; +alignas(16) u64 __msan_va_arg_tls[kMsanParamTlsSize / sizeof(u64)]; +alignas(16) u32 __msan_va_arg_origin_tls[kMsanParamTlsSize / sizeof(u32)]; +#endif + internal_memset(__msan_param_tls, 0, sizeof(__msan_param_tls)); internal_memset(__msan_retval_tls, 0, sizeof(__msan_retval_tls)); internal_memset(__msan_va_arg_tls, 0, sizeof(__msan_va_arg_tls)); @@ -441,12 +453,25 @@ static void CheckUnwind() { stack.Print(); } +extern "C" void __msan_init_tls() { + if (__msan_param_tls) + return; + + __msan_param_tls = (u64*)mmap(nullptr, 0x1000, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + __msan_param_origin_tls = (u32*)mmap(nullptr, 0x1000, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + __msan_retval_tls = (u64*)mmap(nullptr, 0x1000, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + __msan_va_arg_tls = (u64*)mmap(nullptr, 0x1000, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + __msan_va_arg_origin_tls = (u32*)mmap(nullptr, 0x1000, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); +} + void __msan_init() { CHECK(!msan_init_is_running); if (msan_inited) return; msan_init_is_running = 1; SanitizerToolName = "MemorySanitizer"; + __msan_init_tls(); + AvoidCVE_2016_2143(); CacheBinaryName(); diff --git a/compiler-rt/lib/msan/msan.h b/compiler-rt/lib/msan/msan.h index 7fb58be67a02cda..68c9e17e73215c2 100644 --- a/compiler-rt/lib/msan/msan.h +++ b/compiler-rt/lib/msan/msan.h @@ -257,6 +257,8 @@ addr_is_type(uptr addr, int mapping_types) { const int kMsanParamTlsSize = 800; const int kMsanRetvalTlsSize = 800; +extern "C" void __msan_init_tls(); + namespace __msan { extern int msan_inited; extern bool msan_init_is_running; diff --git a/compiler-rt/lib/msan/msan_interceptors.cpp b/compiler-rt/lib/msan/msan_interceptors.cpp index c540523e0eaed92..34f8fef1bfc40a1 100644 --- a/compiler-rt/lib/msan/msan_interceptors.cpp +++ b/compiler-rt/lib/msan/msan_interceptors.cpp @@ -1155,6 +1155,7 @@ extern "C" int pthread_attr_destroy(void *attr); static void *MsanThreadStartFunc(void *arg) { MsanThread *t = (MsanThread *)arg; + __msan_init_tls(); SetCurrentThread(t); t->Init(); SetSigProcMask(&t->starting_sigset_, nullptr); diff --git a/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp b/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp index c979e81ac1a3fe1..0d3bcf19a9ccc2e 100644 --- a/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp @@ -861,25 +861,25 @@ void MemorySanitizer::createUserspaceApi(Module &M, const TargetLibraryInfo &TLI // Create the global TLS variables. RetvalTLS = getOrInsertGlobal(M, "__msan_retval_tls", - ArrayType::get(IRB.getInt64Ty(), kRetvalTLSSize / 8)); + PointerType::get(IRB.getInt64Ty(), 0)); RetvalOriginTLS = getOrInsertGlobal(M, "__msan_retval_origin_tls", OriginTy); ParamTLS = getOrInsertGlobal(M, "__msan_param_tls", - ArrayType::get(IRB.getInt64Ty(), kParamTLSSize / 8)); + PointerType::get(IRB.getInt64Ty(), 0)); ParamOriginTLS = getOrInsertGlobal(M, "__msan_param_origin_tls", - ArrayType::get(OriginTy, kParamTLSSize / 4)); + PointerType::get(OriginTy, 0)); VAArgTLS = getOrInsertGlobal(M, "__msan_va_arg_tls", - ArrayType::get(IRB.getInt64Ty(), kParamTLSSize / 8)); + PointerType::get(IRB.getInt64Ty(), 0)); VAArgOriginTLS = getOrInsertGlobal(M, "__msan_va_arg_origin_tls", - ArrayType::get(OriginTy, kParamTLSSize / 4)); + PointerType::get(OriginTy, 0)); VAArgOverflowSizeTLS = getOrInsertGlobal(M, "__msan_va_arg_overflow_size_tls", IRB.getInt64Ty());