From 8219d92987c7d9641d6b24c4d5be29e3a80fd6b9 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 22 Dec 2020 19:25:24 -0700 Subject: [PATCH] stage2: fix Cache deadlock and build more of TSAN * rename is_compiler_rt_or_libc to skip_linker_dependencies and set it to `true` for all sub-Compilations. I believe this resolves the deadlock we were experiencing on Drone CI and on some users' computers. I will remove the CI workaround in a follow-up commit. * enabling TSAN automatically causes the Compilation to link against libc++ even if not requested, because TSAN depends on libc++. * add -fno-rtti flags where appropriate when building TSAN objects. Thanks Firefox317 for pointing this out. * TSAN support: resolve all the undefined symbols. We are still seeing a dependency on __gcc_personality_v0 but will resolve this one in a follow-up commit. * static libs do not try to build libc++ or libc++abi. --- lib/tsan/interception/interception_linux.cpp | 83 ++ lib/tsan/interception/interception_mac.cpp | 18 + .../interception/interception_type_test.cpp | 39 + lib/tsan/interception/interception_win.cpp | 1022 +++++++++++++++++ .../sanitizer_allocator_checks.cpp | 22 + .../sanitizer_allocator_report.cpp | 137 +++ .../sanitizer_common_libcdep.cpp | 149 +++ .../sanitizer_common_nolibc.cpp | 34 + .../sanitizer_linux_libcdep.cpp | 846 ++++++++++++++ .../sanitizer_mac_libcdep.cpp | 29 + .../sanitizer_posix_libcdep.cpp | 509 ++++++++ .../sanitizer_common/sanitizer_stackdepot.cpp | 149 +++ .../sanitizer_common/sanitizer_stacktrace.cpp | 133 +++ .../sanitizer_stacktrace_libcdep.cpp | 159 +++ .../sanitizer_stacktrace_printer.cpp | 263 +++++ .../sanitizer_stacktrace_sparc.cpp | 85 ++ .../sanitizer_stoptheworld_linux_libcdep.cpp | 573 +++++++++ .../sanitizer_stoptheworld_netbsd_libcdep.cpp | 364 ++++++ .../sanitizer_common/sanitizer_symbolizer.cpp | 135 +++ .../sanitizer_symbolizer_libbacktrace.cpp | 209 ++++ .../sanitizer_symbolizer_libcdep.cpp | 554 +++++++++ .../sanitizer_symbolizer_mac.cpp | 249 ++++ .../sanitizer_symbolizer_markup.cpp | 146 +++ .../sanitizer_symbolizer_posix_libcdep.cpp | 492 ++++++++ .../sanitizer_symbolizer_report.cpp | 293 +++++ .../sanitizer_symbolizer_win.cpp | 318 +++++ .../sanitizer_unwind_linux_libcdep.cpp | 180 +++ .../sanitizer_common/sanitizer_unwind_win.cpp | 75 ++ lib/tsan/tsan_interceptors_mac.cpp | 519 +++++++++ lib/tsan/tsan_interceptors_mach_vm.cpp | 52 + lib/tsan/tsan_platform_linux.cpp | 517 +++++++++ lib/tsan/tsan_platform_mac.cpp | 324 ++++++ lib/tsan/tsan_platform_posix.cpp | 167 +++ lib/tsan/tsan_rtl_aarch64.S | 245 ++++ lib/tsan/tsan_rtl_amd64.S | 366 ++++++ lib/tsan/tsan_rtl_mips64.S | 214 ++++ lib/tsan/tsan_rtl_ppc64.S | 288 +++++ src/Compilation.zig | 33 +- src/glibc.zig | 2 +- src/libcxx.zig | 2 + src/libtsan.zig | 198 +++- src/libunwind.zig | 1 + src/link.zig | 2 +- src/link/Coff.zig | 4 +- src/link/Elf.zig | 6 +- src/link/MachO.zig | 4 +- src/link/Wasm.zig | 2 +- src/musl.zig | 2 +- 48 files changed, 10172 insertions(+), 41 deletions(-) create mode 100644 lib/tsan/interception/interception_linux.cpp create mode 100644 lib/tsan/interception/interception_mac.cpp create mode 100644 lib/tsan/interception/interception_type_test.cpp create mode 100644 lib/tsan/interception/interception_win.cpp create mode 100644 lib/tsan/sanitizer_common/sanitizer_allocator_checks.cpp create mode 100644 lib/tsan/sanitizer_common/sanitizer_allocator_report.cpp create mode 100644 lib/tsan/sanitizer_common/sanitizer_common_libcdep.cpp create mode 100644 lib/tsan/sanitizer_common/sanitizer_common_nolibc.cpp create mode 100644 lib/tsan/sanitizer_common/sanitizer_linux_libcdep.cpp create mode 100644 lib/tsan/sanitizer_common/sanitizer_mac_libcdep.cpp create mode 100644 lib/tsan/sanitizer_common/sanitizer_posix_libcdep.cpp create mode 100644 lib/tsan/sanitizer_common/sanitizer_stackdepot.cpp create mode 100644 lib/tsan/sanitizer_common/sanitizer_stacktrace.cpp create mode 100644 lib/tsan/sanitizer_common/sanitizer_stacktrace_libcdep.cpp create mode 100644 lib/tsan/sanitizer_common/sanitizer_stacktrace_printer.cpp create mode 100644 lib/tsan/sanitizer_common/sanitizer_stacktrace_sparc.cpp create mode 100644 lib/tsan/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp create mode 100644 lib/tsan/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp create mode 100644 lib/tsan/sanitizer_common/sanitizer_symbolizer.cpp create mode 100644 lib/tsan/sanitizer_common/sanitizer_symbolizer_libbacktrace.cpp create mode 100644 lib/tsan/sanitizer_common/sanitizer_symbolizer_libcdep.cpp create mode 100644 lib/tsan/sanitizer_common/sanitizer_symbolizer_mac.cpp create mode 100644 lib/tsan/sanitizer_common/sanitizer_symbolizer_markup.cpp create mode 100644 lib/tsan/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp create mode 100644 lib/tsan/sanitizer_common/sanitizer_symbolizer_report.cpp create mode 100644 lib/tsan/sanitizer_common/sanitizer_symbolizer_win.cpp create mode 100644 lib/tsan/sanitizer_common/sanitizer_unwind_linux_libcdep.cpp create mode 100644 lib/tsan/sanitizer_common/sanitizer_unwind_win.cpp create mode 100644 lib/tsan/tsan_interceptors_mac.cpp create mode 100644 lib/tsan/tsan_interceptors_mach_vm.cpp create mode 100644 lib/tsan/tsan_platform_linux.cpp create mode 100644 lib/tsan/tsan_platform_mac.cpp create mode 100644 lib/tsan/tsan_platform_posix.cpp create mode 100644 lib/tsan/tsan_rtl_aarch64.S create mode 100644 lib/tsan/tsan_rtl_amd64.S create mode 100644 lib/tsan/tsan_rtl_mips64.S create mode 100644 lib/tsan/tsan_rtl_ppc64.S diff --git a/lib/tsan/interception/interception_linux.cpp b/lib/tsan/interception/interception_linux.cpp new file mode 100644 index 0000000000..950cd51265 --- /dev/null +++ b/lib/tsan/interception/interception_linux.cpp @@ -0,0 +1,83 @@ +//===-- interception_linux.cpp ----------------------------------*- C++ -*-===// +// +// 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 AddressSanitizer, an address sanity checker. +// +// Linux-specific interception methods. +//===----------------------------------------------------------------------===// + +#include "interception.h" + +#if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \ + SANITIZER_OPENBSD || SANITIZER_SOLARIS + +#include // for dlsym() and dlvsym() + +namespace __interception { + +#if SANITIZER_NETBSD +static int StrCmp(const char *s1, const char *s2) { + while (true) { + if (*s1 != *s2) + return false; + if (*s1 == 0) + return true; + s1++; + s2++; + } +} +#endif + +static void *GetFuncAddr(const char *name, uptr wrapper_addr) { +#if SANITIZER_NETBSD + // FIXME: Find a better way to handle renames + if (StrCmp(name, "sigaction")) + name = "__sigaction14"; +#endif + void *addr = dlsym(RTLD_NEXT, name); + if (!addr) { + // If the lookup using RTLD_NEXT failed, the sanitizer runtime library is + // later in the library search order than the DSO that we are trying to + // intercept, which means that we cannot intercept this function. We still + // want the address of the real definition, though, so look it up using + // RTLD_DEFAULT. + addr = dlsym(RTLD_DEFAULT, name); + + // In case `name' is not loaded, dlsym ends up finding the actual wrapper. + // We don't want to intercept the wrapper and have it point to itself. + if ((uptr)addr == wrapper_addr) + addr = nullptr; + } + return addr; +} + +bool InterceptFunction(const char *name, uptr *ptr_to_real, uptr func, + uptr wrapper) { + void *addr = GetFuncAddr(name, wrapper); + *ptr_to_real = (uptr)addr; + return addr && (func == wrapper); +} + +// Android and Solaris do not have dlvsym +#if !SANITIZER_ANDROID && !SANITIZER_SOLARIS && !SANITIZER_OPENBSD +static void *GetFuncAddr(const char *name, const char *ver) { + return dlvsym(RTLD_NEXT, name, ver); +} + +bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real, + uptr func, uptr wrapper) { + void *addr = GetFuncAddr(name, ver); + *ptr_to_real = (uptr)addr; + return addr && (func == wrapper); +} +#endif // !SANITIZER_ANDROID + +} // namespace __interception + +#endif // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || + // SANITIZER_OPENBSD || SANITIZER_SOLARIS diff --git a/lib/tsan/interception/interception_mac.cpp b/lib/tsan/interception/interception_mac.cpp new file mode 100644 index 0000000000..fb6eadcff5 --- /dev/null +++ b/lib/tsan/interception/interception_mac.cpp @@ -0,0 +1,18 @@ +//===-- interception_mac.cpp ------------------------------------*- C++ -*-===// +// +// 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 AddressSanitizer, an address sanity checker. +// +// Mac-specific interception methods. +//===----------------------------------------------------------------------===// + +#include "interception.h" + +#if SANITIZER_MAC + +#endif // SANITIZER_MAC diff --git a/lib/tsan/interception/interception_type_test.cpp b/lib/tsan/interception/interception_type_test.cpp new file mode 100644 index 0000000000..a611604a70 --- /dev/null +++ b/lib/tsan/interception/interception_type_test.cpp @@ -0,0 +1,39 @@ +//===-- interception_type_test.cpp ------------------------------*- C++ -*-===// +// +// 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 AddressSanitizer, an address sanity checker. +// +// Compile-time tests of the internal type definitions. +//===----------------------------------------------------------------------===// + +#include "interception.h" + +#if SANITIZER_LINUX || SANITIZER_MAC + +#include +#include +#include + +COMPILER_CHECK(sizeof(::SIZE_T) == sizeof(size_t)); +COMPILER_CHECK(sizeof(::SSIZE_T) == sizeof(ssize_t)); +COMPILER_CHECK(sizeof(::PTRDIFF_T) == sizeof(ptrdiff_t)); +COMPILER_CHECK(sizeof(::INTMAX_T) == sizeof(intmax_t)); + +#if !SANITIZER_MAC +COMPILER_CHECK(sizeof(::OFF64_T) == sizeof(off64_t)); +#endif + +// The following are the cases when pread (and friends) is used instead of +// pread64. In those cases we need OFF_T to match off_t. We don't care about the +// rest (they depend on _FILE_OFFSET_BITS setting when building an application). +# if SANITIZER_ANDROID || !defined _FILE_OFFSET_BITS || \ + _FILE_OFFSET_BITS != 64 +COMPILER_CHECK(sizeof(::OFF_T) == sizeof(off_t)); +# endif + +#endif diff --git a/lib/tsan/interception/interception_win.cpp b/lib/tsan/interception/interception_win.cpp new file mode 100644 index 0000000000..1a1c327e61 --- /dev/null +++ b/lib/tsan/interception/interception_win.cpp @@ -0,0 +1,1022 @@ +//===-- interception_linux.cpp ----------------------------------*- C++ -*-===// +// +// 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 AddressSanitizer, an address sanity checker. +// +// Windows-specific interception methods. +// +// This file is implementing several hooking techniques to intercept calls +// to functions. The hooks are dynamically installed by modifying the assembly +// code. +// +// The hooking techniques are making assumptions on the way the code is +// generated and are safe under these assumptions. +// +// On 64-bit architecture, there is no direct 64-bit jump instruction. To allow +// arbitrary branching on the whole memory space, the notion of trampoline +// region is used. A trampoline region is a memory space withing 2G boundary +// where it is safe to add custom assembly code to build 64-bit jumps. +// +// Hooking techniques +// ================== +// +// 1) Detour +// +// The Detour hooking technique is assuming the presence of an header with +// padding and an overridable 2-bytes nop instruction (mov edi, edi). The +// nop instruction can safely be replaced by a 2-bytes jump without any need +// to save the instruction. A jump to the target is encoded in the function +// header and the nop instruction is replaced by a short jump to the header. +// +// head: 5 x nop head: jmp +// func: mov edi, edi --> func: jmp short +// [...] real: [...] +// +// This technique is only implemented on 32-bit architecture. +// Most of the time, Windows API are hookable with the detour technique. +// +// 2) Redirect Jump +// +// The redirect jump is applicable when the first instruction is a direct +// jump. The instruction is replaced by jump to the hook. +// +// func: jmp