From 7bb5e4c19246a8b15f8083f15cafb282b11d24f4 Mon Sep 17 00:00:00 2001 From: Ryan Macnak Date: Wed, 17 Dec 2025 14:08:00 -0800 Subject: [PATCH] [build] Fix Windows ASAN build to actually use ASAN. Bug: https://github.com/dart-lang/sdk/issues/62263 Change-Id: I77a44aeff0a0685730ff3e5c897e338ddc5561a7 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/464781 Commit-Queue: Ryan Macnak Reviewed-by: Alexander Aprelev --- build/config/BUILDCONFIG.gn | 6 +++ build/config/compiler/BUILD.gn | 54 +++++++++++++++++----- runtime/BUILD.gn | 2 +- runtime/tests/vm/dart/asan/read_test.dart | 2 +- runtime/tests/vm/dart/asan/write_test.dart | 2 +- runtime/tests/vm/dart/msan/read_test.dart | 2 +- 6 files changed, 53 insertions(+), 15 deletions(-) diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn index 20646b228f4..5c74ed867f4 100644 --- a/build/config/BUILDCONFIG.gn +++ b/build/config/BUILDCONFIG.gn @@ -525,6 +525,12 @@ foreach(_target_type, ] } } + if (is_win && is_asan) { + if (!defined(data_deps)) { + data_deps = [] + } + data_deps += [ "//build/config/compiler:copy_sanitizer_runtime" ] + } } } } else { diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn index b041a075b5e..6830b0c1b14 100644 --- a/build/config/compiler/BUILD.gn +++ b/build/config/compiler/BUILD.gn @@ -38,6 +38,13 @@ config("default_include_dirs") { ] } +if (is_win && is_asan) { + copy("copy_sanitizer_runtime") { + sources = [ "//buildtools/win-x64/clang/lib/clang/22/lib/x86_64-pc-windows-msvc/clang_rt.asan_dynamic.dll" ] + outputs = [ "$root_out_dir/{{source_file_part}}" ] + } +} + # compiler --------------------------------------------------------------------- # # Base compiler configuration. @@ -107,11 +114,38 @@ config("compiler") { ldflags += [ "-Wl,--fix-cortex-a53-843419" ] } - # Common options for AddressSanitizer, LeakSanitizer, ThreadSanitizer and - # MemorySanitizer + if (use_custom_libcxx) { + cflags_cc += [ "-nostdinc++" ] + include_dirs = [ + "//buildtools/third_party/libc++/trunk/include", + "//buildtools/third_party/libc++abi/trunk/include", + ] + } + } + + # Common options for AddressSanitizer, LeakSanitizer, ThreadSanitizer and + # MemorySanitizer + if (is_clang || !is_win) { if (is_asan) { cflags += [ "-fsanitize=address" ] - ldflags += [ "-fsanitize=address" ] + if (is_win) { + # Windows directly calls link.exe instead of the compiler driver when + # linking. Hence, pass the runtime libraries instead of -fsanitize=address + # or -fsanitize=fuzzer. + _clang_lib_dir = + "//buildtools/win-x64/clang/lib/clang/22/lib/x86_64-pc-windows-msvc" + libs = [ "$_clang_lib_dir/clang_rt.asan_dynamic.lib" ] + ldflags += [ "-libpath:" + rebase_path("$_clang_lib_dir") ] + if (is_shared_library) { + ldflags += [ "-wholearchive:clang_rt.asan_dynamic_runtime_thunk.lib" ] + libs += [ "$_clang_lib_dir/clang_rt.asan_dynamic_runtime_thunk.lib" ] + } else { + ldflags += [ "-wholearchive:clang_rt.asan_static_runtime_thunk.lib" ] + libs += [ "$_clang_lib_dir/clang_rt.asan_static_runtime_thunk.lib" ] + } + } else { + ldflags += [ "-fsanitize=address" ] + } } if (is_hwasan && is_android && current_cpu == "arm64") { cflags += [ "-fsanitize=hwaddress" ] @@ -156,14 +190,6 @@ config("compiler") { "@loader_path/../../../../buildtools/mac-$host_cpu/clang/lib/clang/22/lib/darwin", ] } - - if (use_custom_libcxx) { - cflags_cc += [ "-nostdinc++" ] - include_dirs = [ - "//buildtools/third_party/libc++/trunk/include", - "//buildtools/third_party/libc++abi/trunk/include", - ] - } } if (is_clang && is_debug) { @@ -814,6 +840,12 @@ if (is_win) { # Warning: This changes C/C++ semantics of function pointer comparison. "/OPT:ICF", ] + if (is_clang) { + common_optimize_on_ldflags += [ + # This interferes with ODR violation checks in ASAN. + "/OPT:NOLLDTAILMERGE", + ] + } } else { common_optimize_on_cflags = [ # Don't emit the GCC version ident directives, they just end up in the diff --git a/runtime/BUILD.gn b/runtime/BUILD.gn index fd0cbf91d32..769f0d2ced5 100644 --- a/runtime/BUILD.gn +++ b/runtime/BUILD.gn @@ -112,7 +112,7 @@ config("dart_precompiler_config") { # In our GN build rules we'll always compile AOT compiler & AOT runtime in # the same mode (TSAN or non-TSAN). - if (is_asan && !is_win) { + if (is_asan) { defines += [ "TARGET_USES_ADDRESS_SANITIZER" ] } else if (is_msan) { defines += [ "TARGET_USES_MEMORY_SANITIZER" ] diff --git a/runtime/tests/vm/dart/asan/read_test.dart b/runtime/tests/vm/dart/asan/read_test.dart index 2036f3aa929..089fe046e37 100644 --- a/runtime/tests/vm/dart/asan/read_test.dart +++ b/runtime/tests/vm/dart/asan/read_test.dart @@ -59,7 +59,7 @@ main(List arguments) { Expect.contains("READ of size 8", result.stderr); //# uint64: ok Expect.contains("READ of size 4", result.stderr); //# float32: ok Expect.contains("READ of size 8", result.stderr); //# float64: ok - if (Platform.executable.contains("aotruntime")) { + if (Platform.executable.contains("aotruntime") && !Platform.isWindows) { Expect.contains("expectedFunction", result.stderr); } } diff --git a/runtime/tests/vm/dart/asan/write_test.dart b/runtime/tests/vm/dart/asan/write_test.dart index f60bca0c6f8..19d29d14de8 100644 --- a/runtime/tests/vm/dart/asan/write_test.dart +++ b/runtime/tests/vm/dart/asan/write_test.dart @@ -59,7 +59,7 @@ main(List arguments) { Expect.contains("WRITE of size 8", result.stderr); //# uint64: ok Expect.contains("WRITE of size 4", result.stderr); //# float32: ok Expect.contains("WRITE of size 8", result.stderr); //# float64: ok - if (Platform.executable.contains("aotruntime")) { + if (Platform.executable.contains("aotruntime") && !Platform.isWindows) { Expect.contains("expectedFunction", result.stderr); } } diff --git a/runtime/tests/vm/dart/msan/read_test.dart b/runtime/tests/vm/dart/msan/read_test.dart index 489a5c04980..14f5807c3eb 100644 --- a/runtime/tests/vm/dart/msan/read_test.dart +++ b/runtime/tests/vm/dart/msan/read_test.dart @@ -59,7 +59,7 @@ main(List arguments) { Expect.contains(", 8)", result.stderr); //# uint64: ok Expect.contains(", 4)", result.stderr); //# float32: ok Expect.contains(", 8)", result.stderr); //# float64: ok - if (Platform.executable.contains("aotruntime")) { + if (Platform.executable.contains("aotruntime") && !Platform.isWindows) { Expect.contains("expectedFunction", result.stderr); } }