tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 5c2c7f553af07454aecf9bdf4d5f427e5ec9e728
parent 7c4c01f032d1fa709db86d662f629729ce74f107
Author: Mike Hommey <mh+mozilla@glandium.org>
Date:   Mon, 20 Oct 2025 23:05:51 +0000

Bug 1994904 - Backport fix for Windows ASAN flags initialization. r=firefox-build-system-reviewers,sergesanspaille

Differential Revision: https://phabricator.services.mozilla.com/D268980

Diffstat:
Mbuild/build-clang/clang-20.json | 1+
Abuild/build-clang/llvmorg-21-init-17702-g0d7e64f5d2b4.patch | 295+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 296 insertions(+), 0 deletions(-)

diff --git a/build/build-clang/clang-20.json b/build/build-clang/clang-20.json @@ -9,6 +9,7 @@ "revert-llvmorg-16-init-11301-g163bb6d64e5f_clang_20.patch", "revert-llvmorg-15-init-13446-g7524fe962e47.patch", "llvmorg-21-init-2651-gbac417107339.patch", + "llvmorg-21-init-17702-g0d7e64f5d2b4.patch", "llvmorg-22-init-4745-gbe179d069664.patch", "android-hardware-buffer-header-workaround.patch", "arm64e-hack.patch", diff --git a/build/build-clang/llvmorg-21-init-17702-g0d7e64f5d2b4.patch b/build/build-clang/llvmorg-21-init-17702-g0d7e64f5d2b4.patch @@ -0,0 +1,295 @@ +From 7eb91b30bedfda404e7b68d94e7ab770b774846a Mon Sep 17 00:00:00 2001 +From: David Justo <david.justo.1996@gmail.com> +Date: Wed, 2 Jul 2025 15:37:28 -0700 +Subject: [PATCH] [ASan][Windows] Honor asan config flags on windows when set + through the user function (#122990) + +**Related to:** https://github.com/llvm/llvm-project/issues/117925 +**Follow up to:** https://github.com/llvm/llvm-project/pull/117929 + +**Context:** +As noted in the linked issue, some ASan configuration flags are not +honored on Windows when set through the `__asan_default_options` user +function. The reason for this is that `__asan_default_options` is not +available by the time `AsanInitInternal` executes, which is responsible +for applying the ASan flags. + +To fix this properly, we'll probably need a deep re-design of ASan +initialization so that it is consistent across OS'es. +In the meantime, this PR offers a practical workaround. + +**This PR:** refactors part of `AsanInitInternal` so that **idempotent** +flag-applying steps are extracted into a new function `ApplyOptions`. +This function is **also** invoked in the "weak function callback" on +Windows (which gets called when `__asan_default_options` is available) +so that, if any flags were set through the user-function, they are +safely applied _then_. + +Today, `ApplyOptions` contains only a subset of flags. My hope is that +`ApplyOptions` will over time, through incremental refactorings +`AsanInitInternal` so that **all** flags are eventually honored. + +Other minor changes: +* The introduction of a `ApplyAllocatorOptions` helper method, needed to +implement `ApplyOptions` for allocator options without re-initializing +the entire allocator. Reinitializing the entire allocator is expensive, +as it may do a whole pass over all the marked memory. To my knowledge, +this isn't needed for the options captured in `ApplyAllocatorOptions`. +* Rename `ProcessFlags` to `ValidateFlags`, which seems like a more +accurate name to what that function does, and prevents confusion when +compared to the new `ApplyOptions` function. +--- + compiler-rt/lib/asan/asan_allocator.cpp | 12 ++++- + compiler-rt/lib/asan/asan_allocator.h | 1 + + compiler-rt/lib/asan/asan_flags.cpp | 32 +++++------- + compiler-rt/lib/asan/asan_internal.h | 1 + + compiler-rt/lib/asan/asan_rtl.cpp | 52 +++++++++++++++---- + .../Windows/alloc_dealloc_mismatch.cpp | 29 +++++++++++ + 6 files changed, 98 insertions(+), 29 deletions(-) + create mode 100644 compiler-rt/test/asan/TestCases/Windows/alloc_dealloc_mismatch.cpp + +diff --git a/compiler-rt/lib/asan/asan_allocator.cpp b/compiler-rt/lib/asan/asan_allocator.cpp +index 3a55c2af6565..d3c0288285b8 100644 +--- a/compiler-rt/lib/asan/asan_allocator.cpp ++++ b/compiler-rt/lib/asan/asan_allocator.cpp +@@ -424,10 +424,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()) { +@@ -977,6 +982,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 db8dc3bebfc6..a94ef958aa75 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 9cfb70bd00c7..190a89345dd1 100644 +--- a/compiler-rt/lib/asan/asan_flags.cpp ++++ b/compiler-rt/lib/asan/asan_flags.cpp +@@ -144,6 +144,7 @@ static void InitializeDefaultFlags() { + DisplayHelpMessages(&asan_parser); + } + ++// Validate flags and report incompatible configurations + static void ProcessFlags() { + Flags *f = flags(); + +@@ -217,11 +218,12 @@ void InitializeFlags() { + ProcessFlags(); + + #if SANITIZER_WINDOWS +- // On Windows, weak symbols 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 ++ // 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 + // __asan_default_options, so we add a callback to be run + // when it is registered with the runtime. + +@@ -232,21 +234,13 @@ void InitializeFlags() { + // __sanitizer_register_weak_function. + AddRegisterWeakFunctionCallback( + reinterpret_cast<uptr>(__asan_default_options), []() { +- FlagParser asan_parser; +- +- RegisterAsanFlags(&asan_parser, flags()); +- RegisterCommonFlags(&asan_parser); +- asan_parser.ParseString(__asan_default_options()); +- +- DisplayHelpMessages(&asan_parser); ++ // We call `InitializeDefaultFlags` again, instead of just parsing ++ // `__asan_default_options` directly, to ensure that flags set through ++ // `ASAN_OPTS` take precedence over those set through ++ // `__asan_default_options`. ++ InitializeDefaultFlags(); + 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); ++ ApplyFlags(); + }); + + # if CAN_SANITIZE_UB +diff --git a/compiler-rt/lib/asan/asan_internal.h b/compiler-rt/lib/asan/asan_internal.h +index 06dfc4b17733..464faad56f32 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 19c6c210b564..1564a8f5164c 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); ++ ++ __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,8 +430,9 @@ static bool AsanInitInternal() { + + CacheBinaryName(); + +- // Initialize flags. This must be done early, because most of the +- // initialization steps look at flags(). ++ // Initialize flags. On Windows it also also register weak function callbacks. ++ // This must be done early, because most of the initialization steps look at ++ // flags(). + InitializeFlags(); + + WaitForDebugger(flags()->sleep_before_init, "before init"); +@@ -416,9 +450,6 @@ static bool AsanInitInternal() { + AsanCheckDynamicRTPrereqs(); + AvoidCVE_2016_2143(); + +- SetCanPoisonMemory(flags()->poison_heap); +- SetMallocContextSize(common_flags()->malloc_context_size); +- + InitializePlatformExceptionHandlers(); + + InitializeHighMemEnd(); +@@ -429,10 +460,6 @@ static bool AsanInitInternal() { + 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 +487,13 @@ 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(); + +diff --git a/compiler-rt/test/asan/TestCases/Windows/alloc_dealloc_mismatch.cpp b/compiler-rt/test/asan/TestCases/Windows/alloc_dealloc_mismatch.cpp +new file mode 100644 +index 000000000000..c7d62f15c3c3 +--- /dev/null ++++ b/compiler-rt/test/asan/TestCases/Windows/alloc_dealloc_mismatch.cpp +@@ -0,0 +1,29 @@ ++// RUN: %clangxx_asan -O0 %s -o %t ++// RUN: %env_asan_opts=alloc_dealloc_mismatch=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-MISMATCH ++// RUN: %env_asan_opts=alloc_dealloc_mismatch=0 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-SUCCESS ++ ++// RUN: %clangxx_asan -O0 %s -o %t -DUSER_FUNCTION ++// RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-MISMATCH ++ ++// It is expected that ASAN_OPTS will override the value set through the user function. ++// RUN: %env_asan_opts=alloc_dealloc_mismatch=0 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-SUCCESS ++ ++#if USER_FUNCTION ++// It's important to test the `alloc_dealloc_mismatch` flag set through the user function because, on Windows, ++// flags configured through the user-defined function `__asan_default_options` are not always be honored. ++// See: https://github.com/llvm/llvm-project/issues/117925 ++extern "C" __declspec(dllexport) extern const char *__asan_default_options() { ++ return "alloc_dealloc_mismatch=1"; ++} ++#endif ++ ++#include <cstdio> ++#include <cstdlib> ++ ++// Tests the `alloc_dealloc_mismatch` flag set both via user function and through the environment variable. ++int main() { ++ // In the 'CHECK-MISMATCH' case, we simply check that the AddressSanitizer reports an error. ++ delete (new int[10]); // CHECK-MISMATCH: AddressSanitizer: ++ printf("Success"); // CHECK-SUCCESS: Success ++ return 0; ++} +\ No newline at end of file +-- +2.51.0.1.g7a422dac74 +