clemenswasser updated this revision to Diff 399689.
clemenswasser edited the summary of this revision.
clemenswasser added a comment.

Updated the Tests.
The Problem with Lsan+Asan still exists. I have just disabled them for now.
I hope anyone can help me with getting the tests to run correctly?


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D115103/new/

https://reviews.llvm.org/D115103

Files:
  clang/lib/Driver/ToolChains/MSVC.cpp
  compiler-rt/cmake/config-ix.cmake
  compiler-rt/lib/lsan/CMakeLists.txt
  compiler-rt/lib/lsan/lsan.h
  compiler-rt/lib/lsan/lsan_allocator.h
  compiler-rt/lib/lsan/lsan_common.cpp
  compiler-rt/lib/lsan/lsan_common.h
  compiler-rt/lib/lsan/lsan_common_win.cpp
  compiler-rt/lib/lsan/lsan_interceptors.cpp
  compiler-rt/lib/lsan/lsan_win.cpp
  compiler-rt/lib/lsan/lsan_win.h
  compiler-rt/test/lsan/TestCases/Darwin/dispatch.mm
  compiler-rt/test/lsan/TestCases/Linux/cleanup_in_tsd_destructor.c
  compiler-rt/test/lsan/TestCases/Linux/disabler_in_tsd_destructor.c
  compiler-rt/test/lsan/TestCases/Linux/use_tls_dynamic.cpp
  compiler-rt/test/lsan/TestCases/Linux/use_tls_pthread_specific_dynamic.cpp
  compiler-rt/test/lsan/TestCases/Linux/use_tls_pthread_specific_static.cpp
  compiler-rt/test/lsan/TestCases/Linux/use_tls_static.cpp
  compiler-rt/test/lsan/TestCases/disabler.c
  compiler-rt/test/lsan/TestCases/disabler.cpp
  compiler-rt/test/lsan/TestCases/do_leak_check_override.cpp
  compiler-rt/test/lsan/TestCases/high_allocator_contention.cpp
  compiler-rt/test/lsan/TestCases/ignore_object.c
  compiler-rt/test/lsan/TestCases/large_allocation_leak.cpp
  compiler-rt/test/lsan/TestCases/leak_check_at_exit.cpp
  compiler-rt/test/lsan/TestCases/link_turned_off.cpp
  compiler-rt/test/lsan/TestCases/many_tls_keys_pthread.cpp
  compiler-rt/test/lsan/TestCases/many_tls_keys_thread.cpp
  compiler-rt/test/lsan/TestCases/pointer_to_self.cpp
  compiler-rt/test/lsan/TestCases/print_suppressions.cpp
  compiler-rt/test/lsan/TestCases/recoverable_leak_check.cpp
  compiler-rt/test/lsan/TestCases/register_root_region.cpp
  compiler-rt/test/lsan/TestCases/stale_stack_leak.cpp
  compiler-rt/test/lsan/TestCases/suppressions_default.cpp
  compiler-rt/test/lsan/TestCases/suppressions_file.cpp
  compiler-rt/test/lsan/TestCases/use_after_return.cpp
  compiler-rt/test/lsan/TestCases/use_globals_initialized.cpp
  compiler-rt/test/lsan/TestCases/use_globals_uninitialized.cpp
  compiler-rt/test/lsan/TestCases/use_globals_unused.cpp
  compiler-rt/test/lsan/TestCases/use_poisoned_asan.cpp
  compiler-rt/test/lsan/TestCases/use_registers.cpp
  compiler-rt/test/lsan/TestCases/use_registers_extra.cpp
  compiler-rt/test/lsan/TestCases/use_stacks.cpp
  compiler-rt/test/lsan/TestCases/use_stacks_threaded.cpp
  compiler-rt/test/lsan/TestCases/use_unaligned.cpp
  compiler-rt/test/lsan/lit.common.cfg.py

Index: compiler-rt/test/lsan/lit.common.cfg.py
===================================================================
--- compiler-rt/test/lsan/lit.common.cfg.py
+++ compiler-rt/test/lsan/lit.common.cfg.py
@@ -22,7 +22,8 @@
 # Choose between standalone and LSan+ASan modes.
 lsan_lit_test_mode = get_required_attr(config, 'lsan_lit_test_mode')
 
-if lsan_lit_test_mode == "Standalone":
+# FIXME: All tests are Standalone on Windows for now. Since all win32 function calls in lsan get intercepted by asan :(
+if lsan_lit_test_mode == "Standalone" or config.host_os == 'Windows':
   config.name = "LeakSanitizer-Standalone"
   lsan_cflags = ["-fsanitize=leak"]
 elif lsan_lit_test_mode == "AddressSanitizer":
@@ -74,12 +75,13 @@
 config.substitutions.append( ("%clangxx_lsan ", build_invocation(clang_lsan_cxxflags)) )
 
 # LeakSanitizer tests are currently supported on
-# Android{aarch64, x86, x86_64}, x86-64 Linux, PowerPC64 Linux, arm Linux, mips64 Linux, s390x Linux and x86_64 Darwin.
+# Windows{x86_64, x86, aarch64, arm}, Android{aarch64, x86, x86_64}, x86-64 Linux, PowerPC64 Linux, arm Linux, mips64 Linux, s390x Linux and x86_64 Darwin.
 supported_android = config.android and config.target_arch in ['x86_64', 'i386', 'aarch64'] and 'android-thread-properties-api' in config.available_features
 supported_linux = (not config.android) and config.host_os == 'Linux' and config.host_arch in ['aarch64', 'x86_64', 'ppc64', 'ppc64le', 'mips64', 'riscv64', 'arm', 'armhf', 'armv7l', 's390x']
 supported_darwin = config.host_os == 'Darwin' and config.target_arch in ['x86_64']
 supported_netbsd = config.host_os == 'NetBSD' and config.target_arch in ['x86_64', 'i386']
-if not (supported_android or supported_linux or supported_darwin or supported_netbsd):
+supported_windows = config.host_os == 'Windows' and config.target_arch in ['x86_64', 'i386', 'aarch64', 'arm']
+if not (supported_android or supported_linux or supported_darwin or supported_netbsd or supported_windows):
   config.unsupported = True
 
 # Don't support Thumb due to broken fast unwinder
Index: compiler-rt/test/lsan/TestCases/use_unaligned.cpp
===================================================================
--- compiler-rt/test/lsan/TestCases/use_unaligned.cpp
+++ compiler-rt/test/lsan/TestCases/use_unaligned.cpp
@@ -1,8 +1,7 @@
 // Test that unaligned pointers are detected correctly.
-// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0"
 // RUN: %clangxx_lsan %s -o %t
-// RUN: %env_lsan_opts=$LSAN_BASE:"use_unaligned=0" not %run %t 2>&1 | FileCheck %s
-// RUN: %env_lsan_opts=$LSAN_BASE:"use_unaligned=1" %run %t 2>&1
+// RUN: %env_lsan_opts="report_objects=1:use_stacks=0:use_registers=0:use_unaligned=0" not %run %t 2>&1 | FileCheck %s
+// RUN: %env_lsan_opts="report_objects=1:use_stacks=0:use_registers=0:use_unaligned=1" %run %t 2>&1
 
 #include <stdio.h>
 #include <stdlib.h>
Index: compiler-rt/test/lsan/TestCases/use_stacks_threaded.cpp
===================================================================
--- compiler-rt/test/lsan/TestCases/use_stacks_threaded.cpp
+++ compiler-rt/test/lsan/TestCases/use_stacks_threaded.cpp
@@ -1,8 +1,7 @@
 // Test that stacks of non-main threads are included in the root set.
-// RUN: LSAN_BASE="report_objects=1:use_registers=0"
 // RUN: %clangxx_lsan -pthread %s -o %t
-// RUN: %env_lsan_opts=$LSAN_BASE:"use_stacks=0" not %run %t 2>&1 | FileCheck %s
-// RUN: %env_lsan_opts=$LSAN_BASE:"use_stacks=1" %run %t 2>&1
+// RUN: %env_lsan_opts="report_objects=1:use_registers=0:use_stacks=0" not %run %t 2>&1 | FileCheck %s
+// RUN: %env_lsan_opts="report_objects=1:use_registers=0:use_stacks=1" %run %t 2>&1
 // RUN: %env_lsan_opts="" %run %t 2>&1
 
 #include <assert.h>
Index: compiler-rt/test/lsan/TestCases/use_stacks.cpp
===================================================================
--- compiler-rt/test/lsan/TestCases/use_stacks.cpp
+++ compiler-rt/test/lsan/TestCases/use_stacks.cpp
@@ -1,8 +1,7 @@
 // Test that stack of main thread is included in the root set.
-// RUN: LSAN_BASE="report_objects=1:use_registers=0"
 // RUN: %clangxx_lsan %s -o %t
