[compiler-rt] [ASan][Windows] Honor asan config flags on windows when set through the user function (PR #122990)

David Justo via llvm-commits llvm-commits at lists.llvm.org
Tue Jan 14 17:52:12 PST 2025


https://github.com/davidmrdavid updated https://github.com/llvm/llvm-project/pull/122990

>From f5b0f9657e71477b9ee178dbefca65009d6a9922 Mon Sep 17 00:00:00 2001
From: David Justo <dajusto at microsoft.com>
Date: Tue, 14 Jan 2025 16:10:48 -0800
Subject: [PATCH 1/2] honor asan config flags on windows when set through the
 user function

---
 compiler-rt/lib/asan/asan_allocator.cpp | 12 +++++-
 compiler-rt/lib/asan/asan_allocator.h   |  1 +
 compiler-rt/lib/asan/asan_flags.cpp     | 23 +++++------
 compiler-rt/lib/asan/asan_internal.h    |  1 +
 compiler-rt/lib/asan/asan_rtl.cpp       | 54 ++++++++++++++++++++-----
 5 files changed, 66 insertions(+), 25 deletions(-)

diff --git a/compiler-rt/lib/asan/asan_allocator.cpp b/compiler-rt/lib/asan/asan_allocator.cpp
index 9e66f77217ec6b..cf041d0a62fc20 100644
--- a/compiler-rt/lib/asan/asan_allocator.cpp
+++ b/compiler-rt/lib/asan/asan_allocator.cpp
@@ -423,10 +423,15 @@ struct Allocator {
     PoisonShadow(chunk, allocated_size, kAsanHeapLeftRedzoneMagic);
   }
 
-  void ReInitialize(const AllocatorOptions &options) {
+  // Apply provided AllocatorOptions to an Allocator
+  void ApplyOptions(const AllocatorOptions &options) {
     SetAllocatorMayReturnNull(options.may_return_null);
     allocator.SetReleaseToOSIntervalMs(options.release_to_os_interval_ms);
     SharedInitCode(options);
+  }
+
+  void ReInitialize(const AllocatorOptions &options) {
+    ApplyOptions(options);
 
     // Poison all existing allocation's redzones.
     if (CanPoisonMemory()) {
@@ -975,6 +980,11 @@ void ReInitializeAllocator(const AllocatorOptions &options) {
   instance.ReInitialize(options);
 }
 
+// Apply provided AllocatorOptions to an Allocator
+void ApplyAllocatorOptions(const AllocatorOptions &options) {
+  instance.ApplyOptions(options);
+}
+
 void GetAllocatorOptions(AllocatorOptions *options) {
   instance.GetOptions(options);
 }
diff --git a/compiler-rt/lib/asan/asan_allocator.h b/compiler-rt/lib/asan/asan_allocator.h
index db8dc3bebfc620..a94ef958aa75ec 100644
--- a/compiler-rt/lib/asan/asan_allocator.h
+++ b/compiler-rt/lib/asan/asan_allocator.h
@@ -47,6 +47,7 @@ struct AllocatorOptions {
 void InitializeAllocator(const AllocatorOptions &options);
 void ReInitializeAllocator(const AllocatorOptions &options);
 void GetAllocatorOptions(AllocatorOptions *options);
+void ApplyAllocatorOptions(const AllocatorOptions &options);
 
 class AsanChunkView {
  public:
diff --git a/compiler-rt/lib/asan/asan_flags.cpp b/compiler-rt/lib/asan/asan_flags.cpp
index 9cfb70bd00c786..9be2273998e40a 100644
--- a/compiler-rt/lib/asan/asan_flags.cpp
+++ b/compiler-rt/lib/asan/asan_flags.cpp
@@ -144,7 +144,8 @@ static void InitializeDefaultFlags() {
   DisplayHelpMessages(&asan_parser);
 }
 
-static void ProcessFlags() {
+// Validate flags and report incompatible configurations
+static void ValidateFlags()s() {
   Flags *f = flags();
 
   // Flag validation:
@@ -214,11 +215,11 @@ static void ProcessFlags() {
 
 void InitializeFlags() {
   InitializeDefaultFlags();
-  ProcessFlags();
+  ValidateFlags();
 
 #if SANITIZER_WINDOWS
-  // On Windows, weak symbols are emulated by having the user program
-  // register which weak functions are defined.
+  // On Windows, weak symbols (such as the `__asan_default_options` function)
+  // are emulated by having the user program register which weak functions are defined.
   // The ASAN DLL will initialize flags prior to user module initialization,
   // so __asan_default_options will not point to the user definition yet.
   // We still want to ensure we capture when options are passed via
@@ -239,14 +240,8 @@ void InitializeFlags() {
         asan_parser.ParseString(__asan_default_options());
 
         DisplayHelpMessages(&asan_parser);
-        ProcessFlags();
-
-        // TODO: Update other globals and data structures that may need to change
-        // after initialization due to new flags potentially being set changing after
-        // `__asan_default_options` is registered.
-        // See GH issue 'https://github.com/llvm/llvm-project/issues/117925' for
-        // details.
-        SetAllocatorMayReturnNull(common_flags()->allocator_may_return_null);
+        ValidateFlags();
+        ApplyFlags();
       });
 
 #  if CAN_SANITIZE_UB
@@ -259,7 +254,7 @@ void InitializeFlags() {
         ubsan_parser.ParseString(__ubsan_default_options());
 
         // To match normal behavior, do not print UBSan help.
-        ProcessFlags();
+        ValidateFlags();
       });
 #  endif
 
@@ -273,7 +268,7 @@ void InitializeFlags() {
         lsan_parser.ParseString(__lsan_default_options());
 
         // To match normal behavior, do not print LSan help.
-        ProcessFlags();
+        ValidateFlags();
       });
 #  endif
 
diff --git a/compiler-rt/lib/asan/asan_internal.h b/compiler-rt/lib/asan/asan_internal.h
index 06dfc4b1773397..464faad56f32d1 100644
--- a/compiler-rt/lib/asan/asan_internal.h
+++ b/compiler-rt/lib/asan/asan_internal.h
@@ -61,6 +61,7 @@ using __sanitizer::StackTrace;
 
 void AsanInitFromRtl();
 bool TryAsanInitFromRtl();
+void ApplyFlags();
 
 // asan_win.cpp
 void InitializePlatformExceptionHandlers();
diff --git a/compiler-rt/lib/asan/asan_rtl.cpp b/compiler-rt/lib/asan/asan_rtl.cpp
index 19c6c210b564c5..65c40d8bf8b13d 100644
--- a/compiler-rt/lib/asan/asan_rtl.cpp
+++ b/compiler-rt/lib/asan/asan_rtl.cpp
@@ -390,6 +390,39 @@ void PrintAddressSpaceLayout() {
           kHighShadowBeg > kMidMemEnd);
 }
 
+// Apply most options specified either through the ASAN_OPTIONS
+// environment variable, or through the `__asan_default_options` user function.
+//
+// This function may be called multiple times, once per weak reference callback on
+// Windows, so it needs to be idempotent.
+//
+// Context:
+// For maximum compatibility on Windows, it is necessary for ASan options to be
+// configured/registered/applied inside this method (instead of in ASanInitInternal,
+// for example). That's because, on Windows, the user-provided definition for `__asan_default_opts`
+// may not be bound when `ASanInitInternal` is invoked (it is bound later).
+//
+// To work around the late binding on windows, `ApplyOptions` will be called, again,
+// after binding to the user-provided `__asan_default_opts` function. Therefore,
+// any flags not configured here are not guaranteed to be configurable
+// through `__asan_default_opts` on Windows.
+//
+//
+// For more details on this issue, see: https://github.com/llvm/llvm-project/issues/117925
+void ApplyFlags() {
+  SetCanPoisonMemory(flags()->poison_heap);
+  SetMallocContextSize(common_flags()->malloc_context_size);
+
+  __sanitizer_set_report_path(common_flags()->log_path);
+
+  __asan_option_detect_stack_use_after_return =
+      flags()->detect_stack_use_after_return;
+
+  AllocatorOptions allocator_options;
+  allocator_options.SetFrom(flags(), common_flags());
+  ApplyAllocatorOptions(allocator_options);
+}
+
 static bool AsanInitInternal() {
   if (LIKELY(AsanInited()))
     return true;
@@ -397,10 +430,13 @@ static bool AsanInitInternal() {
 
   CacheBinaryName();
 
-  // Initialize flags. This must be done early, because most of the
-  // initialization steps look at flags().
+  // Initialize flags and register weak function callbacks for windows.
+  // This must be done early, because most of the initialization steps look at flags().
   InitializeFlags();
 
+  // NOTE: The sleep before/after init` flags will not work on Windows when set through
+  // `__asan_default_options`, because that function is not guaranteed to be bound
+  // this early in initialization.
   WaitForDebugger(flags()->sleep_before_init, "before init");
 
   // Stop performing init at this point if we are being loaded via
@@ -416,9 +452,6 @@ static bool AsanInitInternal() {
   AsanCheckDynamicRTPrereqs();
   AvoidCVE_2016_2143();
 
-  SetCanPoisonMemory(flags()->poison_heap);
-  SetMallocContextSize(common_flags()->malloc_context_size);
-
   InitializePlatformExceptionHandlers();
 
   InitializeHighMemEnd();
@@ -428,11 +461,6 @@ static bool AsanInitInternal() {
   SetCheckUnwindCallback(CheckUnwind);
   SetPrintfAndReportCallback(AppendToErrorMessageBuffer);
 
-  __sanitizer_set_report_path(common_flags()->log_path);
-
-  __asan_option_detect_stack_use_after_return =
-      flags()->detect_stack_use_after_return;
-
   __sanitizer::InitializePlatformEarly();
 
   // Setup internal allocator callback.
@@ -460,6 +488,12 @@ static bool AsanInitInternal() {
   allocator_options.SetFrom(flags(), common_flags());
   InitializeAllocator(allocator_options);
 
+  // Apply ASan flags.
+  // NOTE: In order for options specified through `__asan_default_options` to be honored on Windows,
+  // it is necessary for those options to be configured inside the `ApplyOptions` method.
+  // See the function-level comment for `ApplyFlags` for more details.
+  ApplyFlags();
+
   if (SANITIZER_START_BACKGROUND_THREAD_IN_ASAN_INTERNAL)
     MaybeStartBackgroudThread();
 

>From 4674c0e0ef6984573e560debaae0415f2f8c7c0f Mon Sep 17 00:00:00 2001
From: David Justo <dajusto at microsoft.com>
Date: Tue, 14 Jan 2025 17:51:13 -0800
Subject: [PATCH 2/2] run: git-clang-format

---
 compiler-rt/lib/asan/asan_flags.cpp | 11 ++++----
 compiler-rt/lib/asan/asan_rtl.cpp   | 39 ++++++++++++++++-------------
 2 files changed, 28 insertions(+), 22 deletions(-)

diff --git a/compiler-rt/lib/asan/asan_flags.cpp b/compiler-rt/lib/asan/asan_flags.cpp
index 9be2273998e40a..14eac16e8e53f4 100644
--- a/compiler-rt/lib/asan/asan_flags.cpp
+++ b/compiler-rt/lib/asan/asan_flags.cpp
@@ -145,7 +145,7 @@ static void InitializeDefaultFlags() {
 }
 
 // Validate flags and report incompatible configurations
-static void ValidateFlags()s() {
+static void ValidateFlags() {
   Flags *f = flags();
 
   // Flag validation:
@@ -219,10 +219,11 @@ void InitializeFlags() {
 
 #if SANITIZER_WINDOWS
   // On Windows, weak symbols (such as the `__asan_default_options` function)
-  // are emulated by having the user program register which weak functions are defined.
-  // The ASAN DLL will initialize flags prior to user module initialization,
-  // so __asan_default_options will not point to the user definition yet.
-  // We still want to ensure we capture when options are passed via
+  // are emulated by having the user program register which weak functions are
+  // defined. The ASAN DLL will initialize flags prior to user module
+  // initialization, so __asan_default_options will not point to the user
+  // definition yet. We still want to ensure we capture when options are passed
+  // via
   // __asan_default_options, so we add a callback to be run
   // when it is registered with the runtime.
 
diff --git a/compiler-rt/lib/asan/asan_rtl.cpp b/compiler-rt/lib/asan/asan_rtl.cpp
index 65c40d8bf8b13d..54c90403426a22 100644
--- a/compiler-rt/lib/asan/asan_rtl.cpp
+++ b/compiler-rt/lib/asan/asan_rtl.cpp
@@ -393,22 +393,24 @@ void PrintAddressSpaceLayout() {
 // Apply most options specified either through the ASAN_OPTIONS
 // environment variable, or through the `__asan_default_options` user function.
 //
-// This function may be called multiple times, once per weak reference callback on
-// Windows, so it needs to be idempotent.
+// This function may be called multiple times, once per weak reference callback
+// on Windows, so it needs to be idempotent.
 //
 // Context:
 // For maximum compatibility on Windows, it is necessary for ASan options to be
-// configured/registered/applied inside this method (instead of in ASanInitInternal,
-// for example). That's because, on Windows, the user-provided definition for `__asan_default_opts`
-// may not be bound when `ASanInitInternal` is invoked (it is bound later).
+// configured/registered/applied inside this method (instead of in
+// ASanInitInternal, for example). That's because, on Windows, the user-provided
+// definition for `__asan_default_opts` may not be bound when `ASanInitInternal`
+// is invoked (it is bound later).
 //
-// To work around the late binding on windows, `ApplyOptions` will be called, again,
-// after binding to the user-provided `__asan_default_opts` function. Therefore,
-// any flags not configured here are not guaranteed to be configurable
-// through `__asan_default_opts` on Windows.
+// To work around the late binding on windows, `ApplyOptions` will be called,
+// again, after binding to the user-provided `__asan_default_opts` function.
+// Therefore, any flags not configured here are not guaranteed to be
+// configurable through `__asan_default_opts` on Windows.
 //
 //
-// For more details on this issue, see: https://github.com/llvm/llvm-project/issues/117925
+// For more details on this issue, see:
+// https://github.com/llvm/llvm-project/issues/117925
 void ApplyFlags() {
   SetCanPoisonMemory(flags()->poison_heap);
   SetMallocContextSize(common_flags()->malloc_context_size);
@@ -431,12 +433,14 @@ static bool AsanInitInternal() {
   CacheBinaryName();
 
   // Initialize flags and register weak function callbacks for windows.
-  // This must be done early, because most of the initialization steps look at flags().
+  // This must be done early, because most of the initialization steps look at
+  // flags().
   InitializeFlags();
 
-  // NOTE: The sleep before/after init` flags will not work on Windows when set through
-  // `__asan_default_options`, because that function is not guaranteed to be bound
-  // this early in initialization.
+  // NOTE: The sleep before/after init` flags will not work on Windows when set
+  // through
+  // `__asan_default_options`, because that function is not guaranteed to be
+  // bound this early in initialization.
   WaitForDebugger(flags()->sleep_before_init, "before init");
 
   // Stop performing init at this point if we are being loaded via
@@ -489,9 +493,10 @@ static bool AsanInitInternal() {
   InitializeAllocator(allocator_options);
 
   // Apply ASan flags.
-  // NOTE: In order for options specified through `__asan_default_options` to be honored on Windows,
-  // it is necessary for those options to be configured inside the `ApplyOptions` method.
-  // See the function-level comment for `ApplyFlags` for more details.
+  // NOTE: In order for options specified through `__asan_default_options` to be
+  // honored on Windows, it is necessary for those options to be configured
+  // inside the `ApplyOptions` method. See the function-level comment for
+  // `ApplyFlags` for more details.
   ApplyFlags();
 
   if (SANITIZER_START_BACKGROUND_THREAD_IN_ASAN_INTERNAL)



More information about the llvm-commits mailing list