mirror of
https://github.com/opnsense/src.git
synced 2026-05-28 04:12:45 -04:00
Vendor import of compiler-rt trunk r300422:
https://llvm.org/svn/llvm-project/compiler-rt/trunk@300422
This commit is contained in:
parent
abacad30a5
commit
ab0bf875a5
675 changed files with 32009 additions and 2608 deletions
|
|
@ -14,16 +14,6 @@ if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR OR COMPILER_RT_STANDALONE
|
|||
endif()
|
||||
|
||||
cmake_minimum_required(VERSION 3.4.3)
|
||||
# FIXME:
|
||||
# The OLD behavior (pre 3.2) for this policy is to not set the value of the
|
||||
# CMAKE_EXE_LINKER_FLAGS variable in the generated test project. The NEW behavior
|
||||
# for this policy is to set the value of the CMAKE_EXE_LINKER_FLAGS variable
|
||||
# in the test project to the same as it is in the calling project. The new
|
||||
# behavior cause the compiler_rt test to fail during try_compile: see
|
||||
# projects/compiler-rt/cmake/Modules/CompilerRTUtils.cmake:121 such that
|
||||
# CAN_TARGET_${arch} is not set properly. This results in COMPILER_RT_SUPPORTED_ARCH
|
||||
# not being updated properly leading to poblems.
|
||||
cmake_policy(SET CMP0056 OLD)
|
||||
|
||||
# Add path for custom compiler-rt modules.
|
||||
list(INSERT CMAKE_MODULE_PATH 0
|
||||
|
|
@ -134,7 +124,7 @@ if(NOT WIN32)
|
|||
endif()
|
||||
append_list_if(COMPILER_RT_HAS_FNO_BUILTIN_FLAG -fno-builtin SANITIZER_COMMON_CFLAGS)
|
||||
append_list_if(COMPILER_RT_HAS_FNO_EXCEPTIONS_FLAG -fno-exceptions SANITIZER_COMMON_CFLAGS)
|
||||
if(NOT COMPILER_RT_DEBUG)
|
||||
if(NOT COMPILER_RT_DEBUG AND NOT APPLE)
|
||||
append_list_if(COMPILER_RT_HAS_FOMIT_FRAME_POINTER_FLAG -fomit-frame-pointer SANITIZER_COMMON_CFLAGS)
|
||||
endif()
|
||||
append_list_if(COMPILER_RT_HAS_FUNWIND_TABLES_FLAG -funwind-tables SANITIZER_COMMON_CFLAGS)
|
||||
|
|
@ -142,9 +132,16 @@ append_list_if(COMPILER_RT_HAS_FNO_STACK_PROTECTOR_FLAG -fno-stack-protector SAN
|
|||
append_list_if(COMPILER_RT_HAS_FNO_SANITIZE_SAFE_STACK_FLAG -fno-sanitize=safe-stack SANITIZER_COMMON_CFLAGS)
|
||||
append_list_if(COMPILER_RT_HAS_FVISIBILITY_HIDDEN_FLAG -fvisibility=hidden SANITIZER_COMMON_CFLAGS)
|
||||
append_list_if(COMPILER_RT_HAS_FVISIBILITY_INLINES_HIDDEN_FLAG -fvisibility-inlines-hidden SANITIZER_COMMON_CFLAGS)
|
||||
append_list_if(COMPILER_RT_HAS_FNO_FUNCTION_SECTIONS_FLAG -fno-function-sections SANITIZER_COMMON_CFLAGS)
|
||||
append_list_if(COMPILER_RT_HAS_FNO_LTO_FLAG -fno-lto SANITIZER_COMMON_CFLAGS)
|
||||
|
||||
# The following is a workaround for powerpc64le. This is the only architecture
|
||||
# that requires -fno-function-sections to work properly. If lacking, the ASan
|
||||
# Linux test function-sections-are-bad.cc fails with the following error:
|
||||
# 'undefined symbol: __sanitizer_unaligned_load32'.
|
||||
if(DEFINED TARGET_powerpc64le_CFLAGS)
|
||||
append_list_if(COMPILER_RT_HAS_FNO_FUNCTION_SECTIONS_FLAG -fno-function-sections TARGET_powerpc64le_CFLAGS)
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
# Replace the /M[DT][d] flags with /MT, and strip any definitions of _DEBUG,
|
||||
# which cause definition mismatches at link time.
|
||||
|
|
@ -246,12 +243,12 @@ else()
|
|||
endif()
|
||||
|
||||
set(COMPILER_RT_LLD_PATH ${LLVM_MAIN_SRC_DIR}/tools/lld)
|
||||
if(EXISTS ${COMPILER_RT_LLD_PATH}/)
|
||||
set(COMPILER_RT_HAS_LLD_SOURCES TRUE)
|
||||
if(EXISTS ${COMPILER_RT_LLD_PATH}/ AND LLVM_TOOL_LLD_BUILD)
|
||||
set(COMPILER_RT_HAS_LLD TRUE)
|
||||
else()
|
||||
set(COMPILER_RT_HAS_LLD_SOURCES FALSE)
|
||||
set(COMPILER_RT_HAS_LLD FALSE)
|
||||
endif()
|
||||
pythonize_bool(COMPILER_RT_HAS_LLD_SOURCES)
|
||||
pythonize_bool(COMPILER_RT_HAS_LLD)
|
||||
|
||||
add_subdirectory(lib)
|
||||
|
||||
|
|
|
|||
|
|
@ -110,6 +110,13 @@ function(add_compiler_rt_runtime name type)
|
|||
"OS;ARCHS;SOURCES;CFLAGS;LINK_FLAGS;DEFS;LINK_LIBS;OBJECT_LIBS"
|
||||
${ARGN})
|
||||
set(libnames)
|
||||
# Until we support this some other way, build compiler-rt runtime without LTO
|
||||
# to allow non-LTO projects to link with it.
|
||||
if(COMPILER_RT_HAS_FNO_LTO_FLAG)
|
||||
set(NO_LTO_FLAGS "-fno-lto")
|
||||
else()
|
||||
set(NO_LTO_FLAGS "")
|
||||
endif()
|
||||
if(APPLE)
|
||||
foreach(os ${LIB_OS})
|
||||
if(type STREQUAL "STATIC")
|
||||
|
|
@ -121,7 +128,7 @@ function(add_compiler_rt_runtime name type)
|
|||
list_intersect(LIB_ARCHS_${libname} DARWIN_${os}_ARCHS LIB_ARCHS)
|
||||
if(LIB_ARCHS_${libname})
|
||||
list(APPEND libnames ${libname})
|
||||
set(extra_cflags_${libname} ${DARWIN_${os}_CFLAGS} ${LIB_CFLAGS})
|
||||
set(extra_cflags_${libname} ${DARWIN_${os}_CFLAGS} ${NO_LTO_FLAGS} ${LIB_CFLAGS})
|
||||
set(output_name_${libname} ${libname}${COMPILER_RT_OS_SUFFIX})
|
||||
set(sources_${libname} ${LIB_SOURCES})
|
||||
format_object_libs(sources_${libname} ${os} ${LIB_OBJECT_LIBS})
|
||||
|
|
@ -149,7 +156,7 @@ function(add_compiler_rt_runtime name type)
|
|||
set(sources_${libname} ${LIB_SOURCES})
|
||||
format_object_libs(sources_${libname} ${arch} ${LIB_OBJECT_LIBS})
|
||||
set(libnames ${libnames} ${libname})
|
||||
set(extra_cflags_${libname} ${TARGET_${arch}_CFLAGS} ${LIB_CFLAGS})
|
||||
set(extra_cflags_${libname} ${TARGET_${arch}_CFLAGS} ${NO_LTO_FLAGS} ${LIB_CFLAGS})
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
|
|
@ -380,6 +387,7 @@ macro(add_custom_libcxx name prefix)
|
|||
-DCMAKE_BUILD_TYPE=Release
|
||||
-DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
|
||||
-DLLVM_PATH=${LLVM_MAIN_SRC_DIR}
|
||||
-DLIBCXX_STANDALONE_BUILD=On
|
||||
LOG_BUILD 1
|
||||
LOG_CONFIGURE 1
|
||||
LOG_INSTALL 1
|
||||
|
|
|
|||
|
|
@ -85,10 +85,12 @@ function(darwin_test_archs os valid_archs)
|
|||
if(TEST_COMPILE_ONLY)
|
||||
try_compile_only(CAN_TARGET_${os}_${arch} -v -arch ${arch} ${DARWIN_${os}_CFLAGS})
|
||||
else()
|
||||
set(SAVED_CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS})
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${arch_linker_flags}")
|
||||
try_compile(CAN_TARGET_${os}_${arch} ${CMAKE_BINARY_DIR} ${SIMPLE_C}
|
||||
COMPILE_DEFINITIONS "-v -arch ${arch}" ${DARWIN_${os}_CFLAGS}
|
||||
CMAKE_FLAGS "-DCMAKE_EXE_LINKER_FLAGS=${arch_linker_flags}"
|
||||
OUTPUT_VARIABLE TEST_OUTPUT)
|
||||
set(CMAKE_EXE_LINKER_FLAGS ${SAVED_CMAKE_EXE_LINKER_FLAGS})
|
||||
endif()
|
||||
if(${CAN_TARGET_${os}_${arch}})
|
||||
list(APPEND working_archs ${arch})
|
||||
|
|
|
|||
|
|
@ -138,15 +138,16 @@ macro(test_target_arch arch def)
|
|||
elseif(TEST_COMPILE_ONLY)
|
||||
try_compile_only(CAN_TARGET_${arch} ${TARGET_${arch}_CFLAGS})
|
||||
else()
|
||||
set(argstring "${CMAKE_EXE_LINKER_FLAGS} ${argstring}")
|
||||
set(FLAG_NO_EXCEPTIONS "")
|
||||
if(COMPILER_RT_HAS_FNO_EXCEPTIONS_FLAG)
|
||||
set(FLAG_NO_EXCEPTIONS " -fno-exceptions ")
|
||||
endif()
|
||||
set(SAVED_CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS})
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${argstring}")
|
||||
try_compile(CAN_TARGET_${arch} ${CMAKE_BINARY_DIR} ${SIMPLE_SOURCE}
|
||||
COMPILE_DEFINITIONS "${TARGET_${arch}_CFLAGS} ${FLAG_NO_EXCEPTIONS}"
|
||||
OUTPUT_VARIABLE TARGET_${arch}_OUTPUT
|
||||
CMAKE_FLAGS "-DCMAKE_EXE_LINKER_FLAGS:STRING=${argstring}")
|
||||
OUTPUT_VARIABLE TARGET_${arch}_OUTPUT)
|
||||
set(CMAKE_EXE_LINKER_FLAGS ${SAVED_CMAKE_EXE_LINKER_FLAGS})
|
||||
endif()
|
||||
endif()
|
||||
if(${CAN_TARGET_${arch}})
|
||||
|
|
@ -225,7 +226,8 @@ macro(load_llvm_config)
|
|||
RESULT_VARIABLE HAD_ERROR
|
||||
OUTPUT_VARIABLE CONFIG_OUTPUT)
|
||||
if(NOT HAD_ERROR)
|
||||
string(STRIP "${CONFIG_OUTPUT}" LLVM_CMAKE_PATH)
|
||||
string(STRIP "${CONFIG_OUTPUT}" LLVM_CMAKE_PATH_FROM_LLVM_CONFIG)
|
||||
file(TO_CMAKE_PATH ${LLVM_CMAKE_PATH_FROM_LLVM_CONFIG} LLVM_CMAKE_PATH)
|
||||
else()
|
||||
file(TO_CMAKE_PATH ${LLVM_BINARY_DIR} LLVM_BINARY_DIR_CMAKE_STYLE)
|
||||
set(LLVM_CMAKE_PATH "${LLVM_BINARY_DIR_CMAKE_STYLE}/lib${LLVM_LIBDIR_SUFFIX}/cmake/llvm")
|
||||
|
|
|
|||
|
|
@ -172,6 +172,7 @@ macro(test_targets)
|
|||
else()
|
||||
test_target_arch(arm "" "-march=armv7-a" "-mfloat-abi=soft")
|
||||
test_target_arch(armhf "" "-march=armv7-a" "-mfloat-abi=hard")
|
||||
test_target_arch(armv6m "" "-march=armv6m" "-mfloat-abi=soft")
|
||||
endif()
|
||||
elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "aarch32")
|
||||
test_target_arch(aarch32 "" "-march=armv8-a")
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ int foo(int x, int y) {
|
|||
|
||||
|
||||
set(ARM64 aarch64)
|
||||
set(ARM32 arm armhf)
|
||||
set(ARM32 arm armhf armv6m)
|
||||
set(X86 i386 i686)
|
||||
set(X86_64 x86_64)
|
||||
set(MIPS32 mips mipsel)
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ check_cxx_compiler_flag(-fno-lto COMPILER_RT_HAS_FNO_LTO_FLAG)
|
|||
check_cxx_compiler_flag("-Werror -msse3" COMPILER_RT_HAS_MSSE3_FLAG)
|
||||
check_cxx_compiler_flag("-Werror -msse4.2" COMPILER_RT_HAS_MSSE4_2_FLAG)
|
||||
check_cxx_compiler_flag(--sysroot=. COMPILER_RT_HAS_SYSROOT_FLAG)
|
||||
check_cxx_compiler_flag("-Werror -mcrc" COMPILER_RT_HAS_MCRC_FLAG)
|
||||
|
||||
if(NOT WIN32 AND NOT CYGWIN)
|
||||
# MinGW warns if -fvisibility-inlines-hidden is used.
|
||||
|
|
@ -163,7 +164,12 @@ set(ALL_SANITIZER_COMMON_SUPPORTED_ARCH ${X86} ${X86_64} ${PPC64}
|
|||
set(ALL_ASAN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64}
|
||||
${MIPS32} ${MIPS64} ${PPC64} ${S390X})
|
||||
set(ALL_DFSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64})
|
||||
set(ALL_LSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64})
|
||||
|
||||
if(APPLE)
|
||||
set(ALL_LSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${MIPS64} ${ARM64})
|
||||
else()
|
||||
set(ALL_LSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${MIPS64} ${ARM64} ${ARM32})
|
||||
endif()
|
||||
set(ALL_MSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64} ${PPC64})
|
||||
set(ALL_PROFILE_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${PPC64}
|
||||
${MIPS32} ${MIPS64} ${S390X})
|
||||
|
|
@ -173,8 +179,8 @@ set(ALL_UBSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64}
|
|||
set(ALL_SAFESTACK_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM64} ${MIPS32} ${MIPS64})
|
||||
set(ALL_CFI_SUPPORTED_ARCH ${X86} ${X86_64} ${MIPS64})
|
||||
set(ALL_ESAN_SUPPORTED_ARCH ${X86_64} ${MIPS64})
|
||||
set(ALL_SCUDO_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32})
|
||||
set(ALL_XRAY_SUPPORTED_ARCH ${X86_64} ${ARM32} ${ARM64})
|
||||
set(ALL_SCUDO_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64})
|
||||
set(ALL_XRAY_SUPPORTED_ARCH ${X86_64} ${ARM32} ${ARM64} ${MIPS32} ${MIPS64} powerpc64le)
|
||||
|
||||
if(APPLE)
|
||||
include(CompilerRTDarwinUtils)
|
||||
|
|
@ -199,7 +205,7 @@ if(APPLE)
|
|||
list(APPEND DARWIN_EMBEDDED_PLATFORMS ios)
|
||||
set(DARWIN_ios_MIN_VER_FLAG -miphoneos-version-min)
|
||||
set(DARWIN_ios_SANITIZER_MIN_VER_FLAG
|
||||
${DARWIN_ios_MIN_VER_FLAG}=7.0)
|
||||
${DARWIN_ios_MIN_VER_FLAG}=8.0)
|
||||
endif()
|
||||
if(COMPILER_RT_ENABLE_WATCHOS)
|
||||
list(APPEND DARWIN_EMBEDDED_PLATFORMS watchos)
|
||||
|
|
@ -484,21 +490,21 @@ else()
|
|||
endif()
|
||||
|
||||
if (PROFILE_SUPPORTED_ARCH AND NOT LLVM_USE_SANITIZER AND
|
||||
OS_NAME MATCHES "Darwin|Linux|FreeBSD|Windows")
|
||||
OS_NAME MATCHES "Darwin|Linux|FreeBSD|Windows|Android")
|
||||
set(COMPILER_RT_HAS_PROFILE TRUE)
|
||||
else()
|
||||
set(COMPILER_RT_HAS_PROFILE FALSE)
|
||||
endif()
|
||||
|
||||
if (COMPILER_RT_HAS_SANITIZER_COMMON AND TSAN_SUPPORTED_ARCH AND
|
||||
OS_NAME MATCHES "Darwin|Linux|FreeBSD")
|
||||
OS_NAME MATCHES "Darwin|Linux|FreeBSD|Android")
|
||||
set(COMPILER_RT_HAS_TSAN TRUE)
|
||||
else()
|
||||
set(COMPILER_RT_HAS_TSAN FALSE)
|
||||
endif()
|
||||
|
||||
if (COMPILER_RT_HAS_SANITIZER_COMMON AND UBSAN_SUPPORTED_ARCH AND
|
||||
OS_NAME MATCHES "Darwin|Linux|FreeBSD|Windows")
|
||||
OS_NAME MATCHES "Darwin|Linux|FreeBSD|Windows|Android")
|
||||
set(COMPILER_RT_HAS_UBSAN TRUE)
|
||||
else()
|
||||
set(COMPILER_RT_HAS_UBSAN FALSE)
|
||||
|
|
|
|||
|
|
@ -1,17 +1,23 @@
|
|||
set(SANITIZER_HEADERS
|
||||
sanitizer/allocator_interface.h
|
||||
sanitizer/asan_interface.h
|
||||
sanitizer/common_interface_defs.h
|
||||
sanitizer/coverage_interface.h
|
||||
sanitizer/dfsan_interface.h
|
||||
sanitizer/esan_interface.h
|
||||
sanitizer/linux_syscall_hooks.h
|
||||
sanitizer/lsan_interface.h
|
||||
sanitizer/msan_interface.h
|
||||
sanitizer/tsan_interface_atomic.h)
|
||||
if (COMPILER_RT_BUILD_SANITIZERS)
|
||||
set(SANITIZER_HEADERS
|
||||
sanitizer/allocator_interface.h
|
||||
sanitizer/asan_interface.h
|
||||
sanitizer/common_interface_defs.h
|
||||
sanitizer/coverage_interface.h
|
||||
sanitizer/dfsan_interface.h
|
||||
sanitizer/esan_interface.h
|
||||
sanitizer/linux_syscall_hooks.h
|
||||
sanitizer/lsan_interface.h
|
||||
sanitizer/msan_interface.h
|
||||
sanitizer/tsan_interface.h
|
||||
sanitizer/tsan_interface_atomic.h)
|
||||
endif(COMPILER_RT_BUILD_SANITIZERS)
|
||||
|
||||
set(XRAY_HEADERS
|
||||
xray/xray_interface.h)
|
||||
if (COMPILER_RT_BUILD_XRAY)
|
||||
set(XRAY_HEADERS
|
||||
xray/xray_interface.h
|
||||
xray/xray_log_interface.h)
|
||||
endif(COMPILER_RT_BUILD_XRAY)
|
||||
|
||||
set(COMPILER_RT_HEADERS
|
||||
${SANITIZER_HEADERS}
|
||||
|
|
|
|||
|
|
@ -158,8 +158,10 @@ extern "C" {
|
|||
// Prints stack traces for all live heap allocations ordered by total
|
||||
// allocation size until `top_percent` of total live heap is shown.
|
||||
// `top_percent` should be between 1 and 100.
|
||||
// At most `max_number_of_contexts` contexts (stack traces) is printed.
|
||||
// Experimental feature currently available only with asan on Linux/x86_64.
|
||||
void __sanitizer_print_memory_profile(size_t top_percent);
|
||||
void __sanitizer_print_memory_profile(size_t top_percent,
|
||||
size_t max_number_of_contexts);
|
||||
|
||||
// Fiber annotation interface.
|
||||
// Before switching to a different stack, one must call
|
||||
|
|
|
|||
121
include/sanitizer/tsan_interface.h
Normal file
121
include/sanitizer/tsan_interface.h
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
//===-- tsan_interface.h ----------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of ThreadSanitizer (TSan), a race detector.
|
||||
//
|
||||
// Public interface header for TSan.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef SANITIZER_TSAN_INTERFACE_H
|
||||
#define SANITIZER_TSAN_INTERFACE_H
|
||||
|
||||
#include <sanitizer/common_interface_defs.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// __tsan_release establishes a happens-before relation with a preceding
|
||||
// __tsan_acquire on the same address.
|
||||
void __tsan_acquire(void *addr);
|
||||
void __tsan_release(void *addr);
|
||||
|
||||
// Annotations for custom mutexes.
|
||||
// The annotations allow to get better reports (with sets of locked mutexes),
|
||||
// detect more types of bugs (e.g. mutex misuses, races between lock/unlock and
|
||||
// destruction and potential deadlocks) and improve precision and performance
|
||||
// (by ignoring individual atomic operations in mutex code). However, the
|
||||
// downside is that annotated mutex code itself is not checked for correctness.
|
||||
|
||||
// Mutex creation flags are passed to __tsan_mutex_create annotation.
|
||||
// If mutex has no constructor and __tsan_mutex_create is not called,
|
||||
// the flags may be passed to __tsan_mutex_pre_lock/__tsan_mutex_post_lock
|
||||
// annotations.
|
||||
|
||||
// Mutex has static storage duration and no-op constructor and destructor.
|
||||
// This effectively makes tsan ignore destroy annotation.
|
||||
const unsigned __tsan_mutex_linker_init = 1 << 0;
|
||||
// Mutex is write reentrant.
|
||||
const unsigned __tsan_mutex_write_reentrant = 1 << 1;
|
||||
// Mutex is read reentrant.
|
||||
const unsigned __tsan_mutex_read_reentrant = 1 << 2;
|
||||
|
||||
// Mutex operation flags:
|
||||
|
||||
// Denotes read lock operation.
|
||||
const unsigned __tsan_mutex_read_lock = 1 << 3;
|
||||
// Denotes try lock operation.
|
||||
const unsigned __tsan_mutex_try_lock = 1 << 4;
|
||||
// Denotes that a try lock operation has failed to acquire the mutex.
|
||||
const unsigned __tsan_mutex_try_lock_failed = 1 << 5;
|
||||
// Denotes that the lock operation acquires multiple recursion levels.
|
||||
// Number of levels is passed in recursion parameter.
|
||||
// This is useful for annotation of e.g. Java builtin monitors,
|
||||
// for which wait operation releases all recursive acquisitions of the mutex.
|
||||
const unsigned __tsan_mutex_recursive_lock = 1 << 6;
|
||||
// Denotes that the unlock operation releases all recursion levels.
|
||||
// Number of released levels is returned and later must be passed to
|
||||
// the corresponding __tsan_mutex_post_lock annotation.
|
||||
const unsigned __tsan_mutex_recursive_unlock = 1 << 7;
|
||||
|
||||
// Annotate creation of a mutex.
|
||||
// Supported flags: mutex creation flags.
|
||||
void __tsan_mutex_create(void *addr, unsigned flags);
|
||||
|
||||
// Annotate destruction of a mutex.
|
||||
// Supported flags: none.
|
||||
void __tsan_mutex_destroy(void *addr, unsigned flags);
|
||||
|
||||
// Annotate start of lock operation.
|
||||
// Supported flags:
|
||||
// - __tsan_mutex_read_lock
|
||||
// - __tsan_mutex_try_lock
|
||||
// - all mutex creation flags
|
||||
void __tsan_mutex_pre_lock(void *addr, unsigned flags);
|
||||
|
||||
// Annotate end of lock operation.
|
||||
// Supported flags:
|
||||
// - __tsan_mutex_read_lock (must match __tsan_mutex_pre_lock)
|
||||
// - __tsan_mutex_try_lock (must match __tsan_mutex_pre_lock)
|
||||
// - __tsan_mutex_try_lock_failed
|
||||
// - __tsan_mutex_recursive_lock
|
||||
// - all mutex creation flags
|
||||
void __tsan_mutex_post_lock(void *addr, unsigned flags, int recursion);
|
||||
|
||||
// Annotate start of unlock operation.
|
||||
// Supported flags:
|
||||
// - __tsan_mutex_read_lock
|
||||
// - __tsan_mutex_recursive_unlock
|
||||
int __tsan_mutex_pre_unlock(void *addr, unsigned flags);
|
||||
|
||||
// Annotate end of unlock operation.
|
||||
// Supported flags:
|
||||
// - __tsan_mutex_read_lock (must match __tsan_mutex_pre_unlock)
|
||||
void __tsan_mutex_post_unlock(void *addr, unsigned flags);
|
||||
|
||||
// Annotate start/end of notify/signal/broadcast operation.
|
||||
// Supported flags: none.
|
||||
void __tsan_mutex_pre_signal(void *addr, unsigned flags);
|
||||
void __tsan_mutex_post_signal(void *addr, unsigned flags);
|
||||
|
||||
// Annotate start/end of a region of code where lock/unlock/signal operation
|
||||
// diverts to do something else unrelated to the mutex. This can be used to
|
||||
// annotate, for example, calls into cooperative scheduler or contention
|
||||
// profiling code.
|
||||
// These annotations must be called only from within
|
||||
// __tsan_mutex_pre/post_lock, __tsan_mutex_pre/post_unlock,
|
||||
// __tsan_mutex_pre/post_signal regions.
|
||||
// Supported flags: none.
|
||||
void __tsan_mutex_pre_divert(void *addr, unsigned flags);
|
||||
void __tsan_mutex_post_divert(void *addr, unsigned flags);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // SANITIZER_TSAN_INTERFACE_H
|
||||
|
|
@ -18,7 +18,13 @@
|
|||
|
||||
extern "C" {
|
||||
|
||||
enum XRayEntryType { ENTRY = 0, EXIT = 1, TAIL = 2 };
|
||||
// Synchronize this with AsmPrinter::SledKind in LLVM.
|
||||
enum XRayEntryType {
|
||||
ENTRY = 0,
|
||||
EXIT = 1,
|
||||
TAIL = 2,
|
||||
LOG_ARGS_ENTRY = 3,
|
||||
};
|
||||
|
||||
// Provide a function to invoke for when instrumentation points are hit. This is
|
||||
// a user-visible control surface that overrides the default implementation. The
|
||||
|
|
@ -60,6 +66,17 @@ extern XRayPatchingStatus __xray_patch();
|
|||
// Reverses the effect of __xray_patch(). See XRayPatchingStatus for possible
|
||||
// result values.
|
||||
extern XRayPatchingStatus __xray_unpatch();
|
||||
|
||||
// Use XRay to log the first argument of each (instrumented) function call.
|
||||
// When this function exits, all threads will have observed the effect and
|
||||
// start logging their subsequent affected function calls (if patched).
|
||||
//
|
||||
// Returns 1 on success, 0 on error.
|
||||
extern int __xray_set_handler_arg1(void (*)(int32_t, XRayEntryType, uint64_t));
|
||||
|
||||
// Disables the XRay handler used to log first arguments of function calls.
|
||||
// Returns 1 on success, 0 on error.
|
||||
extern int __xray_remove_handler_arg1();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
60
include/xray/xray_log_interface.h
Normal file
60
include/xray/xray_log_interface.h
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
//===-- xray_log_interface.h ----------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of XRay, a function call tracing system.
|
||||
//
|
||||
// APIs for installing a new logging implementation.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef XRAY_XRAY_LOG_INTERFACE_H
|
||||
#define XRAY_XRAY_LOG_INTERFACE_H
|
||||
|
||||
#include "xray/xray_interface.h"
|
||||
#include <stddef.h>
|
||||
|
||||
extern "C" {
|
||||
|
||||
enum XRayLogInitStatus {
|
||||
XRAY_LOG_UNINITIALIZED = 0,
|
||||
XRAY_LOG_INITIALIZING = 1,
|
||||
XRAY_LOG_INITIALIZED = 2,
|
||||
XRAY_LOG_FINALIZING = 3,
|
||||
XRAY_LOG_FINALIZED = 4,
|
||||
};
|
||||
|
||||
enum XRayLogFlushStatus {
|
||||
XRAY_LOG_NOT_FLUSHING = 0,
|
||||
XRAY_LOG_FLUSHING = 1,
|
||||
XRAY_LOG_FLUSHED = 2,
|
||||
};
|
||||
|
||||
struct XRayLogImpl {
|
||||
XRayLogInitStatus (*log_init)(size_t, size_t, void *, size_t);
|
||||
XRayLogInitStatus (*log_finalize)();
|
||||
void (*handle_arg0)(int32_t, XRayEntryType);
|
||||
XRayLogFlushStatus (*flush_log)();
|
||||
};
|
||||
|
||||
void __xray_set_log_impl(XRayLogImpl Impl);
|
||||
XRayLogInitStatus __xray_log_init(size_t BufferSize, size_t MaxBuffers,
|
||||
void *Args, size_t ArgsSize);
|
||||
XRayLogInitStatus __xray_log_finalize();
|
||||
XRayLogFlushStatus __xray_log_flushLog();
|
||||
|
||||
} // extern "C"
|
||||
|
||||
namespace __xray {
|
||||
// Options used by the LLVM XRay FDR implementation.
|
||||
struct FDRLoggingOptions {
|
||||
bool ReportErrors = false;
|
||||
int Fd = -1;
|
||||
};
|
||||
|
||||
} // namespace __xray
|
||||
|
||||
#endif // XRAY_XRAY_LOG_INTERFACE_H
|
||||
|
|
@ -21,8 +21,17 @@ namespace __xray {
|
|||
|
||||
enum FileTypes {
|
||||
NAIVE_LOG = 0,
|
||||
FDR_LOG = 1,
|
||||
};
|
||||
|
||||
// FDR mode use of the union field in the XRayFileHeader.
|
||||
struct alignas(16) FdrAdditionalHeaderData {
|
||||
uint64_t ThreadBufferSize;
|
||||
};
|
||||
|
||||
static_assert(sizeof(FdrAdditionalHeaderData) == 16,
|
||||
"FdrAdditionalHeaderData != 16 bytes");
|
||||
|
||||
// This data structure is used to describe the contents of the file. We use this
|
||||
// for versioning the supported XRay file formats.
|
||||
struct alignas(32) XRayFileHeader {
|
||||
|
|
@ -40,6 +49,16 @@ struct alignas(32) XRayFileHeader {
|
|||
|
||||
// The frequency by which TSC increases per-second.
|
||||
alignas(8) uint64_t CycleFrequency = 0;
|
||||
|
||||
union {
|
||||
char FreeForm[16];
|
||||
// The current civiltime timestamp, as retrived from 'clock_gettime'. This
|
||||
// allows readers of the file to determine when the file was created or
|
||||
// written down.
|
||||
struct timespec TS;
|
||||
|
||||
struct FdrAdditionalHeaderData FdrData;
|
||||
};
|
||||
} __attribute__((packed));
|
||||
|
||||
static_assert(sizeof(XRayFileHeader) == 32, "XRayFileHeader != 32 bytes");
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ set(ASAN_PREINIT_SOURCES
|
|||
include_directories(..)
|
||||
|
||||
set(ASAN_CFLAGS ${SANITIZER_COMMON_CFLAGS})
|
||||
|
||||
append_rtti_flag(OFF ASAN_CFLAGS)
|
||||
|
||||
set(ASAN_DYNAMIC_LINK_FLAGS)
|
||||
|
|
@ -107,6 +108,7 @@ add_compiler_rt_component(asan)
|
|||
|
||||
if(APPLE)
|
||||
add_weak_symbols("asan" WEAK_SYMBOL_LINK_FLAGS)
|
||||
add_weak_symbols("lsan" WEAK_SYMBOL_LINK_FLAGS)
|
||||
add_weak_symbols("ubsan" WEAK_SYMBOL_LINK_FLAGS)
|
||||
add_weak_symbols("sanitizer_common" WEAK_SYMBOL_LINK_FLAGS)
|
||||
|
||||
|
|
@ -176,6 +178,21 @@ else()
|
|||
set(VERSION_SCRIPT_FLAG)
|
||||
endif()
|
||||
|
||||
set(ASAN_DYNAMIC_WEAK_INTERCEPTION)
|
||||
if (MSVC)
|
||||
add_compiler_rt_object_libraries(AsanWeakInterception
|
||||
${SANITIZER_COMMON_SUPPORTED_OS}
|
||||
ARCHS ${arch}
|
||||
SOURCES asan_win_weak_interception.cc
|
||||
CFLAGS ${ASAN_CFLAGS} -DSANITIZER_DYNAMIC
|
||||
DEFS ${ASAN_COMMON_DEFINITIONS})
|
||||
set(ASAN_DYNAMIC_WEAK_INTERCEPTION
|
||||
AsanWeakInterception
|
||||
UbsanWeakInterception
|
||||
SancovWeakInterception
|
||||
SanitizerCommonWeakInterception)
|
||||
endif()
|
||||
|
||||
add_compiler_rt_runtime(clang_rt.asan
|
||||
SHARED
|
||||
ARCHS ${arch}
|
||||
|
|
@ -187,6 +204,7 @@ else()
|
|||
# add_dependencies(clang_rt.asan-dynamic-${arch} clang_rt.asan-dynamic-${arch}-version-list)
|
||||
RTAsan_dynamic_version_script_dummy
|
||||
RTUbsan_cxx
|
||||
${ASAN_DYNAMIC_WEAK_INTERCEPTION}
|
||||
CFLAGS ${ASAN_DYNAMIC_CFLAGS}
|
||||
LINK_FLAGS ${ASAN_DYNAMIC_LINK_FLAGS}
|
||||
${VERSION_SCRIPT_FLAG}
|
||||
|
|
@ -205,28 +223,46 @@ else()
|
|||
endif()
|
||||
|
||||
if (WIN32)
|
||||
add_compiler_rt_object_libraries(AsanDllThunk
|
||||
${SANITIZER_COMMON_SUPPORTED_OS}
|
||||
ARCHS ${arch}
|
||||
SOURCES asan_globals_win.cc
|
||||
asan_win_dll_thunk.cc
|
||||
CFLAGS ${ASAN_CFLAGS} -DSANITIZER_DLL_THUNK
|
||||
DEFS ${ASAN_COMMON_DEFINITIONS})
|
||||
|
||||
add_compiler_rt_runtime(clang_rt.asan_dll_thunk
|
||||
STATIC
|
||||
ARCHS ${arch}
|
||||
SOURCES asan_win_dll_thunk.cc
|
||||
asan_globals_win.cc
|
||||
$<TARGET_OBJECTS:RTInterception.${arch}>
|
||||
CFLAGS ${ASAN_CFLAGS} -DASAN_DLL_THUNK
|
||||
DEFS ${ASAN_COMMON_DEFINITIONS}
|
||||
OBJECT_LIBS AsanDllThunk
|
||||
UbsanDllThunk
|
||||
SancovDllThunk
|
||||
SanitizerCommonDllThunk
|
||||
SOURCES $<TARGET_OBJECTS:RTInterception.${arch}>
|
||||
PARENT_TARGET asan)
|
||||
|
||||
set(DYNAMIC_RUNTIME_THUNK_CFLAGS "-DASAN_DYNAMIC_RUNTIME_THUNK")
|
||||
set(DYNAMIC_RUNTIME_THUNK_CFLAGS "-DSANITIZER_DYNAMIC_RUNTIME_THUNK")
|
||||
if(MSVC)
|
||||
list(APPEND DYNAMIC_RUNTIME_THUNK_CFLAGS "-Zl")
|
||||
elseif(CMAKE_C_COMPILER_ID MATCHES Clang)
|
||||
list(APPEND DYNAMIC_RUNTIME_THUNK_CFLAGS "-nodefaultlibs")
|
||||
endif()
|
||||
|
||||
add_compiler_rt_object_libraries(AsanDynamicRuntimeThunk
|
||||
${SANITIZER_COMMON_SUPPORTED_OS}
|
||||
ARCHS ${arch}
|
||||
SOURCES asan_globals_win.cc
|
||||
asan_win_dynamic_runtime_thunk.cc
|
||||
CFLAGS ${ASAN_CFLAGS} ${DYNAMIC_RUNTIME_THUNK_CFLAGS}
|
||||
DEFS ${ASAN_COMMON_DEFINITIONS})
|
||||
|
||||
add_compiler_rt_runtime(clang_rt.asan_dynamic_runtime_thunk
|
||||
STATIC
|
||||
ARCHS ${arch}
|
||||
SOURCES asan_win_dynamic_runtime_thunk.cc
|
||||
asan_globals_win.cc
|
||||
OBJECT_LIBS AsanDynamicRuntimeThunk
|
||||
UbsanDynamicRuntimeThunk
|
||||
SancovDynamicRuntimeThunk
|
||||
SanitizerCommonDynamicRuntimeThunk
|
||||
CFLAGS ${ASAN_CFLAGS} ${DYNAMIC_RUNTIME_THUNK_CFLAGS}
|
||||
DEFS ${ASAN_COMMON_DEFINITIONS}
|
||||
PARENT_TARGET asan)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
__asan_*
|
||||
__lsan_*
|
||||
__ubsan_*
|
||||
__sancov_*
|
||||
|
|
|
|||
|
|
@ -523,6 +523,18 @@ struct Allocator {
|
|||
AsanThread *t = GetCurrentThread();
|
||||
m->free_tid = t ? t->tid() : 0;
|
||||
m->free_context_id = StackDepotPut(*stack);
|
||||
|
||||
Flags &fl = *flags();
|
||||
if (fl.max_free_fill_size > 0) {
|
||||
// We have to skip the chunk header, it contains free_context_id.
|
||||
uptr scribble_start = (uptr)m + kChunkHeaderSize + kChunkHeader2Size;
|
||||
if (m->UsedSize() >= kChunkHeader2Size) { // Skip Header2 in user area.
|
||||
uptr size_to_fill = m->UsedSize() - kChunkHeader2Size;
|
||||
size_to_fill = Min(size_to_fill, (uptr)fl.max_free_fill_size);
|
||||
REAL(memset)((void *)scribble_start, fl.free_fill_byte, size_to_fill);
|
||||
}
|
||||
}
|
||||
|
||||
// Poison the region.
|
||||
PoisonShadow(m->Beg(),
|
||||
RoundUpTo(m->UsedSize(), SHADOW_GRANULARITY),
|
||||
|
|
@ -554,7 +566,17 @@ struct Allocator {
|
|||
uptr chunk_beg = p - kChunkHeaderSize;
|
||||
AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg);
|
||||
|
||||
// On Windows, uninstrumented DLLs may allocate memory before ASan hooks
|
||||
// malloc. Don't report an invalid free in this case.
|
||||
if (SANITIZER_WINDOWS &&
|
||||
!get_allocator().PointerIsMine(ptr)) {
|
||||
if (!IsSystemHeapAddress(p))
|
||||
ReportFreeNotMalloced(p, stack);
|
||||
return;
|
||||
}
|
||||
|
||||
ASAN_FREE_HOOK(ptr);
|
||||
|
||||
// Must mark the chunk as quarantined before any changes to its metadata.
|
||||
// Do not quarantine given chunk if we failed to set CHUNK_QUARANTINE flag.
|
||||
if (!AtomicallySetQuarantineFlagIfAllocated(m, ptr, stack)) return;
|
||||
|
|
@ -790,8 +812,12 @@ void *asan_realloc(void *p, uptr size, BufferedStackTrace *stack) {
|
|||
if (!p)
|
||||
return instance.Allocate(size, 8, stack, FROM_MALLOC, true);
|
||||
if (size == 0) {
|
||||
instance.Deallocate(p, 0, stack, FROM_MALLOC);
|
||||
return nullptr;
|
||||
if (flags()->allocator_frees_and_returns_null_on_realloc_zero) {
|
||||
instance.Deallocate(p, 0, stack, FROM_MALLOC);
|
||||
return nullptr;
|
||||
}
|
||||
// Allocate a size of 1 if we shouldn't free() on Realloc to 0
|
||||
size = 1;
|
||||
}
|
||||
return instance.Reallocate(p, size, stack);
|
||||
}
|
||||
|
|
@ -958,15 +984,13 @@ uptr __sanitizer_get_allocated_size(const void *p) {
|
|||
|
||||
#if !SANITIZER_SUPPORTS_WEAK_HOOKS
|
||||
// Provide default (no-op) implementation of malloc hooks.
|
||||
extern "C" {
|
||||
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
|
||||
void __sanitizer_malloc_hook(void *ptr, uptr size) {
|
||||
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_malloc_hook,
|
||||
void *ptr, uptr size) {
|
||||
(void)ptr;
|
||||
(void)size;
|
||||
}
|
||||
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
|
||||
void __sanitizer_free_hook(void *ptr) {
|
||||
|
||||
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_free_hook, void *ptr) {
|
||||
(void)ptr;
|
||||
}
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -252,6 +252,9 @@ static void PrintAccessAndVarIntersection(const StackVarDescr &var, uptr addr,
|
|||
str.append("%c", var.name_pos[i]);
|
||||
}
|
||||
str.append("'");
|
||||
if (var.line > 0) {
|
||||
str.append(" (line %d)", var.line);
|
||||
}
|
||||
if (pos_descr) {
|
||||
Decorator d;
|
||||
// FIXME: we may want to also print the size of the access here,
|
||||
|
|
|
|||
|
|
@ -58,10 +58,22 @@ static void MaybeDumpRegisters(void *context) {
|
|||
SignalContext::DumpAllRegisters(context);
|
||||
}
|
||||
|
||||
static void MaybeReportNonExecRegion(uptr pc) {
|
||||
#if SANITIZER_FREEBSD || SANITIZER_LINUX
|
||||
MemoryMappingLayout proc_maps(/*cache_enabled*/ true);
|
||||
uptr start, end, protection;
|
||||
while (proc_maps.Next(&start, &end, nullptr, nullptr, 0, &protection)) {
|
||||
if (pc >= start && pc < end &&
|
||||
!(protection & MemoryMappingLayout::kProtectionExecute))
|
||||
Report("Hint: PC is at a non-executable region. Maybe a wild jump?\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void ErrorDeadlySignal::Print() {
|
||||
Decorator d;
|
||||
Printf("%s", d.Warning());
|
||||
const char *description = DescribeSignalOrException(signo);
|
||||
const char *description = __sanitizer::DescribeSignalOrException(signo);
|
||||
Report(
|
||||
"ERROR: AddressSanitizer: %s on unknown address %p (pc %p bp %p sp %p "
|
||||
"T%d)\n",
|
||||
|
|
@ -77,6 +89,7 @@ void ErrorDeadlySignal::Print() {
|
|||
if (addr < GetPageSizeCached())
|
||||
Report("Hint: address points to the zero page.\n");
|
||||
}
|
||||
MaybeReportNonExecRegion(pc);
|
||||
scariness.Print();
|
||||
BufferedStackTrace stack;
|
||||
GetStackTraceWithPcBpAndContext(&stack, kStackTraceMax, pc, bp, context,
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ void InitializeFlags() {
|
|||
{
|
||||
CommonFlags cf;
|
||||
cf.CopyFrom(*common_flags());
|
||||
cf.detect_leaks = CAN_SANITIZE_LEAKS;
|
||||
cf.detect_leaks = cf.detect_leaks && CAN_SANITIZE_LEAKS;
|
||||
cf.external_symbolizer_path = GetEnv("ASAN_SYMBOLIZER_PATH");
|
||||
cf.malloc_context_size = kDefaultMallocContextSize;
|
||||
cf.intercept_tls_get_addr = true;
|
||||
|
|
@ -95,6 +95,18 @@ void InitializeFlags() {
|
|||
RegisterCommonFlags(&ubsan_parser);
|
||||
#endif
|
||||
|
||||
if (SANITIZER_MAC) {
|
||||
// Support macOS MallocScribble and MallocPreScribble:
|
||||
// <https://developer.apple.com/library/content/documentation/Performance/
|
||||
// Conceptual/ManagingMemory/Articles/MallocDebug.html>
|
||||
if (GetEnv("MallocScribble")) {
|
||||
f->max_free_fill_size = 0x1000;
|
||||
}
|
||||
if (GetEnv("MallocPreScribble")) {
|
||||
f->malloc_fill_byte = 0xaa;
|
||||
}
|
||||
}
|
||||
|
||||
// Override from ASan compile definition.
|
||||
const char *asan_compile_def = MaybeUseAsanDefaultOptionsCompileDefinition();
|
||||
asan_parser.ParseString(asan_compile_def);
|
||||
|
|
@ -186,9 +198,6 @@ void InitializeFlags() {
|
|||
|
||||
} // namespace __asan
|
||||
|
||||
#if !SANITIZER_SUPPORTS_WEAK_HOOKS
|
||||
extern "C" {
|
||||
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
|
||||
const char* __asan_default_options() { return ""; }
|
||||
} // extern "C"
|
||||
#endif
|
||||
SANITIZER_INTERFACE_WEAK_DEF(const char*, __asan_default_options, void) {
|
||||
return "";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,8 +63,14 @@ ASAN_FLAG(
|
|||
int, max_malloc_fill_size, 0x1000, // By default, fill only the first 4K.
|
||||
"ASan allocator flag. max_malloc_fill_size is the maximal amount of "
|
||||
"bytes that will be filled with malloc_fill_byte on malloc.")
|
||||
ASAN_FLAG(
|
||||
int, max_free_fill_size, 0,
|
||||
"ASan allocator flag. max_free_fill_size is the maximal amount of "
|
||||
"bytes that will be filled with free_fill_byte during free.")
|
||||
ASAN_FLAG(int, malloc_fill_byte, 0xbe,
|
||||
"Value used to fill the newly allocated memory.")
|
||||
ASAN_FLAG(int, free_fill_byte, 0x55,
|
||||
"Value used to fill deallocated memory.")
|
||||
ASAN_FLAG(bool, allow_user_poisoning, true,
|
||||
"If set, user may manually mark memory regions as poisoned or "
|
||||
"unpoisoned.")
|
||||
|
|
@ -148,3 +154,10 @@ ASAN_FLAG(bool, halt_on_error, true,
|
|||
"(WARNING: USE AT YOUR OWN RISK!)")
|
||||
ASAN_FLAG(bool, use_odr_indicator, false,
|
||||
"Use special ODR indicator symbol for ODR violation detection")
|
||||
ASAN_FLAG(bool, allocator_frees_and_returns_null_on_realloc_zero, true,
|
||||
"realloc(p, 0) is equivalent to free(p) by default (Same as the "
|
||||
"POSIX standard). If set to false, realloc(p, 0) will return a "
|
||||
"pointer to an allocated space which can not be used.")
|
||||
ASAN_FLAG(bool, verify_asan_link_order, true,
|
||||
"Check position of ASan runtime in library list (needs to be disabled"
|
||||
" when other library has to be preloaded system-wide)")
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ static void call_on_globals(void (*hook)(__asan_global *, uptr)) {
|
|||
__asan_global *end = &__asan_globals_end;
|
||||
uptr bytediff = (uptr)end - (uptr)start;
|
||||
if (bytediff % sizeof(__asan_global) != 0) {
|
||||
#ifdef ASAN_DLL_THUNK
|
||||
#ifdef SANITIZER_DLL_THUNK
|
||||
__debugbreak();
|
||||
#else
|
||||
CHECK("corrupt asan global array");
|
||||
|
|
|
|||
|
|
@ -1,34 +0,0 @@
|
|||
//===-- asan_globals_win.h --------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Interface to the Windows-specific global management code. Separated into a
|
||||
// standalone header to allow inclusion from asan_win_dynamic_runtime_thunk,
|
||||
// which defines symbols that clash with other sanitizer headers.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef ASAN_GLOBALS_WIN_H
|
||||
#define ASAN_GLOBALS_WIN_H
|
||||
|
||||
#if !defined(_MSC_VER)
|
||||
#error "this file is Windows-only, and uses MSVC pragmas"
|
||||
#endif
|
||||
|
||||
#if defined(_WIN64)
|
||||
#define SANITIZER_SYM_PREFIX
|
||||
#else
|
||||
#define SANITIZER_SYM_PREFIX "_"
|
||||
#endif
|
||||
|
||||
// Use this macro to force linking asan_globals_win.cc into the DSO.
|
||||
#define ASAN_LINK_GLOBALS_WIN() \
|
||||
__pragma( \
|
||||
comment(linker, "/include:" SANITIZER_SYM_PREFIX "__asan_dso_reg_hook"))
|
||||
|
||||
#endif // ASAN_GLOBALS_WIN_H
|
||||
|
|
@ -228,9 +228,11 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)
|
|||
// Strict init-order checking is dlopen-hostile:
|
||||
// https://github.com/google/sanitizers/issues/178
|
||||
#define COMMON_INTERCEPTOR_ON_DLOPEN(filename, flag) \
|
||||
if (flags()->strict_init_order) { \
|
||||
StopInitOrderChecking(); \
|
||||
}
|
||||
do { \
|
||||
if (flags()->strict_init_order) \
|
||||
StopInitOrderChecking(); \
|
||||
CheckNoDeepBind(filename, flag); \
|
||||
} while (false)
|
||||
#define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit()
|
||||
#define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle) \
|
||||
CoverageUpdateMapping()
|
||||
|
|
|
|||
167
lib/asan/asan_interface.inc
Normal file
167
lib/asan/asan_interface.inc
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
//===-- asan_interface.inc ------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Asan interface list.
|
||||
//===----------------------------------------------------------------------===//
|
||||
INTERFACE_FUNCTION(__asan_addr_is_in_fake_stack)
|
||||
INTERFACE_FUNCTION(__asan_address_is_poisoned)
|
||||
INTERFACE_FUNCTION(__asan_after_dynamic_init)
|
||||
INTERFACE_FUNCTION(__asan_alloca_poison)
|
||||
INTERFACE_FUNCTION(__asan_allocas_unpoison)
|
||||
INTERFACE_FUNCTION(__asan_before_dynamic_init)
|
||||
INTERFACE_FUNCTION(__asan_describe_address)
|
||||
INTERFACE_FUNCTION(__asan_exp_load1)
|
||||
INTERFACE_FUNCTION(__asan_exp_load2)
|
||||
INTERFACE_FUNCTION(__asan_exp_load4)
|
||||
INTERFACE_FUNCTION(__asan_exp_load8)
|
||||
INTERFACE_FUNCTION(__asan_exp_load16)
|
||||
INTERFACE_FUNCTION(__asan_exp_loadN)
|
||||
INTERFACE_FUNCTION(__asan_exp_store1)
|
||||
INTERFACE_FUNCTION(__asan_exp_store2)
|
||||
INTERFACE_FUNCTION(__asan_exp_store4)
|
||||
INTERFACE_FUNCTION(__asan_exp_store8)
|
||||
INTERFACE_FUNCTION(__asan_exp_store16)
|
||||
INTERFACE_FUNCTION(__asan_exp_storeN)
|
||||
INTERFACE_FUNCTION(__asan_get_alloc_stack)
|
||||
INTERFACE_FUNCTION(__asan_get_current_fake_stack)
|
||||
INTERFACE_FUNCTION(__asan_get_free_stack)
|
||||
INTERFACE_FUNCTION(__asan_get_report_access_size)
|
||||
INTERFACE_FUNCTION(__asan_get_report_access_type)
|
||||
INTERFACE_FUNCTION(__asan_get_report_address)
|
||||
INTERFACE_FUNCTION(__asan_get_report_bp)
|
||||
INTERFACE_FUNCTION(__asan_get_report_description)
|
||||
INTERFACE_FUNCTION(__asan_get_report_pc)
|
||||
INTERFACE_FUNCTION(__asan_get_report_sp)
|
||||
INTERFACE_FUNCTION(__asan_get_shadow_mapping)
|
||||
INTERFACE_FUNCTION(__asan_handle_no_return)
|
||||
INTERFACE_FUNCTION(__asan_init)
|
||||
INTERFACE_FUNCTION(__asan_load_cxx_array_cookie)
|
||||
INTERFACE_FUNCTION(__asan_load1)
|
||||
INTERFACE_FUNCTION(__asan_load2)
|
||||
INTERFACE_FUNCTION(__asan_load4)
|
||||
INTERFACE_FUNCTION(__asan_load8)
|
||||
INTERFACE_FUNCTION(__asan_load16)
|
||||
INTERFACE_FUNCTION(__asan_loadN)
|
||||
INTERFACE_FUNCTION(__asan_load1_noabort)
|
||||
INTERFACE_FUNCTION(__asan_load2_noabort)
|
||||
INTERFACE_FUNCTION(__asan_load4_noabort)
|
||||
INTERFACE_FUNCTION(__asan_load8_noabort)
|
||||
INTERFACE_FUNCTION(__asan_load16_noabort)
|
||||
INTERFACE_FUNCTION(__asan_loadN_noabort)
|
||||
INTERFACE_FUNCTION(__asan_locate_address)
|
||||
INTERFACE_FUNCTION(__asan_memcpy)
|
||||
INTERFACE_FUNCTION(__asan_memmove)
|
||||
INTERFACE_FUNCTION(__asan_memset)
|
||||
INTERFACE_FUNCTION(__asan_poison_cxx_array_cookie)
|
||||
INTERFACE_FUNCTION(__asan_poison_intra_object_redzone)
|
||||
INTERFACE_FUNCTION(__asan_poison_memory_region)
|
||||
INTERFACE_FUNCTION(__asan_poison_stack_memory)
|
||||
INTERFACE_FUNCTION(__asan_print_accumulated_stats)
|
||||
INTERFACE_FUNCTION(__asan_region_is_poisoned)
|
||||
INTERFACE_FUNCTION(__asan_register_globals)
|
||||
INTERFACE_FUNCTION(__asan_register_image_globals)
|
||||
INTERFACE_FUNCTION(__asan_report_error)
|
||||
INTERFACE_FUNCTION(__asan_report_exp_load1)
|
||||
INTERFACE_FUNCTION(__asan_report_exp_load2)
|
||||
INTERFACE_FUNCTION(__asan_report_exp_load4)
|
||||
INTERFACE_FUNCTION(__asan_report_exp_load8)
|
||||
INTERFACE_FUNCTION(__asan_report_exp_load16)
|
||||
INTERFACE_FUNCTION(__asan_report_exp_load_n)
|
||||
INTERFACE_FUNCTION(__asan_report_exp_store1)
|
||||
INTERFACE_FUNCTION(__asan_report_exp_store2)
|
||||
INTERFACE_FUNCTION(__asan_report_exp_store4)
|
||||
INTERFACE_FUNCTION(__asan_report_exp_store8)
|
||||
INTERFACE_FUNCTION(__asan_report_exp_store16)
|
||||
INTERFACE_FUNCTION(__asan_report_exp_store_n)
|
||||
INTERFACE_FUNCTION(__asan_report_load1)
|
||||
INTERFACE_FUNCTION(__asan_report_load2)
|
||||
INTERFACE_FUNCTION(__asan_report_load4)
|
||||
INTERFACE_FUNCTION(__asan_report_load8)
|
||||
INTERFACE_FUNCTION(__asan_report_load16)
|
||||
INTERFACE_FUNCTION(__asan_report_load_n)
|
||||
INTERFACE_FUNCTION(__asan_report_load1_noabort)
|
||||
INTERFACE_FUNCTION(__asan_report_load2_noabort)
|
||||
INTERFACE_FUNCTION(__asan_report_load4_noabort)
|
||||
INTERFACE_FUNCTION(__asan_report_load8_noabort)
|
||||
INTERFACE_FUNCTION(__asan_report_load16_noabort)
|
||||
INTERFACE_FUNCTION(__asan_report_load_n_noabort)
|
||||
INTERFACE_FUNCTION(__asan_report_present)
|
||||
INTERFACE_FUNCTION(__asan_report_store1)
|
||||
INTERFACE_FUNCTION(__asan_report_store2)
|
||||
INTERFACE_FUNCTION(__asan_report_store4)
|
||||
INTERFACE_FUNCTION(__asan_report_store8)
|
||||
INTERFACE_FUNCTION(__asan_report_store16)
|
||||
INTERFACE_FUNCTION(__asan_report_store_n)
|
||||
INTERFACE_FUNCTION(__asan_report_store1_noabort)
|
||||
INTERFACE_FUNCTION(__asan_report_store2_noabort)
|
||||
INTERFACE_FUNCTION(__asan_report_store4_noabort)
|
||||
INTERFACE_FUNCTION(__asan_report_store8_noabort)
|
||||
INTERFACE_FUNCTION(__asan_report_store16_noabort)
|
||||
INTERFACE_FUNCTION(__asan_report_store_n_noabort)
|
||||
INTERFACE_FUNCTION(__asan_set_death_callback)
|
||||
INTERFACE_FUNCTION(__asan_set_error_report_callback)
|
||||
INTERFACE_FUNCTION(__asan_set_shadow_00)
|
||||
INTERFACE_FUNCTION(__asan_set_shadow_f1)
|
||||
INTERFACE_FUNCTION(__asan_set_shadow_f2)
|
||||
INTERFACE_FUNCTION(__asan_set_shadow_f3)
|
||||
INTERFACE_FUNCTION(__asan_set_shadow_f5)
|
||||
INTERFACE_FUNCTION(__asan_set_shadow_f8)
|
||||
INTERFACE_FUNCTION(__asan_stack_free_0)
|
||||
INTERFACE_FUNCTION(__asan_stack_free_1)
|
||||
INTERFACE_FUNCTION(__asan_stack_free_2)
|
||||
INTERFACE_FUNCTION(__asan_stack_free_3)
|
||||
INTERFACE_FUNCTION(__asan_stack_free_4)
|
||||
INTERFACE_FUNCTION(__asan_stack_free_5)
|
||||
INTERFACE_FUNCTION(__asan_stack_free_6)
|
||||
INTERFACE_FUNCTION(__asan_stack_free_7)
|
||||
INTERFACE_FUNCTION(__asan_stack_free_8)
|
||||
INTERFACE_FUNCTION(__asan_stack_free_9)
|
||||
INTERFACE_FUNCTION(__asan_stack_free_10)
|
||||
INTERFACE_FUNCTION(__asan_stack_malloc_0)
|
||||
INTERFACE_FUNCTION(__asan_stack_malloc_1)
|
||||
INTERFACE_FUNCTION(__asan_stack_malloc_2)
|
||||
INTERFACE_FUNCTION(__asan_stack_malloc_3)
|
||||
INTERFACE_FUNCTION(__asan_stack_malloc_4)
|
||||
INTERFACE_FUNCTION(__asan_stack_malloc_5)
|
||||
INTERFACE_FUNCTION(__asan_stack_malloc_6)
|
||||
INTERFACE_FUNCTION(__asan_stack_malloc_7)
|
||||
INTERFACE_FUNCTION(__asan_stack_malloc_8)
|
||||
INTERFACE_FUNCTION(__asan_stack_malloc_9)
|
||||
INTERFACE_FUNCTION(__asan_stack_malloc_10)
|
||||
INTERFACE_FUNCTION(__asan_store1)
|
||||
INTERFACE_FUNCTION(__asan_store2)
|
||||
INTERFACE_FUNCTION(__asan_store4)
|
||||
INTERFACE_FUNCTION(__asan_store8)
|
||||
INTERFACE_FUNCTION(__asan_store16)
|
||||
INTERFACE_FUNCTION(__asan_storeN)
|
||||
INTERFACE_FUNCTION(__asan_store1_noabort)
|
||||
INTERFACE_FUNCTION(__asan_store2_noabort)
|
||||
INTERFACE_FUNCTION(__asan_store4_noabort)
|
||||
INTERFACE_FUNCTION(__asan_store8_noabort)
|
||||
INTERFACE_FUNCTION(__asan_store16_noabort)
|
||||
INTERFACE_FUNCTION(__asan_storeN_noabort)
|
||||
INTERFACE_FUNCTION(__asan_unpoison_intra_object_redzone)
|
||||
INTERFACE_FUNCTION(__asan_unpoison_memory_region)
|
||||
INTERFACE_FUNCTION(__asan_unpoison_stack_memory)
|
||||
INTERFACE_FUNCTION(__asan_unregister_globals)
|
||||
INTERFACE_FUNCTION(__asan_unregister_image_globals)
|
||||
INTERFACE_FUNCTION(__asan_version_mismatch_check_v8)
|
||||
INTERFACE_FUNCTION(__sanitizer_finish_switch_fiber)
|
||||
INTERFACE_FUNCTION(__sanitizer_print_stack_trace)
|
||||
INTERFACE_FUNCTION(__sanitizer_ptr_cmp)
|
||||
INTERFACE_FUNCTION(__sanitizer_ptr_sub)
|
||||
INTERFACE_FUNCTION(__sanitizer_start_switch_fiber)
|
||||
INTERFACE_FUNCTION(__sanitizer_unaligned_load16)
|
||||
INTERFACE_FUNCTION(__sanitizer_unaligned_load32)
|
||||
INTERFACE_FUNCTION(__sanitizer_unaligned_load64)
|
||||
INTERFACE_FUNCTION(__sanitizer_unaligned_store16)
|
||||
INTERFACE_FUNCTION(__sanitizer_unaligned_store32)
|
||||
INTERFACE_FUNCTION(__sanitizer_unaligned_store64)
|
||||
INTERFACE_WEAK_FUNCTION(__asan_default_options)
|
||||
INTERFACE_WEAK_FUNCTION(__asan_default_suppressions)
|
||||
INTERFACE_WEAK_FUNCTION(__asan_on_error)
|
||||
|
|
@ -165,12 +165,12 @@ extern "C" {
|
|||
void __asan_set_error_report_callback(void (*callback)(const char*));
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
|
||||
/* OPTIONAL */ void __asan_on_error();
|
||||
void __asan_on_error();
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE void __asan_print_accumulated_stats();
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
|
||||
/* OPTIONAL */ const char* __asan_default_options();
|
||||
const char* __asan_default_options();
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
extern uptr __asan_shadow_memory_dynamic_address;
|
||||
|
|
@ -242,6 +242,9 @@ extern "C" {
|
|||
void __asan_alloca_poison(uptr addr, uptr size);
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void __asan_allocas_unpoison(uptr top, uptr bottom);
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
|
||||
const char* __asan_default_suppressions();
|
||||
} // extern "C"
|
||||
|
||||
#endif // ASAN_INTERFACE_INTERNAL_H
|
||||
|
|
|
|||
|
|
@ -64,9 +64,9 @@ void AsanInitFromRtl();
|
|||
|
||||
// asan_win.cc
|
||||
void InitializePlatformExceptionHandlers();
|
||||
|
||||
// asan_win.cc / asan_posix.cc
|
||||
const char *DescribeSignalOrException(int signo);
|
||||
// Returns whether an address is a valid allocated system heap block.
|
||||
// 'addr' must point to the beginning of the block.
|
||||
bool IsSystemHeapAddress(uptr addr);
|
||||
|
||||
// asan_rtl.cc
|
||||
void NORETURN ShowStatsAndAbort();
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ namespace __asan {
|
|||
|
||||
void InitializePlatformInterceptors() {}
|
||||
void InitializePlatformExceptionHandlers() {}
|
||||
bool IsSystemHeapAddress (uptr addr) { return false; }
|
||||
|
||||
void *AsanDoesNotSupportStaticLinkage() {
|
||||
// This will fail to link with -static.
|
||||
|
|
@ -110,7 +111,7 @@ static void ReportIncompatibleRT() {
|
|||
}
|
||||
|
||||
void AsanCheckDynamicRTPrereqs() {
|
||||
if (!ASAN_DYNAMIC)
|
||||
if (!ASAN_DYNAMIC || !flags()->verify_asan_link_order)
|
||||
return;
|
||||
|
||||
// Ensure that dynamic RT is the first DSO in the list
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ namespace __asan {
|
|||
|
||||
void InitializePlatformInterceptors() {}
|
||||
void InitializePlatformExceptionHandlers() {}
|
||||
bool IsSystemHeapAddress (uptr addr) { return false; }
|
||||
|
||||
// No-op. Mac does not support static linkage anyway.
|
||||
void *AsanDoesNotSupportStaticLinkage() {
|
||||
|
|
@ -138,7 +139,8 @@ void asan_register_worker_thread(int parent_tid, StackTrace *stack) {
|
|||
t = AsanThread::Create(/* start_routine */ nullptr, /* arg */ nullptr,
|
||||
parent_tid, stack, /* detached */ true);
|
||||
t->Init();
|
||||
asanThreadRegistry().StartThread(t->tid(), 0, 0);
|
||||
asanThreadRegistry().StartThread(t->tid(), GetTid(),
|
||||
/* workerthread */ true, 0);
|
||||
SetCurrentThread(t);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ void *realloc(void *ptr, size_t size) {
|
|||
|
||||
ALLOCATION_FUNCTION_ATTRIBUTE
|
||||
void *_realloc_dbg(void *ptr, size_t size, int) {
|
||||
CHECK(!"_realloc_dbg should not exist!");
|
||||
UNREACHABLE("_realloc_dbg should not exist!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -191,7 +191,6 @@ static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000
|
|||
|
||||
#define SHADOW_GRANULARITY (1ULL << SHADOW_SCALE)
|
||||
#define MEM_TO_SHADOW(mem) (((mem) >> SHADOW_SCALE) + (SHADOW_OFFSET))
|
||||
#define SHADOW_TO_MEM(shadow) (((shadow) - SHADOW_OFFSET) << SHADOW_SCALE)
|
||||
|
||||
#define kLowMemBeg 0
|
||||
#define kLowMemEnd (SHADOW_OFFSET ? SHADOW_OFFSET - 1 : 0)
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ class HeapProfile {
|
|||
}
|
||||
}
|
||||
|
||||
void Print(uptr top_percent) {
|
||||
void Print(uptr top_percent, uptr max_number_of_contexts) {
|
||||
InternalSort(&allocations_, allocations_.size(),
|
||||
[](const AllocationSite &a, const AllocationSite &b) {
|
||||
return a.total_size > b.total_size;
|
||||
|
|
@ -57,12 +57,14 @@ class HeapProfile {
|
|||
uptr total_shown = 0;
|
||||
Printf("Live Heap Allocations: %zd bytes in %zd chunks; quarantined: "
|
||||
"%zd bytes in %zd chunks; %zd other chunks; total chunks: %zd; "
|
||||
"showing top %zd%%\n",
|
||||
"showing top %zd%% (at most %zd unique contexts)\n",
|
||||
total_allocated_user_size_, total_allocated_count_,
|
||||
total_quarantined_user_size_, total_quarantined_count_,
|
||||
total_other_count_, total_allocated_count_ +
|
||||
total_quarantined_count_ + total_other_count_, top_percent);
|
||||
for (uptr i = 0; i < allocations_.size(); i++) {
|
||||
total_quarantined_count_ + total_other_count_, top_percent,
|
||||
max_number_of_contexts);
|
||||
for (uptr i = 0; i < Min(allocations_.size(), max_number_of_contexts);
|
||||
i++) {
|
||||
auto &a = allocations_[i];
|
||||
Printf("%zd byte(s) (%zd%%) in %zd allocation(s)\n", a.total_size,
|
||||
a.total_size * 100 / total_allocated_user_size_, a.count);
|
||||
|
|
@ -103,16 +105,23 @@ static void MemoryProfileCB(const SuspendedThreadsList &suspended_threads_list,
|
|||
void *argument) {
|
||||
HeapProfile hp;
|
||||
__lsan::ForEachChunk(ChunkCallback, &hp);
|
||||
hp.Print(reinterpret_cast<uptr>(argument));
|
||||
uptr *Arg = reinterpret_cast<uptr*>(argument);
|
||||
hp.Print(Arg[0], Arg[1]);
|
||||
}
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
#endif // CAN_SANITIZE_LEAKS
|
||||
|
||||
extern "C" {
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void __sanitizer_print_memory_profile(uptr top_percent) {
|
||||
__sanitizer::StopTheWorld(__asan::MemoryProfileCB, (void*)top_percent);
|
||||
void __sanitizer_print_memory_profile(uptr top_percent,
|
||||
uptr max_number_of_contexts) {
|
||||
#if CAN_SANITIZE_LEAKS
|
||||
uptr Arg[2];
|
||||
Arg[0] = top_percent;
|
||||
Arg[1] = max_number_of_contexts;
|
||||
__sanitizer::StopTheWorld(__asan::MemoryProfileCB, Arg);
|
||||
#endif // CAN_SANITIZE_LEAKS
|
||||
}
|
||||
} // extern "C"
|
||||
|
||||
#endif // CAN_SANITIZE_LEAKS
|
||||
|
|
|
|||
|
|
@ -33,19 +33,6 @@
|
|||
|
||||
namespace __asan {
|
||||
|
||||
const char *DescribeSignalOrException(int signo) {
|
||||
switch (signo) {
|
||||
case SIGFPE:
|
||||
return "FPE";
|
||||
case SIGILL:
|
||||
return "ILL";
|
||||
case SIGABRT:
|
||||
return "ABRT";
|
||||
default:
|
||||
return "SEGV";
|
||||
}
|
||||
}
|
||||
|
||||
void AsanOnDeadlySignal(int signo, void *siginfo, void *context) {
|
||||
ScopedDeadlySignal signal_scope(GetCurrentThread());
|
||||
int code = (int)((siginfo_t*)siginfo)->si_code;
|
||||
|
|
|
|||
|
|
@ -88,7 +88,8 @@ bool ParseFrameDescription(const char *frame_descr,
|
|||
char *p;
|
||||
// This string is created by the compiler and has the following form:
|
||||
// "n alloc_1 alloc_2 ... alloc_n"
|
||||
// where alloc_i looks like "offset size len ObjectName".
|
||||
// where alloc_i looks like "offset size len ObjectName"
|
||||
// or "offset size len ObjectName:line".
|
||||
uptr n_objects = (uptr)internal_simple_strtoll(frame_descr, &p, 10);
|
||||
if (n_objects == 0)
|
||||
return false;
|
||||
|
|
@ -101,7 +102,14 @@ bool ParseFrameDescription(const char *frame_descr,
|
|||
return false;
|
||||
}
|
||||
p++;
|
||||
StackVarDescr var = {beg, size, p, len};
|
||||
char *colon_pos = internal_strchr(p, ':');
|
||||
uptr line = 0;
|
||||
uptr name_len = len;
|
||||
if (colon_pos != nullptr && colon_pos < p + len) {
|
||||
name_len = colon_pos - p;
|
||||
line = (uptr)internal_simple_strtoll(colon_pos + 1, nullptr, 10);
|
||||
}
|
||||
StackVarDescr var = {beg, size, p, name_len, line};
|
||||
vars->push_back(var);
|
||||
p += len;
|
||||
}
|
||||
|
|
@ -488,9 +496,6 @@ void __sanitizer_ptr_cmp(void *a, void *b) {
|
|||
}
|
||||
} // extern "C"
|
||||
|
||||
#if !SANITIZER_SUPPORTS_WEAK_HOOKS
|
||||
// Provide default implementation of __asan_on_error that does nothing
|
||||
// and may be overriden by user.
|
||||
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE NOINLINE
|
||||
void __asan_on_error() {}
|
||||
#endif
|
||||
SANITIZER_INTERFACE_WEAK_DEF(void, __asan_on_error, void) {}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ struct StackVarDescr {
|
|||
uptr size;
|
||||
const char *name_pos;
|
||||
uptr name_len;
|
||||
uptr line;
|
||||
};
|
||||
|
||||
// Returns the number of globals close to the provided address and copies
|
||||
|
|
|
|||
|
|
@ -31,15 +31,9 @@ static const char *kSuppressionTypes[] = {
|
|||
kInterceptorName, kInterceptorViaFunction, kInterceptorViaLibrary,
|
||||
kODRViolation};
|
||||
|
||||
extern "C" {
|
||||
#if SANITIZER_SUPPORTS_WEAK_HOOKS
|
||||
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
|
||||
const char *__asan_default_suppressions();
|
||||
#else
|
||||
// No week hooks, provide empty implementation.
|
||||
const char *__asan_default_suppressions() { return ""; }
|
||||
#endif // SANITIZER_SUPPORTS_WEAK_HOOKS
|
||||
} // extern "C"
|
||||
SANITIZER_INTERFACE_WEAK_DEF(const char *, __asan_default_suppressions, void) {
|
||||
return "";
|
||||
}
|
||||
|
||||
void InitializeSuppressions() {
|
||||
CHECK_EQ(nullptr, suppression_ctx);
|
||||
|
|
|
|||
|
|
@ -239,7 +239,8 @@ void AsanThread::Init() {
|
|||
thread_return_t AsanThread::ThreadStart(
|
||||
uptr os_id, atomic_uintptr_t *signal_thread_is_registered) {
|
||||
Init();
|
||||
asanThreadRegistry().StartThread(tid(), os_id, nullptr);
|
||||
asanThreadRegistry().StartThread(tid(), os_id, /*workerthread*/ false,
|
||||
nullptr);
|
||||
if (signal_thread_is_registered)
|
||||
atomic_store(signal_thread_is_registered, 1, memory_order_release);
|
||||
|
||||
|
|
@ -299,24 +300,27 @@ bool AsanThread::GetStackFrameAccessByAddr(uptr addr,
|
|||
return true;
|
||||
}
|
||||
uptr aligned_addr = addr & ~(SANITIZER_WORDSIZE/8 - 1); // align addr.
|
||||
uptr mem_ptr = RoundDownTo(aligned_addr, SHADOW_GRANULARITY);
|
||||
u8 *shadow_ptr = (u8*)MemToShadow(aligned_addr);
|
||||
u8 *shadow_bottom = (u8*)MemToShadow(bottom);
|
||||
|
||||
while (shadow_ptr >= shadow_bottom &&
|
||||
*shadow_ptr != kAsanStackLeftRedzoneMagic) {
|
||||
shadow_ptr--;
|
||||
mem_ptr -= SHADOW_GRANULARITY;
|
||||
}
|
||||
|
||||
while (shadow_ptr >= shadow_bottom &&
|
||||
*shadow_ptr == kAsanStackLeftRedzoneMagic) {
|
||||
shadow_ptr--;
|
||||
mem_ptr -= SHADOW_GRANULARITY;
|
||||
}
|
||||
|
||||
if (shadow_ptr < shadow_bottom) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uptr* ptr = (uptr*)SHADOW_TO_MEM((uptr)(shadow_ptr + 1));
|
||||
uptr* ptr = (uptr*)(mem_ptr + SHADOW_GRANULARITY);
|
||||
CHECK(ptr[0] == kCurrentStackFrameMagic);
|
||||
access->offset = addr - (uptr)ptr;
|
||||
access->frame_pc = ptr[2];
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@
|
|||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "asan_globals_win.h"
|
||||
#include "asan_interceptors.h"
|
||||
#include "asan_internal.h"
|
||||
#include "asan_report.h"
|
||||
|
|
@ -28,6 +27,8 @@
|
|||
#include "asan_mapping.h"
|
||||
#include "sanitizer_common/sanitizer_libc.h"
|
||||
#include "sanitizer_common/sanitizer_mutex.h"
|
||||
#include "sanitizer_common/sanitizer_win.h"
|
||||
#include "sanitizer_common/sanitizer_win_defs.h"
|
||||
|
||||
using namespace __asan; // NOLINT
|
||||
|
||||
|
|
@ -43,35 +44,50 @@ uptr __asan_get_shadow_memory_dynamic_address() {
|
|||
__asan_init();
|
||||
return __asan_shadow_memory_dynamic_address;
|
||||
}
|
||||
|
||||
// -------------------- A workaround for the absence of weak symbols ----- {{{
|
||||
// We don't have a direct equivalent of weak symbols when using MSVC, but we can
|
||||
// use the /alternatename directive to tell the linker to default a specific
|
||||
// symbol to a specific value, which works nicely for allocator hooks and
|
||||
// __asan_default_options().
|
||||
void __sanitizer_default_malloc_hook(void *ptr, uptr size) { }
|
||||
void __sanitizer_default_free_hook(void *ptr) { }
|
||||
const char* __asan_default_default_options() { return ""; }
|
||||
const char* __asan_default_default_suppressions() { return ""; }
|
||||
void __asan_default_on_error() {}
|
||||
// 64-bit msvc will not prepend an underscore for symbols.
|
||||
#ifdef _WIN64
|
||||
#pragma comment(linker, "/alternatename:__sanitizer_malloc_hook=__sanitizer_default_malloc_hook") // NOLINT
|
||||
#pragma comment(linker, "/alternatename:__sanitizer_free_hook=__sanitizer_default_free_hook") // NOLINT
|
||||
#pragma comment(linker, "/alternatename:__asan_default_options=__asan_default_default_options") // NOLINT
|
||||
#pragma comment(linker, "/alternatename:__asan_default_suppressions=__asan_default_default_suppressions") // NOLINT
|
||||
#pragma comment(linker, "/alternatename:__asan_on_error=__asan_default_on_error") // NOLINT
|
||||
#else
|
||||
#pragma comment(linker, "/alternatename:___sanitizer_malloc_hook=___sanitizer_default_malloc_hook") // NOLINT
|
||||
#pragma comment(linker, "/alternatename:___sanitizer_free_hook=___sanitizer_default_free_hook") // NOLINT
|
||||
#pragma comment(linker, "/alternatename:___asan_default_options=___asan_default_default_options") // NOLINT
|
||||
#pragma comment(linker, "/alternatename:___asan_default_suppressions=___asan_default_default_suppressions") // NOLINT
|
||||
#pragma comment(linker, "/alternatename:___asan_on_error=___asan_default_on_error") // NOLINT
|
||||
#endif
|
||||
// }}}
|
||||
} // extern "C"
|
||||
|
||||
// ---------------------- Windows-specific interceptors ---------------- {{{
|
||||
static LPTOP_LEVEL_EXCEPTION_FILTER default_seh_handler;
|
||||
static LPTOP_LEVEL_EXCEPTION_FILTER user_seh_handler;
|
||||
|
||||
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
|
||||
long __asan_unhandled_exception_filter(EXCEPTION_POINTERS *info) {
|
||||
EXCEPTION_RECORD *exception_record = info->ExceptionRecord;
|
||||
CONTEXT *context = info->ContextRecord;
|
||||
|
||||
// FIXME: Handle EXCEPTION_STACK_OVERFLOW here.
|
||||
|
||||
SignalContext sig = SignalContext::Create(exception_record, context);
|
||||
ReportDeadlySignal(exception_record->ExceptionCode, sig);
|
||||
UNREACHABLE("returned from reporting deadly signal");
|
||||
}
|
||||
|
||||
// Wrapper SEH Handler. If the exception should be handled by asan, we call
|
||||
// __asan_unhandled_exception_filter, otherwise, we execute the user provided
|
||||
// exception handler or the default.
|
||||
static long WINAPI SEHHandler(EXCEPTION_POINTERS *info) {
|
||||
DWORD exception_code = info->ExceptionRecord->ExceptionCode;
|
||||
if (__sanitizer::IsHandledDeadlyException(exception_code))
|
||||
return __asan_unhandled_exception_filter(info);
|
||||
if (user_seh_handler)
|
||||
return user_seh_handler(info);
|
||||
// Bubble out to the default exception filter.
|
||||
if (default_seh_handler)
|
||||
return default_seh_handler(info);
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
INTERCEPTOR_WINAPI(LPTOP_LEVEL_EXCEPTION_FILTER, SetUnhandledExceptionFilter,
|
||||
LPTOP_LEVEL_EXCEPTION_FILTER ExceptionFilter) {
|
||||
CHECK(REAL(SetUnhandledExceptionFilter));
|
||||
if (ExceptionFilter == &SEHHandler || common_flags()->allow_user_segv_handler)
|
||||
return REAL(SetUnhandledExceptionFilter)(ExceptionFilter);
|
||||
// We record the user provided exception handler to be called for all the
|
||||
// exceptions unhandled by asan.
|
||||
Swap(ExceptionFilter, user_seh_handler);
|
||||
return ExceptionFilter;
|
||||
}
|
||||
|
||||
INTERCEPTOR_WINAPI(void, RtlRaiseException, EXCEPTION_RECORD *ExceptionRecord) {
|
||||
CHECK(REAL(RtlRaiseException));
|
||||
// This is a noreturn function, unless it's one of the exceptions raised to
|
||||
|
|
@ -144,6 +160,7 @@ namespace __asan {
|
|||
|
||||
void InitializePlatformInterceptors() {
|
||||
ASAN_INTERCEPT_FUNC(CreateThread);
|
||||
ASAN_INTERCEPT_FUNC(SetUnhandledExceptionFilter);
|
||||
|
||||
#ifdef _WIN64
|
||||
ASAN_INTERCEPT_FUNC(__C_specific_handler);
|
||||
|
|
@ -260,60 +277,8 @@ void InitializePlatformExceptionHandlers() {
|
|||
#endif
|
||||
}
|
||||
|
||||
static LPTOP_LEVEL_EXCEPTION_FILTER default_seh_handler;
|
||||
|
||||
// Check based on flags if we should report this exception.
|
||||
static bool ShouldReportDeadlyException(unsigned code) {
|
||||
switch (code) {
|
||||
case EXCEPTION_ACCESS_VIOLATION:
|
||||
case EXCEPTION_IN_PAGE_ERROR:
|
||||
return common_flags()->handle_segv;
|
||||
case EXCEPTION_BREAKPOINT:
|
||||
case EXCEPTION_ILLEGAL_INSTRUCTION: {
|
||||
return common_flags()->handle_sigill;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Return the textual name for this exception.
|
||||
const char *DescribeSignalOrException(int signo) {
|
||||
unsigned code = signo;
|
||||
// Get the string description of the exception if this is a known deadly
|
||||
// exception.
|
||||
switch (code) {
|
||||
case EXCEPTION_ACCESS_VIOLATION:
|
||||
return "access-violation";
|
||||
case EXCEPTION_IN_PAGE_ERROR:
|
||||
return "in-page-error";
|
||||
case EXCEPTION_BREAKPOINT:
|
||||
return "breakpoint";
|
||||
case EXCEPTION_ILLEGAL_INSTRUCTION:
|
||||
return "illegal-instruction";
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
|
||||
long __asan_unhandled_exception_filter(EXCEPTION_POINTERS *info) {
|
||||
EXCEPTION_RECORD *exception_record = info->ExceptionRecord;
|
||||
CONTEXT *context = info->ContextRecord;
|
||||
|
||||
// Continue the search if the signal wasn't deadly.
|
||||
if (!ShouldReportDeadlyException(exception_record->ExceptionCode))
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
// FIXME: Handle EXCEPTION_STACK_OVERFLOW here.
|
||||
|
||||
SignalContext sig = SignalContext::Create(exception_record, context);
|
||||
ReportDeadlySignal(exception_record->ExceptionCode, sig);
|
||||
UNREACHABLE("returned from reporting deadly signal");
|
||||
}
|
||||
|
||||
static long WINAPI SEHHandler(EXCEPTION_POINTERS *info) {
|
||||
__asan_unhandled_exception_filter(info);
|
||||
|
||||
// Bubble out to the default exception filter.
|
||||
return default_seh_handler(info);
|
||||
bool IsSystemHeapAddress(uptr addr) {
|
||||
return ::HeapValidate(GetProcessHeap(), 0, (void*)addr) != FALSE;
|
||||
}
|
||||
|
||||
// We want to install our own exception handler (EH) to print helpful reports
|
||||
|
|
@ -368,7 +333,7 @@ __declspec(allocate(".CRT$XLAB")) void (NTAPI *__asan_tls_init)(void *,
|
|||
unsigned long, void *) = asan_thread_init;
|
||||
#endif
|
||||
|
||||
ASAN_LINK_GLOBALS_WIN()
|
||||
WIN_FORCE_LINK(__asan_dso_reg_hook)
|
||||
|
||||
// }}}
|
||||
} // namespace __asan
|
||||
|
|
|
|||
|
|
@ -15,388 +15,41 @@
|
|||
// See https://github.com/google/sanitizers/issues/209 for the details.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Only compile this code when building asan_dll_thunk.lib
|
||||
// Using #ifdef rather than relying on Makefiles etc.
|
||||
// simplifies the build procedure.
|
||||
#ifdef ASAN_DLL_THUNK
|
||||
#ifdef SANITIZER_DLL_THUNK
|
||||
#include "asan_init_version.h"
|
||||
#include "asan_globals_win.h"
|
||||
#include "interception/interception.h"
|
||||
#include "sanitizer_common/sanitizer_win_defs.h"
|
||||
#include "sanitizer_common/sanitizer_win_dll_thunk.h"
|
||||
#include "sanitizer_common/sanitizer_platform_interceptors.h"
|
||||
|
||||
#ifdef _M_IX86
|
||||
#define WINAPI __stdcall
|
||||
#else
|
||||
#define WINAPI
|
||||
#endif
|
||||
// ASan own interface functions.
|
||||
#define INTERFACE_FUNCTION(Name) INTERCEPT_SANITIZER_FUNCTION(Name)
|
||||
#define INTERFACE_WEAK_FUNCTION(Name) INTERCEPT_SANITIZER_WEAK_FUNCTION(Name)
|
||||
#include "asan_interface.inc"
|
||||
|
||||
// ---------- Function interception helper functions and macros ----------- {{{1
|
||||
extern "C" {
|
||||
void *WINAPI GetModuleHandleA(const char *module_name);
|
||||
void *WINAPI GetProcAddress(void *module, const char *proc_name);
|
||||
void abort();
|
||||
}
|
||||
// Memory allocation functions.
|
||||
INTERCEPT_WRAP_V_W(free)
|
||||
INTERCEPT_WRAP_V_W(_free_base)
|
||||
INTERCEPT_WRAP_V_WW(_free_dbg)
|
||||
|
||||
using namespace __sanitizer;
|
||||
INTERCEPT_WRAP_W_W(malloc)
|
||||
INTERCEPT_WRAP_W_W(_malloc_base)
|
||||
INTERCEPT_WRAP_W_WWWW(_malloc_dbg)
|
||||
|
||||
static uptr getRealProcAddressOrDie(const char *name) {
|
||||
uptr ret =
|
||||
__interception::InternalGetProcAddress((void *)GetModuleHandleA(0), name);
|
||||
if (!ret)
|
||||
abort();
|
||||
return ret;
|
||||
}
|
||||
INTERCEPT_WRAP_W_WW(calloc)
|
||||
INTERCEPT_WRAP_W_WW(_calloc_base)
|
||||
INTERCEPT_WRAP_W_WWWWW(_calloc_dbg)
|
||||
INTERCEPT_WRAP_W_WWW(_calloc_impl)
|
||||
|
||||
// We need to intercept some functions (e.g. ASan interface, memory allocator --
|
||||
// let's call them "hooks") exported by the DLL thunk and forward the hooks to
|
||||
// the runtime in the main module.
|
||||
// However, we don't want to keep two lists of these hooks.
|
||||
// To avoid that, the list of hooks should be defined using the
|
||||
// INTERCEPT_WHEN_POSSIBLE macro. Then, all these hooks can be intercepted
|
||||
// at once by calling INTERCEPT_HOOKS().
|
||||
INTERCEPT_WRAP_W_WW(realloc)
|
||||
INTERCEPT_WRAP_W_WW(_realloc_base)
|
||||
INTERCEPT_WRAP_W_WWW(_realloc_dbg)
|
||||
INTERCEPT_WRAP_W_WWW(_recalloc)
|
||||
INTERCEPT_WRAP_W_WWW(_recalloc_base)
|
||||
|
||||
// Use macro+template magic to automatically generate the list of hooks.
|
||||
// Each hook at line LINE defines a template class with a static
|
||||
// FunctionInterceptor<LINE>::Execute() method intercepting the hook.
|
||||
// The default implementation of FunctionInterceptor<LINE> is to call
|
||||
// the Execute() method corresponding to the previous line.
|
||||
template<int LINE>
|
||||
struct FunctionInterceptor {
|
||||
static void Execute() { FunctionInterceptor<LINE-1>::Execute(); }
|
||||
};
|
||||
|
||||
// There shouldn't be any hooks with negative definition line number.
|
||||
template<>
|
||||
struct FunctionInterceptor<0> {
|
||||
static void Execute() {}
|
||||
};
|
||||
|
||||
#define INTERCEPT_WHEN_POSSIBLE(main_function, dll_function) \
|
||||
template <> struct FunctionInterceptor<__LINE__> { \
|
||||
static void Execute() { \
|
||||
uptr wrapper = getRealProcAddressOrDie(main_function); \
|
||||
if (!__interception::OverrideFunction((uptr)dll_function, wrapper, 0)) \
|
||||
abort(); \
|
||||
FunctionInterceptor<__LINE__ - 1>::Execute(); \
|
||||
} \
|
||||
};
|
||||
|
||||
// Special case of hooks -- ASan own interface functions. Those are only called
|
||||
// after __asan_init, thus an empty implementation is sufficient.
|
||||
#define INTERFACE_FUNCTION(name) \
|
||||
extern "C" __declspec(noinline) void name() { \
|
||||
volatile int prevent_icf = (__LINE__ << 8); (void)prevent_icf; \
|
||||
__debugbreak(); \
|
||||
} \
|
||||
INTERCEPT_WHEN_POSSIBLE(#name, name)
|
||||
|
||||
// INTERCEPT_HOOKS must be used after the last INTERCEPT_WHEN_POSSIBLE.
|
||||
#define INTERCEPT_HOOKS FunctionInterceptor<__LINE__>::Execute
|
||||
|
||||
// We can't define our own version of strlen etc. because that would lead to
|
||||
// link-time or even type mismatch errors. Instead, we can declare a function
|
||||
// just to be able to get its address. Me may miss the first few calls to the
|
||||
// functions since it can be called before __asan_init, but that would lead to
|
||||
// false negatives in the startup code before user's global initializers, which
|
||||
// isn't a big deal.
|
||||
#define INTERCEPT_LIBRARY_FUNCTION(name) \
|
||||
extern "C" void name(); \
|
||||
INTERCEPT_WHEN_POSSIBLE(WRAPPER_NAME(name), name)
|
||||
|
||||
// Disable compiler warnings that show up if we declare our own version
|
||||
// of a compiler intrinsic (e.g. strlen).
|
||||
#pragma warning(disable: 4391)
|
||||
#pragma warning(disable: 4392)
|
||||
|
||||
static void InterceptHooks();
|
||||
// }}}
|
||||
|
||||
// ---------- Function wrapping helpers ----------------------------------- {{{1
|
||||
#define WRAP_V_V(name) \
|
||||
extern "C" void name() { \
|
||||
typedef decltype(name) *fntype; \
|
||||
static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
|
||||
fn(); \
|
||||
} \
|
||||
INTERCEPT_WHEN_POSSIBLE(#name, name);
|
||||
|
||||
#define WRAP_V_W(name) \
|
||||
extern "C" void name(void *arg) { \
|
||||
typedef decltype(name) *fntype; \
|
||||
static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
|
||||
fn(arg); \
|
||||
} \
|
||||
INTERCEPT_WHEN_POSSIBLE(#name, name);
|
||||
|
||||
#define WRAP_V_WW(name) \
|
||||
extern "C" void name(void *arg1, void *arg2) { \
|
||||
typedef decltype(name) *fntype; \
|
||||
static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
|
||||
fn(arg1, arg2); \
|
||||
} \
|
||||
INTERCEPT_WHEN_POSSIBLE(#name, name);
|
||||
|
||||
#define WRAP_V_WWW(name) \
|
||||
extern "C" void name(void *arg1, void *arg2, void *arg3) { \
|
||||
typedef decltype(name) *fntype; \
|
||||
static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
|
||||
fn(arg1, arg2, arg3); \
|
||||
} \
|
||||
INTERCEPT_WHEN_POSSIBLE(#name, name);
|
||||
|
||||
#define WRAP_W_V(name) \
|
||||
extern "C" void *name() { \
|
||||
typedef decltype(name) *fntype; \
|
||||
static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
|
||||
return fn(); \
|
||||
} \
|
||||
INTERCEPT_WHEN_POSSIBLE(#name, name);
|
||||
|
||||
#define WRAP_W_W(name) \
|
||||
extern "C" void *name(void *arg) { \
|
||||
typedef decltype(name) *fntype; \
|
||||
static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
|
||||
return fn(arg); \
|
||||
} \
|
||||
INTERCEPT_WHEN_POSSIBLE(#name, name);
|
||||
|
||||
#define WRAP_W_WW(name) \
|
||||
extern "C" void *name(void *arg1, void *arg2) { \
|
||||
typedef decltype(name) *fntype; \
|
||||
static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
|
||||
return fn(arg1, arg2); \
|
||||
} \
|
||||
INTERCEPT_WHEN_POSSIBLE(#name, name);
|
||||
|
||||
#define WRAP_W_WWW(name) \
|
||||
extern "C" void *name(void *arg1, void *arg2, void *arg3) { \
|
||||
typedef decltype(name) *fntype; \
|
||||
static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
|
||||
return fn(arg1, arg2, arg3); \
|
||||
} \
|
||||
INTERCEPT_WHEN_POSSIBLE(#name, name);
|
||||
|
||||
#define WRAP_W_WWWW(name) \
|
||||
extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4) { \
|
||||
typedef decltype(name) *fntype; \
|
||||
static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
|
||||
return fn(arg1, arg2, arg3, arg4); \
|
||||
} \
|
||||
INTERCEPT_WHEN_POSSIBLE(#name, name);
|
||||
|
||||
#define WRAP_W_WWWWW(name) \
|
||||
extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4, \
|
||||
void *arg5) { \
|
||||
typedef decltype(name) *fntype; \
|
||||
static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
|
||||
return fn(arg1, arg2, arg3, arg4, arg5); \
|
||||
} \
|
||||
INTERCEPT_WHEN_POSSIBLE(#name, name);
|
||||
|
||||
#define WRAP_W_WWWWWW(name) \
|
||||
extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4, \
|
||||
void *arg5, void *arg6) { \
|
||||
typedef decltype(name) *fntype; \
|
||||
static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
|
||||
return fn(arg1, arg2, arg3, arg4, arg5, arg6); \
|
||||
} \
|
||||
INTERCEPT_WHEN_POSSIBLE(#name, name);
|
||||
// }}}
|
||||
|
||||
// ----------------- ASan own interface functions --------------------
|
||||
// Don't use the INTERFACE_FUNCTION machinery for this function as we actually
|
||||
// want to call it in the __asan_init interceptor.
|
||||
WRAP_W_V(__asan_should_detect_stack_use_after_return)
|
||||
WRAP_W_V(__asan_get_shadow_memory_dynamic_address)
|
||||
|
||||
extern "C" {
|
||||
int __asan_option_detect_stack_use_after_return;
|
||||
uptr __asan_shadow_memory_dynamic_address;
|
||||
|
||||
// Manually wrap __asan_init as we need to initialize
|
||||
// __asan_option_detect_stack_use_after_return afterwards.
|
||||
void __asan_init() {
|
||||
typedef void (*fntype)();
|
||||
static fntype fn = 0;
|
||||
// __asan_init is expected to be called by only one thread.
|
||||
if (fn) return;
|
||||
|
||||
fn = (fntype)getRealProcAddressOrDie("__asan_init");
|
||||
fn();
|
||||
__asan_option_detect_stack_use_after_return =
|
||||
(__asan_should_detect_stack_use_after_return() != 0);
|
||||
__asan_shadow_memory_dynamic_address =
|
||||
(uptr)__asan_get_shadow_memory_dynamic_address();
|
||||
InterceptHooks();
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void __asan_version_mismatch_check() {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
INTERFACE_FUNCTION(__asan_handle_no_return)
|
||||
INTERFACE_FUNCTION(__asan_unhandled_exception_filter)
|
||||
|
||||
INTERFACE_FUNCTION(__asan_report_store1)
|
||||
INTERFACE_FUNCTION(__asan_report_store2)
|
||||
INTERFACE_FUNCTION(__asan_report_store4)
|
||||
INTERFACE_FUNCTION(__asan_report_store8)
|
||||
INTERFACE_FUNCTION(__asan_report_store16)
|
||||
INTERFACE_FUNCTION(__asan_report_store_n)
|
||||
|
||||
INTERFACE_FUNCTION(__asan_report_load1)
|
||||
INTERFACE_FUNCTION(__asan_report_load2)
|
||||
INTERFACE_FUNCTION(__asan_report_load4)
|
||||
INTERFACE_FUNCTION(__asan_report_load8)
|
||||
INTERFACE_FUNCTION(__asan_report_load16)
|
||||
INTERFACE_FUNCTION(__asan_report_load_n)
|
||||
|
||||
INTERFACE_FUNCTION(__asan_store1)
|
||||
INTERFACE_FUNCTION(__asan_store2)
|
||||
INTERFACE_FUNCTION(__asan_store4)
|
||||
INTERFACE_FUNCTION(__asan_store8)
|
||||
INTERFACE_FUNCTION(__asan_store16)
|
||||
INTERFACE_FUNCTION(__asan_storeN)
|
||||
|
||||
INTERFACE_FUNCTION(__asan_load1)
|
||||
INTERFACE_FUNCTION(__asan_load2)
|
||||
INTERFACE_FUNCTION(__asan_load4)
|
||||
INTERFACE_FUNCTION(__asan_load8)
|
||||
INTERFACE_FUNCTION(__asan_load16)
|
||||
INTERFACE_FUNCTION(__asan_loadN)
|
||||
|
||||
INTERFACE_FUNCTION(__asan_memcpy);
|
||||
INTERFACE_FUNCTION(__asan_memset);
|
||||
INTERFACE_FUNCTION(__asan_memmove);
|
||||
|
||||
INTERFACE_FUNCTION(__asan_set_shadow_00);
|
||||
INTERFACE_FUNCTION(__asan_set_shadow_f1);
|
||||
INTERFACE_FUNCTION(__asan_set_shadow_f2);
|
||||
INTERFACE_FUNCTION(__asan_set_shadow_f3);
|
||||
INTERFACE_FUNCTION(__asan_set_shadow_f5);
|
||||
INTERFACE_FUNCTION(__asan_set_shadow_f8);
|
||||
|
||||
INTERFACE_FUNCTION(__asan_alloca_poison);
|
||||
INTERFACE_FUNCTION(__asan_allocas_unpoison);
|
||||
|
||||
INTERFACE_FUNCTION(__asan_register_globals)
|
||||
INTERFACE_FUNCTION(__asan_unregister_globals)
|
||||
|
||||
INTERFACE_FUNCTION(__asan_before_dynamic_init)
|
||||
INTERFACE_FUNCTION(__asan_after_dynamic_init)
|
||||
|
||||
INTERFACE_FUNCTION(__asan_poison_stack_memory)
|
||||
INTERFACE_FUNCTION(__asan_unpoison_stack_memory)
|
||||
|
||||
INTERFACE_FUNCTION(__asan_poison_memory_region)
|
||||
INTERFACE_FUNCTION(__asan_unpoison_memory_region)
|
||||
|
||||
INTERFACE_FUNCTION(__asan_address_is_poisoned)
|
||||
INTERFACE_FUNCTION(__asan_region_is_poisoned)
|
||||
|
||||
INTERFACE_FUNCTION(__asan_get_current_fake_stack)
|
||||
INTERFACE_FUNCTION(__asan_addr_is_in_fake_stack)
|
||||
|
||||
INTERFACE_FUNCTION(__asan_stack_malloc_0)
|
||||
INTERFACE_FUNCTION(__asan_stack_malloc_1)
|
||||
INTERFACE_FUNCTION(__asan_stack_malloc_2)
|
||||
INTERFACE_FUNCTION(__asan_stack_malloc_3)
|
||||
INTERFACE_FUNCTION(__asan_stack_malloc_4)
|
||||
INTERFACE_FUNCTION(__asan_stack_malloc_5)
|
||||
INTERFACE_FUNCTION(__asan_stack_malloc_6)
|
||||
INTERFACE_FUNCTION(__asan_stack_malloc_7)
|
||||
INTERFACE_FUNCTION(__asan_stack_malloc_8)
|
||||
INTERFACE_FUNCTION(__asan_stack_malloc_9)
|
||||
INTERFACE_FUNCTION(__asan_stack_malloc_10)
|
||||
|
||||
INTERFACE_FUNCTION(__asan_stack_free_0)
|
||||
INTERFACE_FUNCTION(__asan_stack_free_1)
|
||||
INTERFACE_FUNCTION(__asan_stack_free_2)
|
||||
INTERFACE_FUNCTION(__asan_stack_free_4)
|
||||
INTERFACE_FUNCTION(__asan_stack_free_5)
|
||||
INTERFACE_FUNCTION(__asan_stack_free_6)
|
||||
INTERFACE_FUNCTION(__asan_stack_free_7)
|
||||
INTERFACE_FUNCTION(__asan_stack_free_8)
|
||||
INTERFACE_FUNCTION(__asan_stack_free_9)
|
||||
INTERFACE_FUNCTION(__asan_stack_free_10)
|
||||
|
||||
// FIXME: we might want to have a sanitizer_win_dll_thunk?
|
||||
INTERFACE_FUNCTION(__sanitizer_annotate_contiguous_container)
|
||||
INTERFACE_FUNCTION(__sanitizer_contiguous_container_find_bad_address)
|
||||
INTERFACE_FUNCTION(__sanitizer_cov)
|
||||
INTERFACE_FUNCTION(__sanitizer_cov_dump)
|
||||
INTERFACE_FUNCTION(__sanitizer_dump_coverage)
|
||||
INTERFACE_FUNCTION(__sanitizer_dump_trace_pc_guard_coverage)
|
||||
INTERFACE_FUNCTION(__sanitizer_cov_indir_call16)
|
||||
INTERFACE_FUNCTION(__sanitizer_cov_init)
|
||||
INTERFACE_FUNCTION(__sanitizer_cov_module_init)
|
||||
INTERFACE_FUNCTION(__sanitizer_cov_trace_basic_block)
|
||||
INTERFACE_FUNCTION(__sanitizer_cov_trace_func_enter)
|
||||
INTERFACE_FUNCTION(__sanitizer_cov_trace_pc_guard)
|
||||
INTERFACE_FUNCTION(__sanitizer_cov_trace_pc_guard_init)
|
||||
INTERFACE_FUNCTION(__sanitizer_cov_with_check)
|
||||
INTERFACE_FUNCTION(__sanitizer_get_allocated_size)
|
||||
INTERFACE_FUNCTION(__sanitizer_get_coverage_guards)
|
||||
INTERFACE_FUNCTION(__sanitizer_get_current_allocated_bytes)
|
||||
INTERFACE_FUNCTION(__sanitizer_get_estimated_allocated_size)
|
||||
INTERFACE_FUNCTION(__sanitizer_get_free_bytes)
|
||||
INTERFACE_FUNCTION(__sanitizer_get_heap_size)
|
||||
INTERFACE_FUNCTION(__sanitizer_get_ownership)
|
||||
INTERFACE_FUNCTION(__sanitizer_get_total_unique_caller_callee_pairs)
|
||||
INTERFACE_FUNCTION(__sanitizer_get_total_unique_coverage)
|
||||
INTERFACE_FUNCTION(__sanitizer_get_unmapped_bytes)
|
||||
INTERFACE_FUNCTION(__sanitizer_maybe_open_cov_file)
|
||||
INTERFACE_FUNCTION(__sanitizer_print_stack_trace)
|
||||
INTERFACE_FUNCTION(__sanitizer_symbolize_pc)
|
||||
INTERFACE_FUNCTION(__sanitizer_symbolize_global)
|
||||
INTERFACE_FUNCTION(__sanitizer_ptr_cmp)
|
||||
INTERFACE_FUNCTION(__sanitizer_ptr_sub)
|
||||
INTERFACE_FUNCTION(__sanitizer_report_error_summary)
|
||||
INTERFACE_FUNCTION(__sanitizer_reset_coverage)
|
||||
INTERFACE_FUNCTION(__sanitizer_get_number_of_counters)
|
||||
INTERFACE_FUNCTION(__sanitizer_update_counter_bitset_and_clear_counters)
|
||||
INTERFACE_FUNCTION(__sanitizer_sandbox_on_notify)
|
||||
INTERFACE_FUNCTION(__sanitizer_set_death_callback)
|
||||
INTERFACE_FUNCTION(__sanitizer_set_report_path)
|
||||
INTERFACE_FUNCTION(__sanitizer_set_report_fd)
|
||||
INTERFACE_FUNCTION(__sanitizer_unaligned_load16)
|
||||
INTERFACE_FUNCTION(__sanitizer_unaligned_load32)
|
||||
INTERFACE_FUNCTION(__sanitizer_unaligned_load64)
|
||||
INTERFACE_FUNCTION(__sanitizer_unaligned_store16)
|
||||
INTERFACE_FUNCTION(__sanitizer_unaligned_store32)
|
||||
INTERFACE_FUNCTION(__sanitizer_unaligned_store64)
|
||||
INTERFACE_FUNCTION(__sanitizer_verify_contiguous_container)
|
||||
INTERFACE_FUNCTION(__sanitizer_install_malloc_and_free_hooks)
|
||||
INTERFACE_FUNCTION(__sanitizer_start_switch_fiber)
|
||||
INTERFACE_FUNCTION(__sanitizer_finish_switch_fiber)
|
||||
INTERFACE_FUNCTION(__sanitizer_get_module_and_offset_for_pc)
|
||||
|
||||
// TODO(timurrrr): Add more interface functions on the as-needed basis.
|
||||
|
||||
// ----------------- Memory allocation functions ---------------------
|
||||
WRAP_V_W(free)
|
||||
WRAP_V_W(_free_base)
|
||||
WRAP_V_WW(_free_dbg)
|
||||
|
||||
WRAP_W_W(malloc)
|
||||
WRAP_W_W(_malloc_base)
|
||||
WRAP_W_WWWW(_malloc_dbg)
|
||||
|
||||
WRAP_W_WW(calloc)
|
||||
WRAP_W_WW(_calloc_base)
|
||||
WRAP_W_WWWWW(_calloc_dbg)
|
||||
WRAP_W_WWW(_calloc_impl)
|
||||
|
||||
WRAP_W_WW(realloc)
|
||||
WRAP_W_WW(_realloc_base)
|
||||
WRAP_W_WWW(_realloc_dbg)
|
||||
WRAP_W_WWW(_recalloc)
|
||||
WRAP_W_WWW(_recalloc_base)
|
||||
|
||||
WRAP_W_W(_msize)
|
||||
WRAP_W_W(_expand)
|
||||
WRAP_W_W(_expand_dbg)
|
||||
INTERCEPT_WRAP_W_W(_msize)
|
||||
INTERCEPT_WRAP_W_W(_expand)
|
||||
INTERCEPT_WRAP_W_W(_expand_dbg)
|
||||
|
||||
// TODO(timurrrr): Might want to add support for _aligned_* allocation
|
||||
// functions to detect a bit more bugs. Those functions seem to wrap malloc().
|
||||
|
|
@ -405,20 +58,6 @@ WRAP_W_W(_expand_dbg)
|
|||
|
||||
INTERCEPT_LIBRARY_FUNCTION(atoi);
|
||||
INTERCEPT_LIBRARY_FUNCTION(atol);
|
||||
|
||||
#ifdef _WIN64
|
||||
INTERCEPT_LIBRARY_FUNCTION(__C_specific_handler);
|
||||
#else
|
||||
INTERCEPT_LIBRARY_FUNCTION(_except_handler3);
|
||||
|
||||
// _except_handler4 checks -GS cookie which is different for each module, so we
|
||||
// can't use INTERCEPT_LIBRARY_FUNCTION(_except_handler4).
|
||||
INTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) {
|
||||
__asan_handle_no_return();
|
||||
return REAL(_except_handler4)(a, b, c, d);
|
||||
}
|
||||
#endif
|
||||
|
||||
INTERCEPT_LIBRARY_FUNCTION(frexp);
|
||||
INTERCEPT_LIBRARY_FUNCTION(longjmp);
|
||||
#if SANITIZER_INTERCEPT_MEMCHR
|
||||
|
|
@ -443,41 +82,70 @@ INTERCEPT_LIBRARY_FUNCTION(strpbrk);
|
|||
INTERCEPT_LIBRARY_FUNCTION(strrchr);
|
||||
INTERCEPT_LIBRARY_FUNCTION(strspn);
|
||||
INTERCEPT_LIBRARY_FUNCTION(strstr);
|
||||
INTERCEPT_LIBRARY_FUNCTION(strtok);
|
||||
INTERCEPT_LIBRARY_FUNCTION(strtol);
|
||||
INTERCEPT_LIBRARY_FUNCTION(wcslen);
|
||||
|
||||
// Must be after all the interceptor declarations due to the way INTERCEPT_HOOKS
|
||||
// is defined.
|
||||
void InterceptHooks() {
|
||||
INTERCEPT_HOOKS();
|
||||
#ifdef _WIN64
|
||||
INTERCEPT_LIBRARY_FUNCTION(__C_specific_handler);
|
||||
#else
|
||||
INTERCEPT_LIBRARY_FUNCTION(_except_handler3);
|
||||
// _except_handler4 checks -GS cookie which is different for each module, so we
|
||||
// can't use INTERCEPT_LIBRARY_FUNCTION(_except_handler4).
|
||||
INTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) {
|
||||
__asan_handle_no_return();
|
||||
return REAL(_except_handler4)(a, b, c, d);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Window specific functions not included in asan_interface.inc.
|
||||
INTERCEPT_WRAP_W_V(__asan_should_detect_stack_use_after_return)
|
||||
INTERCEPT_WRAP_W_V(__asan_get_shadow_memory_dynamic_address)
|
||||
INTERCEPT_WRAP_W_W(__asan_unhandled_exception_filter)
|
||||
|
||||
using namespace __sanitizer;
|
||||
|
||||
extern "C" {
|
||||
int __asan_option_detect_stack_use_after_return;
|
||||
uptr __asan_shadow_memory_dynamic_address;
|
||||
} // extern "C"
|
||||
|
||||
static int asan_dll_thunk_init() {
|
||||
typedef void (*fntype)();
|
||||
static fntype fn = 0;
|
||||
// asan_dll_thunk_init is expected to be called by only one thread.
|
||||
if (fn) return 0;
|
||||
|
||||
// Ensure all interception was executed.
|
||||
__dll_thunk_init();
|
||||
|
||||
fn = (fntype) dllThunkGetRealAddrOrDie("__asan_init");
|
||||
fn();
|
||||
__asan_option_detect_stack_use_after_return =
|
||||
(__asan_should_detect_stack_use_after_return() != 0);
|
||||
__asan_shadow_memory_dynamic_address =
|
||||
(uptr)__asan_get_shadow_memory_dynamic_address();
|
||||
|
||||
#ifndef _WIN64
|
||||
INTERCEPT_FUNCTION(_except_handler4);
|
||||
#endif
|
||||
}
|
||||
|
||||
// We want to call __asan_init before C/C++ initializers/constructors are
|
||||
// executed, otherwise functions like memset might be invoked.
|
||||
// For some strange reason, merely linking in asan_preinit.cc doesn't work
|
||||
// as the callback is never called... Is link.exe doing something too smart?
|
||||
|
||||
// In DLLs, the callbacks are expected to return 0,
|
||||
// otherwise CRT initialization fails.
|
||||
static int call_asan_init() {
|
||||
__asan_init();
|
||||
// In DLLs, the callbacks are expected to return 0,
|
||||
// otherwise CRT initialization fails.
|
||||
return 0;
|
||||
}
|
||||
|
||||
#pragma section(".CRT$XIB", long, read) // NOLINT
|
||||
__declspec(allocate(".CRT$XIB")) int (*__asan_preinit)() = call_asan_init;
|
||||
__declspec(allocate(".CRT$XIB")) int (*__asan_preinit)() = asan_dll_thunk_init;
|
||||
|
||||
static void WINAPI asan_thread_init(void *mod, unsigned long reason,
|
||||
void *reserved) {
|
||||
if (reason == /*DLL_PROCESS_ATTACH=*/1) __asan_init();
|
||||
void *reserved) {
|
||||
if (reason == /*DLL_PROCESS_ATTACH=*/1) asan_dll_thunk_init();
|
||||
}
|
||||
|
||||
#pragma section(".CRT$XLAB", long, read) // NOLINT
|
||||
__declspec(allocate(".CRT$XLAB")) void (WINAPI *__asan_tls_init)(void *,
|
||||
unsigned long, void *) = asan_thread_init;
|
||||
|
||||
ASAN_LINK_GLOBALS_WIN()
|
||||
WIN_FORCE_LINK(__asan_dso_reg_hook)
|
||||
|
||||
#endif // ASAN_DLL_THUNK
|
||||
#endif // SANITIZER_DLL_THUNK
|
||||
|
|
|
|||
|
|
@ -14,20 +14,24 @@
|
|||
// using the default "import library" generated when linking the DLL RTL.
|
||||
//
|
||||
// This includes:
|
||||
// - creating weak aliases to default implementation imported from asan dll.
|
||||
// - forwarding the detect_stack_use_after_return runtime option
|
||||
// - working around deficiencies of the MD runtime
|
||||
// - installing a custom SEH handler
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Only compile this code when building asan_dynamic_runtime_thunk.lib
|
||||
// Using #ifdef rather than relying on Makefiles etc.
|
||||
// simplifies the build procedure.
|
||||
#ifdef ASAN_DYNAMIC_RUNTIME_THUNK
|
||||
#include "asan_globals_win.h"
|
||||
#ifdef SANITIZER_DYNAMIC_RUNTIME_THUNK
|
||||
#define SANITIZER_IMPORT_INTERFACE 1
|
||||
#include "sanitizer_common/sanitizer_win_defs.h"
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
// Define weak alias for all weak functions imported from asan dll.
|
||||
#define INTERFACE_FUNCTION(Name)
|
||||
#define INTERFACE_WEAK_FUNCTION(Name) WIN_WEAK_IMPORT_DEF(Name)
|
||||
#include "asan_interface.inc"
|
||||
|
||||
// First, declare CRT sections we'll be using in this file
|
||||
#pragma section(".CRT$XIB", long, read) // NOLINT
|
||||
#pragma section(".CRT$XID", long, read) // NOLINT
|
||||
|
|
@ -122,6 +126,6 @@ __declspec(allocate(".CRT$XCAB")) int (*__asan_seh_interceptor)() =
|
|||
SetSEHFilter;
|
||||
}
|
||||
|
||||
ASAN_LINK_GLOBALS_WIN()
|
||||
WIN_FORCE_LINK(__asan_dso_reg_hook)
|
||||
|
||||
#endif // ASAN_DYNAMIC_RUNTIME_THUNK
|
||||
#endif // SANITIZER_DYNAMIC_RUNTIME_THUNK
|
||||
|
|
|
|||
23
lib/asan/asan_win_weak_interception.cc
Normal file
23
lib/asan/asan_win_weak_interception.cc
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
//===-- asan_win_weak_interception.cc -------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// This module should be included in Address Sanitizer when it is implemented as
|
||||
// a shared library on Windows (dll), in order to delegate the calls of weak
|
||||
// functions to the implementation in the main executable when a strong
|
||||
// definition is provided.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifdef SANITIZER_DYNAMIC
|
||||
#include "sanitizer_common/sanitizer_win_weak_interception.h"
|
||||
#include "asan_interface_internal.h"
|
||||
// Check if strong definitions for weak functions are present in the main
|
||||
// executable. If that is the case, override dll functions to point to strong
|
||||
// implementations.
|
||||
#define INTERFACE_FUNCTION(Name)
|
||||
#define INTERFACE_WEAK_FUNCTION(Name) INTERCEPT_SANITIZER_WEAK_FUNCTION(Name)
|
||||
#include "asan_interface.inc"
|
||||
#endif // SANITIZER_DYNAMIC
|
||||
|
|
@ -89,10 +89,12 @@ class LLVMSymbolizer(Symbolizer):
|
|||
for hint in self.dsym_hints:
|
||||
cmd.append('--dsym-hint=%s' % hint)
|
||||
if DEBUG:
|
||||
print ' '.join(cmd)
|
||||
print(' '.join(cmd))
|
||||
try:
|
||||
result = subprocess.Popen(cmd, stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE)
|
||||
stdout=subprocess.PIPE,
|
||||
bufsize=0,
|
||||
universal_newlines=True)
|
||||
except OSError:
|
||||
result = None
|
||||
return result
|
||||
|
|
@ -105,8 +107,8 @@ class LLVMSymbolizer(Symbolizer):
|
|||
try:
|
||||
symbolizer_input = '"%s" %s' % (binary, offset)
|
||||
if DEBUG:
|
||||
print symbolizer_input
|
||||
print >> self.pipe.stdin, symbolizer_input
|
||||
print(symbolizer_input)
|
||||
self.pipe.stdin.write("%s\n" % symbolizer_input)
|
||||
while True:
|
||||
function_name = self.pipe.stdout.readline().rstrip()
|
||||
if not function_name:
|
||||
|
|
@ -151,9 +153,11 @@ class Addr2LineSymbolizer(Symbolizer):
|
|||
cmd += ['--demangle']
|
||||
cmd += ['-e', self.binary]
|
||||
if DEBUG:
|
||||
print ' '.join(cmd)
|
||||
print(' '.join(cmd))
|
||||
return subprocess.Popen(cmd,
|
||||
stdin=subprocess.PIPE, stdout=subprocess.PIPE)
|
||||
stdin=subprocess.PIPE, stdout=subprocess.PIPE,
|
||||
bufsize=0,
|
||||
universal_newlines=True)
|
||||
|
||||
def symbolize(self, addr, binary, offset):
|
||||
"""Overrides Symbolizer.symbolize."""
|
||||
|
|
@ -161,8 +165,8 @@ class Addr2LineSymbolizer(Symbolizer):
|
|||
return None
|
||||
lines = []
|
||||
try:
|
||||
print >> self.pipe.stdin, offset
|
||||
print >> self.pipe.stdin, self.output_terminator
|
||||
self.pipe.stdin.write("%s\n" % offset)
|
||||
self.pipe.stdin.write("%s\n" % self.output_terminator)
|
||||
is_first_frame = True
|
||||
while True:
|
||||
function_name = self.pipe.stdout.readline().rstrip()
|
||||
|
|
@ -219,7 +223,7 @@ class DarwinSymbolizer(Symbolizer):
|
|||
|
||||
def open_atos(self):
|
||||
if DEBUG:
|
||||
print 'atos -o %s -arch %s' % (self.binary, self.arch)
|
||||
print('atos -o %s -arch %s' % (self.binary, self.arch))
|
||||
cmdline = ['atos', '-o', self.binary, '-arch', self.arch]
|
||||
self.atos = UnbufferedLineConverter(cmdline, close_stderr=True)
|
||||
|
||||
|
|
@ -234,7 +238,7 @@ class DarwinSymbolizer(Symbolizer):
|
|||
# foo(type1, type2) (in object.name) (filename.cc:80)
|
||||
match = re.match('^(.*) \(in (.*)\) \((.*:\d*)\)$', atos_line)
|
||||
if DEBUG:
|
||||
print 'atos_line: ', atos_line
|
||||
print('atos_line: ', atos_line)
|
||||
if match:
|
||||
function_name = match.group(1)
|
||||
function_name = re.sub('\(.*?\)', '', function_name)
|
||||
|
|
@ -348,7 +352,7 @@ class BreakpadSymbolizer(Symbolizer):
|
|||
function_name, file_name, line_no = res
|
||||
result = ['%s in %s %s:%d' % (
|
||||
addr, function_name, file_name, line_no)]
|
||||
print result
|
||||
print(result)
|
||||
return result
|
||||
else:
|
||||
return None
|
||||
|
|
@ -434,7 +438,7 @@ class SymbolizationLoop(object):
|
|||
self.frame_no = 0
|
||||
for line in logfile:
|
||||
processed = self.process_line(line)
|
||||
print '\n'.join(processed)
|
||||
print('\n'.join(processed))
|
||||
|
||||
def process_line_echo(self, line):
|
||||
return [line.rstrip()]
|
||||
|
|
@ -448,7 +452,7 @@ class SymbolizationLoop(object):
|
|||
if not match:
|
||||
return [self.current_line]
|
||||
if DEBUG:
|
||||
print line
|
||||
print(line)
|
||||
_, frameno_str, addr, binary, offset = match.groups()
|
||||
arch = ""
|
||||
# Arch can be embedded in the filename, e.g.: "libabc.dylib:x86_64h"
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include "sanitizer_common/sanitizer_internal_defs.h"
|
||||
#include <sanitizer/allocator_interface.h>
|
||||
#include <sanitizer/asan_interface.h>
|
||||
#include <vector>
|
||||
|
||||
TEST(AddressSanitizerInterface, GetEstimatedAllocatedSize) {
|
||||
EXPECT_EQ(0U, __sanitizer_get_estimated_allocated_size(0));
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
#include "asan_interface_internal.h"
|
||||
#include "asan_test_utils.h"
|
||||
#include <vector>
|
||||
|
||||
TEST(AddressSanitizerInternalInterface, SetShadow) {
|
||||
std::vector<char> buffer(17, 0xff);
|
||||
|
|
|
|||
|
|
@ -237,4 +237,5 @@ void TestNSURLDeallocation() {
|
|||
[[NSURL alloc] initWithString:@"Saved Application State"
|
||||
relativeToURL:base];
|
||||
[u release];
|
||||
[base release];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "asan_test_utils.h"
|
||||
#include <vector>
|
||||
|
||||
template<typename T>
|
||||
void MemSetOOBTestTemplate(size_t length) {
|
||||
|
|
@ -76,7 +77,7 @@ TEST(AddressSanitizer, MemSetOOBTest) {
|
|||
// Strictly speaking we are not guaranteed to find such two pointers,
|
||||
// but given the structure of asan's allocator we will.
|
||||
static bool AllocateTwoAdjacentArrays(char **x1, char **x2, size_t size) {
|
||||
vector<uintptr_t> v;
|
||||
std::vector<uintptr_t> v;
|
||||
bool res = false;
|
||||
for (size_t i = 0; i < 1000U && !res; i++) {
|
||||
v.push_back(reinterpret_cast<uintptr_t>(new char[size]));
|
||||
|
|
|
|||
|
|
@ -97,6 +97,9 @@ TEST(AddressSanitizer, NoInstMallocTest) {
|
|||
MallocStress(ASAN_LOW_MEMORY ? 300000 : 1000000);
|
||||
}
|
||||
|
||||
#ifndef __powerpc64__
|
||||
// FIXME: This has not reliably worked on powerpc since r279664. Re-enable
|
||||
// this once the problem is tracked down and fixed.
|
||||
TEST(AddressSanitizer, ThreadedMallocStressTest) {
|
||||
const int kNumThreads = 4;
|
||||
const int kNumIterations = (ASAN_LOW_MEMORY) ? 10000 : 100000;
|
||||
|
|
@ -109,6 +112,7 @@ TEST(AddressSanitizer, ThreadedMallocStressTest) {
|
|||
PTHREAD_JOIN(t[i], 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void PrintShadow(const char *tag, uptr ptr, size_t size) {
|
||||
fprintf(stderr, "%s shadow: %lx size % 3ld: ", tag, (long)ptr, (long)size);
|
||||
|
|
@ -206,6 +210,10 @@ void *ThreadedOneSizeMallocStress(void *unused) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
#ifndef __powerpc64__
|
||||
// FIXME: This has not reliably worked on powerpc since r279664. Re-enable
|
||||
// this once the problem is tracked down and fixed.
|
||||
|
||||
TEST(AddressSanitizer, ThreadedOneSizeMallocStressTest) {
|
||||
const int kNumThreads = 4;
|
||||
pthread_t t[kNumThreads];
|
||||
|
|
@ -216,6 +224,7 @@ TEST(AddressSanitizer, ThreadedOneSizeMallocStressTest) {
|
|||
PTHREAD_JOIN(t[i], 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(AddressSanitizer, ShadowRegionIsPoisonedTest) {
|
||||
using __asan::kHighMemEnd;
|
||||
|
|
|
|||
|
|
@ -337,8 +337,9 @@ void *ManyThreadsWorker(void *a) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
#if !defined(__aarch64__)
|
||||
#if !defined(__aarch64__) && !defined(__powerpc64__)
|
||||
// FIXME: Infinite loop in AArch64 (PR24389).
|
||||
// FIXME: Also occasional hang on powerpc. Maybe same problem as on AArch64?
|
||||
TEST(AddressSanitizer, ManyThreadsTest) {
|
||||
const size_t kNumThreads =
|
||||
(SANITIZER_WORDSIZE == 32 || ASAN_AVOID_EXPENSIVE_TESTS) ? 30 : 1000;
|
||||
|
|
@ -684,6 +685,7 @@ void *ThreadStackReuseFunc2(void *unused) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
#if !defined(__thumb__)
|
||||
TEST(AddressSanitizer, ThreadStackReuseTest) {
|
||||
pthread_t t;
|
||||
PTHREAD_CREATE(&t, 0, ThreadStackReuseFunc1, 0);
|
||||
|
|
@ -691,6 +693,7 @@ TEST(AddressSanitizer, ThreadStackReuseTest) {
|
|||
PTHREAD_CREATE(&t, 0, ThreadStackReuseFunc2, 0);
|
||||
PTHREAD_JOIN(t, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__SSE2__)
|
||||
#include <emmintrin.h>
|
||||
|
|
@ -945,7 +948,7 @@ TEST(AddressSanitizer, ShadowGapTest) {
|
|||
char *addr = (char*)0x0000100000080000;
|
||||
# endif
|
||||
#endif
|
||||
EXPECT_DEATH(*addr = 1, "AddressSanitizer: SEGV on unknown");
|
||||
EXPECT_DEATH(*addr = 1, "AddressSanitizer: (SEGV|BUS) on unknown");
|
||||
}
|
||||
#endif // ASAN_NEEDS_SEGV
|
||||
|
||||
|
|
@ -1090,6 +1093,11 @@ TEST(AddressSanitizer, ThreadedStressStackReuseTest) {
|
|||
}
|
||||
}
|
||||
|
||||
// pthread_exit tries to perform unwinding stuff that leads to dlopen'ing
|
||||
// libgcc_s.so. dlopen in its turn calls malloc to store "libgcc_s.so" string
|
||||
// that confuses LSan on Thumb because it fails to understand that this
|
||||
// allocation happens in dynamic linker and should be ignored.
|
||||
#if !defined(__thumb__)
|
||||
static void *PthreadExit(void *a) {
|
||||
pthread_exit(0);
|
||||
return 0;
|
||||
|
|
@ -1102,6 +1110,7 @@ TEST(AddressSanitizer, PthreadExitTest) {
|
|||
PTHREAD_JOIN(t, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// FIXME: Why does clang-cl define __EXCEPTIONS?
|
||||
#if defined(__EXCEPTIONS) && !defined(_WIN32)
|
||||
|
|
|
|||
|
|
@ -17,13 +17,9 @@
|
|||
#ifndef ASAN_TEST_CONFIG_H
|
||||
#define ASAN_TEST_CONFIG_H
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using std::map;
|
||||
|
||||
#ifndef ASAN_UAR
|
||||
# error "please define ASAN_UAR"
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ set(GENERIC_SOURCES
|
|||
extendsfdf2.c
|
||||
extendhfsf2.c
|
||||
ffsdi2.c
|
||||
ffssi2.c
|
||||
ffsti2.c
|
||||
fixdfdi.c
|
||||
fixdfsi.c
|
||||
|
|
@ -132,6 +133,7 @@ set(GENERIC_SOURCES
|
|||
negvdi2.c
|
||||
negvsi2.c
|
||||
negvti2.c
|
||||
os_version_check.c
|
||||
paritydi2.c
|
||||
paritysi2.c
|
||||
parityti2.c
|
||||
|
|
@ -174,15 +176,6 @@ if(COMPILER_RT_HAS_ATOMIC_KEYWORD AND NOT COMPILER_RT_EXCLUDE_ATOMIC_BUILTIN)
|
|||
atomic.c)
|
||||
endif()
|
||||
|
||||
set(MSVC_SOURCES
|
||||
divsc3.c
|
||||
divdc3.c
|
||||
divxc3.c
|
||||
mulsc3.c
|
||||
muldc3.c
|
||||
mulxc3.c)
|
||||
|
||||
|
||||
if(APPLE)
|
||||
set(GENERIC_SOURCES
|
||||
${GENERIC_SOURCES}
|
||||
|
|
@ -262,9 +255,9 @@ else () # MSVC
|
|||
x86_64/floatdidf.c
|
||||
x86_64/floatdisf.c
|
||||
x86_64/floatdixf.c
|
||||
${MSVC_SOURCES})
|
||||
${GENERIC_SOURCES})
|
||||
set(x86_64h_SOURCES ${x86_64_SOURCES})
|
||||
set(i386_SOURCES ${MSVC_SOURCES})
|
||||
set(i386_SOURCES ${GENERIC_SOURCES})
|
||||
set(i686_SOURCES ${i386_SOURCES})
|
||||
endif () # if (NOT MSVC)
|
||||
|
||||
|
|
@ -302,6 +295,13 @@ set(arm_SOURCES
|
|||
arm/umodsi3.S
|
||||
${GENERIC_SOURCES})
|
||||
|
||||
set(thumb1_SOURCES
|
||||
arm/divsi3.S
|
||||
arm/udivsi3.S
|
||||
arm/comparesf2.S
|
||||
arm/addsf3.S
|
||||
${GENERIC_SOURCES})
|
||||
|
||||
set(arm_EABI_SOURCES
|
||||
arm/aeabi_cdcmp.S
|
||||
arm/aeabi_cdcmpeq_check_nan.c
|
||||
|
|
@ -320,6 +320,7 @@ set(arm_EABI_SOURCES
|
|||
arm/aeabi_memset.S
|
||||
arm/aeabi_uidivmod.S
|
||||
arm/aeabi_uldivmod.S)
|
||||
|
||||
set(arm_Thumb1_JT_SOURCES
|
||||
arm/switch16.S
|
||||
arm/switch32.S
|
||||
|
|
@ -401,6 +402,10 @@ elseif(NOT WIN32)
|
|||
${arm_SOURCES}
|
||||
${arm_EABI_SOURCES}
|
||||
${arm_Thumb1_SOURCES})
|
||||
|
||||
set(thumb1_SOURCES
|
||||
${thumb1_SOURCES}
|
||||
${arm_EABI_SOURCES})
|
||||
endif()
|
||||
|
||||
set(aarch64_SOURCES
|
||||
|
|
@ -431,7 +436,7 @@ set(armv7k_SOURCES ${arm_SOURCES})
|
|||
set(arm64_SOURCES ${aarch64_SOURCES})
|
||||
|
||||
# macho_embedded archs
|
||||
set(armv6m_SOURCES ${GENERIC_SOURCES})
|
||||
set(armv6m_SOURCES ${thumb1_SOURCES})
|
||||
set(armv7m_SOURCES ${arm_SOURCES})
|
||||
set(armv7em_SOURCES ${arm_SOURCES})
|
||||
|
||||
|
|
@ -486,7 +491,7 @@ else ()
|
|||
# Needed for clear_cache on debug mode, due to r7's usage in inline asm.
|
||||
# Release mode already sets it via -O2/3, Debug mode doesn't.
|
||||
if (${arch} STREQUAL "armhf")
|
||||
list(APPEND BUILTIN_CFLAGS -fomit-frame-pointer)
|
||||
list(APPEND BUILTIN_CFLAGS -fomit-frame-pointer -DCOMPILER_RT_ARMHF_TARGET)
|
||||
endif()
|
||||
|
||||
add_compiler_rt_runtime(clang_rt.builtins
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ si_int __ctzsi2(si_int a); // count trailing zeros
|
|||
si_int __ctzdi2(di_int a); // count trailing zeros
|
||||
si_int __ctzti2(ti_int a); // count trailing zeros
|
||||
|
||||
si_int __ffssi2(si_int a); // find least significant 1 bit
|
||||
si_int __ffsdi2(di_int a); // find least significant 1 bit
|
||||
si_int __ffsti2(ti_int a); // find least significant 1 bit
|
||||
|
||||
|
|
|
|||
277
lib/builtins/arm/addsf3.S
Normal file
277
lib/builtins/arm/addsf3.S
Normal file
|
|
@ -0,0 +1,277 @@
|
|||
/*===-- addsf3.S - Adds two single precision floating pointer numbers-----===//
|
||||
*
|
||||
* The LLVM Compiler Infrastructure
|
||||
*
|
||||
* This file is dual licensed under the MIT and the University of Illinois Open
|
||||
* Source Licenses. See LICENSE.TXT for details.
|
||||
*
|
||||
*===----------------------------------------------------------------------===//
|
||||
*
|
||||
* This file implements the __addsf3 (single precision floating pointer number
|
||||
* addition with the IEEE-754 default rounding (to nearest, ties to even)
|
||||
* function for the ARM Thumb1 ISA.
|
||||
*
|
||||
*===----------------------------------------------------------------------===*/
|
||||
|
||||
#include "../assembly.h"
|
||||
#define significandBits 23
|
||||
#define typeWidth 32
|
||||
|
||||
.syntax unified
|
||||
.text
|
||||
.thumb
|
||||
.p2align 2
|
||||
|
||||
DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_fadd, __addsf3)
|
||||
|
||||
DEFINE_COMPILERRT_THUMB_FUNCTION(__addsf3)
|
||||
push {r4, r5, r6, r7, lr}
|
||||
// Get the absolute value of a and b.
|
||||
lsls r2, r0, #1
|
||||
lsls r3, r1, #1
|
||||
lsrs r2, r2, #1 /* aAbs */
|
||||
beq LOCAL_LABEL(a_zero_nan_inf)
|
||||
lsrs r3, r3, #1 /* bAbs */
|
||||
beq LOCAL_LABEL(zero_nan_inf)
|
||||
|
||||
// Detect if a or b is infinity or Nan.
|
||||
lsrs r6, r2, #(significandBits)
|
||||
lsrs r7, r3, #(significandBits)
|
||||
cmp r6, #0xFF
|
||||
beq LOCAL_LABEL(zero_nan_inf)
|
||||
cmp r7, #0xFF
|
||||
beq LOCAL_LABEL(zero_nan_inf)
|
||||
|
||||
// Swap Rep and Abs so that a and aAbs has the larger absolute value.
|
||||
cmp r2, r3
|
||||
bhs LOCAL_LABEL(no_swap)
|
||||
movs r4, r0
|
||||
movs r5, r2
|
||||
movs r0, r1
|
||||
movs r2, r3
|
||||
movs r1, r4
|
||||
movs r3, r5
|
||||
LOCAL_LABEL(no_swap):
|
||||
|
||||
// Get the significands and shift them to give us round, guard and sticky.
|
||||
lsls r4, r0, #(typeWidth - significandBits)
|
||||
lsrs r4, r4, #(typeWidth - significandBits - 3) /* aSignificand << 3 */
|
||||
lsls r5, r1, #(typeWidth - significandBits)
|
||||
lsrs r5, r5, #(typeWidth - significandBits - 3) /* bSignificand << 3 */
|
||||
|
||||
// Get the implicitBit.
|
||||
movs r6, #1
|
||||
lsls r6, r6, #(significandBits + 3)
|
||||
|
||||
// Get aExponent and set implicit bit if necessary.
|
||||
lsrs r2, r2, #(significandBits)
|
||||
beq LOCAL_LABEL(a_done_implicit_bit)
|
||||
orrs r4, r6
|
||||
LOCAL_LABEL(a_done_implicit_bit):
|
||||
|
||||
// Get bExponent and set implicit bit if necessary.
|
||||
lsrs r3, r3, #(significandBits)
|
||||
beq LOCAL_LABEL(b_done_implicit_bit)
|
||||
orrs r5, r6
|
||||
LOCAL_LABEL(b_done_implicit_bit):
|
||||
|
||||
// Get the difference in exponents.
|
||||
subs r6, r2, r3
|
||||
beq LOCAL_LABEL(done_align)
|
||||
|
||||
// If b is denormal, then a must be normal as align > 0, and we only need to
|
||||
// right shift bSignificand by (align - 1) bits.
|
||||
cmp r3, #0
|
||||
bne 1f
|
||||
subs r6, r6, #1
|
||||
1:
|
||||
|
||||
// No longer needs bExponent. r3 is dead here.
|
||||
// Set sticky bits of b: sticky = bSignificand << (typeWidth - align).
|
||||
movs r3, #(typeWidth)
|
||||
subs r3, r3, r6
|
||||
movs r7, r5
|
||||
lsls r7, r3
|
||||
beq 1f
|
||||
movs r7, #1
|
||||
1:
|
||||
|
||||
// bSignificand = bSignificand >> align | sticky;
|
||||
lsrs r5, r6
|
||||
orrs r5, r7
|
||||
bne LOCAL_LABEL(done_align)
|
||||
movs r5, #1 // sticky; b is known to be non-zero.
|
||||
|
||||
LOCAL_LABEL(done_align):
|
||||
// isSubtraction = (aRep ^ bRep) >> 31;
|
||||
movs r7, r0
|
||||
eors r7, r1
|
||||
lsrs r7, #31
|
||||
bne LOCAL_LABEL(do_substraction)
|
||||
|
||||
// Same sign, do Addition.
|
||||
|
||||
// aSignificand += bSignificand;
|
||||
adds r4, r4, r5
|
||||
|
||||
// Check carry bit.
|
||||
movs r6, #1
|
||||
lsls r6, r6, #(significandBits + 3 + 1)
|
||||
movs r7, r4
|
||||
ands r7, r6
|
||||
beq LOCAL_LABEL(form_result)
|
||||
// If the addition carried up, we need to right-shift the result and
|
||||
// adjust the exponent.
|
||||
movs r7, r4
|
||||
movs r6, #1
|
||||
ands r7, r6 // sticky = aSignificand & 1;
|
||||
lsrs r4, #1
|
||||
orrs r4, r7 // result Significand
|
||||
adds r2, #1 // result Exponent
|
||||
// If we have overflowed the type, return +/- infinity.
|
||||
cmp r2, 0xFF
|
||||
beq LOCAL_LABEL(ret_inf)
|
||||
|
||||
LOCAL_LABEL(form_result):
|
||||
// Shift the sign, exponent and significand into place.
|
||||
lsrs r0, #(typeWidth - 1)
|
||||
lsls r0, #(typeWidth - 1) // Get Sign.
|
||||
lsls r2, #(significandBits)
|
||||
orrs r0, r2
|
||||
movs r1, r4
|
||||
lsls r4, #(typeWidth - significandBits - 3)
|
||||
lsrs r4, #(typeWidth - significandBits)
|
||||
orrs r0, r4
|
||||
|
||||
// Final rounding. The result may overflow to infinity, but that is the
|
||||
// correct result in that case.
|
||||
// roundGuardSticky = aSignificand & 0x7;
|
||||
movs r2, #0x7
|
||||
ands r1, r2
|
||||
// if (roundGuardSticky > 0x4) result++;
|
||||
|
||||
cmp r1, #0x4
|
||||
blt LOCAL_LABEL(done_round)
|
||||
beq 1f
|
||||
adds r0, #1
|
||||
pop {r4, r5, r6, r7, pc}
|
||||
1:
|
||||
|
||||
// if (roundGuardSticky == 0x4) result += result & 1;
|
||||
movs r1, r0
|
||||
lsrs r1, #1
|
||||
bcc LOCAL_LABEL(done_round)
|
||||
adds r0, r0, #1
|
||||
LOCAL_LABEL(done_round):
|
||||
pop {r4, r5, r6, r7, pc}
|
||||
|
||||
LOCAL_LABEL(do_substraction):
|
||||
subs r4, r4, r5 // aSignificand -= bSignificand;
|
||||
beq LOCAL_LABEL(ret_zero)
|
||||
movs r6, r4
|
||||
cmp r2, 0
|
||||
beq LOCAL_LABEL(form_result) // if a's exp is 0, no need to normalize.
|
||||
// If partial cancellation occured, we need to left-shift the result
|
||||
// and adjust the exponent:
|
||||
lsrs r6, r6, #(significandBits + 3)
|
||||
bne LOCAL_LABEL(form_result)
|
||||
|
||||
push {r0, r1, r2, r3}
|
||||
movs r0, r4
|
||||
bl __clzsi2
|
||||
movs r5, r0
|
||||
pop {r0, r1, r2, r3}
|
||||
// shift = rep_clz(aSignificand) - rep_clz(implicitBit << 3);
|
||||
subs r5, r5, #(typeWidth - significandBits - 3 - 1)
|
||||
// aSignificand <<= shift; aExponent -= shift;
|
||||
lsls r4, r5
|
||||
subs r2, r2, r5
|
||||
bgt LOCAL_LABEL(form_result)
|
||||
|
||||
// Do normalization if aExponent <= 0.
|
||||
movs r6, #1
|
||||
subs r6, r6, r2 // 1 - aExponent;
|
||||
movs r2, #0 // aExponent = 0;
|
||||
movs r3, #(typeWidth) // bExponent is dead.
|
||||
subs r3, r3, r6
|
||||
movs r7, r4
|
||||
lsls r7, r3 // stickyBit = (bool)(aSignificant << (typeWidth - align))
|
||||
beq 1f
|
||||
movs r7, #1
|
||||
1:
|
||||
lsrs r4, r6 /* aSignificand >> shift */
|
||||
orrs r4, r7
|
||||
b LOCAL_LABEL(form_result)
|
||||
|
||||
LOCAL_LABEL(ret_zero):
|
||||
movs r0, #0
|
||||
pop {r4, r5, r6, r7, pc}
|
||||
|
||||
|
||||
LOCAL_LABEL(a_zero_nan_inf):
|
||||
lsrs r3, r3, #1
|
||||
|
||||
LOCAL_LABEL(zero_nan_inf):
|
||||
// Here r2 has aAbs, r3 has bAbs
|
||||
movs r4, #0xFF
|
||||
lsls r4, r4, #(significandBits) // Make +inf.
|
||||
|
||||
cmp r2, r4
|
||||
bhi LOCAL_LABEL(a_is_nan)
|
||||
cmp r3, r4
|
||||
bhi LOCAL_LABEL(b_is_nan)
|
||||
|
||||
cmp r2, r4
|
||||
bne LOCAL_LABEL(a_is_rational)
|
||||
// aAbs is INF.
|
||||
eors r1, r0 // aRep ^ bRep.
|
||||
movs r6, #1
|
||||
lsls r6, r6, #(typeWidth - 1) // get sign mask.
|
||||
cmp r1, r6 // if they only differ on sign bit, it's -INF + INF
|
||||
beq LOCAL_LABEL(a_is_nan)
|
||||
pop {r4, r5, r6, r7, pc}
|
||||
|
||||
LOCAL_LABEL(a_is_rational):
|
||||
cmp r3, r4
|
||||
bne LOCAL_LABEL(b_is_rational)
|
||||
movs r0, r1
|
||||
pop {r4, r5, r6, r7, pc}
|
||||
|
||||
LOCAL_LABEL(b_is_rational):
|
||||
// either a or b or both are zero.
|
||||
adds r4, r2, r3
|
||||
beq LOCAL_LABEL(both_zero)
|
||||
cmp r2, #0 // is absA 0 ?
|
||||
beq LOCAL_LABEL(ret_b)
|
||||
pop {r4, r5, r6, r7, pc}
|
||||
|
||||
LOCAL_LABEL(both_zero):
|
||||
ands r0, r1 // +0 + -0 = +0
|
||||
pop {r4, r5, r6, r7, pc}
|
||||
|
||||
LOCAL_LABEL(ret_b):
|
||||
movs r0, r1
|
||||
|
||||
LOCAL_LABEL(ret):
|
||||
pop {r4, r5, r6, r7, pc}
|
||||
|
||||
LOCAL_LABEL(b_is_nan):
|
||||
movs r0, r1
|
||||
LOCAL_LABEL(a_is_nan):
|
||||
movs r1, #1
|
||||
lsls r1, r1, #(significandBits -1) // r1 is quiet bit.
|
||||
orrs r0, r1
|
||||
pop {r4, r5, r6, r7, pc}
|
||||
|
||||
LOCAL_LABEL(ret_inf):
|
||||
movs r4, #0xFF
|
||||
lsls r4, r4, #(significandBits)
|
||||
orrs r0, r4
|
||||
lsrs r0, r0, #(significandBits)
|
||||
lsls r0, r0, #(significandBits)
|
||||
pop {r4, r5, r6, r7, pc}
|
||||
|
||||
|
||||
END_COMPILERRT_FUNCTION(__addsf3)
|
||||
|
||||
NO_EXEC_STACK_DIRECTIVE
|
||||
|
|
@ -30,6 +30,19 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cdcmpeq)
|
|||
push {r0-r3, lr}
|
||||
bl __aeabi_cdcmpeq_check_nan
|
||||
cmp r0, #1
|
||||
#if __ARM_ARCH_ISA_THUMB == 1
|
||||
beq 1f
|
||||
// NaN has been ruled out, so __aeabi_cdcmple can't trap
|
||||
mov r0, sp
|
||||
ldm r0, {r0-r3}
|
||||
bl __aeabi_cdcmple
|
||||
pop {r0-r3, pc}
|
||||
1:
|
||||
// Z = 0, C = 1
|
||||
movs r0, #0xF
|
||||
lsls r0, r0, #31
|
||||
pop {r0-r3, pc}
|
||||
#else
|
||||
pop {r0-r3, lr}
|
||||
|
||||
// NaN has been ruled out, so __aeabi_cdcmple can't trap
|
||||
|
|
@ -37,6 +50,7 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cdcmpeq)
|
|||
|
||||
msr CPSR_f, #APSR_C
|
||||
JMP(lr)
|
||||
#endif
|
||||
END_COMPILERRT_FUNCTION(__aeabi_cdcmpeq)
|
||||
|
||||
|
||||
|
|
@ -59,6 +73,28 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cdcmple)
|
|||
|
||||
bl __aeabi_dcmplt
|
||||
cmp r0, #1
|
||||
#if __ARM_ARCH_ISA_THUMB == 1
|
||||
bne 1f
|
||||
// Z = 0, C = 0
|
||||
movs r0, #1
|
||||
lsls r0, r0, #1
|
||||
pop {r0-r3, pc}
|
||||
1:
|
||||
mov r0, sp
|
||||
ldm r0, {r0-r3}
|
||||
bl __aeabi_dcmpeq
|
||||
cmp r0, #1
|
||||
bne 2f
|
||||
// Z = 1, C = 1
|
||||
movs r0, #2
|
||||
lsls r0, r0, #31
|
||||
pop {r0-r3, pc}
|
||||
2:
|
||||
// Z = 0, C = 1
|
||||
movs r0, #0xF
|
||||
lsls r0, r0, #31
|
||||
pop {r0-r3, pc}
|
||||
#else
|
||||
moveq ip, #0
|
||||
beq 1f
|
||||
|
||||
|
|
@ -72,6 +108,7 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cdcmple)
|
|||
msr CPSR_f, ip
|
||||
pop {r0-r3}
|
||||
POP_PC()
|
||||
#endif
|
||||
END_COMPILERRT_FUNCTION(__aeabi_cdcmple)
|
||||
|
||||
// int __aeabi_cdrcmple(double a, double b) {
|
||||
|
|
|
|||
|
|
@ -30,6 +30,19 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cfcmpeq)
|
|||
push {r0-r3, lr}
|
||||
bl __aeabi_cfcmpeq_check_nan
|
||||
cmp r0, #1
|
||||
#if __ARM_ARCH_ISA_THUMB == 1
|
||||
beq 1f
|
||||
// NaN has been ruled out, so __aeabi_cfcmple can't trap
|
||||
mov r0, sp
|
||||
ldm r0, {r0-r3}
|
||||
bl __aeabi_cfcmple
|
||||
pop {r0-r3, pc}
|
||||
1:
|
||||
// Z = 0, C = 1
|
||||
movs r0, #0xF
|
||||
lsls r0, r0, #31
|
||||
pop {r0-r3, pc}
|
||||
#else
|
||||
pop {r0-r3, lr}
|
||||
|
||||
// NaN has been ruled out, so __aeabi_cfcmple can't trap
|
||||
|
|
@ -37,6 +50,7 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cfcmpeq)
|
|||
|
||||
msr CPSR_f, #APSR_C
|
||||
JMP(lr)
|
||||
#endif
|
||||
END_COMPILERRT_FUNCTION(__aeabi_cfcmpeq)
|
||||
|
||||
|
||||
|
|
@ -59,6 +73,28 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cfcmple)
|
|||
|
||||
bl __aeabi_fcmplt
|
||||
cmp r0, #1
|
||||
#if __ARM_ARCH_ISA_THUMB == 1
|
||||
bne 1f
|
||||
// Z = 0, C = 0
|
||||
movs r0, #1
|
||||
lsls r0, r0, #1
|
||||
pop {r0-r3, pc}
|
||||
1:
|
||||
mov r0, sp
|
||||
ldm r0, {r0-r3}
|
||||
bl __aeabi_fcmpeq
|
||||
cmp r0, #1
|
||||
bne 2f
|
||||
// Z = 1, C = 1
|
||||
movs r0, #2
|
||||
lsls r0, r0, #31
|
||||
pop {r0-r3, pc}
|
||||
2:
|
||||
// Z = 0, C = 1
|
||||
movs r0, #0xF
|
||||
lsls r0, r0, #31
|
||||
pop {r0-r3, pc}
|
||||
#else
|
||||
moveq ip, #0
|
||||
beq 1f
|
||||
|
||||
|
|
@ -72,6 +108,7 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cfcmple)
|
|||
msr CPSR_f, ip
|
||||
pop {r0-r3}
|
||||
POP_PC()
|
||||
#endif
|
||||
END_COMPILERRT_FUNCTION(__aeabi_cfcmple)
|
||||
|
||||
// int __aeabi_cfrcmple(float a, float b) {
|
||||
|
|
|
|||
|
|
@ -26,10 +26,10 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_dcmp ## cond) \
|
|||
bl SYMBOL_NAME(__ ## cond ## df2) SEPARATOR \
|
||||
cmp r0, #0 SEPARATOR \
|
||||
b ## cond 1f SEPARATOR \
|
||||
mov r0, #0 SEPARATOR \
|
||||
movs r0, #0 SEPARATOR \
|
||||
pop { r4, pc } SEPARATOR \
|
||||
1: SEPARATOR \
|
||||
mov r0, #1 SEPARATOR \
|
||||
movs r0, #1 SEPARATOR \
|
||||
pop { r4, pc } SEPARATOR \
|
||||
END_COMPILERRT_FUNCTION(__aeabi_dcmp ## cond)
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_idivmod)
|
|||
push {r0, r1, lr}
|
||||
bl SYMBOL_NAME(__divsi3)
|
||||
pop {r1, r2, r3} // now r0 = quot, r1 = num, r2 = denom
|
||||
muls r2, r2, r0 // r2 = quot * denom
|
||||
muls r2, r0, r2 // r2 = quot * denom
|
||||
subs r1, r1, r2
|
||||
JMP (r3)
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -23,23 +23,23 @@
|
|||
.syntax unified
|
||||
.p2align 2
|
||||
DEFINE_COMPILERRT_FUNCTION(__aeabi_ldivmod)
|
||||
push {r11, lr}
|
||||
push {r6, lr}
|
||||
sub sp, sp, #16
|
||||
add r12, sp, #8
|
||||
str r12, [sp]
|
||||
add r6, sp, #8
|
||||
str r6, [sp]
|
||||
#if defined(__MINGW32__)
|
||||
mov r12, r0
|
||||
mov r0, r2
|
||||
mov r2, r12
|
||||
mov r12, r1
|
||||
mov r1, r3
|
||||
mov r3, r12
|
||||
movs r6, r0
|
||||
movs r0, r2
|
||||
movs r2, r6
|
||||
movs r6, r1
|
||||
movs r1, r3
|
||||
movs r3, r6
|
||||
#endif
|
||||
bl SYMBOL_NAME(__divmoddi4)
|
||||
ldr r2, [sp, #8]
|
||||
ldr r3, [sp, #12]
|
||||
add sp, sp, #16
|
||||
pop {r11, pc}
|
||||
pop {r6, pc}
|
||||
END_COMPILERRT_FUNCTION(__aeabi_ldivmod)
|
||||
|
||||
NO_EXEC_STACK_DIRECTIVE
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memset8, __aeabi_memset)
|
|||
|
||||
DEFINE_COMPILERRT_FUNCTION(__aeabi_memclr)
|
||||
mov r2, r1
|
||||
mov r1, #0
|
||||
movs r1, #0
|
||||
b memset
|
||||
END_COMPILERRT_FUNCTION(__aeabi_memclr)
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_uidivmod)
|
|||
push {r0, r1, lr}
|
||||
bl SYMBOL_NAME(__aeabi_uidiv)
|
||||
pop {r1, r2, r3}
|
||||
muls r2, r2, r0 // r2 = quot * denom
|
||||
muls r2, r0, r2 // r2 = quot * denom
|
||||
subs r1, r1, r2
|
||||
JMP (r3)
|
||||
LOCAL_LABEL(case_denom_larger):
|
||||
|
|
|
|||
|
|
@ -23,23 +23,23 @@
|
|||
.syntax unified
|
||||
.p2align 2
|
||||
DEFINE_COMPILERRT_FUNCTION(__aeabi_uldivmod)
|
||||
push {r11, lr}
|
||||
push {r6, lr}
|
||||
sub sp, sp, #16
|
||||
add r12, sp, #8
|
||||
str r12, [sp]
|
||||
add r6, sp, #8
|
||||
str r6, [sp]
|
||||
#if defined(__MINGW32__)
|
||||
mov r12, r0
|
||||
mov r0, r2
|
||||
mov r2, r12
|
||||
mov r12, r1
|
||||
mov r1, r3
|
||||
mov r3, r12
|
||||
movs r6, r0
|
||||
movs r0, r2
|
||||
movs r2, r6
|
||||
movs r6, r1
|
||||
movs r1, r3
|
||||
movs r3, r6
|
||||
#endif
|
||||
bl SYMBOL_NAME(__udivmoddi4)
|
||||
ldr r2, [sp, #8]
|
||||
ldr r3, [sp, #12]
|
||||
add sp, sp, #16
|
||||
pop {r11, pc}
|
||||
pop {r6, pc}
|
||||
END_COMPILERRT_FUNCTION(__aeabi_uldivmod)
|
||||
|
||||
NO_EXEC_STACK_DIRECTIVE
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ DEFINE_COMPILERRT_FUNCTION(__eqsf2)
|
|||
// the subsequent operations.
|
||||
#if __ARM_ARCH_ISA_THUMB == 1
|
||||
lsrs r6, r3, #1
|
||||
orrs r6, r2, r6
|
||||
orrs r6, r2
|
||||
#else
|
||||
orrs r12, r2, r3, lsr #1
|
||||
#endif
|
||||
|
|
@ -194,7 +194,7 @@ DEFINE_COMPILERRT_FUNCTION(__gtsf2)
|
|||
lsls r2, r0, #1
|
||||
lsls r3, r1, #1
|
||||
lsrs r6, r3, #1
|
||||
orrs r6, r2, r6
|
||||
orrs r6, r2
|
||||
beq 1f
|
||||
movs r6, r0
|
||||
eors r6, r1
|
||||
|
|
|
|||
|
|
@ -37,7 +37,16 @@ DEFINE_COMPILERRT_FUNCTION(__udivsi3)
|
|||
beq LOCAL_LABEL(divby0)
|
||||
udiv r0, r0, r1
|
||||
bx lr
|
||||
#else
|
||||
|
||||
LOCAL_LABEL(divby0):
|
||||
mov r0, #0
|
||||
# ifdef __ARM_EABI__
|
||||
b __aeabi_idiv0
|
||||
# else
|
||||
JMP(lr)
|
||||
# endif
|
||||
|
||||
#else /* ! __ARM_ARCH_EXT_IDIV__ */
|
||||
cmp r1, #1
|
||||
bcc LOCAL_LABEL(divby0)
|
||||
#if __ARM_ARCH_ISA_THUMB == 1
|
||||
|
|
@ -186,9 +195,12 @@ LOCAL_LABEL(skip_1):
|
|||
LOCAL_LABEL(divby0):
|
||||
movs r0, #0
|
||||
# if defined(__ARM_EABI__)
|
||||
push {r7, lr}
|
||||
bl __aeabi_idiv0 // due to relocation limit, can't use b.
|
||||
# endif
|
||||
pop {r7, pc}
|
||||
# else
|
||||
JMP(lr)
|
||||
# endif
|
||||
|
||||
|
||||
#if __ARM_ARCH_ISA_THUMB == 1
|
||||
|
|
@ -252,16 +264,6 @@ LOCAL_LABEL(div0block):
|
|||
JMP(lr)
|
||||
#endif /* __ARM_ARCH_EXT_IDIV__ */
|
||||
|
||||
#if __ARM_ARCH_EXT_IDIV__
|
||||
LOCAL_LABEL(divby0):
|
||||
mov r0, #0
|
||||
# ifdef __ARM_EABI__
|
||||
b __aeabi_idiv0
|
||||
# else
|
||||
JMP(lr)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
END_COMPILERRT_FUNCTION(__udivsi3)
|
||||
|
||||
NO_EXEC_STACK_DIRECTIVE
|
||||
|
|
|
|||
|
|
@ -82,10 +82,6 @@ uintptr_t GetCurrentProcess(void);
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) && defined(__arm__)
|
||||
#include <asm/unistd.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The compiler generates calls to __clear_cache() when creating
|
||||
* trampoline functions on the stack for use with nested functions.
|
||||
|
|
@ -94,7 +90,7 @@ uintptr_t GetCurrentProcess(void);
|
|||
*/
|
||||
|
||||
void __clear_cache(void *start, void *end) {
|
||||
#if __i386__ || __x86_64__
|
||||
#if __i386__ || __x86_64__ || defined(_M_IX86) || defined(_M_X64)
|
||||
/*
|
||||
* Intel processors have a unified instruction and data cache
|
||||
* so there is nothing to do
|
||||
|
|
@ -108,6 +104,15 @@ void __clear_cache(void *start, void *end) {
|
|||
|
||||
sysarch(ARM_SYNC_ICACHE, &arg);
|
||||
#elif defined(__linux__)
|
||||
/*
|
||||
* We used to include asm/unistd.h for the __ARM_NR_cacheflush define, but
|
||||
* it also brought many other unused defines, as well as a dependency on
|
||||
* kernel headers to be installed.
|
||||
*
|
||||
* This value is stable at least since Linux 3.13 and should remain so for
|
||||
* compatibility reasons, warranting it's re-definition here.
|
||||
*/
|
||||
#define __ARM_NR_cacheflush 0x0f0002
|
||||
register int start_reg __asm("r0") = (int) (intptr_t) start;
|
||||
const register int end_reg __asm("r1") = (int) (intptr_t) end;
|
||||
const register int flags __asm("r2") = 0;
|
||||
|
|
|
|||
|
|
@ -27,6 +27,10 @@
|
|||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
#ifndef __has_attribute
|
||||
#define __has_attribute(attr) 0
|
||||
#endif
|
||||
|
||||
enum VendorSignatures {
|
||||
SIG_INTEL = 0x756e6547 /* Genu */,
|
||||
SIG_AMD = 0x68747541 /* Auth */
|
||||
|
|
@ -720,14 +724,17 @@ static unsigned getAvailableFeatures(unsigned int ECX, unsigned int EDX,
|
|||
return Features;
|
||||
}
|
||||
|
||||
#ifdef HAVE_INIT_PRIORITY
|
||||
#define CONSTRUCTOR_PRIORITY (101)
|
||||
#if defined(HAVE_INIT_PRIORITY)
|
||||
#define CONSTRUCTOR_ATTRIBUTE __attribute__((__constructor__ 101))
|
||||
#elif __has_attribute(__constructor__)
|
||||
#define CONSTRUCTOR_ATTRIBUTE __attribute__((__constructor__))
|
||||
#else
|
||||
#define CONSTRUCTOR_PRIORITY
|
||||
// FIXME: For MSVC, we should make a function pointer global in .CRT$X?? so that
|
||||
// this runs during initialization.
|
||||
#define CONSTRUCTOR_ATTRIBUTE
|
||||
#endif
|
||||
|
||||
int __cpu_indicator_init(void)
|
||||
__attribute__((constructor CONSTRUCTOR_PRIORITY));
|
||||
int __cpu_indicator_init(void) CONSTRUCTOR_ATTRIBUTE;
|
||||
|
||||
struct __processor_model {
|
||||
unsigned int __cpu_vendor;
|
||||
|
|
@ -742,7 +749,7 @@ struct __processor_model {
|
|||
the priority set. However, it still runs after ifunc initializers and
|
||||
needs to be called explicitly there. */
|
||||
|
||||
int __attribute__((constructor CONSTRUCTOR_PRIORITY))
|
||||
int CONSTRUCTOR_ATTRIBUTE
|
||||
__cpu_indicator_init(void) {
|
||||
unsigned int EAX, EBX, ECX, EDX;
|
||||
unsigned int MaxLeaf = 5;
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
/* Returns: the quotient of (a + ib) / (c + id) */
|
||||
|
||||
COMPILER_RT_ABI long double _Complex
|
||||
COMPILER_RT_ABI Lcomplex
|
||||
__divtc3(long double __a, long double __b, long double __c, long double __d)
|
||||
{
|
||||
int __ilogbw = 0;
|
||||
|
|
@ -29,31 +29,31 @@ __divtc3(long double __a, long double __b, long double __c, long double __d)
|
|||
__d = crt_scalbnl(__d, -__ilogbw);
|
||||
}
|
||||
long double __denom = __c * __c + __d * __d;
|
||||
long double _Complex z;
|
||||
__real__ z = crt_scalbnl((__a * __c + __b * __d) / __denom, -__ilogbw);
|
||||
__imag__ z = crt_scalbnl((__b * __c - __a * __d) / __denom, -__ilogbw);
|
||||
if (crt_isnan(__real__ z) && crt_isnan(__imag__ z))
|
||||
Lcomplex z;
|
||||
COMPLEX_REAL(z) = crt_scalbnl((__a * __c + __b * __d) / __denom, -__ilogbw);
|
||||
COMPLEX_IMAGINARY(z) = crt_scalbnl((__b * __c - __a * __d) / __denom, -__ilogbw);
|
||||
if (crt_isnan(COMPLEX_REAL(z)) && crt_isnan(COMPLEX_IMAGINARY(z)))
|
||||
{
|
||||
if ((__denom == 0.0) && (!crt_isnan(__a) || !crt_isnan(__b)))
|
||||
{
|
||||
__real__ z = crt_copysignl(CRT_INFINITY, __c) * __a;
|
||||
__imag__ z = crt_copysignl(CRT_INFINITY, __c) * __b;
|
||||
COMPLEX_REAL(z) = crt_copysignl(CRT_INFINITY, __c) * __a;
|
||||
COMPLEX_IMAGINARY(z) = crt_copysignl(CRT_INFINITY, __c) * __b;
|
||||
}
|
||||
else if ((crt_isinf(__a) || crt_isinf(__b)) &&
|
||||
crt_isfinite(__c) && crt_isfinite(__d))
|
||||
{
|
||||
__a = crt_copysignl(crt_isinf(__a) ? 1.0 : 0.0, __a);
|
||||
__b = crt_copysignl(crt_isinf(__b) ? 1.0 : 0.0, __b);
|
||||
__real__ z = CRT_INFINITY * (__a * __c + __b * __d);
|
||||
__imag__ z = CRT_INFINITY * (__b * __c - __a * __d);
|
||||
COMPLEX_REAL(z) = CRT_INFINITY * (__a * __c + __b * __d);
|
||||
COMPLEX_IMAGINARY(z) = CRT_INFINITY * (__b * __c - __a * __d);
|
||||
}
|
||||
else if (crt_isinf(__logbw) && __logbw > 0.0 &&
|
||||
crt_isfinite(__a) && crt_isfinite(__b))
|
||||
{
|
||||
__c = crt_copysignl(crt_isinf(__c) ? 1.0 : 0.0, __c);
|
||||
__d = crt_copysignl(crt_isinf(__d) ? 1.0 : 0.0, __d);
|
||||
__real__ z = 0.0 * (__a * __c + __b * __d);
|
||||
__imag__ z = 0.0 * (__b * __c - __a * __d);
|
||||
COMPLEX_REAL(z) = 0.0 * (__a * __c + __b * __d);
|
||||
COMPLEX_IMAGINARY(z) = 0.0 * (__b * __c - __a * __d);
|
||||
}
|
||||
}
|
||||
return z;
|
||||
|
|
|
|||
29
lib/builtins/ffssi2.c
Normal file
29
lib/builtins/ffssi2.c
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/* ===-- ffssi2.c - Implement __ffssi2 -------------------------------------===
|
||||
*
|
||||
* The LLVM Compiler Infrastructure
|
||||
*
|
||||
* This file is dual licensed under the MIT and the University of Illinois Open
|
||||
* Source Licenses. See LICENSE.TXT for details.
|
||||
*
|
||||
* ===----------------------------------------------------------------------===
|
||||
*
|
||||
* This file implements __ffssi2 for the compiler_rt library.
|
||||
*
|
||||
* ===----------------------------------------------------------------------===
|
||||
*/
|
||||
|
||||
#include "int_lib.h"
|
||||
|
||||
/* Returns: the index of the least significant 1-bit in a, or
|
||||
* the value zero if a is zero. The least significant bit is index one.
|
||||
*/
|
||||
|
||||
COMPILER_RT_ABI si_int
|
||||
__ffssi2(si_int a)
|
||||
{
|
||||
if (a == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return __builtin_ctz(a) + 1;
|
||||
}
|
||||
|
|
@ -32,7 +32,11 @@
|
|||
#if __ARM_EABI__
|
||||
# define ARM_EABI_FNALIAS(aeabi_name, name) \
|
||||
void __aeabi_##aeabi_name() __attribute__((alias("__" #name)));
|
||||
# define COMPILER_RT_ABI __attribute__((pcs("aapcs")))
|
||||
# ifdef COMPILER_RT_ARMHF_TARGET
|
||||
# define COMPILER_RT_ABI
|
||||
# else
|
||||
# define COMPILER_RT_ABI __attribute__((pcs("aapcs")))
|
||||
# endif
|
||||
#else
|
||||
# define ARM_EABI_FNALIAS(aeabi_name, name)
|
||||
# define COMPILER_RT_ABI
|
||||
|
|
|
|||
178
lib/builtins/os_version_check.c
Normal file
178
lib/builtins/os_version_check.c
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
/* ===-- os_version_check.c - OS version checking -------------------------===
|
||||
*
|
||||
* The LLVM Compiler Infrastructure
|
||||
*
|
||||
* This file is dual licensed under the MIT and the University of Illinois Open
|
||||
* Source Licenses. See LICENSE.TXT for details.
|
||||
*
|
||||
* ===----------------------------------------------------------------------===
|
||||
*
|
||||
* This file implements the function __isOSVersionAtLeast, used by
|
||||
* Objective-C's @available
|
||||
*
|
||||
* ===----------------------------------------------------------------------===
|
||||
*/
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <dispatch/dispatch.h>
|
||||
#include <TargetConditionals.h>
|
||||
#include <dlfcn.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* These three variables hold the host's OS version. */
|
||||
static int32_t GlobalMajor, GlobalMinor, GlobalSubminor;
|
||||
static dispatch_once_t DispatchOnceCounter;
|
||||
|
||||
/* Find and parse the SystemVersion.plist file. */
|
||||
static void parseSystemVersionPList(void *Unused) {
|
||||
(void)Unused;
|
||||
/* Load CoreFoundation dynamically */
|
||||
const void *NullAllocator = dlsym(RTLD_DEFAULT, "kCFAllocatorNull");
|
||||
if (!NullAllocator)
|
||||
return;
|
||||
const CFAllocatorRef kCFAllocatorNull =
|
||||
*(const CFAllocatorRef *)NullAllocator;
|
||||
typeof(CFDataCreateWithBytesNoCopy) *CFDataCreateWithBytesNoCopyFunc =
|
||||
(typeof(CFDataCreateWithBytesNoCopy) *)dlsym(
|
||||
RTLD_DEFAULT, "CFDataCreateWithBytesNoCopy");
|
||||
if (!CFDataCreateWithBytesNoCopyFunc)
|
||||
return;
|
||||
typeof(CFPropertyListCreateWithData) *CFPropertyListCreateWithDataFunc =
|
||||
(typeof(CFPropertyListCreateWithData) *)dlsym(
|
||||
RTLD_DEFAULT, "CFPropertyListCreateWithData");
|
||||
/* CFPropertyListCreateWithData was introduced only in macOS 10.6+, so it
|
||||
* will be NULL on earlier OS versions. */
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
typeof(CFPropertyListCreateFromXMLData) *CFPropertyListCreateFromXMLDataFunc =
|
||||
(typeof(CFPropertyListCreateFromXMLData) *)dlsym(
|
||||
RTLD_DEFAULT, "CFPropertyListCreateFromXMLData");
|
||||
#pragma clang diagnostic pop
|
||||
/* CFPropertyListCreateFromXMLDataFunc is deprecated in macOS 10.10, so it
|
||||
* might be NULL in future OS versions. */
|
||||
if (!CFPropertyListCreateWithDataFunc && !CFPropertyListCreateFromXMLDataFunc)
|
||||
return;
|
||||
typeof(CFStringCreateWithCStringNoCopy) *CFStringCreateWithCStringNoCopyFunc =
|
||||
(typeof(CFStringCreateWithCStringNoCopy) *)dlsym(
|
||||
RTLD_DEFAULT, "CFStringCreateWithCStringNoCopy");
|
||||
if (!CFStringCreateWithCStringNoCopyFunc)
|
||||
return;
|
||||
typeof(CFDictionaryGetValue) *CFDictionaryGetValueFunc =
|
||||
(typeof(CFDictionaryGetValue) *)dlsym(RTLD_DEFAULT,
|
||||
"CFDictionaryGetValue");
|
||||
if (!CFDictionaryGetValueFunc)
|
||||
return;
|
||||
typeof(CFGetTypeID) *CFGetTypeIDFunc =
|
||||
(typeof(CFGetTypeID) *)dlsym(RTLD_DEFAULT, "CFGetTypeID");
|
||||
if (!CFGetTypeIDFunc)
|
||||
return;
|
||||
typeof(CFStringGetTypeID) *CFStringGetTypeIDFunc =
|
||||
(typeof(CFStringGetTypeID) *)dlsym(RTLD_DEFAULT, "CFStringGetTypeID");
|
||||
if (!CFStringGetTypeIDFunc)
|
||||
return;
|
||||
typeof(CFStringGetCString) *CFStringGetCStringFunc =
|
||||
(typeof(CFStringGetCString) *)dlsym(RTLD_DEFAULT, "CFStringGetCString");
|
||||
if (!CFStringGetCStringFunc)
|
||||
return;
|
||||
typeof(CFRelease) *CFReleaseFunc =
|
||||
(typeof(CFRelease) *)dlsym(RTLD_DEFAULT, "CFRelease");
|
||||
if (!CFReleaseFunc)
|
||||
return;
|
||||
|
||||
char *PListPath = "/System/Library/CoreServices/SystemVersion.plist";
|
||||
|
||||
#if TARGET_OS_SIMULATOR
|
||||
char *PListPathPrefix = getenv("IPHONE_SIMULATOR_ROOT");
|
||||
if (!PListPathPrefix)
|
||||
return;
|
||||
char FullPath[strlen(PListPathPrefix) + strlen(PListPath) + 1];
|
||||
strcpy(FullPath, PListPathPrefix);
|
||||
strcat(FullPath, PListPath);
|
||||
PListPath = FullPath;
|
||||
#endif
|
||||
FILE *PropertyList = fopen(PListPath, "r");
|
||||
if (!PropertyList)
|
||||
return;
|
||||
|
||||
/* Dynamically allocated stuff. */
|
||||
CFDictionaryRef PListRef = NULL;
|
||||
CFDataRef FileContentsRef = NULL;
|
||||
UInt8 *PListBuf = NULL;
|
||||
|
||||
fseek(PropertyList, 0, SEEK_END);
|
||||
long PListFileSize = ftell(PropertyList);
|
||||
if (PListFileSize < 0)
|
||||
goto Fail;
|
||||
rewind(PropertyList);
|
||||
|
||||
PListBuf = malloc((size_t)PListFileSize);
|
||||
if (!PListBuf)
|
||||
goto Fail;
|
||||
|
||||
size_t NumRead = fread(PListBuf, 1, (size_t)PListFileSize, PropertyList);
|
||||
if (NumRead != (size_t)PListFileSize)
|
||||
goto Fail;
|
||||
|
||||
/* Get the file buffer into CF's format. We pass in a null allocator here *
|
||||
* because we free PListBuf ourselves */
|
||||
FileContentsRef = (*CFDataCreateWithBytesNoCopyFunc)(
|
||||
NULL, PListBuf, (CFIndex)NumRead, kCFAllocatorNull);
|
||||
if (!FileContentsRef)
|
||||
goto Fail;
|
||||
|
||||
if (CFPropertyListCreateWithDataFunc)
|
||||
PListRef = (*CFPropertyListCreateWithDataFunc)(
|
||||
NULL, FileContentsRef, kCFPropertyListImmutable, NULL, NULL);
|
||||
else
|
||||
PListRef = (*CFPropertyListCreateFromXMLDataFunc)(
|
||||
NULL, FileContentsRef, kCFPropertyListImmutable, NULL);
|
||||
if (!PListRef)
|
||||
goto Fail;
|
||||
|
||||
CFStringRef ProductVersion = (*CFStringCreateWithCStringNoCopyFunc)(
|
||||
NULL, "ProductVersion", kCFStringEncodingASCII, kCFAllocatorNull);
|
||||
if (!ProductVersion)
|
||||
goto Fail;
|
||||
CFTypeRef OpaqueValue = (*CFDictionaryGetValueFunc)(PListRef, ProductVersion);
|
||||
(*CFReleaseFunc)(ProductVersion);
|
||||
if (!OpaqueValue ||
|
||||
(*CFGetTypeIDFunc)(OpaqueValue) != (*CFStringGetTypeIDFunc)())
|
||||
goto Fail;
|
||||
|
||||
char VersionStr[32];
|
||||
if (!(*CFStringGetCStringFunc)((CFStringRef)OpaqueValue, VersionStr,
|
||||
sizeof(VersionStr), kCFStringEncodingUTF8))
|
||||
goto Fail;
|
||||
sscanf(VersionStr, "%d.%d.%d", &GlobalMajor, &GlobalMinor, &GlobalSubminor);
|
||||
|
||||
Fail:
|
||||
if (PListRef)
|
||||
(*CFReleaseFunc)(PListRef);
|
||||
if (FileContentsRef)
|
||||
(*CFReleaseFunc)(FileContentsRef);
|
||||
free(PListBuf);
|
||||
fclose(PropertyList);
|
||||
}
|
||||
|
||||
int32_t __isOSVersionAtLeast(int32_t Major, int32_t Minor, int32_t Subminor) {
|
||||
/* Populate the global version variables, if they haven't already. */
|
||||
dispatch_once_f(&DispatchOnceCounter, NULL, parseSystemVersionPList);
|
||||
|
||||
if (Major < GlobalMajor) return 1;
|
||||
if (Major > GlobalMajor) return 0;
|
||||
if (Minor < GlobalMinor) return 1;
|
||||
if (Minor > GlobalMinor) return 0;
|
||||
return Subminor <= GlobalSubminor;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* Silence an empty translation unit warning. */
|
||||
typedef int unused;
|
||||
|
||||
#endif
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
/* double __floatdidf(di_int a); */
|
||||
|
||||
#ifdef __x86_64__
|
||||
#if defined(__x86_64__) || defined(_M_X64)
|
||||
|
||||
#include "../int_lib.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
* License. See LICENSE.TXT for details.
|
||||
*/
|
||||
|
||||
#ifdef __x86_64__
|
||||
#if defined(__x86_64__) || defined(_M_X64)
|
||||
|
||||
#include "../int_lib.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -188,12 +188,14 @@ uptr find_cfi_check_in_dso(dl_phdr_info *info) {
|
|||
}
|
||||
}
|
||||
if (!dynamic) return 0;
|
||||
uptr strtab = 0, symtab = 0;
|
||||
uptr strtab = 0, symtab = 0, strsz = 0;
|
||||
for (const ElfW(Dyn) *p = dynamic; p->d_tag != PT_NULL; ++p) {
|
||||
if (p->d_tag == DT_SYMTAB)
|
||||
symtab = p->d_un.d_ptr;
|
||||
else if (p->d_tag == DT_STRTAB)
|
||||
strtab = p->d_un.d_ptr;
|
||||
else if (p->d_tag == DT_STRSZ)
|
||||
strsz = p->d_un.d_ptr;
|
||||
}
|
||||
|
||||
if (symtab > strtab) {
|
||||
|
|
@ -209,7 +211,8 @@ uptr find_cfi_check_in_dso(dl_phdr_info *info) {
|
|||
if (phdr->p_type == PT_LOAD) {
|
||||
uptr beg = info->dlpi_addr + phdr->p_vaddr;
|
||||
uptr end = beg + phdr->p_memsz;
|
||||
if (strtab >= beg && strtab < end && symtab >= beg && symtab < end)
|
||||
if (strtab >= beg && strtab + strsz < end && symtab >= beg &&
|
||||
symtab < end)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -222,9 +225,14 @@ uptr find_cfi_check_in_dso(dl_phdr_info *info) {
|
|||
|
||||
for (const ElfW(Sym) *p = (const ElfW(Sym) *)symtab; (ElfW(Addr))p < strtab;
|
||||
++p) {
|
||||
// There is no reliable way to find the end of the symbol table. In
|
||||
// lld-produces files, there are other sections between symtab and strtab.
|
||||
// Stop looking when the symbol name is not inside strtab.
|
||||
if (p->st_name >= strsz) break;
|
||||
char *name = (char*)(strtab + p->st_name);
|
||||
if (strcmp(name, "__cfi_check") == 0) {
|
||||
assert(p->st_info == ELF32_ST_INFO(STB_GLOBAL, STT_FUNC));
|
||||
assert(p->st_info == ELF32_ST_INFO(STB_GLOBAL, STT_FUNC) ||
|
||||
p->st_info == ELF32_ST_INFO(STB_WEAK, STT_FUNC));
|
||||
uptr addr = info->dlpi_addr + p->st_value;
|
||||
return addr;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -304,20 +304,6 @@ INTERCEPTOR(int, unlink, char *path) {
|
|||
return REAL(unlink)(path);
|
||||
}
|
||||
|
||||
INTERCEPTOR(uptr, fread, void *ptr, uptr size, uptr nmemb, void *f) {
|
||||
void *ctx;
|
||||
COMMON_INTERCEPTOR_ENTER(ctx, fread, ptr, size, nmemb, f);
|
||||
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size * nmemb);
|
||||
return REAL(fread)(ptr, size, nmemb, f);
|
||||
}
|
||||
|
||||
INTERCEPTOR(uptr, fwrite, const void *p, uptr size, uptr nmemb, void *f) {
|
||||
void *ctx;
|
||||
COMMON_INTERCEPTOR_ENTER(ctx, fwrite, p, size, nmemb, f);
|
||||
COMMON_INTERCEPTOR_READ_RANGE(ctx, p, size * nmemb);
|
||||
return REAL(fwrite)(p, size, nmemb, f);
|
||||
}
|
||||
|
||||
INTERCEPTOR(int, puts, const char *s) {
|
||||
void *ctx;
|
||||
COMMON_INTERCEPTOR_ENTER(ctx, puts, s);
|
||||
|
|
|
|||
|
|
@ -878,6 +878,8 @@ uptr InternalGetProcAddress(void *module, const char *func_name) {
|
|||
|
||||
IMAGE_DATA_DIRECTORY *export_directory =
|
||||
&headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
|
||||
if (export_directory->Size == 0)
|
||||
return 0;
|
||||
RVAPtr<IMAGE_EXPORT_DIRECTORY> exports(module,
|
||||
export_directory->VirtualAddress);
|
||||
RVAPtr<DWORD> functions(module, exports->AddressOfFunctions);
|
||||
|
|
|
|||
|
|
@ -613,6 +613,13 @@ TEST(Interception, PatchableFunctionPadding) {
|
|||
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode6, override, prefix));
|
||||
}
|
||||
|
||||
TEST(Interception, EmptyExportTable) {
|
||||
// We try to get a pointer to a function from an executable that doesn't
|
||||
// export any symbol (empty export table).
|
||||
uptr FunPtr = InternalGetProcAddress((void *)GetModuleHandleA(0), "example");
|
||||
EXPECT_EQ(0U, FunPtr);
|
||||
}
|
||||
|
||||
} // namespace __interception
|
||||
|
||||
#endif // SANITIZER_WINDOWS
|
||||
|
|
|
|||
|
|
@ -5,12 +5,15 @@ append_rtti_flag(OFF LSAN_CFLAGS)
|
|||
|
||||
set(LSAN_COMMON_SOURCES
|
||||
lsan_common.cc
|
||||
lsan_common_linux.cc)
|
||||
lsan_common_linux.cc
|
||||
lsan_common_mac.cc)
|
||||
|
||||
set(LSAN_SOURCES
|
||||
lsan.cc
|
||||
lsan_allocator.cc
|
||||
lsan_linux.cc
|
||||
lsan_interceptors.cc
|
||||
lsan_malloc_mac.cc
|
||||
lsan_preinit.cc
|
||||
lsan_thread.cc)
|
||||
|
||||
|
|
@ -24,16 +27,34 @@ add_compiler_rt_object_libraries(RTLSanCommon
|
|||
|
||||
if(COMPILER_RT_HAS_LSAN)
|
||||
add_compiler_rt_component(lsan)
|
||||
foreach(arch ${LSAN_SUPPORTED_ARCH})
|
||||
if(APPLE)
|
||||
add_weak_symbols("lsan" WEAK_SYMBOL_LINK_FLAGS)
|
||||
add_weak_symbols("sanitizer_common" WEAK_SYMBOL_LINK_FLAGS)
|
||||
|
||||
add_compiler_rt_runtime(clang_rt.lsan
|
||||
STATIC
|
||||
ARCHS ${arch}
|
||||
SHARED
|
||||
OS ${SANITIZER_COMMON_SUPPORTED_OS}
|
||||
ARCHS ${LSAN_SUPPORTED_ARCH}
|
||||
SOURCES ${LSAN_SOURCES}
|
||||
$<TARGET_OBJECTS:RTInterception.${arch}>
|
||||
$<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
|
||||
$<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
|
||||
$<TARGET_OBJECTS:RTLSanCommon.${arch}>
|
||||
OBJECT_LIBS RTLSanCommon
|
||||
RTInterception
|
||||
RTSanitizerCommon
|
||||
RTSanitizerCommonLibc
|
||||
CFLAGS ${LSAN_CFLAGS}
|
||||
LINK_FLAGS ${WEAK_SYMBOL_LINK_FLAGS}
|
||||
PARENT_TARGET lsan)
|
||||
endforeach()
|
||||
else()
|
||||
foreach(arch ${LSAN_SUPPORTED_ARCH})
|
||||
add_compiler_rt_runtime(clang_rt.lsan
|
||||
STATIC
|
||||
ARCHS ${arch}
|
||||
SOURCES ${LSAN_SOURCES}
|
||||
$<TARGET_OBJECTS:RTInterception.${arch}>
|
||||
$<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
|
||||
$<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
|
||||
$<TARGET_OBJECTS:RTLSanCommon.${arch}>
|
||||
CFLAGS ${LSAN_CFLAGS}
|
||||
PARENT_TARGET lsan)
|
||||
endforeach()
|
||||
endif()
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ extern "C" void __lsan_init() {
|
|||
InitializeFlags();
|
||||
InitCommonLsan();
|
||||
InitializeAllocator();
|
||||
ReplaceSystemMalloc();
|
||||
InitTlsSize();
|
||||
InitializeInterceptors();
|
||||
InitializeThreadRegistry();
|
||||
|
|
|
|||
|
|
@ -41,6 +41,13 @@
|
|||
namespace __lsan {
|
||||
|
||||
void InitializeInterceptors();
|
||||
void ReplaceSystemMalloc();
|
||||
|
||||
#define ENSURE_LSAN_INITED do { \
|
||||
CHECK(!lsan_init_is_running); \
|
||||
if (!lsan_inited) \
|
||||
__lsan_init(); \
|
||||
} while (0)
|
||||
|
||||
} // namespace __lsan
|
||||
|
||||
|
|
|
|||
|
|
@ -24,44 +24,18 @@
|
|||
extern "C" void *memset(void *ptr, int value, uptr num);
|
||||
|
||||
namespace __lsan {
|
||||
|
||||
struct ChunkMetadata {
|
||||
u8 allocated : 8; // Must be first.
|
||||
ChunkTag tag : 2;
|
||||
uptr requested_size : 54;
|
||||
u32 stack_trace_id;
|
||||
};
|
||||
|
||||
#if defined(__mips64) || defined(__aarch64__)
|
||||
#if defined(__i386__) || defined(__arm__)
|
||||
static const uptr kMaxAllowedMallocSize = 1UL << 30;
|
||||
#elif defined(__mips64) || defined(__aarch64__)
|
||||
static const uptr kMaxAllowedMallocSize = 4UL << 30;
|
||||
static const uptr kRegionSizeLog = 20;
|
||||
static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog;
|
||||
typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap;
|
||||
typedef CompactSizeClassMap SizeClassMap;
|
||||
typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE,
|
||||
sizeof(ChunkMetadata), SizeClassMap, kRegionSizeLog, ByteMap>
|
||||
PrimaryAllocator;
|
||||
#else
|
||||
static const uptr kMaxAllowedMallocSize = 8UL << 30;
|
||||
|
||||
struct AP64 { // Allocator64 parameters. Deliberately using a short name.
|
||||
static const uptr kSpaceBeg = 0x600000000000ULL;
|
||||
static const uptr kSpaceSize = 0x40000000000ULL; // 4T.
|
||||
static const uptr kMetadataSize = sizeof(ChunkMetadata);
|
||||
typedef DefaultSizeClassMap SizeClassMap;
|
||||
typedef NoOpMapUnmapCallback MapUnmapCallback;
|
||||
static const uptr kFlags = 0;
|
||||
};
|
||||
|
||||
typedef SizeClassAllocator64<AP64> PrimaryAllocator;
|
||||
#endif
|
||||
typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
|
||||
typedef LargeMmapAllocator<> SecondaryAllocator;
|
||||
typedef CombinedAllocator<PrimaryAllocator, AllocatorCache,
|
||||
SecondaryAllocator> Allocator;
|
||||
|
||||
static Allocator allocator;
|
||||
static THREADLOCAL AllocatorCache cache;
|
||||
|
||||
void InitializeAllocator() {
|
||||
allocator.InitLinkerInitialized(
|
||||
|
|
@ -70,7 +44,7 @@ void InitializeAllocator() {
|
|||
}
|
||||
|
||||
void AllocatorThreadFinish() {
|
||||
allocator.SwallowCache(&cache);
|
||||
allocator.SwallowCache(GetAllocatorCache());
|
||||
}
|
||||
|
||||
static ChunkMetadata *Metadata(const void *p) {
|
||||
|
|
@ -102,7 +76,7 @@ void *Allocate(const StackTrace &stack, uptr size, uptr alignment,
|
|||
Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", size);
|
||||
return nullptr;
|
||||
}
|
||||
void *p = allocator.Allocate(&cache, size, alignment, false);
|
||||
void *p = allocator.Allocate(GetAllocatorCache(), size, alignment, false);
|
||||
// Do not rely on the allocator to clear the memory (it's slow).
|
||||
if (cleared && allocator.FromPrimary(p))
|
||||
memset(p, 0, size);
|
||||
|
|
@ -116,7 +90,7 @@ void Deallocate(void *p) {
|
|||
if (&__sanitizer_free_hook) __sanitizer_free_hook(p);
|
||||
RunFreeHooks(p);
|
||||
RegisterDeallocation(p);
|
||||
allocator.Deallocate(&cache, p);
|
||||
allocator.Deallocate(GetAllocatorCache(), p);
|
||||
}
|
||||
|
||||
void *Reallocate(const StackTrace &stack, void *p, uptr new_size,
|
||||
|
|
@ -124,17 +98,17 @@ void *Reallocate(const StackTrace &stack, void *p, uptr new_size,
|
|||
RegisterDeallocation(p);
|
||||
if (new_size > kMaxAllowedMallocSize) {
|
||||
Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", new_size);
|
||||
allocator.Deallocate(&cache, p);
|
||||
allocator.Deallocate(GetAllocatorCache(), p);
|
||||
return nullptr;
|
||||
}
|
||||
p = allocator.Reallocate(&cache, p, new_size, alignment);
|
||||
p = allocator.Reallocate(GetAllocatorCache(), p, new_size, alignment);
|
||||
RegisterAllocation(stack, p, new_size);
|
||||
return p;
|
||||
}
|
||||
|
||||
void GetAllocatorCacheRange(uptr *begin, uptr *end) {
|
||||
*begin = (uptr)&cache;
|
||||
*end = *begin + sizeof(cache);
|
||||
*begin = (uptr)GetAllocatorCache();
|
||||
*end = *begin + sizeof(AllocatorCache);
|
||||
}
|
||||
|
||||
uptr GetMallocUsableSize(const void *p) {
|
||||
|
|
@ -143,6 +117,37 @@ uptr GetMallocUsableSize(const void *p) {
|
|||
return m->requested_size;
|
||||
}
|
||||
|
||||
void *lsan_memalign(uptr alignment, uptr size, const StackTrace &stack) {
|
||||
return Allocate(stack, size, alignment, kAlwaysClearMemory);
|
||||
}
|
||||
|
||||
void *lsan_malloc(uptr size, const StackTrace &stack) {
|
||||
return Allocate(stack, size, 1, kAlwaysClearMemory);
|
||||
}
|
||||
|
||||
void lsan_free(void *p) {
|
||||
Deallocate(p);
|
||||
}
|
||||
|
||||
void *lsan_realloc(void *p, uptr size, const StackTrace &stack) {
|
||||
return Reallocate(stack, p, size, 1);
|
||||
}
|
||||
|
||||
void *lsan_calloc(uptr nmemb, uptr size, const StackTrace &stack) {
|
||||
size *= nmemb;
|
||||
return Allocate(stack, size, 1, true);
|
||||
}
|
||||
|
||||
void *lsan_valloc(uptr size, const StackTrace &stack) {
|
||||
if (size == 0)
|
||||
size = GetPageSizeCached();
|
||||
return Allocate(stack, size, GetPageSizeCached(), kAlwaysClearMemory);
|
||||
}
|
||||
|
||||
uptr lsan_mz_size(const void *p) {
|
||||
return GetMallocUsableSize(p);
|
||||
}
|
||||
|
||||
///// Interface to the common LSan module. /////
|
||||
|
||||
void LockAllocator() {
|
||||
|
|
|
|||
|
|
@ -15,8 +15,10 @@
|
|||
#ifndef LSAN_ALLOCATOR_H
|
||||
#define LSAN_ALLOCATOR_H
|
||||
|
||||
#include "sanitizer_common/sanitizer_allocator.h"
|
||||
#include "sanitizer_common/sanitizer_common.h"
|
||||
#include "sanitizer_common/sanitizer_internal_defs.h"
|
||||
#include "lsan_common.h"
|
||||
|
||||
namespace __lsan {
|
||||
|
||||
|
|
@ -34,6 +36,53 @@ void GetAllocatorCacheRange(uptr *begin, uptr *end);
|
|||
void AllocatorThreadFinish();
|
||||
void InitializeAllocator();
|
||||
|
||||
const bool kAlwaysClearMemory = true;
|
||||
|
||||
struct ChunkMetadata {
|
||||
u8 allocated : 8; // Must be first.
|
||||
ChunkTag tag : 2;
|
||||
#if SANITIZER_WORDSIZE == 64
|
||||
uptr requested_size : 54;
|
||||
#else
|
||||
uptr requested_size : 32;
|
||||
uptr padding : 22;
|
||||
#endif
|
||||
u32 stack_trace_id;
|
||||
};
|
||||
|
||||
#if defined(__mips64) || defined(__aarch64__) || defined(__i386__) || \
|
||||
defined(__arm__)
|
||||
static const uptr kRegionSizeLog = 20;
|
||||
static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog;
|
||||
typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap;
|
||||
typedef CompactSizeClassMap SizeClassMap;
|
||||
typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE,
|
||||
sizeof(ChunkMetadata), SizeClassMap, kRegionSizeLog, ByteMap>
|
||||
PrimaryAllocator;
|
||||
#elif defined(__x86_64__)
|
||||
struct AP64 { // Allocator64 parameters. Deliberately using a short name.
|
||||
static const uptr kSpaceBeg = 0x600000000000ULL;
|
||||
static const uptr kSpaceSize = 0x40000000000ULL; // 4T.
|
||||
static const uptr kMetadataSize = sizeof(ChunkMetadata);
|
||||
typedef DefaultSizeClassMap SizeClassMap;
|
||||
typedef NoOpMapUnmapCallback MapUnmapCallback;
|
||||
static const uptr kFlags = 0;
|
||||
};
|
||||
|
||||
typedef SizeClassAllocator64<AP64> PrimaryAllocator;
|
||||
#endif
|
||||
typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
|
||||
|
||||
AllocatorCache *GetAllocatorCache();
|
||||
|
||||
void *lsan_memalign(uptr alignment, uptr size, const StackTrace &stack);
|
||||
void *lsan_malloc(uptr size, const StackTrace &stack);
|
||||
void lsan_free(void *p);
|
||||
void *lsan_realloc(void *p, uptr size, const StackTrace &stack);
|
||||
void *lsan_calloc(uptr nmemb, uptr size, const StackTrace &stack);
|
||||
void *lsan_valloc(uptr size, const StackTrace &stack);
|
||||
uptr lsan_mz_size(const void *p);
|
||||
|
||||
} // namespace __lsan
|
||||
|
||||
#endif // LSAN_ALLOCATOR_H
|
||||
|
|
|
|||
|
|
@ -32,20 +32,15 @@ namespace __lsan {
|
|||
// also to protect the global list of root regions.
|
||||
BlockingMutex global_mutex(LINKER_INITIALIZED);
|
||||
|
||||
__attribute__((tls_model("initial-exec")))
|
||||
THREADLOCAL int disable_counter;
|
||||
bool DisabledInThisThread() { return disable_counter > 0; }
|
||||
void DisableInThisThread() { disable_counter++; }
|
||||
void EnableInThisThread() {
|
||||
if (!disable_counter && common_flags()->detect_leaks) {
|
||||
Flags lsan_flags;
|
||||
|
||||
void DisableCounterUnderflow() {
|
||||
if (common_flags()->detect_leaks) {
|
||||
Report("Unmatched call to __lsan_enable().\n");
|
||||
Die();
|
||||
}
|
||||
disable_counter--;
|
||||
}
|
||||
|
||||
Flags lsan_flags;
|
||||
|
||||
void Flags::SetDefaults() {
|
||||
#define LSAN_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue;
|
||||
#include "lsan_flags.inc"
|
||||
|
|
@ -180,6 +175,23 @@ void ScanRangeForPointers(uptr begin, uptr end,
|
|||
}
|
||||
}
|
||||
|
||||
// Scans a global range for pointers
|
||||
void ScanGlobalRange(uptr begin, uptr end, Frontier *frontier) {
|
||||
uptr allocator_begin = 0, allocator_end = 0;
|
||||
GetAllocatorGlobalRange(&allocator_begin, &allocator_end);
|
||||
if (begin <= allocator_begin && allocator_begin < end) {
|
||||
CHECK_LE(allocator_begin, allocator_end);
|
||||
CHECK_LE(allocator_end, end);
|
||||
if (begin < allocator_begin)
|
||||
ScanRangeForPointers(begin, allocator_begin, frontier, "GLOBAL",
|
||||
kReachable);
|
||||
if (allocator_end < end)
|
||||
ScanRangeForPointers(allocator_end, end, frontier, "GLOBAL", kReachable);
|
||||
} else {
|
||||
ScanRangeForPointers(begin, end, frontier, "GLOBAL", kReachable);
|
||||
}
|
||||
}
|
||||
|
||||
void ForEachExtraStackRangeCb(uptr begin, uptr end, void* arg) {
|
||||
Frontier *frontier = reinterpret_cast<Frontier *>(arg);
|
||||
ScanRangeForPointers(begin, end, frontier, "FAKE STACK", kReachable);
|
||||
|
|
@ -206,11 +218,13 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
|
|||
continue;
|
||||
}
|
||||
uptr sp;
|
||||
bool have_registers =
|
||||
(suspended_threads.GetRegistersAndSP(i, registers.data(), &sp) == 0);
|
||||
if (!have_registers) {
|
||||
Report("Unable to get registers from thread %d.\n");
|
||||
// If unable to get SP, consider the entire stack to be reachable.
|
||||
PtraceRegistersStatus have_registers =
|
||||
suspended_threads.GetRegistersAndSP(i, registers.data(), &sp);
|
||||
if (have_registers != REGISTERS_AVAILABLE) {
|
||||
Report("Unable to get registers from thread %d.\n", os_id);
|
||||
// If unable to get SP, consider the entire stack to be reachable unless
|
||||
// GetRegistersAndSP failed with ESRCH.
|
||||
if (have_registers == REGISTERS_UNAVAILABLE_FATAL) continue;
|
||||
sp = stack_begin;
|
||||
}
|
||||
|
||||
|
|
@ -258,7 +272,7 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
|
|||
if (tls_end > cache_end)
|
||||
ScanRangeForPointers(cache_end, tls_end, frontier, "TLS", kReachable);
|
||||
}
|
||||
if (dtls) {
|
||||
if (dtls && !DTLSInDestruction(dtls)) {
|
||||
for (uptr j = 0; j < dtls->dtv_size; ++j) {
|
||||
uptr dtls_beg = dtls->dtv[j].beg;
|
||||
uptr dtls_end = dtls_beg + dtls->dtv[j].size;
|
||||
|
|
@ -268,6 +282,10 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
|
|||
kReachable);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// We are handling a thread with DTLS under destruction. Log about
|
||||
// this and continue.
|
||||
LOG_THREADS("Thread %d has DTLS under destruction.\n", os_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,8 +22,23 @@
|
|||
#include "sanitizer_common/sanitizer_stoptheworld.h"
|
||||
#include "sanitizer_common/sanitizer_symbolizer.h"
|
||||
|
||||
#if (SANITIZER_LINUX && !SANITIZER_ANDROID) && (SANITIZER_WORDSIZE == 64) \
|
||||
&& (defined(__x86_64__) || defined(__mips64) || defined(__aarch64__))
|
||||
// LeakSanitizer relies on some Glibc's internals (e.g. TLS machinery) thus
|
||||
// supported for Linux only. Also, LSan doesn't like 32 bit architectures
|
||||
// because of "small" (4 bytes) pointer size that leads to high false negative
|
||||
// ratio on large leaks. But we still want to have it for some 32 bit arches
|
||||
// (e.g. x86), see https://github.com/google/sanitizers/issues/403.
|
||||
// To enable LeakSanitizer on new architecture, one need to implement
|
||||
// internal_clone function as well as (probably) adjust TLS machinery for
|
||||
// new architecture inside sanitizer library.
|
||||
#if (SANITIZER_LINUX && !SANITIZER_ANDROID || SANITIZER_MAC) && \
|
||||
(SANITIZER_WORDSIZE == 64) && \
|
||||
(defined(__x86_64__) || defined(__mips64) || defined(__aarch64__))
|
||||
#define CAN_SANITIZE_LEAKS 1
|
||||
#elif defined(__i386__) && \
|
||||
(SANITIZER_LINUX && !SANITIZER_ANDROID || SANITIZER_MAC)
|
||||
#define CAN_SANITIZE_LEAKS 1
|
||||
#elif defined(__arm__) && \
|
||||
SANITIZER_LINUX && !SANITIZER_ANDROID
|
||||
#define CAN_SANITIZE_LEAKS 1
|
||||
#else
|
||||
#define CAN_SANITIZE_LEAKS 0
|
||||
|
|
@ -44,6 +59,8 @@ enum ChunkTag {
|
|||
kIgnored = 3
|
||||
};
|
||||
|
||||
const u32 kInvalidTid = (u32) -1;
|
||||
|
||||
struct Flags {
|
||||
#define LSAN_FLAG(Type, Name, DefaultValue, Description) Type Name;
|
||||
#include "lsan_flags.inc"
|
||||
|
|
@ -107,6 +124,7 @@ void DoStopTheWorld(StopTheWorldCallback callback, void* argument);
|
|||
void ScanRangeForPointers(uptr begin, uptr end,
|
||||
Frontier *frontier,
|
||||
const char *region_type, ChunkTag tag);
|
||||
void ScanGlobalRange(uptr begin, uptr end, Frontier *frontier);
|
||||
|
||||
enum IgnoreObjectResult {
|
||||
kIgnoreObjectSuccess,
|
||||
|
|
@ -117,6 +135,7 @@ enum IgnoreObjectResult {
|
|||
// Functions called from the parent tool.
|
||||
void InitCommonLsan();
|
||||
void DoLeakCheck();
|
||||
void DisableCounterUnderflow();
|
||||
bool DisabledInThisThread();
|
||||
|
||||
// Used to implement __lsan::ScopedDisabler.
|
||||
|
|
@ -129,15 +148,38 @@ struct ScopedInterceptorDisabler {
|
|||
~ScopedInterceptorDisabler() { EnableInThisThread(); }
|
||||
};
|
||||
|
||||
// Special case for "new T[0]" where T is a type with DTOR.
|
||||
// new T[0] will allocate one word for the array size (0) and store a pointer
|
||||
// to the end of allocated chunk.
|
||||
inline bool IsSpecialCaseOfOperatorNew0(uptr chunk_beg, uptr chunk_size,
|
||||
uptr addr) {
|
||||
// According to Itanium C++ ABI array cookie is a one word containing
|
||||
// size of allocated array.
|
||||
static inline bool IsItaniumABIArrayCookie(uptr chunk_beg, uptr chunk_size,
|
||||
uptr addr) {
|
||||
return chunk_size == sizeof(uptr) && chunk_beg + chunk_size == addr &&
|
||||
*reinterpret_cast<uptr *>(chunk_beg) == 0;
|
||||
}
|
||||
|
||||
// According to ARM C++ ABI array cookie consists of two words:
|
||||
// struct array_cookie {
|
||||
// std::size_t element_size; // element_size != 0
|
||||
// std::size_t element_count;
|
||||
// };
|
||||
static inline bool IsARMABIArrayCookie(uptr chunk_beg, uptr chunk_size,
|
||||
uptr addr) {
|
||||
return chunk_size == 2 * sizeof(uptr) && chunk_beg + chunk_size == addr &&
|
||||
*reinterpret_cast<uptr *>(chunk_beg + sizeof(uptr)) == 0;
|
||||
}
|
||||
|
||||
// Special case for "new T[0]" where T is a type with DTOR.
|
||||
// new T[0] will allocate a cookie (one or two words) for the array size (0)
|
||||
// and store a pointer to the end of allocated chunk. The actual cookie layout
|
||||
// varies between platforms according to their C++ ABI implementation.
|
||||
inline bool IsSpecialCaseOfOperatorNew0(uptr chunk_beg, uptr chunk_size,
|
||||
uptr addr) {
|
||||
#if defined(__arm__)
|
||||
return IsARMABIArrayCookie(chunk_beg, chunk_size, addr);
|
||||
#else
|
||||
return IsItaniumABIArrayCookie(chunk_beg, chunk_size, addr);
|
||||
#endif
|
||||
}
|
||||
|
||||
// The following must be implemented in the parent tool.
|
||||
|
||||
void ForEachChunk(ForEachChunkCallback callback, void *arg);
|
||||
|
|
|
|||
|
|
@ -34,6 +34,17 @@ static bool IsLinker(const char* full_name) {
|
|||
return LibraryNameIs(full_name, kLinkerName);
|
||||
}
|
||||
|
||||
__attribute__((tls_model("initial-exec")))
|
||||
THREADLOCAL int disable_counter;
|
||||
bool DisabledInThisThread() { return disable_counter > 0; }
|
||||
void DisableInThisThread() { disable_counter++; }
|
||||
void EnableInThisThread() {
|
||||
if (disable_counter == 0) {
|
||||
DisableCounterUnderflow();
|
||||
}
|
||||
disable_counter--;
|
||||
}
|
||||
|
||||
void InitializePlatformSpecificModules() {
|
||||
ListOfModules modules;
|
||||
modules.init();
|
||||
|
|
@ -67,20 +78,7 @@ static int ProcessGlobalRegionsCallback(struct dl_phdr_info *info, size_t size,
|
|||
continue;
|
||||
uptr begin = info->dlpi_addr + phdr->p_vaddr;
|
||||
uptr end = begin + phdr->p_memsz;
|
||||
uptr allocator_begin = 0, allocator_end = 0;
|
||||
GetAllocatorGlobalRange(&allocator_begin, &allocator_end);
|
||||
if (begin <= allocator_begin && allocator_begin < end) {
|
||||
CHECK_LE(allocator_begin, allocator_end);
|
||||
CHECK_LE(allocator_end, end);
|
||||
if (begin < allocator_begin)
|
||||
ScanRangeForPointers(begin, allocator_begin, frontier, "GLOBAL",
|
||||
kReachable);
|
||||
if (allocator_end < end)
|
||||
ScanRangeForPointers(allocator_end, end, frontier, "GLOBAL",
|
||||
kReachable);
|
||||
} else {
|
||||
ScanRangeForPointers(begin, end, frontier, "GLOBAL", kReachable);
|
||||
}
|
||||
ScanGlobalRange(begin, end, frontier);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
126
lib/lsan/lsan_common_mac.cc
Normal file
126
lib/lsan/lsan_common_mac.cc
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
//=-- lsan_common_mac.cc --------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of LeakSanitizer.
|
||||
// Implementation of common leak checking functionality. Darwin-specific code.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "sanitizer_common/sanitizer_platform.h"
|
||||
#include "lsan_common.h"
|
||||
|
||||
#if CAN_SANITIZE_LEAKS && SANITIZER_MAC
|
||||
|
||||
#include "sanitizer_common/sanitizer_allocator_internal.h"
|
||||
#include "lsan_allocator.h"
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
namespace __lsan {
|
||||
|
||||
typedef struct {
|
||||
int disable_counter;
|
||||
u32 current_thread_id;
|
||||
AllocatorCache cache;
|
||||
} thread_local_data_t;
|
||||
|
||||
static pthread_key_t key;
|
||||
static pthread_once_t key_once = PTHREAD_ONCE_INIT;
|
||||
|
||||
// The main thread destructor requires the current thread id,
|
||||
// so we can't destroy it until it's been used and reset to invalid tid
|
||||
void restore_tid_data(void *ptr) {
|
||||
thread_local_data_t *data = (thread_local_data_t *)ptr;
|
||||
if (data->current_thread_id != kInvalidTid)
|
||||
pthread_setspecific(key, data);
|
||||
}
|
||||
|
||||
static void make_tls_key() {
|
||||
CHECK_EQ(pthread_key_create(&key, restore_tid_data), 0);
|
||||
}
|
||||
|
||||
static thread_local_data_t *get_tls_val(bool alloc) {
|
||||
pthread_once(&key_once, make_tls_key);
|
||||
|
||||
thread_local_data_t *ptr = (thread_local_data_t *)pthread_getspecific(key);
|
||||
if (ptr == NULL && alloc) {
|
||||
ptr = (thread_local_data_t *)InternalAlloc(sizeof(*ptr));
|
||||
ptr->disable_counter = 0;
|
||||
ptr->current_thread_id = kInvalidTid;
|
||||
ptr->cache = AllocatorCache();
|
||||
pthread_setspecific(key, ptr);
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
bool DisabledInThisThread() {
|
||||
thread_local_data_t *data = get_tls_val(false);
|
||||
return data ? data->disable_counter > 0 : false;
|
||||
}
|
||||
|
||||
void DisableInThisThread() { ++get_tls_val(true)->disable_counter; }
|
||||
|
||||
void EnableInThisThread() {
|
||||
int *disable_counter = &get_tls_val(true)->disable_counter;
|
||||
if (*disable_counter == 0) {
|
||||
DisableCounterUnderflow();
|
||||
}
|
||||
--*disable_counter;
|
||||
}
|
||||
|
||||
u32 GetCurrentThread() {
|
||||
thread_local_data_t *data = get_tls_val(false);
|
||||
CHECK(data);
|
||||
return data->current_thread_id;
|
||||
}
|
||||
|
||||
void SetCurrentThread(u32 tid) { get_tls_val(true)->current_thread_id = tid; }
|
||||
|
||||
AllocatorCache *GetAllocatorCache() { return &get_tls_val(true)->cache; }
|
||||
|
||||
// Required on Linux for initialization of TLS behavior, but should not be
|
||||
// required on Darwin.
|
||||
void InitializePlatformSpecificModules() {
|
||||
if (flags()->use_tls) {
|
||||
Report("use_tls=1 is not supported on Darwin.\n");
|
||||
Die();
|
||||
}
|
||||
}
|
||||
|
||||
// Scans global variables for heap pointers.
|
||||
void ProcessGlobalRegions(Frontier *frontier) {
|
||||
MemoryMappingLayout memory_mapping(false);
|
||||
InternalMmapVector<LoadedModule> modules(/*initial_capacity*/ 128);
|
||||
memory_mapping.DumpListOfModules(&modules);
|
||||
for (uptr i = 0; i < modules.size(); ++i) {
|
||||
// Even when global scanning is disabled, we still need to scan
|
||||
// system libraries for stashed pointers
|
||||
if (!flags()->use_globals && modules[i].instrumented()) continue;
|
||||
|
||||
for (const __sanitizer::LoadedModule::AddressRange &range :
|
||||
modules[i].ranges()) {
|
||||
if (range.executable) continue;
|
||||
|
||||
ScanGlobalRange(range.beg, range.end, frontier);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessPlatformSpecificAllocations(Frontier *frontier) {
|
||||
CHECK(0 && "unimplemented");
|
||||
}
|
||||
|
||||
void DoStopTheWorld(StopTheWorldCallback callback, void *argument) {
|
||||
CHECK(0 && "unimplemented");
|
||||
}
|
||||
|
||||
} // namespace __lsan
|
||||
|
||||
#endif // CAN_SANITIZE_LEAKS && SANITIZER_MAC
|
||||
|
|
@ -30,7 +30,7 @@ LSAN_FLAG(bool, use_globals, true,
|
|||
"Root set: include global variables (.data and .bss)")
|
||||
LSAN_FLAG(bool, use_stacks, true, "Root set: include thread stacks")
|
||||
LSAN_FLAG(bool, use_registers, true, "Root set: include thread registers")
|
||||
LSAN_FLAG(bool, use_tls, true,
|
||||
LSAN_FLAG(bool, use_tls, !SANITIZER_MAC,
|
||||
"Root set: include TLS and thread-specific storage")
|
||||
LSAN_FLAG(bool, use_root_regions, true,
|
||||
"Root set: include regions added via __lsan_register_root_region().")
|
||||
|
|
|
|||
|
|
@ -21,12 +21,15 @@
|
|||
#include "sanitizer_common/sanitizer_linux.h"
|
||||
#include "sanitizer_common/sanitizer_platform_interceptors.h"
|
||||
#include "sanitizer_common/sanitizer_platform_limits_posix.h"
|
||||
#include "sanitizer_common/sanitizer_posix.h"
|
||||
#include "sanitizer_common/sanitizer_tls_get_addr.h"
|
||||
#include "lsan.h"
|
||||
#include "lsan_allocator.h"
|
||||
#include "lsan_common.h"
|
||||
#include "lsan_thread.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
using namespace __lsan;
|
||||
|
||||
extern "C" {
|
||||
|
|
@ -37,29 +40,22 @@ int pthread_key_create(unsigned *key, void (*destructor)(void* v));
|
|||
int pthread_setspecific(unsigned key, const void *v);
|
||||
}
|
||||
|
||||
#define ENSURE_LSAN_INITED do { \
|
||||
CHECK(!lsan_init_is_running); \
|
||||
if (!lsan_inited) \
|
||||
__lsan_init(); \
|
||||
} while (0)
|
||||
|
||||
///// Malloc/free interceptors. /////
|
||||
|
||||
const bool kAlwaysClearMemory = true;
|
||||
|
||||
namespace std {
|
||||
struct nothrow_t;
|
||||
}
|
||||
|
||||
#if !SANITIZER_MAC
|
||||
INTERCEPTOR(void*, malloc, uptr size) {
|
||||
ENSURE_LSAN_INITED;
|
||||
GET_STACK_TRACE_MALLOC;
|
||||
return Allocate(stack, size, 1, kAlwaysClearMemory);
|
||||
return lsan_malloc(size, stack);
|
||||
}
|
||||
|
||||
INTERCEPTOR(void, free, void *p) {
|
||||
ENSURE_LSAN_INITED;
|
||||
Deallocate(p);
|
||||
lsan_free(p);
|
||||
}
|
||||
|
||||
INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
|
||||
|
|
@ -77,28 +73,42 @@ INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
|
|||
if (CallocShouldReturnNullDueToOverflow(size, nmemb)) return nullptr;
|
||||
ENSURE_LSAN_INITED;
|
||||
GET_STACK_TRACE_MALLOC;
|
||||
size *= nmemb;
|
||||
return Allocate(stack, size, 1, true);
|
||||
return lsan_calloc(nmemb, size, stack);
|
||||
}
|
||||
|
||||
INTERCEPTOR(void*, realloc, void *q, uptr size) {
|
||||
ENSURE_LSAN_INITED;
|
||||
GET_STACK_TRACE_MALLOC;
|
||||
return Reallocate(stack, q, size, 1);
|
||||
return lsan_realloc(q, size, stack);
|
||||
}
|
||||
|
||||
INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) {
|
||||
ENSURE_LSAN_INITED;
|
||||
GET_STACK_TRACE_MALLOC;
|
||||
*memptr = lsan_memalign(alignment, size, stack);
|
||||
// FIXME: Return ENOMEM if user requested more than max alloc size.
|
||||
return 0;
|
||||
}
|
||||
|
||||
INTERCEPTOR(void*, valloc, uptr size) {
|
||||
ENSURE_LSAN_INITED;
|
||||
GET_STACK_TRACE_MALLOC;
|
||||
return lsan_valloc(size, stack);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SANITIZER_INTERCEPT_MEMALIGN
|
||||
INTERCEPTOR(void*, memalign, uptr alignment, uptr size) {
|
||||
ENSURE_LSAN_INITED;
|
||||
GET_STACK_TRACE_MALLOC;
|
||||
return Allocate(stack, size, alignment, kAlwaysClearMemory);
|
||||
return lsan_memalign(alignment, size, stack);
|
||||
}
|
||||
#define LSAN_MAYBE_INTERCEPT_MEMALIGN INTERCEPT_FUNCTION(memalign)
|
||||
|
||||
INTERCEPTOR(void *, __libc_memalign, uptr alignment, uptr size) {
|
||||
ENSURE_LSAN_INITED;
|
||||
GET_STACK_TRACE_MALLOC;
|
||||
void *res = Allocate(stack, size, alignment, kAlwaysClearMemory);
|
||||
void *res = lsan_memalign(alignment, size, stack);
|
||||
DTLS_on_libc_memalign(res, size);
|
||||
return res;
|
||||
}
|
||||
|
|
@ -108,32 +118,27 @@ INTERCEPTOR(void *, __libc_memalign, uptr alignment, uptr size) {
|
|||
#define LSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN
|
||||
#endif // SANITIZER_INTERCEPT_MEMALIGN
|
||||
|
||||
#if SANITIZER_INTERCEPT_ALIGNED_ALLOC
|
||||
INTERCEPTOR(void*, aligned_alloc, uptr alignment, uptr size) {
|
||||
ENSURE_LSAN_INITED;
|
||||
GET_STACK_TRACE_MALLOC;
|
||||
return Allocate(stack, size, alignment, kAlwaysClearMemory);
|
||||
}
|
||||
|
||||
INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) {
|
||||
ENSURE_LSAN_INITED;
|
||||
GET_STACK_TRACE_MALLOC;
|
||||
*memptr = Allocate(stack, size, alignment, kAlwaysClearMemory);
|
||||
// FIXME: Return ENOMEM if user requested more than max alloc size.
|
||||
return 0;
|
||||
}
|
||||
|
||||
INTERCEPTOR(void*, valloc, uptr size) {
|
||||
ENSURE_LSAN_INITED;
|
||||
GET_STACK_TRACE_MALLOC;
|
||||
if (size == 0)
|
||||
size = GetPageSizeCached();
|
||||
return Allocate(stack, size, GetPageSizeCached(), kAlwaysClearMemory);
|
||||
return lsan_memalign(alignment, size, stack);
|
||||
}
|
||||
#define LSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC INTERCEPT_FUNCTION(aligned_alloc)
|
||||
#else
|
||||
#define LSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC
|
||||
#endif
|
||||
|
||||
#if SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE
|
||||
INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {
|
||||
ENSURE_LSAN_INITED;
|
||||
return GetMallocUsableSize(ptr);
|
||||
}
|
||||
#define LSAN_MAYBE_INTERCEPT_MALLOC_USABLE_SIZE \
|
||||
INTERCEPT_FUNCTION(malloc_usable_size)
|
||||
#else
|
||||
#define LSAN_MAYBE_INTERCEPT_MALLOC_USABLE_SIZE
|
||||
#endif
|
||||
|
||||
#if SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO
|
||||
struct fake_mallinfo {
|
||||
|
|
@ -186,13 +191,13 @@ INTERCEPTOR(void, cfree, void *p) ALIAS(WRAPPER_NAME(free));
|
|||
return Allocate(stack, size, 1, kAlwaysClearMemory);
|
||||
|
||||
INTERCEPTOR_ATTRIBUTE
|
||||
void *operator new(uptr size) { OPERATOR_NEW_BODY; }
|
||||
void *operator new(size_t size) { OPERATOR_NEW_BODY; }
|
||||
INTERCEPTOR_ATTRIBUTE
|
||||
void *operator new[](uptr size) { OPERATOR_NEW_BODY; }
|
||||
void *operator new[](size_t size) { OPERATOR_NEW_BODY; }
|
||||
INTERCEPTOR_ATTRIBUTE
|
||||
void *operator new(uptr size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
|
||||
void *operator new(size_t size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
|
||||
INTERCEPTOR_ATTRIBUTE
|
||||
void *operator new[](uptr size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
|
||||
void *operator new[](size_t size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
|
||||
|
||||
#define OPERATOR_DELETE_BODY \
|
||||
ENSURE_LSAN_INITED; \
|
||||
|
|
@ -277,7 +282,8 @@ INTERCEPTOR(int, pthread_create, void *th, void *attr,
|
|||
res = REAL(pthread_create)(th, attr, __lsan_thread_start_func, &p);
|
||||
}
|
||||
if (res == 0) {
|
||||
int tid = ThreadCreate(GetCurrentThread(), *(uptr *)th, detached);
|
||||
int tid = ThreadCreate(GetCurrentThread(), *(uptr *)th,
|
||||
IsStateDetached(detached));
|
||||
CHECK_NE(tid, 0);
|
||||
atomic_store(&p.tid, tid, memory_order_release);
|
||||
while (atomic_load(&p.tid, memory_order_acquire) != 0)
|
||||
|
|
@ -307,11 +313,11 @@ void InitializeInterceptors() {
|
|||
INTERCEPT_FUNCTION(realloc);
|
||||
LSAN_MAYBE_INTERCEPT_MEMALIGN;
|
||||
LSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN;
|
||||
INTERCEPT_FUNCTION(aligned_alloc);
|
||||
LSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC;
|
||||
INTERCEPT_FUNCTION(posix_memalign);
|
||||
INTERCEPT_FUNCTION(valloc);
|
||||
LSAN_MAYBE_INTERCEPT_PVALLOC;
|
||||
INTERCEPT_FUNCTION(malloc_usable_size);
|
||||
LSAN_MAYBE_INTERCEPT_MALLOC_USABLE_SIZE;
|
||||
LSAN_MAYBE_INTERCEPT_MALLINFO;
|
||||
LSAN_MAYBE_INTERCEPT_MALLOPT;
|
||||
INTERCEPT_FUNCTION(pthread_create);
|
||||
|
|
|
|||
33
lib/lsan/lsan_linux.cc
Normal file
33
lib/lsan/lsan_linux.cc
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
//=-- lsan_linux.cc -------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of LeakSanitizer. Linux-specific code.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "sanitizer_common/sanitizer_platform.h"
|
||||
|
||||
#if SANITIZER_LINUX
|
||||
|
||||
#include "lsan_allocator.h"
|
||||
|
||||
namespace __lsan {
|
||||
|
||||
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 ReplaceSystemMalloc() {}
|
||||
|
||||
} // namespace __lsan
|
||||
|
||||
#endif // SANITIZER_LINUX
|
||||
55
lib/lsan/lsan_malloc_mac.cc
Normal file
55
lib/lsan/lsan_malloc_mac.cc
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
//===-- lsan_malloc_mac.cc ------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of LeakSanitizer (LSan), a memory leak detector.
|
||||
//
|
||||
// Mac-specific malloc interception.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "sanitizer_common/sanitizer_platform.h"
|
||||
#if SANITIZER_MAC
|
||||
|
||||
#include "lsan.h"
|
||||
#include "lsan_allocator.h"
|
||||
#include "lsan_thread.h"
|
||||
|
||||
using namespace __lsan;
|
||||
#define COMMON_MALLOC_ZONE_NAME "lsan"
|
||||
#define COMMON_MALLOC_ENTER() ENSURE_LSAN_INITED
|
||||
#define COMMON_MALLOC_SANITIZER_INITIALIZED lsan_inited
|
||||
#define COMMON_MALLOC_FORCE_LOCK()
|
||||
#define COMMON_MALLOC_FORCE_UNLOCK()
|
||||
#define COMMON_MALLOC_MEMALIGN(alignment, size) \
|
||||
GET_STACK_TRACE_MALLOC; \
|
||||
void *p = lsan_memalign(alignment, size, stack)
|
||||
#define COMMON_MALLOC_MALLOC(size) \
|
||||
GET_STACK_TRACE_MALLOC; \
|
||||
void *p = lsan_malloc(size, stack)
|
||||
#define COMMON_MALLOC_REALLOC(ptr, size) \
|
||||
GET_STACK_TRACE_MALLOC; \
|
||||
void *p = lsan_realloc(ptr, size, stack)
|
||||
#define COMMON_MALLOC_CALLOC(count, size) \
|
||||
GET_STACK_TRACE_MALLOC; \
|
||||
void *p = lsan_calloc(count, size, stack)
|
||||
#define COMMON_MALLOC_VALLOC(size) \
|
||||
GET_STACK_TRACE_MALLOC; \
|
||||
void *p = lsan_valloc(size, stack)
|
||||
#define COMMON_MALLOC_FREE(ptr) \
|
||||
lsan_free(ptr)
|
||||
#define COMMON_MALLOC_SIZE(ptr) \
|
||||
uptr size = lsan_mz_size(ptr)
|
||||
#define COMMON_MALLOC_FILL_STATS(zone, stats)
|
||||
#define COMMON_MALLOC_REPORT_UNKNOWN_REALLOC(ptr, zone_ptr, zone_name) \
|
||||
(void)zone_name; \
|
||||
Report("mz_realloc(%p) -- attempting to realloc unallocated memory.\n", ptr);
|
||||
#define COMMON_MALLOC_NAMESPACE __lsan
|
||||
|
||||
#include "sanitizer_common/sanitizer_malloc_mac.inc"
|
||||
|
||||
#endif // SANITIZER_MAC
|
||||
|
|
@ -19,13 +19,11 @@
|
|||
#include "sanitizer_common/sanitizer_thread_registry.h"
|
||||
#include "sanitizer_common/sanitizer_tls_get_addr.h"
|
||||
#include "lsan_allocator.h"
|
||||
#include "lsan_common.h"
|
||||
|
||||
namespace __lsan {
|
||||
|
||||
const u32 kInvalidTid = (u32) -1;
|
||||
|
||||
static ThreadRegistry *thread_registry;
|
||||
static THREADLOCAL u32 current_thread_tid = kInvalidTid;
|
||||
|
||||
static ThreadContextBase *CreateThreadContext(u32 tid) {
|
||||
void *mem = MmapOrDie(sizeof(ThreadContext), "ThreadContext");
|
||||
|
|
@ -41,14 +39,6 @@ void InitializeThreadRegistry() {
|
|||
ThreadRegistry(CreateThreadContext, kMaxThreads, kThreadQuarantineSize);
|
||||
}
|
||||
|
||||
u32 GetCurrentThread() {
|
||||
return current_thread_tid;
|
||||
}
|
||||
|
||||
void SetCurrentThread(u32 tid) {
|
||||
current_thread_tid = tid;
|
||||
}
|
||||
|
||||
ThreadContext::ThreadContext(int tid)
|
||||
: ThreadContextBase(tid),
|
||||
stack_begin_(0),
|
||||
|
|
@ -97,11 +87,12 @@ void ThreadStart(u32 tid, uptr os_id) {
|
|||
args.tls_end = args.tls_begin + tls_size;
|
||||
GetAllocatorCacheRange(&args.cache_begin, &args.cache_end);
|
||||
args.dtls = DTLS_Get();
|
||||
thread_registry->StartThread(tid, os_id, &args);
|
||||
thread_registry->StartThread(tid, os_id, /*workerthread*/ false, &args);
|
||||
}
|
||||
|
||||
void ThreadFinish() {
|
||||
thread_registry->FinishThread(GetCurrentThread());
|
||||
SetCurrentThread(kInvalidTid);
|
||||
}
|
||||
|
||||
ThreadContext *CurrentThreadContext() {
|
||||
|
|
|
|||
2
lib/lsan/weak_symbols.txt
Normal file
2
lib/lsan/weak_symbols.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
___lsan_default_suppressions
|
||||
___lsan_is_turned_off
|
||||
|
|
@ -123,14 +123,6 @@ static void *AllocateFromLocalPool(uptr size_in_bytes) {
|
|||
#define CHECK_UNPOISONED_STRING(x, n) \
|
||||
CHECK_UNPOISONED_STRING_OF_LEN((x), internal_strlen(x), (n))
|
||||
|
||||
INTERCEPTOR(SIZE_T, fread, void *ptr, SIZE_T size, SIZE_T nmemb, void *file) {
|
||||
ENSURE_MSAN_INITED();
|
||||
SIZE_T res = REAL(fread)(ptr, size, nmemb, file);
|
||||
if (res > 0)
|
||||
__msan_unpoison(ptr, res *size);
|
||||
return res;
|
||||
}
|
||||
|
||||
#if !SANITIZER_FREEBSD
|
||||
INTERCEPTOR(SIZE_T, fread_unlocked, void *ptr, SIZE_T size, SIZE_T nmemb,
|
||||
void *file) {
|
||||
|
|
@ -580,6 +572,13 @@ INTERCEPTOR(SIZE_T, wcslen, const wchar_t *s) {
|
|||
return res;
|
||||
}
|
||||
|
||||
INTERCEPTOR(SIZE_T, wcsnlen, const wchar_t *s, SIZE_T n) {
|
||||
ENSURE_MSAN_INITED();
|
||||
SIZE_T res = REAL(wcsnlen)(s, n);
|
||||
CHECK_UNPOISONED(s, sizeof(wchar_t) * Min(res + 1, n));
|
||||
return res;
|
||||
}
|
||||
|
||||
// wchar_t *wcschr(const wchar_t *wcs, wchar_t wc);
|
||||
INTERCEPTOR(wchar_t *, wcschr, void *s, wchar_t wc, void *ps) {
|
||||
ENSURE_MSAN_INITED();
|
||||
|
|
@ -597,6 +596,18 @@ INTERCEPTOR(wchar_t *, wcscpy, wchar_t *dest, const wchar_t *src) {
|
|||
return res;
|
||||
}
|
||||
|
||||
INTERCEPTOR(wchar_t *, wcsncpy, wchar_t *dest, const wchar_t *src,
|
||||
SIZE_T n) { // NOLINT
|
||||
ENSURE_MSAN_INITED();
|
||||
GET_STORE_STACK_TRACE;
|
||||
SIZE_T copy_size = REAL(wcsnlen)(src, n);
|
||||
if (copy_size < n) copy_size++; // trailing \0
|
||||
wchar_t *res = REAL(wcsncpy)(dest, src, n); // NOLINT
|
||||
CopyShadowAndOrigin(dest, src, copy_size * sizeof(wchar_t), &stack);
|
||||
__msan_unpoison(dest + copy_size, (n - copy_size) * sizeof(wchar_t));
|
||||
return res;
|
||||
}
|
||||
|
||||
// wchar_t *wmemcpy(wchar_t *dest, const wchar_t *src, SIZE_T n);
|
||||
INTERCEPTOR(wchar_t *, wmemcpy, wchar_t *dest, const wchar_t *src, SIZE_T n) {
|
||||
ENSURE_MSAN_INITED();
|
||||
|
|
@ -1565,8 +1576,10 @@ void InitializeInterceptors() {
|
|||
INTERCEPT_FUNCTION(mbtowc);
|
||||
INTERCEPT_FUNCTION(mbrtowc);
|
||||
INTERCEPT_FUNCTION(wcslen);
|
||||
INTERCEPT_FUNCTION(wcsnlen);
|
||||
INTERCEPT_FUNCTION(wcschr);
|
||||
INTERCEPT_FUNCTION(wcscpy);
|
||||
INTERCEPT_FUNCTION(wcsncpy);
|
||||
INTERCEPT_FUNCTION(wcscmp);
|
||||
INTERCEPT_FUNCTION(getenv);
|
||||
INTERCEPT_FUNCTION(setenv);
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ set(MSAN_UNITTEST_COMMON_CFLAGS
|
|||
-Wno-zero-length-array
|
||||
-Wno-uninitialized
|
||||
-Werror=sign-compare
|
||||
-Wno-gnu-zero-variadic-macro-arguments
|
||||
)
|
||||
set(MSAN_UNITTEST_INSTRUMENTED_CFLAGS
|
||||
${MSAN_UNITTEST_COMMON_CFLAGS}
|
||||
|
|
|
|||
|
|
@ -175,10 +175,16 @@ void ExpectPoisonedWithOrigin(const T& t, unsigned origin) {
|
|||
}
|
||||
|
||||
#define EXPECT_NOT_POISONED(x) EXPECT_EQ(true, TestForNotPoisoned((x)))
|
||||
#define EXPECT_NOT_POISONED2(data, size) \
|
||||
EXPECT_EQ(true, TestForNotPoisoned((data), (size)))
|
||||
|
||||
bool TestForNotPoisoned(const void *data, size_t size) {
|
||||
return __msan_test_shadow(data, size) == -1;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool TestForNotPoisoned(const T& t) {
|
||||
return __msan_test_shadow((void*)&t, sizeof(t)) == -1;
|
||||
return TestForNotPoisoned((void *)&t, sizeof(t));
|
||||
}
|
||||
|
||||
static U8 poisoned_array[100];
|
||||
|
|
@ -879,92 +885,203 @@ TEST(MemorySanitizer, bind_getsockname) {
|
|||
close(sock);
|
||||
}
|
||||
|
||||
TEST(MemorySanitizer, accept) {
|
||||
int listen_socket = socket(AF_INET, SOCK_STREAM, 0);
|
||||
class SocketAddr {
|
||||
public:
|
||||
virtual ~SocketAddr() = default;
|
||||
virtual struct sockaddr *ptr() = 0;
|
||||
virtual size_t size() const = 0;
|
||||
|
||||
template <class... Args>
|
||||
static std::unique_ptr<SocketAddr> Create(int family, Args... args);
|
||||
};
|
||||
|
||||
class SocketAddr4 : public SocketAddr {
|
||||
public:
|
||||
SocketAddr4() { EXPECT_POISONED(sai_); }
|
||||
explicit SocketAddr4(uint16_t port) {
|
||||
memset(&sai_, 0, sizeof(sai_));
|
||||
sai_.sin_family = AF_INET;
|
||||
sai_.sin_port = port;
|
||||
sai_.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
}
|
||||
|
||||
sockaddr *ptr() override { return reinterpret_cast<sockaddr *>(&sai_); }
|
||||
|
||||
size_t size() const override { return sizeof(sai_); }
|
||||
|
||||
private:
|
||||
sockaddr_in sai_;
|
||||
};
|
||||
|
||||
class SocketAddr6 : public SocketAddr {
|
||||
public:
|
||||
SocketAddr6() { EXPECT_POISONED(sai_); }
|
||||
explicit SocketAddr6(uint16_t port) {
|
||||
memset(&sai_, 0, sizeof(sai_));
|
||||
sai_.sin6_family = AF_INET6;
|
||||
sai_.sin6_port = port;
|
||||
sai_.sin6_addr = in6addr_loopback;
|
||||
}
|
||||
|
||||
sockaddr *ptr() override { return reinterpret_cast<sockaddr *>(&sai_); }
|
||||
|
||||
size_t size() const override { return sizeof(sai_); }
|
||||
|
||||
private:
|
||||
sockaddr_in6 sai_;
|
||||
};
|
||||
|
||||
template <class... Args>
|
||||
std::unique_ptr<SocketAddr> SocketAddr::Create(int family, Args... args) {
|
||||
if (family == AF_INET)
|
||||
return std::unique_ptr<SocketAddr>(new SocketAddr4(args...));
|
||||
return std::unique_ptr<SocketAddr>(new SocketAddr6(args...));
|
||||
}
|
||||
|
||||
class MemorySanitizerIpTest : public ::testing::TestWithParam<int> {
|
||||
public:
|
||||
void SetUp() override {
|
||||
ASSERT_TRUE(GetParam() == AF_INET || GetParam() == AF_INET6);
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
std::unique_ptr<SocketAddr> CreateSockAddr(Args... args) const {
|
||||
return SocketAddr::Create(GetParam(), args...);
|
||||
}
|
||||
|
||||
int CreateSocket(int socket_type) const {
|
||||
return socket(GetParam(), socket_type, 0);
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<int> GetAvailableIpSocketFamilies() {
|
||||
std::vector<int> result;
|
||||
|
||||
for (int i : {AF_INET, AF_INET6}) {
|
||||
int s = socket(i, SOCK_STREAM, 0);
|
||||
if (s > 0) {
|
||||
auto sai = SocketAddr::Create(i, 0);
|
||||
if (bind(s, sai->ptr(), sai->size()) == 0) result.push_back(i);
|
||||
close(s);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(IpTests, MemorySanitizerIpTest,
|
||||
::testing::ValuesIn(GetAvailableIpSocketFamilies()));
|
||||
|
||||
TEST_P(MemorySanitizerIpTest, accept) {
|
||||
int listen_socket = CreateSocket(SOCK_STREAM);
|
||||
ASSERT_LT(0, listen_socket);
|
||||
|
||||
struct sockaddr_in sai;
|
||||
memset(&sai, 0, sizeof(sai));
|
||||
sai.sin_family = AF_INET;
|
||||
sai.sin_port = 0;
|
||||
sai.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
int res = bind(listen_socket, (struct sockaddr *)&sai, sizeof(sai));
|
||||
auto sai = CreateSockAddr(0);
|
||||
int res = bind(listen_socket, sai->ptr(), sai->size());
|
||||
ASSERT_EQ(0, res);
|
||||
|
||||
res = listen(listen_socket, 1);
|
||||
ASSERT_EQ(0, res);
|
||||
|
||||
socklen_t sz = sizeof(sai);
|
||||
res = getsockname(listen_socket, (struct sockaddr *)&sai, &sz);
|
||||
socklen_t sz = sai->size();
|
||||
res = getsockname(listen_socket, sai->ptr(), &sz);
|
||||
ASSERT_EQ(0, res);
|
||||
ASSERT_EQ(sizeof(sai), sz);
|
||||
ASSERT_EQ(sai->size(), sz);
|
||||
|
||||
int connect_socket = socket(AF_INET, SOCK_STREAM, 0);
|
||||
int connect_socket = CreateSocket(SOCK_STREAM);
|
||||
ASSERT_LT(0, connect_socket);
|
||||
res = fcntl(connect_socket, F_SETFL, O_NONBLOCK);
|
||||
ASSERT_EQ(0, res);
|
||||
res = connect(connect_socket, (struct sockaddr *)&sai, sizeof(sai));
|
||||
res = connect(connect_socket, sai->ptr(), sai->size());
|
||||
// On FreeBSD this connection completes immediately.
|
||||
if (res != 0) {
|
||||
ASSERT_EQ(-1, res);
|
||||
ASSERT_EQ(EINPROGRESS, errno);
|
||||
}
|
||||
|
||||
__msan_poison(&sai, sizeof(sai));
|
||||
int new_sock = accept(listen_socket, (struct sockaddr *)&sai, &sz);
|
||||
__msan_poison(sai->ptr(), sai->size());
|
||||
int new_sock = accept(listen_socket, sai->ptr(), &sz);
|
||||
ASSERT_LT(0, new_sock);
|
||||
ASSERT_EQ(sizeof(sai), sz);
|
||||
EXPECT_NOT_POISONED(sai);
|
||||
ASSERT_EQ(sai->size(), sz);
|
||||
EXPECT_NOT_POISONED2(sai->ptr(), sai->size());
|
||||
|
||||
__msan_poison(&sai, sizeof(sai));
|
||||
res = getpeername(new_sock, (struct sockaddr *)&sai, &sz);
|
||||
__msan_poison(sai->ptr(), sai->size());
|
||||
res = getpeername(new_sock, sai->ptr(), &sz);
|
||||
ASSERT_EQ(0, res);
|
||||
ASSERT_EQ(sizeof(sai), sz);
|
||||
EXPECT_NOT_POISONED(sai);
|
||||
ASSERT_EQ(sai->size(), sz);
|
||||
EXPECT_NOT_POISONED2(sai->ptr(), sai->size());
|
||||
|
||||
close(new_sock);
|
||||
close(connect_socket);
|
||||
close(listen_socket);
|
||||
}
|
||||
|
||||
TEST(MemorySanitizer, getaddrinfo) {
|
||||
struct addrinfo *ai;
|
||||
struct addrinfo hints;
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = AF_INET;
|
||||
int res = getaddrinfo("localhost", NULL, &hints, &ai);
|
||||
ASSERT_EQ(0, res);
|
||||
EXPECT_NOT_POISONED(*ai);
|
||||
ASSERT_EQ(sizeof(sockaddr_in), ai->ai_addrlen);
|
||||
EXPECT_NOT_POISONED(*(sockaddr_in*)ai->ai_addr);
|
||||
}
|
||||
TEST_P(MemorySanitizerIpTest, recvmsg) {
|
||||
int server_socket = CreateSocket(SOCK_DGRAM);
|
||||
ASSERT_LT(0, server_socket);
|
||||
|
||||
TEST(MemorySanitizer, getnameinfo) {
|
||||
struct sockaddr_in sai;
|
||||
memset(&sai, 0, sizeof(sai));
|
||||
sai.sin_family = AF_INET;
|
||||
sai.sin_port = 80;
|
||||
sai.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
char host[500];
|
||||
char serv[500];
|
||||
int res = getnameinfo((struct sockaddr *)&sai, sizeof(sai), host,
|
||||
sizeof(host), serv, sizeof(serv), 0);
|
||||
auto sai = CreateSockAddr(0);
|
||||
int res = bind(server_socket, sai->ptr(), sai->size());
|
||||
ASSERT_EQ(0, res);
|
||||
EXPECT_NOT_POISONED(host[0]);
|
||||
EXPECT_POISONED(host[sizeof(host) - 1]);
|
||||
|
||||
ASSERT_NE(0U, strlen(host));
|
||||
EXPECT_NOT_POISONED(serv[0]);
|
||||
EXPECT_POISONED(serv[sizeof(serv) - 1]);
|
||||
ASSERT_NE(0U, strlen(serv));
|
||||
socklen_t sz = sai->size();
|
||||
res = getsockname(server_socket, sai->ptr(), &sz);
|
||||
ASSERT_EQ(0, res);
|
||||
ASSERT_EQ(sai->size(), sz);
|
||||
|
||||
int client_socket = CreateSocket(SOCK_DGRAM);
|
||||
ASSERT_LT(0, client_socket);
|
||||
|
||||
auto client_sai = CreateSockAddr(0);
|
||||
res = bind(client_socket, client_sai->ptr(), client_sai->size());
|
||||
ASSERT_EQ(0, res);
|
||||
|
||||
sz = client_sai->size();
|
||||
res = getsockname(client_socket, client_sai->ptr(), &sz);
|
||||
ASSERT_EQ(0, res);
|
||||
ASSERT_EQ(client_sai->size(), sz);
|
||||
|
||||
const char *s = "message text";
|
||||
struct iovec iov;
|
||||
iov.iov_base = (void *)s;
|
||||
iov.iov_len = strlen(s) + 1;
|
||||
struct msghdr msg;
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.msg_name = sai->ptr();
|
||||
msg.msg_namelen = sai->size();
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
res = sendmsg(client_socket, &msg, 0);
|
||||
ASSERT_LT(0, res);
|
||||
|
||||
char buf[1000];
|
||||
struct iovec recv_iov;
|
||||
recv_iov.iov_base = (void *)&buf;
|
||||
recv_iov.iov_len = sizeof(buf);
|
||||
auto recv_sai = CreateSockAddr();
|
||||
struct msghdr recv_msg;
|
||||
memset(&recv_msg, 0, sizeof(recv_msg));
|
||||
recv_msg.msg_name = recv_sai->ptr();
|
||||
recv_msg.msg_namelen = recv_sai->size();
|
||||
recv_msg.msg_iov = &recv_iov;
|
||||
recv_msg.msg_iovlen = 1;
|
||||
res = recvmsg(server_socket, &recv_msg, 0);
|
||||
ASSERT_LT(0, res);
|
||||
|
||||
ASSERT_EQ(recv_sai->size(), recv_msg.msg_namelen);
|
||||
EXPECT_NOT_POISONED2(recv_sai->ptr(), recv_sai->size());
|
||||
EXPECT_STREQ(s, buf);
|
||||
|
||||
close(server_socket);
|
||||
close(client_socket);
|
||||
}
|
||||
|
||||
#define EXPECT_HOSTENT_NOT_POISONED(he) \
|
||||
do { \
|
||||
EXPECT_NOT_POISONED(*(he)); \
|
||||
ASSERT_NE((void *) 0, (he)->h_name); \
|
||||
ASSERT_NE((void *) 0, (he)->h_aliases); \
|
||||
ASSERT_NE((void *) 0, (he)->h_addr_list); \
|
||||
ASSERT_NE((void *)0, (he)->h_name); \
|
||||
ASSERT_NE((void *)0, (he)->h_aliases); \
|
||||
ASSERT_NE((void *)0, (he)->h_addr_list); \
|
||||
EXPECT_NOT_POISONED(strlen((he)->h_name)); \
|
||||
char **p = (he)->h_aliases; \
|
||||
while (*p) { \
|
||||
|
|
@ -993,76 +1110,38 @@ TEST(MemorySanitizer, gethostbyname) {
|
|||
EXPECT_HOSTENT_NOT_POISONED(he);
|
||||
}
|
||||
|
||||
#endif // MSAN_TEST_DISABLE_GETHOSTBYNAME
|
||||
#endif // MSAN_TEST_DISABLE_GETHOSTBYNAME
|
||||
|
||||
TEST(MemorySanitizer, recvmsg) {
|
||||
int server_socket = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
ASSERT_LT(0, server_socket);
|
||||
TEST(MemorySanitizer, getaddrinfo) {
|
||||
struct addrinfo *ai;
|
||||
struct addrinfo hints;
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = AF_INET;
|
||||
int res = getaddrinfo("localhost", NULL, &hints, &ai);
|
||||
ASSERT_EQ(0, res);
|
||||
EXPECT_NOT_POISONED(*ai);
|
||||
ASSERT_EQ(sizeof(sockaddr_in), ai->ai_addrlen);
|
||||
EXPECT_NOT_POISONED(*(sockaddr_in *)ai->ai_addr);
|
||||
}
|
||||
|
||||
TEST(MemorySanitizer, getnameinfo) {
|
||||
struct sockaddr_in sai;
|
||||
memset(&sai, 0, sizeof(sai));
|
||||
sai.sin_family = AF_INET;
|
||||
sai.sin_port = 0;
|
||||
sai.sin_port = 80;
|
||||
sai.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
int res = bind(server_socket, (struct sockaddr *)&sai, sizeof(sai));
|
||||
char host[500];
|
||||
char serv[500];
|
||||
int res = getnameinfo((struct sockaddr *)&sai, sizeof(sai), host,
|
||||
sizeof(host), serv, sizeof(serv), 0);
|
||||
ASSERT_EQ(0, res);
|
||||
EXPECT_NOT_POISONED(host[0]);
|
||||
EXPECT_POISONED(host[sizeof(host) - 1]);
|
||||
|
||||
socklen_t sz = sizeof(sai);
|
||||
res = getsockname(server_socket, (struct sockaddr *)&sai, &sz);
|
||||
ASSERT_EQ(0, res);
|
||||
ASSERT_EQ(sizeof(sai), sz);
|
||||
|
||||
|
||||
int client_socket = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
ASSERT_LT(0, client_socket);
|
||||
|
||||
struct sockaddr_in client_sai;
|
||||
memset(&client_sai, 0, sizeof(client_sai));
|
||||
client_sai.sin_family = AF_INET;
|
||||
client_sai.sin_port = 0;
|
||||
client_sai.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
res = bind(client_socket, (struct sockaddr *)&client_sai, sizeof(client_sai));
|
||||
ASSERT_EQ(0, res);
|
||||
|
||||
sz = sizeof(client_sai);
|
||||
res = getsockname(client_socket, (struct sockaddr *)&client_sai, &sz);
|
||||
ASSERT_EQ(0, res);
|
||||
ASSERT_EQ(sizeof(client_sai), sz);
|
||||
|
||||
const char *s = "message text";
|
||||
struct iovec iov;
|
||||
iov.iov_base = (void *)s;
|
||||
iov.iov_len = strlen(s) + 1;
|
||||
struct msghdr msg;
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.msg_name = &sai;
|
||||
msg.msg_namelen = sizeof(sai);
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
res = sendmsg(client_socket, &msg, 0);
|
||||
ASSERT_LT(0, res);
|
||||
|
||||
|
||||
char buf[1000];
|
||||
struct iovec recv_iov;
|
||||
recv_iov.iov_base = (void *)&buf;
|
||||
recv_iov.iov_len = sizeof(buf);
|
||||
struct sockaddr_in recv_sai;
|
||||
struct msghdr recv_msg;
|
||||
memset(&recv_msg, 0, sizeof(recv_msg));
|
||||
recv_msg.msg_name = &recv_sai;
|
||||
recv_msg.msg_namelen = sizeof(recv_sai);
|
||||
recv_msg.msg_iov = &recv_iov;
|
||||
recv_msg.msg_iovlen = 1;
|
||||
res = recvmsg(server_socket, &recv_msg, 0);
|
||||
ASSERT_LT(0, res);
|
||||
|
||||
ASSERT_EQ(sizeof(recv_sai), recv_msg.msg_namelen);
|
||||
EXPECT_NOT_POISONED(*(struct sockaddr_in *)recv_msg.msg_name);
|
||||
EXPECT_STREQ(s, buf);
|
||||
|
||||
close(server_socket);
|
||||
close(client_socket);
|
||||
ASSERT_NE(0U, strlen(host));
|
||||
EXPECT_NOT_POISONED(serv[0]);
|
||||
EXPECT_POISONED(serv[sizeof(serv) - 1]);
|
||||
ASSERT_NE(0U, strlen(serv));
|
||||
}
|
||||
|
||||
TEST(MemorySanitizer, gethostbyname2) {
|
||||
|
|
@ -3502,6 +3581,21 @@ TEST(MemorySanitizer, getgroups) {
|
|||
EXPECT_NOT_POISONED(gids[i]);
|
||||
}
|
||||
|
||||
TEST(MemorySanitizer, getgroups_zero) {
|
||||
gid_t group;
|
||||
int n = getgroups(0, &group);
|
||||
ASSERT_GE(n, 0);
|
||||
}
|
||||
|
||||
TEST(MemorySanitizer, getgroups_negative) {
|
||||
gid_t group;
|
||||
int n = getgroups(-1, 0);
|
||||
ASSERT_EQ(-1, n);
|
||||
|
||||
n = getgroups(-1, 0);
|
||||
ASSERT_EQ(-1, n);
|
||||
}
|
||||
|
||||
TEST(MemorySanitizer, wordexp) {
|
||||
wordexp_t w;
|
||||
int res = wordexp("a b c", &w, 0);
|
||||
|
|
@ -3602,6 +3696,18 @@ TEST(MemorySanitizer, ICmpVectorRelational) {
|
|||
EXPECT_POISONED(_mm_cmpgt_epi16(poisoned(_mm_set1_epi16(6), _mm_set1_epi16(0xF)),
|
||||
poisoned(_mm_set1_epi16(7), _mm_set1_epi16(0))));
|
||||
}
|
||||
|
||||
TEST(MemorySanitizer, stmxcsr_ldmxcsr) {
|
||||
U4 x = _mm_getcsr();
|
||||
EXPECT_NOT_POISONED(x);
|
||||
|
||||
_mm_setcsr(x);
|
||||
|
||||
__msan_poison(&x, sizeof(x));
|
||||
U4 origin = __LINE__;
|
||||
__msan_set_origin(&x, sizeof(x), origin);
|
||||
EXPECT_UMR_O(_mm_setcsr(x), origin);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Volatile bitfield store is implemented as load-mask-store
|
||||
|
|
|
|||
|
|
@ -153,7 +153,17 @@ INSTR_PROF_RAW_HEADER(uint64_t, ValueKindLast, IPVK_Last)
|
|||
VALUE_PROF_FUNC_PARAM(uint64_t, TargetValue, Type::getInt64Ty(Ctx)) \
|
||||
INSTR_PROF_COMMA
|
||||
VALUE_PROF_FUNC_PARAM(void *, Data, Type::getInt8PtrTy(Ctx)) INSTR_PROF_COMMA
|
||||
#ifndef VALUE_RANGE_PROF
|
||||
VALUE_PROF_FUNC_PARAM(uint32_t, CounterIndex, Type::getInt32Ty(Ctx))
|
||||
#else /* VALUE_RANGE_PROF */
|
||||
VALUE_PROF_FUNC_PARAM(uint32_t, CounterIndex, Type::getInt32Ty(Ctx)) \
|
||||
INSTR_PROF_COMMA
|
||||
VALUE_PROF_FUNC_PARAM(uint64_t, PreciseRangeStart, Type::getInt64Ty(Ctx)) \
|
||||
INSTR_PROF_COMMA
|
||||
VALUE_PROF_FUNC_PARAM(uint64_t, PreciseRangeLast, Type::getInt64Ty(Ctx)) \
|
||||
INSTR_PROF_COMMA
|
||||
VALUE_PROF_FUNC_PARAM(uint64_t, LargeValue, Type::getInt64Ty(Ctx))
|
||||
#endif /*VALUE_RANGE_PROF */
|
||||
#undef VALUE_PROF_FUNC_PARAM
|
||||
#undef INSTR_PROF_COMMA
|
||||
/* VALUE_PROF_FUNC_PARAM end */
|
||||
|
|
@ -174,13 +184,15 @@ VALUE_PROF_FUNC_PARAM(uint32_t, CounterIndex, Type::getInt32Ty(Ctx))
|
|||
* name hash and the function address.
|
||||
*/
|
||||
VALUE_PROF_KIND(IPVK_IndirectCallTarget, 0)
|
||||
/* For memory intrinsic functions size profiling. */
|
||||
VALUE_PROF_KIND(IPVK_MemOPSize, 1)
|
||||
/* These two kinds must be the last to be
|
||||
* declared. This is to make sure the string
|
||||
* array created with the template can be
|
||||
* indexed with the kind value.
|
||||
*/
|
||||
VALUE_PROF_KIND(IPVK_First, IPVK_IndirectCallTarget)
|
||||
VALUE_PROF_KIND(IPVK_Last, IPVK_IndirectCallTarget)
|
||||
VALUE_PROF_KIND(IPVK_Last, IPVK_MemOPSize)
|
||||
|
||||
#undef VALUE_PROF_KIND
|
||||
/* VALUE_PROF_KIND end */
|
||||
|
|
@ -234,6 +246,31 @@ COVMAP_HEADER(uint32_t, Int32Ty, Version, \
|
|||
/* COVMAP_HEADER end. */
|
||||
|
||||
|
||||
#ifdef INSTR_PROF_SECT_ENTRY
|
||||
#define INSTR_PROF_DATA_DEFINED
|
||||
INSTR_PROF_SECT_ENTRY(IPSK_data, \
|
||||
INSTR_PROF_QUOTE(INSTR_PROF_DATA_COMMON), \
|
||||
INSTR_PROF_QUOTE(INSTR_PROF_DATA_COFF), "__DATA,")
|
||||
INSTR_PROF_SECT_ENTRY(IPSK_cnts, \
|
||||
INSTR_PROF_QUOTE(INSTR_PROF_CNTS_COMMON), \
|
||||
INSTR_PROF_QUOTE(INSTR_PROF_CNTS_COFF), "__DATA,")
|
||||
INSTR_PROF_SECT_ENTRY(IPSK_name, \
|
||||
INSTR_PROF_QUOTE(INSTR_PROF_NAME_COMMON), \
|
||||
INSTR_PROF_QUOTE(INSTR_PROF_NAME_COFF), "__DATA,")
|
||||
INSTR_PROF_SECT_ENTRY(IPSK_vals, \
|
||||
INSTR_PROF_QUOTE(INSTR_PROF_VALS_COMMON), \
|
||||
INSTR_PROF_QUOTE(INSTR_PROF_VALS_COFF), "__DATA,")
|
||||
INSTR_PROF_SECT_ENTRY(IPSK_vnodes, \
|
||||
INSTR_PROF_QUOTE(INSTR_PROF_VNODES_COMMON), \
|
||||
INSTR_PROF_QUOTE(INSTR_PROF_VNODES_COFF), "__DATA,")
|
||||
INSTR_PROF_SECT_ENTRY(IPSK_covmap, \
|
||||
INSTR_PROF_QUOTE(INSTR_PROF_COVMAP_COMMON), \
|
||||
INSTR_PROF_QUOTE(INSTR_PROF_COVMAP_COFF), "__LLVM_COV,")
|
||||
|
||||
#undef INSTR_PROF_SECT_ENTRY
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef INSTR_PROF_VALUE_PROF_DATA
|
||||
#define INSTR_PROF_DATA_DEFINED
|
||||
|
||||
|
|
@ -610,17 +647,47 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
|
|||
* specified via command line. */
|
||||
#define INSTR_PROF_PROFILE_NAME_VAR __llvm_profile_filename
|
||||
|
||||
/* section name strings common to all targets other
|
||||
than WIN32 */
|
||||
#define INSTR_PROF_DATA_COMMON __llvm_prf_data
|
||||
#define INSTR_PROF_NAME_COMMON __llvm_prf_names
|
||||
#define INSTR_PROF_CNTS_COMMON __llvm_prf_cnts
|
||||
#define INSTR_PROF_VALS_COMMON __llvm_prf_vals
|
||||
#define INSTR_PROF_VNODES_COMMON __llvm_prf_vnds
|
||||
#define INSTR_PROF_COVMAP_COMMON __llvm_covmap
|
||||
/* Win32 */
|
||||
#define INSTR_PROF_DATA_COFF .lprfd
|
||||
#define INSTR_PROF_NAME_COFF .lprfn
|
||||
#define INSTR_PROF_CNTS_COFF .lprfc
|
||||
#define INSTR_PROF_VALS_COFF .lprfv
|
||||
#define INSTR_PROF_VNODES_COFF .lprfnd
|
||||
#define INSTR_PROF_COVMAP_COFF .lcovmap
|
||||
|
||||
#ifdef _WIN32
|
||||
/* Runtime section names and name strings. */
|
||||
#define INSTR_PROF_DATA_SECT_NAME __llvm_prf_data
|
||||
#define INSTR_PROF_NAME_SECT_NAME __llvm_prf_names
|
||||
#define INSTR_PROF_CNTS_SECT_NAME __llvm_prf_cnts
|
||||
#define INSTR_PROF_DATA_SECT_NAME INSTR_PROF_DATA_COFF
|
||||
#define INSTR_PROF_NAME_SECT_NAME INSTR_PROF_NAME_COFF
|
||||
#define INSTR_PROF_CNTS_SECT_NAME INSTR_PROF_CNTS_COFF
|
||||
/* Array of pointers. Each pointer points to a list
|
||||
* of value nodes associated with one value site.
|
||||
*/
|
||||
#define INSTR_PROF_VALS_SECT_NAME __llvm_prf_vals
|
||||
#define INSTR_PROF_VALS_SECT_NAME INSTR_PROF_VALS_COFF
|
||||
/* Value profile nodes section. */
|
||||
#define INSTR_PROF_VNODES_SECT_NAME __llvm_prf_vnds
|
||||
#define INSTR_PROF_COVMAP_SECT_NAME __llvm_covmap
|
||||
#define INSTR_PROF_VNODES_SECT_NAME INSTR_PROF_VNODES_COFF
|
||||
#define INSTR_PROF_COVMAP_SECT_NAME INSTR_PROF_COVMAP_COFF
|
||||
#else
|
||||
/* Runtime section names and name strings. */
|
||||
#define INSTR_PROF_DATA_SECT_NAME INSTR_PROF_DATA_COMMON
|
||||
#define INSTR_PROF_NAME_SECT_NAME INSTR_PROF_NAME_COMMON
|
||||
#define INSTR_PROF_CNTS_SECT_NAME INSTR_PROF_CNTS_COMMON
|
||||
/* Array of pointers. Each pointer points to a list
|
||||
* of value nodes associated with one value site.
|
||||
*/
|
||||
#define INSTR_PROF_VALS_SECT_NAME INSTR_PROF_VALS_COMMON
|
||||
/* Value profile nodes section. */
|
||||
#define INSTR_PROF_VNODES_SECT_NAME INSTR_PROF_VNODES_COMMON
|
||||
#define INSTR_PROF_COVMAP_SECT_NAME INSTR_PROF_COVMAP_COMMON
|
||||
#endif
|
||||
|
||||
#define INSTR_PROF_DATA_SECT_NAME_STR \
|
||||
INSTR_PROF_QUOTE(INSTR_PROF_DATA_SECT_NAME)
|
||||
|
|
@ -649,6 +716,9 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
|
|||
#define INSTR_PROF_VALUE_PROF_FUNC __llvm_profile_instrument_target
|
||||
#define INSTR_PROF_VALUE_PROF_FUNC_STR \
|
||||
INSTR_PROF_QUOTE(INSTR_PROF_VALUE_PROF_FUNC)
|
||||
#define INSTR_PROF_VALUE_RANGE_PROF_FUNC __llvm_profile_instrument_range
|
||||
#define INSTR_PROF_VALUE_RANGE_PROF_FUNC_STR \
|
||||
INSTR_PROF_QUOTE(INSTR_PROF_VALUE_RANGE_PROF_FUNC)
|
||||
|
||||
/* InstrProfile per-function control data alignment. */
|
||||
#define INSTR_PROF_DATA_ALIGNMENT 8
|
||||
|
|
|
|||
|
|
@ -172,6 +172,16 @@ static int doProfileMerging(FILE *ProfileFile) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Create the directory holding the file, if needed. */
|
||||
static void createProfileDir(const char *Filename) {
|
||||
size_t Length = strlen(Filename);
|
||||
if (lprofFindFirstDirSeparator(Filename)) {
|
||||
char *Copy = (char *)COMPILER_RT_ALLOCA(Length + 1);
|
||||
strncpy(Copy, Filename, Length + 1);
|
||||
__llvm_profile_recursive_mkdir(Copy);
|
||||
}
|
||||
}
|
||||
|
||||
/* Open the profile data for merging. It opens the file in r+b mode with
|
||||
* file locking. If the file has content which is compatible with the
|
||||
* current process, it also reads in the profile data in the file and merge
|
||||
|
|
@ -184,6 +194,7 @@ static FILE *openFileForMerging(const char *ProfileFileName) {
|
|||
FILE *ProfileFile;
|
||||
int rc;
|
||||
|
||||
createProfileDir(ProfileFileName);
|
||||
ProfileFile = lprofOpenFileEx(ProfileFileName);
|
||||
if (!ProfileFile)
|
||||
return NULL;
|
||||
|
|
@ -233,18 +244,13 @@ static void truncateCurrentFile(void) {
|
|||
if (!Filename)
|
||||
return;
|
||||
|
||||
/* Create the directory holding the file, if needed. */
|
||||
if (lprofFindFirstDirSeparator(Filename)) {
|
||||
char *Copy = (char *)COMPILER_RT_ALLOCA(Length + 1);
|
||||
strncpy(Copy, Filename, Length + 1);
|
||||
__llvm_profile_recursive_mkdir(Copy);
|
||||
}
|
||||
|
||||
/* By pass file truncation to allow online raw profile
|
||||
* merging. */
|
||||
if (lprofCurFilename.MergePoolSize)
|
||||
return;
|
||||
|
||||
createProfileDir(Filename);
|
||||
|
||||
/* Truncate the file. Later we'll reopen and append. */
|
||||
File = fopen(Filename, "w");
|
||||
if (!File)
|
||||
|
|
@ -524,6 +530,7 @@ int __llvm_profile_write_file(void) {
|
|||
int rc, Length;
|
||||
const char *Filename;
|
||||
char *FilenameBuf;
|
||||
int PDeathSig = 0;
|
||||
|
||||
if (lprofProfileDumped()) {
|
||||
PROF_NOTE("Profile data not written to file: %s.\n",
|
||||
|
|
@ -550,10 +557,18 @@ int __llvm_profile_write_file(void) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
// Temporarily suspend getting SIGKILL when the parent exits.
|
||||
PDeathSig = lprofSuspendSigKill();
|
||||
|
||||
/* Write profile data to the file. */
|
||||
rc = writeFile(Filename);
|
||||
if (rc)
|
||||
PROF_ERR("Failed to write file \"%s\": %s\n", Filename, strerror(errno));
|
||||
|
||||
// Restore SIGKILL.
|
||||
if (PDeathSig == 1)
|
||||
lprofRestoreSigKill();
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,11 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <signal.h>
|
||||
#include <sys/prctl.h>
|
||||
#endif
|
||||
|
||||
COMPILER_RT_VISIBILITY
|
||||
void __llvm_profile_recursive_mkdir(char *path) {
|
||||
int i;
|
||||
|
|
@ -219,3 +224,21 @@ COMPILER_RT_VISIBILITY const char *lprofFindLastDirSeparator(const char *Path) {
|
|||
#endif
|
||||
return Sep;
|
||||
}
|
||||
|
||||
COMPILER_RT_VISIBILITY int lprofSuspendSigKill() {
|
||||
#if defined(__linux__)
|
||||
int PDeachSig = 0;
|
||||
/* Temporarily suspend getting SIGKILL upon exit of the parent process. */
|
||||
if (prctl(PR_GET_PDEATHSIG, &PDeachSig) == 0 && PDeachSig == SIGKILL)
|
||||
prctl(PR_SET_PDEATHSIG, 0);
|
||||
return (PDeachSig == SIGKILL);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
COMPILER_RT_VISIBILITY void lprofRestoreSigKill() {
|
||||
#if defined(__linux__)
|
||||
prctl(PR_SET_PDEATHSIG, SIGKILL);
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,4 +51,12 @@ int lprofGetHostName(char *Name, int Len);
|
|||
unsigned lprofBoolCmpXchg(void **Ptr, void *OldV, void *NewV);
|
||||
void *lprofPtrFetchAdd(void **Mem, long ByteIncr);
|
||||
|
||||
/* Temporarily suspend SIGKILL. Return value of 1 means a restore is needed.
|
||||
* Other return values mean no restore is needed.
|
||||
*/
|
||||
int lprofSuspendSigKill();
|
||||
|
||||
/* Restore previously suspended SIGKILL. */
|
||||
void lprofRestoreSigKill();
|
||||
|
||||
#endif /* PROFILE_INSTRPROFILINGUTIL_H */
|
||||
|
|
|
|||
|
|
@ -219,6 +219,35 @@ __llvm_profile_instrument_target(uint64_t TargetValue, void *Data,
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The target values are partitioned into multiple regions/ranges. There is one
|
||||
* contiguous region which is precise -- every value in the range is tracked
|
||||
* individually. A value outside the precise region will be collapsed into one
|
||||
* value depending on the region it falls in.
|
||||
*
|
||||
* There are three regions:
|
||||
* 1. (-inf, PreciseRangeStart) and (PreciseRangeLast, LargeRangeValue) belong
|
||||
* to one region -- all values here should be mapped to one value of
|
||||
* "PreciseRangeLast + 1".
|
||||
* 2. [PreciseRangeStart, PreciseRangeLast]
|
||||
* 3. Large values: [LargeValue, +inf) maps to one value of LargeValue.
|
||||
*
|
||||
* The range for large values is optional. The default value of INT64_MIN
|
||||
* indicates it is not specified.
|
||||
*/
|
||||
COMPILER_RT_VISIBILITY void __llvm_profile_instrument_range(
|
||||
uint64_t TargetValue, void *Data, uint32_t CounterIndex,
|
||||
int64_t PreciseRangeStart, int64_t PreciseRangeLast, int64_t LargeValue) {
|
||||
|
||||
if (LargeValue != INT64_MIN && (int64_t)TargetValue >= LargeValue)
|
||||
TargetValue = LargeValue;
|
||||
else if ((int64_t)TargetValue < PreciseRangeStart ||
|
||||
(int64_t)TargetValue > PreciseRangeLast)
|
||||
TargetValue = PreciseRangeLast + 1;
|
||||
|
||||
__llvm_profile_instrument_target(TargetValue, Data, CounterIndex);
|
||||
}
|
||||
|
||||
/*
|
||||
* A wrapper struct that represents value profile runtime data.
|
||||
* Like InstrProfRecord class which is used by profiling host tools,
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ set(SANITIZER_SOURCES_NOTERMINATION
|
|||
sanitizer_stackdepot.cc
|
||||
sanitizer_stacktrace.cc
|
||||
sanitizer_stacktrace_printer.cc
|
||||
sanitizer_stoptheworld_mac.cc
|
||||
sanitizer_suppressions.cc
|
||||
sanitizer_symbolizer.cc
|
||||
sanitizer_symbolizer_libbacktrace.cc
|
||||
|
|
@ -56,6 +57,7 @@ set(SANITIZER_LIBCDEP_SOURCES
|
|||
sanitizer_coverage_libcdep.cc
|
||||
sanitizer_coverage_libcdep_new.cc
|
||||
sanitizer_coverage_mapping_libcdep.cc
|
||||
sanitizer_coverage_win_sections.cc
|
||||
sanitizer_linux_libcdep.cc
|
||||
sanitizer_posix_libcdep.cc
|
||||
sanitizer_stacktrace_libcdep.cc
|
||||
|
|
@ -126,7 +128,10 @@ set(SANITIZER_HEADERS
|
|||
sanitizer_syscall_generic.inc
|
||||
sanitizer_syscall_linux_x86_64.inc
|
||||
sanitizer_syscall_linux_aarch64.inc
|
||||
sanitizer_thread_registry.h)
|
||||
sanitizer_thread_registry.h
|
||||
sanitizer_win.h)
|
||||
|
||||
include_directories(..)
|
||||
|
||||
set(SANITIZER_COMMON_DEFINITIONS)
|
||||
|
||||
|
|
@ -184,6 +189,55 @@ add_compiler_rt_object_libraries(RTSanitizerCommonLibc
|
|||
CFLAGS ${SANITIZER_CFLAGS}
|
||||
DEFS ${SANITIZER_COMMON_DEFINITIONS})
|
||||
|
||||
if(WIN32)
|
||||
add_compiler_rt_object_libraries(SanitizerCommonWeakInterception
|
||||
${SANITIZER_COMMON_SUPPORTED_OS}
|
||||
ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH}
|
||||
SOURCES sanitizer_win_weak_interception.cc
|
||||
CFLAGS ${SANITIZER_CFLAGS} -DSANITIZER_DYNAMIC
|
||||
DEFS ${SANITIZER_COMMON_DEFINITIONS})
|
||||
add_compiler_rt_object_libraries(SancovWeakInterception
|
||||
${SANITIZER_COMMON_SUPPORTED_OS}
|
||||
ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH}
|
||||
SOURCES sanitizer_coverage_win_weak_interception.cc
|
||||
CFLAGS ${SANITIZER_CFLAGS} -DSANITIZER_DYNAMIC
|
||||
DEFS ${SANITIZER_COMMON_DEFINITIONS})
|
||||
|
||||
add_compiler_rt_object_libraries(SanitizerCommonDllThunk
|
||||
${SANITIZER_COMMON_SUPPORTED_OS}
|
||||
ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH}
|
||||
SOURCES sanitizer_win_dll_thunk.cc
|
||||
CFLAGS ${SANITIZER_CFLAGS} -DSANITIZER_DLL_THUNK
|
||||
DEFS ${SANITIZER_COMMON_DEFINITIONS})
|
||||
add_compiler_rt_object_libraries(SancovDllThunk
|
||||
${SANITIZER_COMMON_SUPPORTED_OS}
|
||||
ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH}
|
||||
SOURCES sanitizer_coverage_win_dll_thunk.cc
|
||||
sanitizer_coverage_win_sections.cc
|
||||
CFLAGS ${SANITIZER_CFLAGS} -DSANITIZER_DLL_THUNK
|
||||
DEFS ${SANITIZER_COMMON_DEFINITIONS})
|
||||
|
||||
set(DYNAMIC_RUNTIME_THUNK_CFLAGS "-DSANITIZER_DYNAMIC_RUNTIME_THUNK")
|
||||
if(MSVC)
|
||||
list(APPEND DYNAMIC_RUNTIME_THUNK_CFLAGS "-Zl")
|
||||
elseif(CMAKE_C_COMPILER_ID MATCHES Clang)
|
||||
list(APPEND DYNAMIC_RUNTIME_THUNK_CFLAGS "-nodefaultlibs")
|
||||
endif()
|
||||
add_compiler_rt_object_libraries(SanitizerCommonDynamicRuntimeThunk
|
||||
${SANITIZER_COMMON_SUPPORTED_OS}
|
||||
ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH}
|
||||
SOURCES sanitizer_win_dynamic_runtime_thunk.cc
|
||||
CFLAGS ${SANITIZER_CFLAGS} ${DYNAMIC_RUNTIME_THUNK_CFLAGS}
|
||||
DEFS ${SANITIZER_COMMON_DEFINITIONS})
|
||||
add_compiler_rt_object_libraries(SancovDynamicRuntimeThunk
|
||||
${SANITIZER_COMMON_SUPPORTED_OS}
|
||||
ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH}
|
||||
SOURCES sanitizer_coverage_win_dynamic_runtime_thunk.cc
|
||||
sanitizer_coverage_win_sections.cc
|
||||
CFLAGS ${SANITIZER_CFLAGS} ${DYNAMIC_RUNTIME_THUNK_CFLAGS}
|
||||
DEFS ${SANITIZER_COMMON_DEFINITIONS})
|
||||
endif()
|
||||
|
||||
# Unit tests for common sanitizer runtime.
|
||||
if(COMPILER_RT_INCLUDE_TESTS)
|
||||
add_subdirectory(tests)
|
||||
|
|
|
|||
|
|
@ -15,10 +15,9 @@
|
|||
#include "sanitizer_flag_parser.h"
|
||||
#include "sanitizer_platform.h"
|
||||
|
||||
#if !SANITIZER_LINUX
|
||||
// other platforms do not have weak symbols out of the box.
|
||||
extern "C" const char* __sancov_default_options() { return ""; }
|
||||
#endif
|
||||
SANITIZER_INTERFACE_WEAK_DEF(const char*, __sancov_default_options, void) {
|
||||
return "";
|
||||
}
|
||||
|
||||
using namespace __sanitizer;
|
||||
|
||||
|
|
|
|||
|
|
@ -32,9 +32,9 @@ inline SancovFlags* sancov_flags() { return &sancov_flags_dont_use_directly; }
|
|||
|
||||
void InitializeSancovFlags();
|
||||
|
||||
} // namespace __sancov
|
||||
|
||||
extern "C" SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE const char*
|
||||
__sancov_default_options();
|
||||
|
||||
} // namespace __sancov
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -34,13 +34,12 @@ SANITIZER_INTERFACE_ATTRIBUTE int __sanitizer_install_malloc_and_free_hooks(
|
|||
void (*free_hook)(const void *));
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
|
||||
/* OPTIONAL */ void __sanitizer_malloc_hook(void *ptr, uptr size);
|
||||
void __sanitizer_malloc_hook(void *ptr, uptr size);
|
||||
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
|
||||
/* OPTIONAL */ void __sanitizer_free_hook(void *ptr);
|
||||
void __sanitizer_free_hook(void *ptr);
|
||||
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
|
||||
void __sanitizer_print_memory_profile(int top_percent);
|
||||
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void
|
||||
__sanitizer_print_memory_profile(uptr top_percent, uptr max_number_of_contexts);
|
||||
} // extern "C"
|
||||
|
||||
#endif // SANITIZER_ALLOCATOR_INTERFACE_H
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue