Skip to content

Commit

Permalink
Attempting to use heap instead of tls for large arrays
Browse files Browse the repository at this point in the history
Workaround issue where older glibc cannot allocate large TLS
blocks after the program has started running ("cannot allocate memory
in static TLS block").

ref:
microsoft/LightGBM#6509
https://bugzilla.redhat.com/show_bug.cgi?id=1722181
  • Loading branch information
ccotter committed Aug 1, 2024
1 parent a5b7dfd commit fff9c28
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 12 deletions.
39 changes: 32 additions & 7 deletions compiler-rt/lib/msan/msan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
#include "ubsan/ubsan_flags.h"
#include "ubsan/ubsan_init.h"

#include <sys/mman.h>

// ACHTUNG! No system header includes in this file.

using namespace __sanitizer;
Expand All @@ -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;
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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();
Expand Down
2 changes: 2 additions & 0 deletions compiler-rt/lib/msan/msan.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions compiler-rt/lib/msan/msan_interceptors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
10 changes: 5 additions & 5 deletions llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down

0 comments on commit fff9c28

Please sign in to comment.