-// RUN: %env_lsan_opts=$LSAN_BASE:"use_stacks=0" not %run %t 2>&1 | FileCheck %s
-// RUN: %env_lsan_opts=$LSAN_BASE:"use_stacks=1" %run %t 2>&1
+// RUN: %env_lsan_opts="report_objects=1:use_registers=0:use_stacks=0" not %run %t 2>&1 | FileCheck %s
+// RUN: %env_lsan_opts="report_objects=1:use_registers=0:use_stacks=1" %run %t 2>&1
 // RUN: %env_lsan_opts="" %run %t 2>&1
 
 #include <stdio.h>
Index: compiler-rt/test/lsan/TestCases/use_registers_extra.cpp
===================================================================
--- compiler-rt/test/lsan/TestCases/use_registers_extra.cpp
+++ compiler-rt/test/lsan/TestCases/use_registers_extra.cpp
@@ -1,8 +1,7 @@
 // Test that registers of running threads are included in the root set.
-// RUN: LSAN_BASE="report_objects=1:use_stacks=0"
 // RUN: %clangxx_lsan -pthread %s -o %t
-// RUN: %env_lsan_opts=$LSAN_BASE:"use_registers=0" not %run %t 2>&1 | FileCheck %s
-// RUN: %env_lsan_opts=$LSAN_BASE:"use_registers=1" %run %t 2>&1
+// RUN: %env_lsan_opts="report_objects=1:use_stacks=0:use_registers=0" not %run %t 2>&1 | FileCheck %s
+// RUN: %env_lsan_opts="report_objects=1:use_stacks=0:use_registers=1" %run %t 2>&1
 // RUN: %env_lsan_opts="" %run %t 2>&1
 
 // FIXME: Support more platforms.
Index: compiler-rt/test/lsan/TestCases/use_registers.cpp
===================================================================
--- compiler-rt/test/lsan/TestCases/use_registers.cpp
+++ compiler-rt/test/lsan/TestCases/use_registers.cpp
@@ -1,8 +1,7 @@
 // Test that registers of running threads are included in the root set.
-// RUN: LSAN_BASE="report_objects=1:use_stacks=0"
 // RUN: %clangxx_lsan -pthread %s -o %t
-// RUN: %env_lsan_opts=$LSAN_BASE:"use_registers=0" not %run %t 2>&1 | FileCheck %s
-// RUN: %env_lsan_opts=$LSAN_BASE:"use_registers=1" %run %t 2>&1
+// RUN: %env_lsan_opts="report_objects=1:use_stacks=0:use_registers=0" not %run %t 2>&1 | FileCheck %s
+// RUN: %env_lsan_opts="report_objects=1:use_stacks=0:use_registers=1" %run %t 2>&1
 // RUN: %env_lsan_opts="" %run %t 2>&1
 
 #include "sanitizer_common/print_address.h"
Index: compiler-rt/test/lsan/TestCases/use_poisoned_asan.cpp
===================================================================
--- compiler-rt/test/lsan/TestCases/use_poisoned_asan.cpp
+++ compiler-rt/test/lsan/TestCases/use_poisoned_asan.cpp
@@ -1,9 +1,8 @@
 // ASan-poisoned memory should be ignored if use_poisoned is false.
 // REQUIRES: asan
-// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0"
 // RUN: %clangxx_lsan %s -o %t
-// RUN: %env_lsan_opts=$LSAN_BASE:"use_poisoned=0" not %run %t 2>&1 | FileCheck %s
-// RUN: %env_lsan_opts=$LSAN_BASE:"use_poisoned=1" %run %t 2>&1
+// RUN: %env_lsan_opts="report_objects=1:use_stacks=0:use_registers=0:use_poisoned=0" not %run %t 2>&1 | FileCheck %s
+// RUN: %env_lsan_opts="report_objects=1:use_stacks=0:use_registers=0:use_poisoned=1" %run %t 2>&1
 
 #include <stdio.h>
 #include <stdlib.h>
Index: compiler-rt/test/lsan/TestCases/use_globals_unused.cpp
===================================================================
--- compiler-rt/test/lsan/TestCases/use_globals_unused.cpp
+++ compiler-rt/test/lsan/TestCases/use_globals_unused.cpp
@@ -1,12 +1,11 @@
 // Test that unused globals are included in the root set.
 // RUN: %clangxx_lsan -O2 %s -DTEST_LIB -c -o %t.o
 // RUN: %clangxx_lsan -O2 %s %t.o -o %t
-// RUN: LSAN_BASE="use_stacks=0:use_registers=0"
-// RUN: %env_lsan_opts=$LSAN_BASE:"use_globals=1" %run %t 2>&1 | FileCheck %s --implicit-check-not=leak
+// RUN: %env_lsan_opts="use_stacks=0:use_registers=0:use_globals=1" %run %t 2>&1 | FileCheck %s --implicit-check-not=leak
 // RUN: %env_lsan_opts="" %run %t 2>&1 | FileCheck %s --implicit-check-not=leak
 
 // FIXME: This check is not very important and fails on arm7.
-// %env_lsan_opts=$LSAN_BASE:"use_globals=0" not %run %t 2>&1 | FileCheck %s --check-prefixes=LEAK
+// %env_lsan_opts="use_stacks=0:use_registers=0:use_globals=0" not %run %t 2>&1 | FileCheck %s --check-prefixes=LEAK
 
 #include <stdio.h>
 #include <stdlib.h>
Index: compiler-rt/test/lsan/TestCases/use_globals_uninitialized.cpp
===================================================================
--- compiler-rt/test/lsan/TestCases/use_globals_uninitialized.cpp
+++ compiler-rt/test/lsan/TestCases/use_globals_uninitialized.cpp
@@ -1,8 +1,7 @@
 // Test that uninitialized globals are included in the root set.
-// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0"
 // RUN: %clangxx_lsan %s -o %t
-// RUN: %env_lsan_opts=$LSAN_BASE:"use_globals=0" not %run %t 2>&1 | FileCheck %s
-// RUN: %env_lsan_opts=$LSAN_BASE:"use_globals=1" %run %t 2>&1
+// RUN: %env_lsan_opts="report_objects=1:use_stacks=0:use_registers=0:use_globals=0" not %run %t 2>&1 | FileCheck %s
+// RUN: %env_lsan_opts="report_objects=1:use_stacks=0:use_registers=0:use_globals=1" %run %t 2>&1
 // RUN: %env_lsan_opts="" %run %t 2>&1
 
 #include <stdio.h>
Index: compiler-rt/test/lsan/TestCases/use_globals_initialized.cpp
===================================================================
--- compiler-rt/test/lsan/TestCases/use_globals_initialized.cpp
+++ compiler-rt/test/lsan/TestCases/use_globals_initialized.cpp
@@ -1,8 +1,7 @@
 // Test that initialized globals are included in the root set.
-// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0"
 // RUN: %clangxx_lsan %s -o %t
-// RUN: %env_lsan_opts=$LSAN_BASE:"use_globals=0" not %run %t 2>&1 | FileCheck %s
-// RUN: %env_lsan_opts=$LSAN_BASE:"use_globals=1" %run %t 2>&1
+// RUN: %env_lsan_opts="report_objects=1:use_stacks=0:use_registers=0:use_globals=0" not %run %t 2>&1 | FileCheck %s
+// RUN: %env_lsan_opts="report_objects=1:use_stacks=0:use_registers=0:use_globals=1" %run %t 2>&1
 // RUN: %env_lsan_opts="" %run %t 2>&1
 
 #include <stdio.h>
Index: compiler-rt/test/lsan/TestCases/use_after_return.cpp
===================================================================
--- compiler-rt/test/lsan/TestCases/use_after_return.cpp
+++ compiler-rt/test/lsan/TestCases/use_after_return.cpp
@@ -1,10 +1,9 @@
 // Test that fake stack (introduced by ASan's use-after-return mode) is included
 // in the root set.
-// RUN: LSAN_BASE="report_objects=1:use_registers=0"
 // RUN: %clangxx_lsan %s -O2 -o %t
-// RUN: ASAN_OPTIONS=detect_stack_use_after_return=1 %env_lsan_opts=$LSAN_BASE:"use_stacks=0" not %run %t 2>&1 | FileCheck %s
-// RUN: ASAN_OPTIONS=detect_stack_use_after_return=1 %env_lsan_opts=$LSAN_BASE:"use_stacks=1" %run %t 2>&1
-// RUN: ASAN_OPTIONS=detect_stack_use_after_return=1 %env_lsan_opts="" %run %t 2>&1
+// RUN: env ASAN_OPTIONS=detect_stack_use_after_return=1 %env_lsan_opts="report_objects=1:use_registers=0:use_stacks=0" not %run %t 2>&1 | FileCheck %s
+// RUN: env ASAN_OPTIONS=detect_stack_use_after_return=1 %env_lsan_opts="report_objects=1:use_registers=0:use_stacks=1" %run %t 2>&1
+// RUN: env ASAN_OPTIONS=detect_stack_use_after_return=1 %env_lsan_opts="" %run %t 2>&1
 
 // Investigate why it does not fail with use_stack=0
 // UNSUPPORTED: arm-linux || armhf-linux
