clemenswasser updated this revision to Diff 421758. clemenswasser added a comment.
Hi, today I found some more time to play/progress with this patch. I'm generally optimistic that most of the basic lsan stuff should already be working on Windows. However without some help of you, I'm unable to get the tests to properly work. The main Problem I looked into today is that `llvm-lit.py` seems to be somehow unable to capture the stdout/err of the tests. More precisely my Debugging showed that when I insert a `print(procs[-1].stdout.read())` at TestRunner.py:790 I get the correctly captured stdout of a test e.g.: ================================================================= ==25028==ERROR: LeakSanitizer: detected memory leaks Direct leak of 1337 byte(s) in 1 object(s) allocated from: #0 0x7ff77fc0488e in __asan_wrap_malloc C:\Users\cleme\dev\cpp\llvm-project\compiler-rt\lib\lsan\lsan_interceptors.cpp:75 #1 0x7ff77fbbaafe in main C:\Users\cleme\dev\cpp\llvm-project\compiler-rt\test\lsan\TestCases\leak_check_at_exit.cpp:13:40 #2 0x7ff77fc09e2b in invoke_main d:\a01\_work\43\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:78 #3 0x7ff77fc09e2b in __scrt_common_main_seh d:\a01\_work\43\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288 #4 0x7ff8cb5654df (C:\Windows\System32\KERNEL32.DLL+0x1800154df) #5 0x7ff8cc9e485a (C:\Windows\SYSTEM32\ntdll.dll+0x18000485a) SUMMARY: LeakSanitizer: 1337 byte(s) leaked in 1 allocation(s). However further below at lines 816-829 this output is lost (`proc.stdout.read()` returns a empty string, which obviously causes any FileCheck afterwards to fail)... and I can't figure out why. The only possible explaination I can think of is that the captured stdout is lost during the next loopiteration over `cmd.commands` 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,111 @@ +//=-- 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; } + +void InstallAtExitCheckLeaks() { + if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) + Atexit(DoLeakCheck); +} + +} // 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 COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name) -#include "sanitizer_common/sanitizer_signal_interceptors.inc" +# 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 @@ -246,12 +246,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 @@ -502,12 +502,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,7 +65,7 @@ template <typename AddressSpaceView> using PrimaryAllocatorASVT = SizeClassAllocator32<AP32<AddressSpaceView>>; using PrimaryAllocator = PrimaryAllocatorASVT<LocalAddressSpaceView>; -#elif defined(__x86_64__) || defined(__powerpc64__) || defined(__s390x__) +#elif SANITIZER_X64 || defined(__powerpc64__) || defined(__s390x__) # if SANITIZER_FUCHSIA || defined(__powerpc64__) const uptr kAllocatorSpace = ~(uptr)0; const uptr kAllocatorSize = 0x40000000000ULL; // 4T. @@ -90,6 +90,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 @@ -716,7 +716,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 @@ -215,6 +215,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 @@ -773,6 +778,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