There is a race in the instrumentation runtime during setup. The setup initializes the function pointers for indirect call instrumentation before the indirect call counters array. If the application spawns a background thread through a constructor (as does jemalloc), the background thread has a chance to derefence that uninitialized array pointer. Defer initialization of these function pointers to prevent this race. Fixes #198181. Co-authored-by: Fabian Parzefall <parzefall@meta.com>
46 lines
1.1 KiB
C++
46 lines
1.1 KiB
C++
// Test that indirect call instrumentation works if background threads are
|
|
// spawned early during application startup. This can be the case with jemalloc,
|
|
// when libstdcxx.so invokes global constructors that call malloc.
|
|
|
|
// REQUIRES: system-linux
|
|
// RUN: %clangxx %cxxflags -Wl,-q %s -o %t.exe -D_GNU_SOURCE -g
|
|
// RUN: llvm-bolt -instrument %t.exe -o %t.bolt.exe
|
|
// RUN: %t.bolt.exe
|
|
|
|
#include <atomic>
|
|
#include <dlfcn.h>
|
|
#include <pthread.h>
|
|
|
|
static pthread_mutex_t M = PTHREAD_MUTEX_INITIALIZER;
|
|
static std::atomic_bool Init;
|
|
static void *(*MallocFn)(size_t);
|
|
static pthread_t Thread;
|
|
|
|
static void target() {}
|
|
static void (*IndTarget)() = target;
|
|
|
|
static void *threadFun(void *) {
|
|
for (int I = 0; I < 1000; ++I)
|
|
IndTarget();
|
|
return nullptr;
|
|
}
|
|
|
|
extern "C" void *malloc(size_t Size) {
|
|
if (!Init) {
|
|
pthread_mutex_lock(&M);
|
|
if (!Init) {
|
|
MallocFn =
|
|
reinterpret_cast<decltype(MallocFn)>(dlsym(RTLD_NEXT, "malloc"));
|
|
Init = true;
|
|
pthread_create(&Thread, nullptr, threadFun, nullptr);
|
|
}
|
|
pthread_mutex_unlock(&M);
|
|
}
|
|
return MallocFn(Size);
|
|
}
|
|
|
|
int main() {
|
|
pthread_join(Thread, nullptr);
|
|
return 0;
|
|
}
|