Index: compiler-rt/test/lsan/TestCases/suppressions_file.cpp
===================================================================
--- compiler-rt/test/lsan/TestCases/suppressions_file.cpp
+++ compiler-rt/test/lsan/TestCases/suppressions_file.cpp
@@ -1,18 +1,17 @@
-// RUN: LSAN_BASE="use_registers=0:use_stacks=0"
 // RUN: %clangxx_lsan %s -o %t
 
 // RUN: rm -f %t.supp
 // RUN: touch %t.supp
 // RUN: %push_to_device %t.supp %device_rundir/%t.supp
-// RUN: %env_lsan_opts="$LSAN_BASE:suppressions='%device_rundir/%t.supp'" not %run %t 2>&1 | FileCheck %s --check-prefix=NOSUPP
+// RUN: %env_lsan_opts="use_registers=0:use_stacks=0:suppressions='%device_rundir/%t.supp'" not %run %t 2>&1 | FileCheck %s --check-prefix=NOSUPP
 
 // RUN: echo "leak:*LSanTestLeakingFunc*" > %t.supp
 // RUN: %push_to_device  %t.supp %device_rundir/%t.supp
-// RUN: %env_lsan_opts="$LSAN_BASE:suppressions='%device_rundir/%t.supp'" not %run %t 2>&1 | FileCheck %s
+// RUN: %env_lsan_opts="use_registers=0:use_stacks=0:suppressions='%device_rundir/%t.supp'" not %run %t 2>&1 | FileCheck %s
 //
 // RUN: echo "leak:%t" > %t.supp
 // RUN: %push_to_device  %t.supp %device_rundir/%t.supp
-// RUN: %env_lsan_opts="$LSAN_BASE:suppressions='%device_rundir/%t.supp':symbolize=false" %run %t
+// RUN: %env_lsan_opts="use_registers=0:use_stacks=0:suppressions='%device_rundir/%t.supp':symbolize=false" %run %t
 
 #include <stdio.h>
 #include <stdlib.h>
Index: compiler-rt/test/lsan/TestCases/suppressions_default.cpp
===================================================================
--- compiler-rt/test/lsan/TestCases/suppressions_default.cpp
+++ compiler-rt/test/lsan/TestCases/suppressions_default.cpp
@@ -1,6 +1,5 @@
-// RUN: LSAN_BASE="use_registers=0:use_stacks=0"
 // RUN: %clangxx_lsan %s -o %t
-// RUN: %env_lsan_opts=$LSAN_BASE not %run %t 2>&1 | FileCheck %s
+// RUN: %env_lsan_opts=use_registers=0:use_stacks=0 not %run %t 2>&1 | FileCheck %s
 
 #include <stdio.h>
 #include <stdlib.h>
Index: compiler-rt/test/lsan/TestCases/stale_stack_leak.cpp
===================================================================
--- compiler-rt/test/lsan/TestCases/stale_stack_leak.cpp
+++ compiler-rt/test/lsan/TestCases/stale_stack_leak.cpp
@@ -1,5 +1,4 @@
 // Test that out-of-scope local variables are ignored by LSan.
-// RUN: LSAN_BASE="report_objects=1:use_registers=0:use_stacks=1"
 
 // LSan-in-ASan fails at -O0 on aarch64, because the stack use-after-return
 // instrumentation stashes the argument to `PutPointerOnStaleStack` on the stack
@@ -10,8 +9,8 @@
 // callee-saved register for rematerialization instead.
 // RUN: %clangxx_lsan -O1 %s -o %t
 
-// RUN: %env_lsan_opts=$LSAN_BASE not %run %t 2>&1 | FileCheck %s
-// RUN: %env_lsan_opts=$LSAN_BASE":exitcode=0" %run %t 2>&1 | FileCheck --check-prefix=CHECK-sanity %s
+// RUN: %env_lsan_opts="report_objects=1:use_registers=0:use_stacks=1" not %run %t 2>&1 | FileCheck %s
+// RUN: %env_lsan_opts="report_objects=1:use_registers=0:use_stacks=1:exitcode=0" %run %t 2>&1 | FileCheck --check-prefix=CHECK-sanity %s
 //
 // x86 passes parameters through stack that may lead to false negatives
 // The same applies to s390x register save areas.
Index: compiler-rt/test/lsan/TestCases/register_root_region.cpp
===================================================================
--- compiler-rt/test/lsan/TestCases/register_root_region.cpp
+++ compiler-rt/test/lsan/TestCases/register_root_region.cpp
@@ -1,9 +1,8 @@
 // Test for __lsan_(un)register_root_region().
-// RUN: LSAN_BASE="use_stacks=0:use_registers=0"
 // RUN: %clangxx_lsan %s -o %t
-// RUN: %env_lsan_opts=$LSAN_BASE %run %t
-// RUN: %env_lsan_opts=$LSAN_BASE not %run %t foo 2>&1 | FileCheck %s
-// RUN: %env_lsan_opts=$LSAN_BASE:use_root_regions=0 not %run %t 2>&1 | FileCheck %s
+// RUN: %env_lsan_opts=use_stacks=0:use_registers=0 %run %t
+// RUN: %env_lsan_opts=use_stacks=0:use_registers=0 not %run %t foo 2>&1 | FileCheck %s
+// RUN: %env_lsan_opts=use_stacks=0:use_registers=0:use_root_regions=0 not %run %t 2>&1 | FileCheck %s
 
 #include <assert.h>
 #include <stdio.h>
Index: compiler-rt/test/lsan/TestCases/recoverable_leak_check.cpp
===================================================================
--- compiler-rt/test/lsan/TestCases/recoverable_leak_check.cpp
+++ compiler-rt/test/lsan/TestCases/recoverable_leak_check.cpp
@@ -1,8 +1,7 @@
 // Test for on-demand leak checking.
-// RUN: LSAN_BASE="use_stacks=0:use_registers=0"
 // RUN: %clangxx_lsan %s -o %t
-// RUN: %env_lsan_opts=$LSAN_BASE %run %t foo 2>&1 | FileCheck %s
-// RUN: %env_lsan_opts=$LSAN_BASE %run %t 2>&1 | FileCheck %s
+// RUN: %env_lsan_opts=use_stacks=0:use_registers=0 %run %t foo 2>&1 | FileCheck %s
+// RUN: %env_lsan_opts=use_stacks=0:use_registers=0 %run %t 2>&1 | FileCheck %s
 //
 // UNSUPPORTED: darwin
 
Index: compiler-rt/test/lsan/TestCases/print_suppressions.cpp
===================================================================
--- compiler-rt/test/lsan/TestCases/print_suppressions.cpp
+++ compiler-rt/test/lsan/TestCases/print_suppressions.cpp
@@ -1,11 +1,10 @@
 // Print matched suppressions only if print_suppressions=1 AND at least one is
 // matched. Default is print_suppressions=true.
-// RUN: LSAN_BASE="use_registers=0:use_stacks=0"
 // RUN: %clangxx_lsan %s -o %t
-// RUN: %env_lsan_opts=$LSAN_BASE:print_suppressions=0 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-dont-print
-// RUN: %env_lsan_opts=$LSAN_BASE %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-dont-print
-// RUN: %env_lsan_opts=$LSAN_BASE:print_suppressions=0 %run %t foo 2>&1 | FileCheck %s --check-prefix=CHECK-dont-print
-// RUN: %env_lsan_opts=$LSAN_BASE %run %t foo 2>&1 | FileCheck %s --check-prefix=CHECK-print
+// RUN: %env_lsan_opts=use_registers=0:use_stacks=0:print_suppressions=0 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-dont-print
+// RUN: %env_lsan_opts=use_registers=0:use_stacks=0 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-dont-print
+// RUN: %env_lsan_opts=use_registers=0:use_stacks=0:print_suppressions=0 %run %t foo 2>&1 | FileCheck %s --check-prefix=CHECK-dont-print
+// RUN: %env_lsan_opts=use_registers=0:use_stacks=0 %run %t foo 2>&1 | FileCheck %s --check-prefix=CHECK-print
 
 #include <stdio.h>
 #include <stdlib.h>
Index: compiler-rt/test/lsan/TestCases/pointer_to_self.cpp
===================================================================
--- compiler-rt/test/lsan/TestCases/pointer_to_self.cpp
+++ compiler-rt/test/lsan/TestCases/pointer_to_self.cpp
@@ -1,8 +1,7 @@
 // Regression test: pointers to self should not confuse LSan into thinking the
 // object is indirectly leaked. Only external pointers count.
-// RUN: LSAN_BASE="report_objects=1:use_registers=0"
 // RUN: %clangxx_lsan %s -o %t
