Index: lib/esan/esan.cpp =================================================================== --- lib/esan/esan.cpp +++ lib/esan/esan.cpp @@ -197,6 +197,9 @@ } initializeShadow(); + if (__esan_which_tool == ESAN_WorkingSet) + initializeShadowWorkingSet(); + initializeInterceptors(); if (__esan_which_tool == ESAN_CacheFrag) { Index: lib/esan/esan_interceptors.cpp =================================================================== --- lib/esan/esan_interceptors.cpp +++ lib/esan/esan_interceptors.cpp @@ -17,6 +17,7 @@ #include "interception/interception.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_libc.h" +#include "sanitizer_common/sanitizer_linux.h" #include "sanitizer_common/sanitizer_stacktrace.h" using namespace __esan; // NOLINT @@ -397,6 +398,11 @@ // This is required to properly use internal_sigaction. namespace __sanitizer { int real_sigaction(int signum, const void *act, void *oldact) { + if (REAL(sigaction) == nullptr) { + // With tcmalloc, this is called during interceptor init and we need + // a raw syscall solution. + return internal_sigaction_syscall(signum, act, oldact); + } return REAL(sigaction)(signum, (const struct sigaction *)act, (struct sigaction *)oldact); } Index: lib/esan/working_set.h =================================================================== --- lib/esan/working_set.h +++ lib/esan/working_set.h @@ -21,6 +21,7 @@ namespace __esan { void initializeWorkingSet(); +void initializeShadowWorkingSet(); int finalizeWorkingSet(); void processRangeAccessWorkingSet(uptr PC, uptr Addr, SIZE_T Size, bool IsWrite); Index: lib/esan/working_set.cpp =================================================================== --- lib/esan/working_set.cpp +++ lib/esan/working_set.cpp @@ -182,10 +182,13 @@ } } -void initializeWorkingSet() { +// Initialization that must be done before any instrumented code is executed. +void initializeShadowWorkingSet() { CHECK(getFlags()->cache_line_size == CacheLineSize); registerMemoryFaultHandler(); +} +void initializeWorkingSet() { if (getFlags()->record_snapshots) { for (u32 i = 0; i < NumFreq; ++i) SizePerFreq[i].initialize(CircularBufferSizes[i]); Index: lib/sanitizer_common/CMakeLists.txt =================================================================== --- lib/sanitizer_common/CMakeLists.txt +++ lib/sanitizer_common/CMakeLists.txt @@ -12,6 +12,7 @@ sanitizer_libignore.cc sanitizer_linux.cc sanitizer_linux_s390.cc + sanitizer_linux_x86_64.S sanitizer_mac.cc sanitizer_persistent_allocator.cc sanitizer_platform_limits_linux.cc @@ -133,6 +134,17 @@ append_list_if(COMPILER_RT_HAS_WGLOBAL_CONSTRUCTORS_FLAG -Wglobal-constructors SANITIZER_CFLAGS) +if (LLVM_ENABLE_PEDANTIC) + # With -pedantic, our .S files raise warnings about empty macro arguments + # from __USER_LABEL_PREFIX__ being an empty arg to GLUE(). Unfortunately, + # there is no simple way to test for an empty define, nor to disable just + # that warning or to disable -pedantic. There is also no simple way to + # remove -pedantic from just this file (we'd have to remove from + # CMAKE_C*_FLAGS and re-add as a source property to all the non-.S files). + set_source_files_properties(sanitizer_linux_x86_64.S + PROPERTIES COMPILE_FLAGS "-w") +endif () + if(APPLE) set(OS_OPTION OS ${SANITIZER_COMMON_SUPPORTED_OS}) endif() Index: lib/sanitizer_common/sanitizer_linux.h =================================================================== --- lib/sanitizer_common/sanitizer_linux.h +++ lib/sanitizer_common/sanitizer_linux.h @@ -42,6 +42,8 @@ // (like the process-wide error reporting SEGV handler) must use // internal_sigaction instead. int internal_sigaction_norestorer(int signum, const void *act, void *oldact); +// Uses a raw system call to avoid interceptors. +int internal_sigaction_syscall(int signum, const void *act, void *oldact); void internal_sigdelset(__sanitizer_sigset_t *set, int signum); #if defined(__x86_64__) || defined(__mips__) || defined(__aarch64__) \ || defined(__powerpc64__) || defined(__s390__) Index: lib/sanitizer_common/sanitizer_linux.cc =================================================================== --- lib/sanitizer_common/sanitizer_linux.cc +++ lib/sanitizer_common/sanitizer_linux.cc @@ -99,6 +99,12 @@ # define SANITIZER_LINUX_USES_64BIT_SYSCALLS 0 #endif +#if defined(__x86_64__) +extern "C" { +extern void internal_sigreturn(); +} +#endif + namespace __sanitizer { #if SANITIZER_LINUX && defined(__x86_64__) @@ -660,6 +666,49 @@ } return result; } + +int internal_sigaction_syscall(int signum, const void *act, void *oldact) { + __sanitizer_kernel_sigaction_t k_act, k_oldact; + internal_memset(&k_act, 0, sizeof(__sanitizer_kernel_sigaction_t)); + internal_memset(&k_oldact, 0, sizeof(__sanitizer_kernel_sigaction_t)); + const __sanitizer_sigaction *u_act = (const __sanitizer_sigaction *)act; + __sanitizer_sigaction *u_oldact = (__sanitizer_sigaction *)oldact; + if (u_act) { + k_act.handler = u_act->handler; + k_act.sigaction = u_act->sigaction; + internal_memcpy(&k_act.sa_mask, &u_act->sa_mask, + sizeof(__sanitizer_kernel_sigset_t)); + // For x64 the kernel requires SA_RESTORER. + k_act.sa_flags = u_act->sa_flags | SA_RESTORER; +#if !SANITIZER_ANDROID || !SANITIZER_MIPS32 + k_act.sa_restorer = u_act->sa_restorer; + if (k_act.sa_restorer == nullptr) { +#if defined(__x86_64__) + k_act.sa_restorer = internal_sigreturn; +#else + CHECK(0); // Not supported yet. +#endif + } +#endif + } + + uptr result = internal_syscall(SYSCALL(rt_sigaction), (uptr)signum, + (uptr)(u_act ? &k_act : nullptr), + (uptr)(u_oldact ? &k_oldact : nullptr), + (uptr)sizeof(__sanitizer_kernel_sigset_t)); + + if ((result == 0) && u_oldact) { + u_oldact->handler = k_oldact.handler; + u_oldact->sigaction = k_oldact.sigaction; + internal_memcpy(&u_oldact->sa_mask, &k_oldact.sa_mask, + sizeof(__sanitizer_kernel_sigset_t)); + u_oldact->sa_flags = k_oldact.sa_flags; +#if !SANITIZER_ANDROID || !SANITIZER_MIPS32 + u_oldact->sa_restorer = k_oldact.sa_restorer; +#endif + } + return result; +} #endif // SANITIZER_LINUX uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set, Index: lib/sanitizer_common/sanitizer_linux_x86_64.S =================================================================== --- /dev/null +++ lib/sanitizer_common/sanitizer_linux_x86_64.S @@ -0,0 +1,20 @@ +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. + +#include "../builtins/assembly.h" + +// Avoid being marked as needing an executable stack: +#if defined(__linux__) && defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif + +// If the "naked" function attribute were supported for x86 we could +// do this via inline asm. +.text +.balign 4 +DEFINE_COMPILERRT_FUNCTION(internal_sigreturn) + mov $0xf, %eax // 0xf == SYS_rt_sigreturn + mov %rcx, %r10 + syscall + ret // Won't normally reach here. +END_COMPILERRT_FUNCTION(internal_sigreturn)