[compiler-rt] Synchronizing ASAN init on Windows (PR #71833)
Zack Johnson via llvm-commits
llvm-commits at lists.llvm.org
Thu Nov 9 09:46:18 PST 2023
https://github.com/zacklj89 created https://github.com/llvm/llvm-project/pull/71833
This is an attempt to synchronize ASAN initialization using `__sanitizer::atomic`s on Windows. One case in particular is a C# application that loads an ASan instrumented library.
This addresses:
1. [This check failure](https://github.com/llvm/llvm-project/blob/1df5ea29b43690b6622db2cad7b745607ca4de6a/compiler-rt/lib/asan/asan_interceptors.h#L29C36-L29C36) if a function is intercepted on T1 and called on T2 before T1 is done with ASAN initialization.
2. [This check failure](https://github.com/llvm/llvm-project/blob/1df5ea29b43690b6622db2cad7b745607ca4de6a/compiler-rt/lib/asan/asan_rtl.cpp#L387) can happen in parallel when two threads call `ENSURE_ASAN_INITED`.
3. [This check failure](https://github.com/llvm/llvm-project/blob/1df5ea29b43690b6622db2cad7b745607ca4de6a/compiler-rt/lib/asan/asan_rtl.cpp#L481) when thread is created before the main thread gets a chance to get created due to when `CreateThread` is intercepted.
Currently, everything is blocked by `#if SANITIZER_WINDOWS` because I'm not 100% sure about how ASan is loaded on other platforms and the implications.
>From 9a50ce75d6d2d3a9e56c7763bfa0a9c287f880bf Mon Sep 17 00:00:00 2001
From: Zachary Johnson <zajohnson at microsoft.com>
Date: Thu, 9 Nov 2023 12:30:06 -0500
Subject: [PATCH] Synchronizing ASAN init on Windows
---
compiler-rt/lib/asan/asan_allocator.cpp | 2 +-
compiler-rt/lib/asan/asan_globals.cpp | 8 +--
compiler-rt/lib/asan/asan_interceptors.cpp | 20 +++---
compiler-rt/lib/asan/asan_interceptors.h | 4 +-
.../asan/asan_interceptors_memintrinsics.cpp | 4 +-
compiler-rt/lib/asan/asan_internal.h | 19 +++++-
compiler-rt/lib/asan/asan_malloc_linux.cpp | 2 +-
compiler-rt/lib/asan/asan_malloc_mac.cpp | 2 +-
compiler-rt/lib/asan/asan_malloc_win.cpp | 10 +--
compiler-rt/lib/asan/asan_rtl.cpp | 66 ++++++++++++++++---
compiler-rt/lib/asan/asan_stack.cpp | 2 +-
compiler-rt/lib/asan/asan_thread.cpp | 23 +++++++
12 files changed, 123 insertions(+), 39 deletions(-)
diff --git a/compiler-rt/lib/asan/asan_allocator.cpp b/compiler-rt/lib/asan/asan_allocator.cpp
index 15eefcb96063a88..22dcf6132707b52 100644
--- a/compiler-rt/lib/asan/asan_allocator.cpp
+++ b/compiler-rt/lib/asan/asan_allocator.cpp
@@ -527,7 +527,7 @@ struct Allocator {
// -------------------- Allocation/Deallocation routines ---------------
void *Allocate(uptr size, uptr alignment, BufferedStackTrace *stack,
AllocType alloc_type, bool can_fill) {
- if (UNLIKELY(!asan_inited))
+ if (UNLIKELY(!AsanInited()))
AsanInitFromRtl();
if (UNLIKELY(IsRssLimitExceeded())) {
if (AllocatorMayReturnNull())
diff --git a/compiler-rt/lib/asan/asan_globals.cpp b/compiler-rt/lib/asan/asan_globals.cpp
index 14c36bdc8e64296..597c710690dadb1 100644
--- a/compiler-rt/lib/asan/asan_globals.cpp
+++ b/compiler-rt/lib/asan/asan_globals.cpp
@@ -196,7 +196,7 @@ static inline bool UseODRIndicator(const Global *g) {
// This function may be called more than once for every global
// so we store the globals in a map.
static void RegisterGlobal(const Global *g) {
- CHECK(asan_inited);
+ CHECK(AsanInited());
if (flags()->report_globals >= 2)
ReportGlobal(*g, "Added");
CHECK(flags()->report_globals);
@@ -237,7 +237,7 @@ static void RegisterGlobal(const Global *g) {
}
static void UnregisterGlobal(const Global *g) {
- CHECK(asan_inited);
+ CHECK(AsanInited());
if (flags()->report_globals >= 2)
ReportGlobal(*g, "Removed");
CHECK(flags()->report_globals);
@@ -427,7 +427,7 @@ void __asan_before_dynamic_init(const char *module_name) {
return;
bool strict_init_order = flags()->strict_init_order;
CHECK(module_name);
- CHECK(asan_inited);
+ CHECK(AsanInited());
Lock lock(&mu_for_globals);
if (flags()->report_globals >= 3)
Printf("DynInitPoison module: %s\n", module_name);
@@ -451,7 +451,7 @@ void __asan_after_dynamic_init() {
!CanPoisonMemory() ||
!dynamic_init_globals)
return;
- CHECK(asan_inited);
+ CHECK(AsanInited());
Lock lock(&mu_for_globals);
// FIXME: Optionally report that we're unpoisoning globals from a module.
for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) {
diff --git a/compiler-rt/lib/asan/asan_interceptors.cpp b/compiler-rt/lib/asan/asan_interceptors.cpp
index 0ee8e0ea786edeb..80d00a728100d1f 100644
--- a/compiler-rt/lib/asan/asan_interceptors.cpp
+++ b/compiler-rt/lib/asan/asan_interceptors.cpp
@@ -99,9 +99,9 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)
#define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \
ASAN_INTERCEPTOR_ENTER(ctx, func); \
do { \
- if (asan_init_is_running) \
+ if (AsanInitIsRunning()) \
return REAL(func)(__VA_ARGS__); \
- if (SANITIZER_APPLE && UNLIKELY(!asan_inited)) \
+ if (SANITIZER_APPLE && UNLIKELY(!AsanInited())) \
return REAL(func)(__VA_ARGS__); \
ENSURE_ASAN_INITED(); \
} while (false)
@@ -138,7 +138,7 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)
# define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit()
# define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle)
# define COMMON_INTERCEPTOR_LIBRARY_UNLOADED()
-# define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (!asan_inited)
+# define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (!AsanInited())
# define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end) \
if (AsanThread *t = GetCurrentThread()) { \
*begin = t->tls_begin(); \
@@ -535,12 +535,12 @@ INTERCEPTOR(char *, strcpy, char *to, const char *from) {
void *ctx;
ASAN_INTERCEPTOR_ENTER(ctx, strcpy);
#if SANITIZER_APPLE
- if (UNLIKELY(!asan_inited))
+ if (UNLIKELY(!AsanInited()))
return REAL(strcpy)(to, from);
#endif
// strcpy is called from malloc_default_purgeable_zone()
// in __asan::ReplaceSystemAlloc() on Mac.
- if (asan_init_is_running) {
+ if (AsanInitIsRunning()) {
return REAL(strcpy)(to, from);
}
ENSURE_ASAN_INITED();
@@ -556,7 +556,7 @@ INTERCEPTOR(char *, strcpy, char *to, const char *from) {
INTERCEPTOR(char*, strdup, const char *s) {
void *ctx;
ASAN_INTERCEPTOR_ENTER(ctx, strdup);
- if (UNLIKELY(!asan_inited)) return internal_strdup(s);
+ if (UNLIKELY(!AsanInited())) return internal_strdup(s);
ENSURE_ASAN_INITED();
uptr length = internal_strlen(s);
if (flags()->replace_str) {
@@ -574,7 +574,7 @@ INTERCEPTOR(char*, strdup, const char *s) {
INTERCEPTOR(char*, __strdup, const char *s) {
void *ctx;
ASAN_INTERCEPTOR_ENTER(ctx, strdup);
- if (UNLIKELY(!asan_inited)) return internal_strdup(s);
+ if (UNLIKELY(!AsanInited())) return internal_strdup(s);
ENSURE_ASAN_INITED();
uptr length = internal_strlen(s);
if (flags()->replace_str) {
@@ -634,7 +634,7 @@ INTERCEPTOR(int, atoi, const char *nptr) {
void *ctx;
ASAN_INTERCEPTOR_ENTER(ctx, atoi);
#if SANITIZER_APPLE
- if (UNLIKELY(!asan_inited)) return REAL(atoi)(nptr);
+ if (UNLIKELY(!AsanInited())) return REAL(atoi)(nptr);
#endif
ENSURE_ASAN_INITED();
if (!flags()->replace_str) {
@@ -655,7 +655,7 @@ INTERCEPTOR(long, atol, const char *nptr) {
void *ctx;
ASAN_INTERCEPTOR_ENTER(ctx, atol);
#if SANITIZER_APPLE
- if (UNLIKELY(!asan_inited)) return REAL(atol)(nptr);
+ if (UNLIKELY(!AsanInited())) return REAL(atol)(nptr);
#endif
ENSURE_ASAN_INITED();
if (!flags()->replace_str) {
@@ -693,7 +693,7 @@ static void AtCxaAtexit(void *unused) {
INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
void *dso_handle) {
#if SANITIZER_APPLE
- if (UNLIKELY(!asan_inited)) return REAL(__cxa_atexit)(func, arg, dso_handle);
+ if (UNLIKELY(!AsanInited())) return REAL(__cxa_atexit)(func, arg, dso_handle);
#endif
ENSURE_ASAN_INITED();
#if CAN_SANITIZE_LEAKS
diff --git a/compiler-rt/lib/asan/asan_interceptors.h b/compiler-rt/lib/asan/asan_interceptors.h
index d00d05587b36881..19a40f18c43fa42 100644
--- a/compiler-rt/lib/asan/asan_interceptors.h
+++ b/compiler-rt/lib/asan/asan_interceptors.h
@@ -26,8 +26,8 @@ void InitializePlatformInterceptors();
#define ENSURE_ASAN_INITED() \
do { \
- CHECK(!asan_init_is_running); \
- if (UNLIKELY(!asan_inited)) { \
+ CHECK(!AsanInitIsRunning()); \
+ if (UNLIKELY(!AsanInited())) {\
AsanInitFromRtl(); \
} \
} while (0)
diff --git a/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp b/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp
index 4e4ea7191d3204f..bdf328f8920634d 100644
--- a/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp
+++ b/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp
@@ -33,7 +33,7 @@ using namespace __asan;
} \
ASAN_READ_RANGE(ctx, from, size); \
ASAN_WRITE_RANGE(ctx, to, size); \
- } else if (UNLIKELY(!asan_inited)) { \
+ } else if (UNLIKELY(!AsanInited())) { \
return internal_memcpy(to, from, size); \
} \
return REAL(memcpy)(to, from, size); \
@@ -44,7 +44,7 @@ using namespace __asan;
do { \
if (LIKELY(replace_intrin_cached)) { \
ASAN_WRITE_RANGE(ctx, block, size); \
- } else if (UNLIKELY(!asan_inited)) { \
+ } else if (UNLIKELY(!AsanInited())) { \
return internal_memset(block, c, size); \
} \
return REAL(memset)(block, c, size); \
diff --git a/compiler-rt/lib/asan/asan_internal.h b/compiler-rt/lib/asan/asan_internal.h
index a5348e35b297eb1..b8b8b44d0dcbb3e 100644
--- a/compiler-rt/lib/asan/asan_internal.h
+++ b/compiler-rt/lib/asan/asan_internal.h
@@ -130,9 +130,22 @@ void InstallAtExitCheckLeaks();
if (&__asan_on_error) \
__asan_on_error()
-extern int asan_inited;
-// Used to avoid infinite recursion in __asan_init().
-extern bool asan_init_is_running;
+// Depending on the loading thread and when ASAN is loaded on Windows,
+// race conditions can appear causing incorrect states or internal check
+// failures.
+//
+// From a multithreaded managed environment, if an ASAN instrumented dll
+// is loading on a spawned thread, an intercepted function may be called on multiple
+// threads while ASAN is still in the process of initialization. This can also
+// cause the ASAN thread registry to create the "main" thread after another
+// thread, resulting in a TID != 0.
+//
+// Two threads can also race to initialize ASAN, resulting in either incorrect
+// state or internal check failures for init already running.
+//
+bool AsanInited();
+bool AsanInitIsRunning(); // Used to avoid infinite recursion in __asan_init().
+
extern bool replace_intrin_cached;
extern void (*death_callback)(void);
// These magic values are written to shadow for better error
diff --git a/compiler-rt/lib/asan/asan_malloc_linux.cpp b/compiler-rt/lib/asan/asan_malloc_linux.cpp
index bab80b96f584b90..0ba74c5d71432bd 100644
--- a/compiler-rt/lib/asan/asan_malloc_linux.cpp
+++ b/compiler-rt/lib/asan/asan_malloc_linux.cpp
@@ -31,7 +31,7 @@
using namespace __asan;
struct DlsymAlloc : public DlSymAllocator<DlsymAlloc> {
- static bool UseImpl() { return asan_init_is_running; }
+ static bool UseImpl() { return AsanInitIsRunning(); }
static void OnAllocate(const void *ptr, uptr size) {
# if CAN_SANITIZE_LEAKS
// Suppress leaks from dlerror(). Previously dlsym hack on global array was
diff --git a/compiler-rt/lib/asan/asan_malloc_mac.cpp b/compiler-rt/lib/asan/asan_malloc_mac.cpp
index 924d1f12640a7a9..242f030b000a299 100644
--- a/compiler-rt/lib/asan/asan_malloc_mac.cpp
+++ b/compiler-rt/lib/asan/asan_malloc_mac.cpp
@@ -23,7 +23,7 @@
using namespace __asan;
#define COMMON_MALLOC_ZONE_NAME "asan"
#define COMMON_MALLOC_ENTER() ENSURE_ASAN_INITED()
-#define COMMON_MALLOC_SANITIZER_INITIALIZED asan_inited
+#define COMMON_MALLOC_SANITIZER_INITIALIZED AsanInited()
#define COMMON_MALLOC_FORCE_LOCK() asan_mz_force_lock()
#define COMMON_MALLOC_FORCE_UNLOCK() asan_mz_force_unlock()
#define COMMON_MALLOC_MEMALIGN(alignment, size) \
diff --git a/compiler-rt/lib/asan/asan_malloc_win.cpp b/compiler-rt/lib/asan/asan_malloc_win.cpp
index ff78d7646a90dc8..7e1d04c36dd5801 100644
--- a/compiler-rt/lib/asan/asan_malloc_win.cpp
+++ b/compiler-rt/lib/asan/asan_malloc_win.cpp
@@ -211,7 +211,7 @@ INTERCEPTOR_WINAPI(size_t, HeapSize, HANDLE hHeap, DWORD dwFlags,
// interception takes place, so if it is not owned by the RTL heap we can
// pass it to the ASAN heap for inspection.
if (flags()->windows_hook_rtl_allocators) {
- if (!asan_inited || OWNED_BY_RTL(hHeap, lpMem))
+ if (!AsanInited() || OWNED_BY_RTL(hHeap, lpMem))
return REAL(HeapSize)(hHeap, dwFlags, lpMem);
} else {
CHECK(dwFlags == 0 && "unsupported heap flags");
@@ -226,7 +226,7 @@ INTERCEPTOR_WINAPI(LPVOID, HeapAlloc, HANDLE hHeap, DWORD dwFlags,
// If the ASAN runtime is not initialized, or we encounter an unsupported
// flag, fall back to the original allocator.
if (flags()->windows_hook_rtl_allocators) {
- if (UNLIKELY(!asan_inited ||
+ if (UNLIKELY(!AsanInited() ||
(dwFlags & HEAP_ALLOCATE_UNSUPPORTED_FLAGS) != 0)) {
return REAL(HeapAlloc)(hHeap, dwFlags, dwBytes);
}
@@ -297,7 +297,7 @@ void *SharedReAlloc(ReAllocFunction reallocFunc, SizeFunction heapSizeFunc,
// If this heap block which was allocated before the ASAN
// runtime came up, use the real HeapFree function.
- if (UNLIKELY(!asan_inited)) {
+ if (UNLIKELY(!AsanInited())) {
return reallocFunc(hHeap, dwFlags, lpMem, dwBytes);
}
bool only_asan_supported_flags =
@@ -420,7 +420,7 @@ size_t RtlSizeHeap(void* HeapHandle, DWORD Flags, void* BaseAddress);
INTERCEPTOR_WINAPI(size_t, RtlSizeHeap, HANDLE HeapHandle, DWORD Flags,
void* BaseAddress) {
if (!flags()->windows_hook_rtl_allocators ||
- UNLIKELY(!asan_inited || OWNED_BY_RTL(HeapHandle, BaseAddress))) {
+ UNLIKELY(!AsanInited() || OWNED_BY_RTL(HeapHandle, BaseAddress))) {
return REAL(RtlSizeHeap)(HeapHandle, Flags, BaseAddress);
}
GET_CURRENT_PC_BP_SP;
@@ -448,7 +448,7 @@ INTERCEPTOR_WINAPI(void*, RtlAllocateHeap, HANDLE HeapHandle, DWORD Flags,
// If the ASAN runtime is not initialized, or we encounter an unsupported
// flag, fall back to the original allocator.
if (!flags()->windows_hook_rtl_allocators ||
- UNLIKELY(!asan_inited ||
+ UNLIKELY(!AsanInited() ||
(Flags & HEAP_ALLOCATE_UNSUPPORTED_FLAGS) != 0)) {
return REAL(RtlAllocateHeap)(HeapHandle, Flags, Size);
}
diff --git a/compiler-rt/lib/asan/asan_rtl.cpp b/compiler-rt/lib/asan/asan_rtl.cpp
index 853083182b48787..2cdaf88278455b0 100644
--- a/compiler-rt/lib/asan/asan_rtl.cpp
+++ b/compiler-rt/lib/asan/asan_rtl.cpp
@@ -71,8 +71,55 @@ static void CheckUnwind() {
}
// -------------------------- Globals --------------------- {{{1
-int asan_inited;
-bool asan_init_is_running;
+#if SANITIZER_WINDOWS
+atomic_uint8_t asan_inited{0};
+atomic_uint8_t asan_init_is_running{0};
+#else
+int asan_inited = 0;
+int asan_init_is_running = 0;
+#endif
+
+void SetAsanInited(u32 val) {
+#if SANITIZER_WINDOWS
+ atomic_store(&asan_inited, val, memory_order_release);
+#else
+ asan_inited = val;
+#endif
+}
+
+void SetAsanInitIsRunning(u32 val) {
+#if SANITIZER_WINDOWS
+ atomic_store(&asan_init_is_running, val, memory_order_release);
+#else
+ asan_init_is_running = val;
+#endif
+}
+
+bool AsanInited() {
+#if SANITIZER_WINDOWS
+ return atomic_load(&asan_inited, memory_order_acquire) == 1;
+#else
+ return asan_inited == 1;
+#endif
+}
+
+bool AsanInitIsRunning() {
+#if SANITIZER_WINDOWS
+ return atomic_load(&asan_init_is_running, memory_order_acquire) == 1;
+#else
+ return asan_init_is_running == 1;
+#endif
+}
+
+void CheckAsanInitRunning() {
+#if SANITIZER_WINDOWS
+ while (AsanInitIsRunning()) {
+ // If ASAN is initializing on another thread, wait for it to finish.
+ }
+#endif
+ return;
+}
+
bool replace_intrin_cached;
#if !ASAN_FIXED_MAPPING
@@ -382,10 +429,11 @@ void PrintAddressSpaceLayout() {
}
static void AsanInitInternal() {
- if (LIKELY(asan_inited)) return;
+ CheckAsanInitRunning();
+ if (LIKELY(AsanInited())) return;
SanitizerToolName = "AddressSanitizer";
- CHECK(!asan_init_is_running && "ASan init calls itself!");
- asan_init_is_running = true;
+ CHECK(!AsanInitIsRunning() && "ASan init calls itself!");
+ SetAsanInitIsRunning(1);
CacheBinaryName();
@@ -398,7 +446,7 @@ static void AsanInitInternal() {
// Stop performing init at this point if we are being loaded via
// dlopen() and the platform supports it.
if (SANITIZER_SUPPORTS_INIT_FOR_DLOPEN && UNLIKELY(HandleDlopenInit())) {
- asan_init_is_running = false;
+ SetAsanInitIsRunning(0);
VReport(1, "AddressSanitizer init is being performed for dlopen().\n");
return;
}
@@ -460,8 +508,8 @@ static void AsanInitInternal() {
// On Linux AsanThread::ThreadStart() calls malloc() that's why asan_inited
// should be set to 1 prior to initializing the threads.
replace_intrin_cached = flags()->replace_intrin;
- asan_inited = 1;
- asan_init_is_running = false;
+ SetAsanInited(1);
+ SetAsanInitIsRunning(0);
if (flags()->atexit)
Atexit(asan_atexit);
@@ -583,7 +631,7 @@ static void UnpoisonFakeStack() {
using namespace __asan;
void NOINLINE __asan_handle_no_return() {
- if (asan_init_is_running)
+ if (AsanInitIsRunning())
return;
if (!PlatformUnpoisonStacks())
diff --git a/compiler-rt/lib/asan/asan_stack.cpp b/compiler-rt/lib/asan/asan_stack.cpp
index 048295d6928ad5d..764c6ac193fb063 100644
--- a/compiler-rt/lib/asan/asan_stack.cpp
+++ b/compiler-rt/lib/asan/asan_stack.cpp
@@ -57,7 +57,7 @@ void __sanitizer::BufferedStackTrace::UnwindImpl(
uptr pc, uptr bp, void *context, bool request_fast, u32 max_depth) {
using namespace __asan;
size = 0;
- if (UNLIKELY(!asan_inited))
+ if (UNLIKELY(!AsanInited()))
return;
request_fast = StackTrace::WillUseFastUnwind(request_fast);
AsanThread *t = GetCurrentThread();
diff --git a/compiler-rt/lib/asan/asan_thread.cpp b/compiler-rt/lib/asan/asan_thread.cpp
index 8798968947e82e6..4f70731a329c341 100644
--- a/compiler-rt/lib/asan/asan_thread.cpp
+++ b/compiler-rt/lib/asan/asan_thread.cpp
@@ -27,6 +27,10 @@ namespace __asan {
// AsanThreadContext implementation.
+#if SANITIZER_WINDOWS
+atomic_uint8_t mainThreadCreated{0};
+#endif
+
void AsanThreadContext::OnCreated(void *arg) {
CreateThreadContextArgs *args = static_cast<CreateThreadContextArgs *>(arg);
if (args->stack)
@@ -93,6 +97,11 @@ AsanThreadContext *GetThreadContextByTidLocked(u32 tid) {
AsanThread *AsanThread::Create(const void *start_data, uptr data_size,
u32 parent_tid, StackTrace *stack,
bool detached) {
+#if SANITIZER_WINDOWS
+ while (atomic_load(&mainThreadCreated, memory_order_acquire) == 0) {
+ // If another thread is trying to be created before the main thread, wait.
+ }
+#endif
uptr PageSize = GetPageSizeCached();
uptr size = RoundUpTo(sizeof(AsanThread), PageSize);
AsanThread *thread = (AsanThread *)MmapOrDie(size, __func__);
@@ -288,11 +297,25 @@ void AsanThread::ThreadStart(tid_t os_id) {
}
AsanThread *CreateMainThread() {
+// Depending on the loading thread, specifically in managed scenarios, the main
+// thread can be created after other threads on Windows. This ensures we start
+// the main thread before those threads.
+#if SANITIZER_WINDOWS
+ uptr PageSize = GetPageSizeCached();
+ uptr size = RoundUpTo(sizeof(AsanThread), PageSize);
+ AsanThread *main_thread = (AsanThread *)MmapOrDie(size, __func__);
+ AsanThreadContext::CreateThreadContextArgs args = {main_thread, nullptr};
+ asanThreadRegistry().CreateThread(0, true, kMainTid, &args);
+ SetCurrentThread(main_thread);
+ main_thread->ThreadStart(internal_getpid());
+ atomic_store(&mainThreadCreated, 1, memory_order_release);
+#else
AsanThread *main_thread = AsanThread::Create(
/* parent_tid */ kMainTid,
/* stack */ nullptr, /* detached */ true);
SetCurrentThread(main_thread);
main_thread->ThreadStart(internal_getpid());
+#endif
return main_thread;
}
More information about the llvm-commits
mailing list