-// RUN: %env_lsan_opts=$LSAN_BASE:"use_stacks=0" not %run %t 2>&1 | FileCheck %s
+// RUN: %env_lsan_opts="report_objects=1:use_registers=0:use_stacks=0" not %run %t 2>&1 | FileCheck %s
 
 #include <stdio.h>
 #include <stdlib.h>
Index: compiler-rt/test/lsan/TestCases/many_tls_keys_thread.cpp
===================================================================
--- compiler-rt/test/lsan/TestCases/many_tls_keys_thread.cpp
+++ compiler-rt/test/lsan/TestCases/many_tls_keys_thread.cpp
@@ -1,8 +1,7 @@
 // Test that lsan handles tls correctly for many threads
-// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0"
 // RUN: %clangxx_lsan %s -o %t
-// RUN: %env_lsan_opts=$LSAN_BASE:"use_tls=0" not %run %t 2>&1 | FileCheck %s
-// RUN: %env_lsan_opts=$LSAN_BASE:"use_tls=1" %run %t 2>&1
+// RUN: %env_lsan_opts="report_objects=1:use_stacks=0:use_registers=0:use_tls=0" not %run %t 2>&1 | FileCheck %s
+// RUN: %env_lsan_opts="report_objects=1:use_stacks=0:use_registers=0:use_tls=1" %run %t 2>&1
 // RUN: %env_lsan_opts="" %run %t 2>&1
 
 // Patch r303906 did not fix all the problems.
Index: compiler-rt/test/lsan/TestCases/many_tls_keys_pthread.cpp
===================================================================
--- compiler-rt/test/lsan/TestCases/many_tls_keys_pthread.cpp
+++ compiler-rt/test/lsan/TestCases/many_tls_keys_pthread.cpp
@@ -1,8 +1,7 @@
 // Test that lsan handles tls correctly for many threads
-// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0"
 // RUN: %clangxx_lsan %s -o %t
-// RUN: %env_lsan_opts=$LSAN_BASE:"use_tls=0" not %run %t 2>&1 | FileCheck %s
-// RUN: %env_lsan_opts=$LSAN_BASE:"use_tls=1" %run %t 2>&1
+// RUN: %env_lsan_opts="report_objects=1:use_stacks=0:use_registers=0:use_tls=0" not %run %t 2>&1 | FileCheck %s
+// RUN: %env_lsan_opts="report_objects=1:use_stacks=0:use_registers=0:use_tls=1" %run %t 2>&1
 // RUN: %env_lsan_opts="" %run %t 2>&1
 
 // On glibc, this requires the range returned by GetTLS to include
Index: compiler-rt/test/lsan/TestCases/link_turned_off.cpp
===================================================================
--- compiler-rt/test/lsan/TestCases/link_turned_off.cpp
+++ compiler-rt/test/lsan/TestCases/link_turned_off.cpp
@@ -1,8 +1,7 @@
 // Test for disabling LSan at link-time.
-// RUN: LSAN_BASE="use_stacks=0:use_registers=0"
 // RUN: %clangxx_lsan %s -o %t
-// RUN: %env_lsan_opts=$LSAN_BASE %run %t
-// RUN: %env_lsan_opts=$LSAN_BASE not %run %t foo 2>&1 | FileCheck %s
+// RUN: %env_lsan_opts=use_stacks=0:use_registers=0 %run %t
+// RUN: %env_lsan_opts=use_stacks=0:use_registers=0 not %run %t foo 2>&1 | FileCheck %s
 //
 // UNSUPPORTED: darwin
 
Index: compiler-rt/test/lsan/TestCases/leak_check_at_exit.cpp
===================================================================
--- compiler-rt/test/lsan/TestCases/leak_check_at_exit.cpp
+++ compiler-rt/test/lsan/TestCases/leak_check_at_exit.cpp
@@ -1,10 +1,9 @@
 // Test for the leak_check_at_exit flag.
-// RUN: LSAN_BASE="use_stacks=0:use_registers=0"
 // RUN: %clangxx_lsan %s -o %t
-// RUN: %env_lsan_opts=$LSAN_BASE not %run %t foo 2>&1 | FileCheck %s --check-prefix=CHECK-do
-// RUN: %env_lsan_opts=$LSAN_BASE not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-do
-// RUN: %env_lsan_opts=$LSAN_BASE:"leak_check_at_exit=0" not %run %t foo 2>&1 | FileCheck %s --check-prefix=CHECK-do
-// RUN: %env_lsan_opts=$LSAN_BASE:"leak_check_at_exit=0" %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-dont
+// RUN: %env_lsan_opts=use_stacks=0:use_registers=0 not %run %t foo 2>&1 | FileCheck %s --check-prefix=CHECK-do
+// RUN: %env_lsan_opts=use_stacks=0:use_registers=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-do
+// RUN: %env_lsan_opts=use_stacks=0:use_registers=0:leak_check_at_exit=0 not %run %t foo 2>&1 | FileCheck %s --check-prefix=CHECK-do
+// RUN: %env_lsan_opts=use_stacks=0:use_registers=0:leak_check_at_exit=0 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-dont
 
 #include <stdio.h>
 #include <stdlib.h>
Index: compiler-rt/test/lsan/TestCases/large_allocation_leak.cpp
===================================================================
--- compiler-rt/test/lsan/TestCases/large_allocation_leak.cpp
+++ compiler-rt/test/lsan/TestCases/large_allocation_leak.cpp
@@ -1,7 +1,6 @@
 // Test that LargeMmapAllocator's chunks aren't reachable via some internal data structure.
-// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0"
 // RUN: %clangxx_lsan %s -o %t
-// RUN: %env_lsan_opts=$LSAN_BASE not %run %t 2>&1 | FileCheck %s
+// RUN: %env_lsan_opts=report_objects=1:use_stacks=0:use_registers=0 not %run %t 2>&1 | FileCheck %s
 
 // For 32 bit LSan it's pretty likely that large chunks are "reachable" from some
 // internal data structures (e.g. Glibc global data).
Index: compiler-rt/test/lsan/TestCases/ignore_object.c
===================================================================
--- compiler-rt/test/lsan/TestCases/ignore_object.c
+++ compiler-rt/test/lsan/TestCases/ignore_object.c
@@ -1,7 +1,6 @@
 // Test for __lsan_ignore_object().
-// RUN: LSAN_BASE="report_objects=1:use_registers=0:use_stacks=0:use_tls=0"
 // RUN: %clang_lsan %s -o %t
-// RUN: %env_lsan_opts=$LSAN_BASE not %run %t 2>&1 | FileCheck %s
+// RUN: %env_lsan_opts=report_objects=1:use_registers=0:use_stacks=0:use_tls=0 not %run %t 2>&1 | FileCheck %s
 
 // Investigate why it does not fail with use_stack=0
 // UNSUPPORTED: arm-linux || armhf-linux
Index: compiler-rt/test/lsan/TestCases/high_allocator_contention.cpp
===================================================================
--- compiler-rt/test/lsan/TestCases/high_allocator_contention.cpp
+++ compiler-rt/test/lsan/TestCases/high_allocator_contention.cpp
@@ -1,8 +1,7 @@
 // A benchmark that executes malloc/free pairs in parallel.
 // Usage: ./a.out number_of_threads total_number_of_allocations
-// RUN: LSAN_BASE="use_ld_allocations=0"
 // RUN: %clangxx_lsan %s -o %t
-// RUN: %env_lsan_opts=$LSAN_BASE %run %t 5 1000000 2>&1
+// RUN: %env_lsan_opts=use_ld_allocations=0 %run %t 5 1000000 2>&1
 #include <assert.h>
 #include <pthread.h>
 #include <stdlib.h>
Index: compiler-rt/test/lsan/TestCases/do_leak_check_override.cpp
===================================================================
--- compiler-rt/test/lsan/TestCases/do_leak_check_override.cpp
+++ compiler-rt/test/lsan/TestCases/do_leak_check_override.cpp
@@ -1,10 +1,9 @@
 // Test for __lsan_do_leak_check(). We test it by making the leak check run
 // before global destructors, which also tests compatibility with HeapChecker's
 // "normal" mode (LSan runs in "strict" mode by default).
-// RUN: LSAN_BASE="use_stacks=0:use_registers=0"
 // RUN: %clangxx_lsan %s -o %t
-// RUN: %env_lsan_opts=$LSAN_BASE not %run %t 2>&1 | FileCheck --check-prefix=CHECK-strict %s
-// RUN: %env_lsan_opts=$LSAN_BASE not %run %t foo 2>&1 | FileCheck --check-prefix=CHECK-normal %s
+// RUN: %env_lsan_opts=use_stacks=0:use_registers=0 not %run %t 2>&1 | FileCheck --check-prefix=CHECK-strict %s
+// RUN: %env_lsan_opts=use_stacks=0:use_registers=0 not %run %t foo 2>&1 | FileCheck --check-prefix=CHECK-normal %s
 
 // Investigate why LeakyGlobal leak does show
 // UNSUPPORTED: arm-linux || armhf-linux
Index: compiler-rt/test/lsan/TestCases/disabler.cpp
===================================================================
--- compiler-rt/test/lsan/TestCases/disabler.cpp
+++ compiler-rt/test/lsan/TestCases/disabler.cpp
@@ -1,7 +1,6 @@
 // Test for ScopedDisabler.
-// RUN: LSAN_BASE="report_objects=1:use_registers=0:use_stacks=0:use_tls=0"
 // RUN: %clangxx_lsan %s -o %t
-// RUN: %env_lsan_opts=$LSAN_BASE not %run %t 2>&1 | FileCheck %s
+// RUN: %env_lsan_opts=report_objects=1:use_registers=0:use_stacks=0:use_tls=0 not %run %t 2>&1 | FileCheck %s
 
 #include <stdio.h>
 #include <stdlib.h>
Index: compiler-rt/test/lsan/TestCases/disabler.c
===================================================================
--- compiler-rt/test/lsan/TestCases/disabler.c
+++ compiler-rt/test/lsan/TestCases/disabler.c
@@ -1,7 +1,6 @@
 // Test for __lsan_disable() / __lsan_enable().
-// RUN: LSAN_BASE="report_objects=1:use_registers=0:use_stacks=0:use_tls=0"
 // RUN: %clang_lsan %s -o %t
-// RUN: %env_lsan_opts=$LSAN_BASE not %run %t 2>&1 | FileCheck %s
+// RUN: %env_lsan_opts=report_objects=1:use_registers=0:use_stacks=0:use_tls=0 not %run %t 2>&1 | FileCheck %s
 
 // Investigate why it does not fail with use_tls=0
 // UNSUPPORTED: arm-linux || armhf-linux
Index: compiler-rt/test/lsan/TestCases/Linux/use_tls_static.cpp
===================================================================
--- compiler-rt/test/lsan/TestCases/Linux/use_tls_static.cpp
+++ compiler-rt/test/lsan/TestCases/Linux/use_tls_static.cpp
@@ -1,8 +1,7 @@
 // Test that statically allocated TLS space is included in the root set.
-// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0"
 // RUN: %clangxx_lsan %s -o %t
-// RUN: %env_lsan_opts=$LSAN_BASE:"use_tls=0" not %run %t 2>&1 | FileCheck %s
-// RUN: %env_lsan_opts=$LSAN_BASE:"use_tls=1" %run %t 2>&1
+// RUN: %env_lsan_opts="report_objects=1:use_stacks=0:use_registers=0:use_tls=0" not %run %t 2>&1 | FileCheck %s
+// RUN: %env_lsan_opts="report_objects=1:use_stacks=0:use_registers=0:use_tls=1" %run %t 2>&1
 // RUN: %env_lsan_opts="" %run %t 2>&1
 
 #include <stdio.h>
Index: compiler-rt/test/lsan/TestCases/Linux/use_tls_pthread_specific_static.cpp
===================================================================
--- compiler-rt/test/lsan/TestCases/Linux/use_tls_pthread_specific_static.cpp
+++ compiler-rt/test/lsan/TestCases/Linux/use_tls_pthread_specific_static.cpp
@@ -1,8 +1,7 @@
 // Test that statically allocated thread-specific storage is included in the root set.
-// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0"
 // RUN: %clangxx_lsan %s -o %t
-// RUN: %env_lsan_opts=$LSAN_BASE:"use_tls=0" not %run %t 2>&1 | FileCheck %s
-// RUN: %env_lsan_opts=$LSAN_BASE:"use_tls=1" %run %t 2>&1
+// RUN: %env_lsan_opts="report_objects=1:use_stacks=0:use_registers=0:use_tls=0" not %run %t 2>&1 | FileCheck %s
+// RUN: %env_lsan_opts="report_objects=1:use_stacks=0:use_registers=0:use_tls=1" %run %t 2>&1
 // RUN: %env_lsan_opts="" %run %t 2>&1
 
 #include <assert.h>
Index: compiler-rt/test/lsan/TestCases/Linux/use_tls_pthread_specific_dynamic.cpp
===================================================================
--- compiler-rt/test/lsan/TestCases/Linux/use_tls_pthread_specific_dynamic.cpp
+++ compiler-rt/test/lsan/TestCases/Linux/use_tls_pthread_specific_dynamic.cpp
@@ -1,8 +1,7 @@
 // Test that dynamically allocated thread-specific storage is included in the root set.
-// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0"
 // RUN: %clangxx_lsan %s -o %t
-// RUN: %env_lsan_opts=$LSAN_BASE:"use_tls=0" not %run %t 2>&1 | FileCheck %s
-// RUN: %env_lsan_opts=$LSAN_BASE:"use_tls=1" %run %t 2>&1
+// RUN: %env_lsan_opts="report_objects=1:use_stacks=0:use_registers=0:use_tls=0" not %run %t 2>&1 | FileCheck %s
+// RUN: %env_lsan_opts="report_objects=1:use_stacks=0:use_registers=0:use_tls=1" %run %t 2>&1
 // RUN: %env_lsan_opts="" %run %t 2>&1
 
 // Investigate why it does not fail with use_tls=0
Index: compiler-rt/test/lsan/TestCases/Linux/use_tls_dynamic.cpp
===================================================================
--- compiler-rt/test/lsan/TestCases/Linux/use_tls_dynamic.cpp
+++ compiler-rt/test/lsan/TestCases/Linux/use_tls_dynamic.cpp
@@ -4,11 +4,10 @@
 // https://bugs.llvm.org/show_bug.cgi?id=37804
 // XFAIL: glibc-2.27
 
-// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0:use_ld_allocations=0"
 // RUN: %clangxx %s -DBUILD_DSO -fPIC -shared -o %t-so.so
 // RUN: %clangxx_lsan %s -o %t
-// RUN: %env_lsan_opts=$LSAN_BASE:"use_tls=0" not %run %t 2>&1 | FileCheck %s
-// RUN: %env_lsan_opts=$LSAN_BASE:"use_tls=1" %run %t 2>&1
+// RUN: %env_lsan_opts="report_objects=1:use_stacks=0:use_registers=0:use_ld_allocations=0:use_tls=0" not %run %t 2>&1 | FileCheck %s
+// RUN: %env_lsan_opts="report_objects=1:use_stacks=0:use_registers=0:use_ld_allocations=0:use_tls=1" %run %t 2>&1
 // RUN: %env_lsan_opts="" %run %t 2>&1
 // UNSUPPORTED: arm,powerpc,i386-linux && !android
 
Index: compiler-rt/test/lsan/TestCases/Linux/disabler_in_tsd_destructor.c
===================================================================
--- compiler-rt/test/lsan/TestCases/Linux/disabler_in_tsd_destructor.c
+++ compiler-rt/test/lsan/TestCases/Linux/disabler_in_tsd_destructor.c
@@ -1,7 +1,6 @@
 // Regression test. Disabler should not depend on TSD validity.
-// RUN: LSAN_BASE="report_objects=1:use_registers=0:use_stacks=0:use_tls=1:use_ld_allocations=0"
 // RUN: %clang_lsan %s -o %t
-// RUN: %env_lsan_opts=$LSAN_BASE %run %t
+// RUN: %env_lsan_opts="report_objects=1:use_registers=0:use_stacks=0:use_tls=1:use_ld_allocations=0" %run %t
 
 #include <assert.h>
 #include <pthread.h>
Index: compiler-rt/test/lsan/TestCases/Linux/cleanup_in_tsd_destructor.c
===================================================================
--- compiler-rt/test/lsan/TestCases/Linux/cleanup_in_tsd_destructor.c
+++ compiler-rt/test/lsan/TestCases/Linux/cleanup_in_tsd_destructor.c
@@ -3,10 +3,9 @@
 // user-installed TSD destructors have finished running (since they may contain
 // additional cleanup tasks). LSan doesn't actually meet that goal 100%, but it
 // makes its best effort.
-// RUN: LSAN_BASE="report_objects=1:use_registers=0:use_stacks=0"
 // RUN: %clang_lsan %s -o %t
-// RUN: %env_lsan_opts=$LSAN_BASE:use_tls=1 %run %t
-// RUN: %env_lsan_opts=$LSAN_BASE:use_tls=0 not %run %t 2>&1 | FileCheck %s
+// RUN: %env_lsan_opts="report_objects=1:use_registers=0:use_stacks=0:use_tls=1" %run %t
+// RUN: %env_lsan_opts="report_objects=1:use_registers=0:use_stacks=0:use_tls=0" not %run %t 2>&1 | FileCheck %s
 
 // Investigate why it does not fail with use_stack=0
 // UNSUPPORTED: arm-linux || armhf-linux
Index: compiler-rt/test/lsan/TestCases/Darwin/dispatch.mm
===================================================================
--- compiler-rt/test/lsan/TestCases/Darwin/dispatch.mm
+++ compiler-rt/test/lsan/TestCases/Darwin/dispatch.mm
@@ -1,9 +1,8 @@
 // Test for threads spawned with wqthread_start
-// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0"
 // RUN: %clangxx_lsan %s -DDISPATCH_ASYNC -o %t-async -framework Foundation
 // RUN: %clangxx_lsan %s -DDISPATCH_SYNC -o %t-sync -framework Foundation
-// RUN: %env_lsan_opts=$LSAN_BASE not %run %t-async 2>&1 | FileCheck %s
-// RUN: %env_lsan_opts=$LSAN_BASE not %run %t-sync 2>&1 | FileCheck %s
+// RUN: %env_lsan_opts="report_objects=1:use_stacks=0:use_registers=0" not %run %t-async 2>&1 | FileCheck %s
+// RUN: %env_lsan_opts="report_objects=1:use_stacks=0:use_registers=0" not %run %t-sync 2>&1 | FileCheck %s
 
 #include <dispatch/dispatch.h>
 #include <pthread.h>
Index: compiler-rt/lib/lsan/lsan_win.h
===================================================================
--- /dev/null
+++ compiler-rt/lib/lsan/lsan_win.h
@@ -0,0 +1,41 @@
+//=-- lsan_win.h -----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+//
+// This file is a part of LeakSanitizer.
+// Standalone LSan RTL code common to Windows systems.
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef LSAN_WINDOWS_H
+#define LSAN_WINDOWS_H
+
+#include "lsan_thread.h"
+#include "sanitizer_common/sanitizer_platform.h"
+
+#if !SANITIZER_WINDOWS
+#  error "lsan_win.h is used only on Windows systems (SANITIZER_WINDOWS)"
+#endif
+
+namespace __sanitizer {
+struct DTLS;
+}
+
+namespace __lsan {
+
+class ThreadContext final : public ThreadContextLsanBase {
+ public:
+  explicit ThreadContext(int tid);
+  void OnStarted(void *arg) override;
+};
+
+void ThreadStart(u32 tid, tid_t os_id,
+                 ThreadType thread_type = ThreadType::Regular);
+
+}  // namespace __lsan
+
+#endif  // LSAN_WINDOWS_H
Index: compiler-rt/lib/lsan/lsan_win.cpp
===================================================================
--- /dev/null
+++ compiler-rt/lib/lsan/lsan_win.cpp
@@ -0,0 +1,106 @@
+//=-- lsan_win.cpp -------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+//
+// This file is a part of LeakSanitizer.
+// Standalone LSan RTL code common to POSIX-like systems.
+//
+//===---------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+
+#if SANITIZER_WINDOWS
+#  include "lsan.h"
+#  include "lsan_allocator.h"
+#  include "sanitizer_common/sanitizer_stacktrace.h"
+#  include "sanitizer_common/sanitizer_tls_get_addr.h"
+
+namespace __lsan {
+
+ThreadContext::ThreadContext(int tid) : ThreadContextLsanBase(tid) {}
+
+struct OnStartedArgs {
+  uptr stack_begin;
+  uptr stack_end;
+  uptr cache_begin;
+  uptr cache_end;
+  uptr tls_begin;
+  uptr tls_end;
+};
+
+void ThreadContext::OnStarted(void *arg) {
+  auto args = reinterpret_cast<const OnStartedArgs *>(arg);
+  stack_begin_ = args->stack_begin;
+  stack_end_ = args->stack_end;
+  cache_begin_ = args->cache_begin;
+  cache_end_ = args->cache_end;
+}
+
+void ThreadStart(u32 tid, tid_t os_id, ThreadType thread_type) {
+  OnStartedArgs args;
+  uptr stack_size = 0;
+  uptr tls_size = 0;
+  GetThreadStackAndTls(tid == kMainTid, &args.stack_begin, &stack_size,
+                       &args.tls_begin, &tls_size);
+  args.stack_end = args.stack_begin + stack_size;
+  args.tls_end = args.tls_begin + tls_size;
+  GetAllocatorCacheRange(&args.cache_begin, &args.cache_end);
+  ThreadContextLsanBase::ThreadStart(tid, os_id, thread_type, &args);
+}
+
+bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end,
+                           uptr *tls_begin, uptr *tls_end, uptr *cache_begin,
+                           uptr *cache_end, DTLS **dtls) {
+  ThreadContext *context = static_cast<ThreadContext *>(
+      GetThreadRegistryLocked()->FindThreadContextByOsIDLocked(os_id));
+  if (!context)
+    return false;
+  *stack_begin = context->stack_begin();
+  *stack_end = context->stack_end();
+  *cache_begin = context->cache_begin();
+  *cache_end = context->cache_end();
+  *dtls = 0;
+  return true;
+}
+
+void InitializeMainThread() {
+  u32 tid = ThreadCreate(kMainTid, true);
+  CHECK_EQ(tid, kMainTid);
+  ThreadStart(tid, GetTid());
+}
+
+static void OnStackUnwind(const SignalContext &sig, const void *,
+                          BufferedStackTrace *stack) {
+  stack->Unwind(StackTrace::GetNextInstructionPc(sig.pc), sig.bp, sig.context,
+                common_flags()->fast_unwind_on_fatal);
+}
+
+void LsanOnDeadlySignal(int signo, void *siginfo, void *context) {
+  HandleDeadlySignal(siginfo, context, GetCurrentThread(), &OnStackUnwind,
+                     nullptr);
+}
+
+void ReplaceSystemMalloc() {}
+
+static THREADLOCAL u32 current_thread_tid = kInvalidTid;
+u32 GetCurrentThread() { return current_thread_tid; }
+void SetCurrentThread(u32 tid) { current_thread_tid = tid; }
+
+static THREADLOCAL AllocatorCache allocator_cache;
+AllocatorCache *GetAllocatorCache() { return &allocator_cache; }
+
+}  // namespace __lsan
+
+int lsan_win_init() {
+  __lsan_init();
+  return 0;
+}
+
+#  pragma section(".CRT$XIB", long, read)
+__declspec(allocate(".CRT$XIB")) int (*__lsan_preinit)() = lsan_win_init;
+
+#endif  // SANITIZER_WINDOWS
Index: compiler-rt/lib/lsan/lsan_interceptors.cpp
===================================================================
--- compiler-rt/lib/lsan/lsan_interceptors.cpp
+++ compiler-rt/lib/lsan/lsan_interceptors.cpp
@@ -99,26 +99,30 @@
   return lsan_realloc(ptr, size, stack);
 }
 
-INTERCEPTOR(void*, reallocarray, void *q, uptr nmemb, uptr size) {
-  ENSURE_LSAN_INITED;
-  GET_STACK_TRACE_MALLOC;
-  return lsan_reallocarray(q, nmemb, size, stack);
-}
-
+#  if SANITIZER_WINDOWS
+#    define LSAN_MAYBE_INTERCEPT_REALLOCARRY
+#    define LSAN_MAYBE_INTERCEPT_POSIX_MEMALIGN
+#    define LSAN_MAYBE_INTERCEPT_VALLOC
+#  else
 INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) {
   ENSURE_LSAN_INITED;
   GET_STACK_TRACE_MALLOC;
   return lsan_posix_memalign(memptr, alignment, size, stack);
 }
+#    define LSAN_MAYBE_INTERCEPT_POSIX_MEMALIGN \
+      INTERCEPT_FUNCTION(posix_memalign)
 
-INTERCEPTOR(void*, valloc, uptr size) {
+INTERCEPTOR(void *, valloc, uptr size) {
   ENSURE_LSAN_INITED;
   GET_STACK_TRACE_MALLOC;
   return lsan_valloc(size, stack);
 }
+#    define LSAN_MAYBE_INTERCEPT_VALLOC INTERCEPT_FUNCTION(valloc)
+#  endif
+
 #endif  // !SANITIZER_MAC
 
-#if SANITIZER_INTERCEPT_MEMALIGN
+#if SANITIZER_INTERCEPT_MEMALIGN && !SANITIZER_WINDOWS
 INTERCEPTOR(void*, memalign, uptr alignment, uptr size) {
   ENSURE_LSAN_INITED;
   GET_STACK_TRACE_MALLOC;
@@ -143,17 +147,24 @@
 #endif  // SANITIZER_INTERCEPT___LIBC_MEMALIGN
 
 #if SANITIZER_INTERCEPT_ALIGNED_ALLOC
-INTERCEPTOR(void*, aligned_alloc, uptr alignment, uptr size) {
+#  if SANITIZER_WINDOWS
+#    define LSAN_ALIGNED_ALLOC_NAME _aligned_malloc
+#  else
+#    define LSAN_ALIGNED_ALLOC_NAME aligned_alloc
+#  endif
+
+INTERCEPTOR(void *, LSAN_ALIGNED_ALLOC_NAME, uptr alignment, uptr size) {
   ENSURE_LSAN_INITED;
   GET_STACK_TRACE_MALLOC;
   return lsan_aligned_alloc(alignment, size, stack);
 }
-#define LSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC INTERCEPT_FUNCTION(aligned_alloc)
+#  define LSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC \
+    INTERCEPT_FUNCTION(LSAN_ALIGNED_ALLOC_NAME)
 #else
-#define LSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC
+#  define LSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC
 #endif
 
-#if SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE
+#if SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE && !SANITIZER_WINDOWS
 INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {
   ENSURE_LSAN_INITED;
   return GetMallocUsableSize(ptr);
@@ -244,9 +255,15 @@
 // OS X we need to intercept them using their mangled names.
 #if !SANITIZER_MAC
 
-INTERCEPTOR_ATTRIBUTE
+#  if SANITIZER_WINDOWS
+#    define INTERCEPTOR_ATTRIBUTE_DIFFERENT_LINKAGE
+#  else
+#    define INTERCEPTOR_ATTRIBUTE_DIFFERENT_LINKAGE INTERCEPTOR_ATTRIBUTE
+#  endif
+
+INTERCEPTOR_ATTRIBUTE_DIFFERENT_LINKAGE
 void *operator new(size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); }
-INTERCEPTOR_ATTRIBUTE
+INTERCEPTOR_ATTRIBUTE_DIFFERENT_LINKAGE
 void *operator new[](size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); }
 INTERCEPTOR_ATTRIBUTE
 void *operator new(size_t size, std::nothrow_t const&)
@@ -267,19 +284,19 @@
 void *operator new[](size_t size, std::align_val_t align, std::nothrow_t const&)
 { OPERATOR_NEW_BODY_ALIGN(true /*nothrow*/); }
 
-INTERCEPTOR_ATTRIBUTE
+INTERCEPTOR_ATTRIBUTE_DIFFERENT_LINKAGE
 void operator delete(void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; }
-INTERCEPTOR_ATTRIBUTE
+INTERCEPTOR_ATTRIBUTE_DIFFERENT_LINKAGE
 void operator delete[](void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; }
 INTERCEPTOR_ATTRIBUTE
 void operator delete(void *ptr, std::nothrow_t const&) { OPERATOR_DELETE_BODY; }
 INTERCEPTOR_ATTRIBUTE
 void operator delete[](void *ptr, std::nothrow_t const &)
 { OPERATOR_DELETE_BODY; }
-INTERCEPTOR_ATTRIBUTE
+INTERCEPTOR_ATTRIBUTE_DIFFERENT_LINKAGE
 void operator delete(void *ptr, size_t size) NOEXCEPT
 { OPERATOR_DELETE_BODY; }
-INTERCEPTOR_ATTRIBUTE
+INTERCEPTOR_ATTRIBUTE_DIFFERENT_LINKAGE
 void operator delete[](void *ptr, size_t size) NOEXCEPT
 { OPERATOR_DELETE_BODY; }
 INTERCEPTOR_ATTRIBUTE
@@ -479,10 +496,14 @@
   return res;
 }
 
+#define LSAN_MAYBE_INTERCEPT_PTHREAD_CREATE INTERCEPT_FUNCTION(pthread_create)
+
 INTERCEPTOR(int, pthread_join, void *t, void **arg) {
   return REAL(pthread_join)(t, arg);
 }
 
+#define LSAN_MAYBE_INTERCEPT_PTHREAD_CREATE INTERCEPT_FUNCTION(pthread_join)
+
 DEFINE_REAL_PTHREAD_FUNCTIONS
 
 INTERCEPTOR(void, _exit, int status) {
@@ -490,9 +511,15 @@
   REAL(_exit)(status);
 }
 
+#define LSAN_MAYBE_INTERCEPT__EXIT INTERCEPT_FUNCTION(_exit)
+
 #define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name)
 #include "sanitizer_common/sanitizer_signal_interceptors.inc"
 
+#else
+#  define LSAN_MAYBE_INTERCEPT_PTHREAD_CREATE
+#  define LSAN_MAYBE_INTERCEPT_PTHREAD_JOIN
+#  define LSAN_MAYBE_INTERCEPT__EXIT
 #endif  // SANITIZER_POSIX
 
 namespace __lsan {
@@ -500,7 +527,9 @@
 void InitializeInterceptors() {
   // Fuchsia doesn't use interceptors that require any setup.
 #if !SANITIZER_FUCHSIA
+#  if SANITIZER_POSIX
   InitializeSignalInterceptors();
+#  endif
 
   INTERCEPT_FUNCTION(malloc);
   INTERCEPT_FUNCTION(free);
@@ -510,15 +539,15 @@
   LSAN_MAYBE_INTERCEPT_MEMALIGN;
   LSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN;
   LSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC;
-  INTERCEPT_FUNCTION(posix_memalign);
-  INTERCEPT_FUNCTION(valloc);
+  LSAN_MAYBE_INTERCEPT_POSIX_MEMALIGN;
+  LSAN_MAYBE_INTERCEPT_VALLOC;
   LSAN_MAYBE_INTERCEPT_PVALLOC;
   LSAN_MAYBE_INTERCEPT_MALLOC_USABLE_SIZE;
   LSAN_MAYBE_INTERCEPT_MALLINFO;
   LSAN_MAYBE_INTERCEPT_MALLOPT;
-  INTERCEPT_FUNCTION(pthread_create);
-  INTERCEPT_FUNCTION(pthread_join);
-  INTERCEPT_FUNCTION(_exit);
+  LSAN_MAYBE_INTERCEPT_PTHREAD_CREATE;
+  LSAN_MAYBE_INTERCEPT_PTHREAD_JOIN;
+  LSAN_MAYBE_INTERCEPT__EXIT;
 
   LSAN_MAYBE_INTERCEPT__LWP_EXIT;
   LSAN_MAYBE_INTERCEPT_THR_EXIT;
@@ -529,7 +558,7 @@
 
   LSAN_MAYBE_INTERCEPT_STRERROR;
 
-#if !SANITIZER_NETBSD && !SANITIZER_FREEBSD
+#if !SANITIZER_NETBSD && !SANITIZER_FREEBSD && !SANITIZER_WINDOWS
   if (pthread_key_create(&g_thread_finalize_key, &thread_finalize)) {
     Report("LeakSanitizer: failed to create thread key.\n");
     Die();
Index: compiler-rt/lib/lsan/lsan_common_win.cpp
===================================================================
--- /dev/null
+++ compiler-rt/lib/lsan/lsan_common_win.cpp
@@ -0,0 +1,95 @@
+//=-- lsan_common_win.cpp -------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of LeakSanitizer.
+// Implementation of common leak checking functionality. Darwin-specific code.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lsan_common.h"
+#include "sanitizer_common/sanitizer_platform.h"
+
+#if CAN_SANITIZE_LEAKS && SANITIZER_WINDOWS
+
+#  define WIN32_LEAN_AND_MEAN
+#  include <windows.h>
+
+// `windows.h` needs to be included before `dbghelp.h`
+#  include <dbghelp.h>
+#  pragma comment(lib, "Dbghelp.lib")
+
+namespace __lsan {
+
+void HandleLeaks() {}
+
+void InitializePlatformSpecificModules() {}
+
+void LockStuffAndStopTheWorld(StopTheWorldCallback callback,
+                              CheckForLeaksParam *argument) {
+  LockThreadRegistry();
+  LockAllocator();
+  StopTheWorld(callback, argument);
+  UnlockAllocator();
+  UnlockThreadRegistry();
+}
+
+THREADLOCAL int disable_counter;
+bool DisabledInThisThread() { return disable_counter > 0; }
+void DisableInThisThread() { disable_counter++; }
+void EnableInThisThread() {
+  if (disable_counter == 0) {
+    DisableCounterUnderflow();
+  }
+  disable_counter--;
+}
+
+BOOL CALLBACK EnumLoadedModulesCallback(PCSTR module_name, DWORD64 module_base,
+                                        ULONG module_size, PVOID user_context) {
+  auto *frontier = reinterpret_cast<Frontier *>(user_context);
+
+  // Parse the PE Headers of all loaded Modules
+  const auto *module_nt_header =
+      ImageNtHeader(reinterpret_cast<PVOID>(module_base));
+
+  CHECK(module_nt_header);
+
+  const auto *section_header =
+      reinterpret_cast<const IMAGE_SECTION_HEADER *>(module_nt_header + 1);
+
+  // Find the `.data` section
+  for (WORD i = 0; i < module_nt_header->FileHeader.NumberOfSections;
+       ++i, ++section_header) {
+    const char data_section_name[6] = ".data";
+    const auto is_data_section =
+        internal_strncmp(reinterpret_cast<const char *>(section_header->Name),
+                         data_section_name, sizeof(data_section_name)) == 0;
+
+    if (!is_data_section)
+      continue;
+
+    ScanGlobalRange(module_base + section_header->VirtualAddress,
+                    module_base + section_header->VirtualAddress +
+                        section_header->Misc.VirtualSize - 1,
+                    frontier);
+  }
+
+  return TRUE;
+}
+
+void ProcessGlobalRegions(Frontier *frontier) {
+  HANDLE this_process = GetCurrentProcess();
+
+  EnumerateLoadedModules(this_process, EnumLoadedModulesCallback, frontier);
+}
+void ProcessPlatformSpecificAllocations(Frontier *frontier) {}
+
+LoadedModule *GetLinker() { return nullptr; }
+
+}  // namespace __lsan
+
+#endif  // CAN_SANITIZE_LEAKS && SANITIZER_WINDOWS
Index: compiler-rt/lib/lsan/lsan_common.h
===================================================================
--- compiler-rt/lib/lsan/lsan_common.h
+++ compiler-rt/lib/lsan/lsan_common.h
@@ -44,7 +44,7 @@
 #  define CAN_SANITIZE_LEAKS 1
 #elif SANITIZER_RISCV64 && SANITIZER_LINUX
 #  define CAN_SANITIZE_LEAKS 1
-#elif SANITIZER_NETBSD || SANITIZER_FUCHSIA
+#elif SANITIZER_NETBSD || SANITIZER_FUCHSIA || SANITIZER_WINDOWS
 #  define CAN_SANITIZE_LEAKS 1
 #else
 #  define CAN_SANITIZE_LEAKS 0
Index: compiler-rt/lib/lsan/lsan_common.cpp
===================================================================
--- compiler-rt/lib/lsan/lsan_common.cpp
+++ compiler-rt/lib/lsan/lsan_common.cpp
@@ -245,12 +245,12 @@
   const uptr kMinAddress = 4 * 4096;
   if (p < kMinAddress)
     return false;
-#  if defined(__x86_64__)
+#  if SANITIZER_X64
   // Accept only canonical form user-space addresses.
   return ((p >> 47) == 0);
 #  elif defined(__mips64)
   return ((p >> 40) == 0);
-#  elif defined(__aarch64__)
+#  elif SANITIZER_ARM64
   unsigned runtimeVMA = (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1);
   return ((p >> runtimeVMA) == 0);
 #  else
@@ -501,12 +501,16 @@
 
 static void ProcessRootRegion(Frontier *frontier,
                               const RootRegion &root_region) {
+#  if SANITIZER_WINDOWS
+  // TODO
+#  else
   MemoryMappingLayout proc_maps(/*cache_enabled*/ true);
   MemoryMappedSegment segment;
   while (proc_maps.Next(&segment)) {
     ScanRootRegion(frontier, root_region, segment.start, segment.end,
                    segment.IsReadable());
   }
+#  endif
 }
 
 // Scans root regions for heap pointers.
Index: compiler-rt/lib/lsan/lsan_allocator.h
===================================================================
--- compiler-rt/lib/lsan/lsan_allocator.h
+++ compiler-rt/lib/lsan/lsan_allocator.h
@@ -49,8 +49,8 @@
   u32 stack_trace_id;
 };
 
-#if defined(__mips64) || defined(__aarch64__) || defined(__i386__) || \
-    defined(__arm__) || SANITIZER_RISCV64 || defined(__hexagon__)
+#if defined(__mips64) || SANITIZER_ARM64 || SANITIZER_I386 || SANITIZER_ARM || \
+    SANITIZER_RISCV64 || defined(__hexagon__)
 template <typename AddressSpaceViewTy>
 struct AP32 {
   static const uptr kSpaceBeg = 0;
@@ -65,20 +65,20 @@
 template <typename AddressSpaceView>
 using PrimaryAllocatorASVT = SizeClassAllocator32<AP32<AddressSpaceView>>;
 using PrimaryAllocator = PrimaryAllocatorASVT<LocalAddressSpaceView>;
-#elif defined(__x86_64__) || defined(__powerpc64__) || defined(__s390x__)
-# if SANITIZER_FUCHSIA
+#elif SANITIZER_X64 || defined(__powerpc64__) || defined(__s390x__)
+#  if SANITIZER_FUCHSIA
 const uptr kAllocatorSpace = ~(uptr)0;
-const uptr kAllocatorSize  =  0x40000000000ULL;  // 4T.
-# elif defined(__powerpc64__)
+const uptr kAllocatorSize = 0x40000000000ULL;  // 4T.
+#  elif defined(__powerpc64__)
 const uptr kAllocatorSpace = 0xa0000000000ULL;
-const uptr kAllocatorSize  = 0x20000000000ULL;  // 2T.
-#elif defined(__s390x__)
+const uptr kAllocatorSize = 0x20000000000ULL;  // 2T.
+#  elif defined(__s390x__)
 const uptr kAllocatorSpace = 0x40000000000ULL;
 const uptr kAllocatorSize = 0x40000000000ULL;  // 4T.
-# else
+#  else
 const uptr kAllocatorSpace = 0x600000000000ULL;
-const uptr kAllocatorSize  = 0x40000000000ULL;  // 4T.
-# endif
+const uptr kAllocatorSize = 0x40000000000ULL;  // 4T.
+#  endif
 template <typename AddressSpaceViewTy>
 struct AP64 {  // Allocator64 parameters. Deliberately using a short name.
   static const uptr kSpaceBeg = kAllocatorSpace;
@@ -93,6 +93,8 @@
 template <typename AddressSpaceView>
 using PrimaryAllocatorASVT = SizeClassAllocator64<AP64<AddressSpaceView>>;
 using PrimaryAllocator = PrimaryAllocatorASVT<LocalAddressSpaceView>;
+#else
+#  error Architecture not supported!
 #endif
 
 template <typename AddressSpaceView>
Index: compiler-rt/lib/lsan/lsan.h
===================================================================
--- compiler-rt/lib/lsan/lsan.h
+++ compiler-rt/lib/lsan/lsan.h
@@ -16,6 +16,8 @@
 #  include "lsan_posix.h"
 #elif SANITIZER_FUCHSIA
 #  include "lsan_fuchsia.h"
+#elif SANITIZER_WINDOWS
+#  include "lsan_win.h"
 #endif
 #include "sanitizer_common/sanitizer_flags.h"
 #include "sanitizer_common/sanitizer_stacktrace.h"
Index: compiler-rt/lib/lsan/CMakeLists.txt
===================================================================
--- compiler-rt/lib/lsan/CMakeLists.txt
+++ compiler-rt/lib/lsan/CMakeLists.txt
@@ -11,6 +11,7 @@
   lsan_common_fuchsia.cpp
   lsan_common_linux.cpp
   lsan_common_mac.cpp
+  lsan_common_win.cpp
   )
 
 set(LSAN_SOURCES
@@ -24,6 +25,7 @@
   lsan_posix.cpp
   lsan_preinit.cpp
   lsan_thread.cpp
+  lsan_win.cpp
   )
 
 set(LSAN_HEADERS
Index: compiler-rt/cmake/config-ix.cmake
===================================================================
--- compiler-rt/cmake/config-ix.cmake
+++ compiler-rt/cmake/config-ix.cmake
@@ -713,7 +713,7 @@
 endif()
 
 if (COMPILER_RT_HAS_SANITIZER_COMMON AND LSAN_SUPPORTED_ARCH AND
-    OS_NAME MATCHES "Android|Darwin|Linux|NetBSD|Fuchsia")
+    OS_NAME MATCHES "Android|Darwin|Linux|NetBSD|Fuchsia|Windows")
   set(COMPILER_RT_HAS_LSAN TRUE)
 else()
   set(COMPILER_RT_HAS_LSAN FALSE)
Index: clang/lib/Driver/ToolChains/MSVC.cpp
===================================================================
--- clang/lib/Driver/ToolChains/MSVC.cpp
+++ clang/lib/Driver/ToolChains/MSVC.cpp
@@ -572,6 +572,11 @@
     }
   }
 
+  if (TC.getSanitizerArgs(Args).needsLsanRt()) {
+    // TODO: Is this all? Asan looks way more complicated
+    CmdArgs.push_back(TC.getCompilerRTArgString(Args, "lsan"));
+  }
+
   Args.AddAllArgValues(CmdArgs, options::OPT__SLASH_link);
 
   // Control Flow Guard checks
@@ -1408,6 +1413,7 @@
   Res |= SanitizerKind::PointerSubtract;
   Res |= SanitizerKind::Fuzzer;
   Res |= SanitizerKind::FuzzerNoLink;
+  Res |= SanitizerKind::Leak;
   Res &= ~SanitizerKind::CFIMFCall;
   return Res;
 }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to