Import compiler-rt trunk r224034.
https://llvm.org/svn/llvm-project/compiler-rt/trunk@224034
This commit is contained in:
parent
8ef50bf3d1
commit
ca9211ecde
@ -1,4 +1,4 @@
|
||||
{
|
||||
"project_id" : "compiler-rt",
|
||||
"conduit_uri" : "http://llvm-reviews.chandlerc.com/"
|
||||
"conduit_uri" : "http://reviews.llvm.org/"
|
||||
}
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,3 +2,4 @@
|
||||
darwin_fat
|
||||
clang_darwin
|
||||
multi_arch
|
||||
*.sw?
|
||||
|
377
CMakeLists.txt
377
CMakeLists.txt
@ -1,49 +1,166 @@
|
||||
# CMake build for CompilerRT.
|
||||
#
|
||||
# This build assumes that CompilerRT is checked out into the
|
||||
# 'projects/compiler-rt' inside of an LLVM tree, it is not a stand-alone build
|
||||
# system.
|
||||
# 'projects/compiler-rt' inside of an LLVM tree.
|
||||
# Standalone build system for CompilerRT is not yet ready.
|
||||
#
|
||||
# An important constraint of the build is that it only produces libraries
|
||||
# based on the ability of the host toolchain to target various platforms.
|
||||
|
||||
include(LLVMParseArguments)
|
||||
# Check if compiler-rt is built as a standalone project.
|
||||
if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
|
||||
project(CompilerRT C CXX)
|
||||
set(COMPILER_RT_STANDALONE_BUILD TRUE)
|
||||
else()
|
||||
set(COMPILER_RT_STANDALONE_BUILD FALSE)
|
||||
endif()
|
||||
|
||||
# The CompilerRT build system requires CMake version 2.8.8 or higher in order
|
||||
# to use its support for building convenience "libraries" as a collection of
|
||||
# .o files. This is particularly useful in producing larger, more complex
|
||||
# runtime libraries.
|
||||
cmake_minimum_required(VERSION 2.8.8)
|
||||
if (NOT MSVC)
|
||||
cmake_minimum_required(VERSION 2.8.8)
|
||||
else()
|
||||
# Version 2.8.12.1 is required to build with Visual Studion 2013.
|
||||
cmake_minimum_required(VERSION 2.8.12.1)
|
||||
endif()
|
||||
|
||||
# FIXME: It may be removed when we use 2.8.12.
|
||||
if(CMAKE_VERSION VERSION_LESS 2.8.12)
|
||||
# Invalidate a couple of keywords.
|
||||
set(cmake_2_8_12_INTERFACE)
|
||||
set(cmake_2_8_12_PRIVATE)
|
||||
else()
|
||||
# Use ${cmake_2_8_12_KEYWORD} intead of KEYWORD in target_link_libraries().
|
||||
set(cmake_2_8_12_INTERFACE INTERFACE)
|
||||
set(cmake_2_8_12_PRIVATE PRIVATE)
|
||||
if(POLICY CMP0022)
|
||||
cmake_policy(SET CMP0022 NEW) # automatic when 2.8.12 is required
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Top level target used to build all compiler-rt libraries.
|
||||
add_custom_target(compiler-rt)
|
||||
add_custom_target(compiler-rt ALL)
|
||||
|
||||
# Compute the Clang version from the LLVM version.
|
||||
# FIXME: We should be able to reuse CLANG_VERSION variable calculated
|
||||
# in Clang cmake files, instead of copying the rules here.
|
||||
string(REGEX MATCH "[0-9]+\\.[0-9]+(\\.[0-9]+)?" CLANG_VERSION
|
||||
if (NOT COMPILER_RT_STANDALONE_BUILD)
|
||||
# Compute the Clang version from the LLVM version.
|
||||
# FIXME: We should be able to reuse CLANG_VERSION variable calculated
|
||||
# in Clang cmake files, instead of copying the rules here.
|
||||
string(REGEX MATCH "[0-9]+\\.[0-9]+(\\.[0-9]+)?" CLANG_VERSION
|
||||
${PACKAGE_VERSION})
|
||||
# Setup the paths where compiler-rt runtimes and headers should be stored.
|
||||
set(LIBCLANG_INSTALL_PATH lib${LLVM_LIBDIR_SUFFIX}/clang/${CLANG_VERSION})
|
||||
string(TOLOWER ${CMAKE_SYSTEM_NAME} LIBCLANG_OS_DIR)
|
||||
set(CLANG_RESOURCE_DIR ${LLVM_BINARY_DIR}/lib/clang/${CLANG_VERSION})
|
||||
set(COMPILER_RT_LIBRARY_OUTPUT_DIR ${CLANG_RESOURCE_DIR}/lib/${LIBCLANG_OS_DIR})
|
||||
set(COMPILER_RT_LIBRARY_INSTALL_DIR
|
||||
${LIBCLANG_INSTALL_PATH}/lib/${LIBCLANG_OS_DIR})
|
||||
# Setup the paths where compiler-rt runtimes and headers should be stored.
|
||||
set(COMPILER_RT_OUTPUT_DIR ${LLVM_LIBRARY_OUTPUT_INTDIR}/clang/${CLANG_VERSION})
|
||||
set(COMPILER_RT_EXEC_OUTPUT_DIR ${LLVM_RUNTIME_OUTPUT_INTDIR})
|
||||
set(COMPILER_RT_INSTALL_PATH lib${LLVM_LIBDIR_SUFFIX}/clang/${CLANG_VERSION})
|
||||
option(COMPILER_RT_INCLUDE_TESTS "Generate and build compiler-rt unit tests."
|
||||
${LLVM_INCLUDE_TESTS})
|
||||
option(COMPILER_RT_ENABLE_WERROR "Fail and stop if warning is triggered"
|
||||
${LLVM_ENABLE_WERROR})
|
||||
# Use just-built Clang to compile/link tests on all platforms, except for
|
||||
# Windows where we need to use clang-cl instead.
|
||||
if(NOT MSVC)
|
||||
set(COMPILER_RT_TEST_COMPILER ${LLVM_RUNTIME_OUTPUT_INTDIR}/clang)
|
||||
else()
|
||||
set(COMPILER_RT_TEST_COMPILER ${LLVM_RUNTIME_OUTPUT_INTDIR}/clang.exe)
|
||||
endif()
|
||||
else()
|
||||
# Take output dir and install path from the user.
|
||||
set(COMPILER_RT_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR} CACHE PATH
|
||||
"Path where built compiler-rt libraries should be stored.")
|
||||
set(COMPILER_RT_EXEC_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/bin CACHE PATH
|
||||
"Path where built compiler-rt executables should be stored.")
|
||||
set(COMPILER_RT_INSTALL_PATH ${CMAKE_INSTALL_PREFIX} CACHE PATH
|
||||
"Path where built compiler-rt libraries should be installed.")
|
||||
option(COMPILER_RT_INCLUDE_TESTS "Generate and build compiler-rt unit tests." OFF)
|
||||
option(COMPILER_RT_ENABLE_WERROR "Fail and stop if warning is triggered" OFF)
|
||||
# Use a host compiler to compile/link tests.
|
||||
set(COMPILER_RT_TEST_COMPILER ${CMAKE_C_COMPILER} CACHE PATH "Compiler to use for testing")
|
||||
|
||||
# Add path for custom modules
|
||||
if (NOT LLVM_CONFIG_PATH)
|
||||
find_program(LLVM_CONFIG_PATH "llvm-config"
|
||||
DOC "Path to llvm-config binary")
|
||||
if (NOT LLVM_CONFIG_PATH)
|
||||
message(FATAL_ERROR "llvm-config not found: specify LLVM_CONFIG_PATH")
|
||||
endif()
|
||||
endif()
|
||||
execute_process(
|
||||
COMMAND ${LLVM_CONFIG_PATH} "--obj-root" "--bindir" "--libdir" "--src-root"
|
||||
RESULT_VARIABLE HAD_ERROR
|
||||
OUTPUT_VARIABLE CONFIG_OUTPUT)
|
||||
if (HAD_ERROR)
|
||||
message(FATAL_ERROR "llvm-config failed with status ${HAD_ERROR}")
|
||||
endif()
|
||||
string(REGEX REPLACE "[ \t]*[\r\n]+[ \t]*" ";" CONFIG_OUTPUT ${CONFIG_OUTPUT})
|
||||
list(GET CONFIG_OUTPUT 0 LLVM_BINARY_DIR)
|
||||
list(GET CONFIG_OUTPUT 1 LLVM_TOOLS_BINARY_DIR)
|
||||
list(GET CONFIG_OUTPUT 2 LLVM_LIBRARY_DIR)
|
||||
list(GET CONFIG_OUTPUT 3 LLVM_MAIN_SRC_DIR)
|
||||
|
||||
# Make use of LLVM CMake modules.
|
||||
file(TO_CMAKE_PATH ${LLVM_BINARY_DIR} LLVM_BINARY_DIR_CMAKE_STYLE)
|
||||
set(LLVM_CMAKE_PATH "${LLVM_BINARY_DIR_CMAKE_STYLE}/share/llvm/cmake")
|
||||
list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_PATH}")
|
||||
# Get some LLVM variables from LLVMConfig.
|
||||
include("${LLVM_CMAKE_PATH}/LLVMConfig.cmake")
|
||||
|
||||
set(LLVM_LIBRARY_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib)
|
||||
|
||||
# Find Python interpreter.
|
||||
set(Python_ADDITIONAL_VERSIONS 2.7 2.6 2.5)
|
||||
include(FindPythonInterp)
|
||||
if(NOT PYTHONINTERP_FOUND)
|
||||
message(FATAL_ERROR "
|
||||
Unable to find Python interpreter required testing. Please install Python
|
||||
or specify the PYTHON_EXECUTABLE CMake variable.")
|
||||
endif()
|
||||
|
||||
# Define default arguments to lit.
|
||||
set(LIT_ARGS_DEFAULT "-sv")
|
||||
if (MSVC OR XCODE)
|
||||
set(LIT_ARGS_DEFAULT "${LIT_ARGS_DEFAULT} --no-progress-bar")
|
||||
endif()
|
||||
set(LLVM_LIT_ARGS "${LIT_ARGS_DEFAULT}" CACHE STRING "Default options for lit")
|
||||
endif()
|
||||
|
||||
if("${COMPILER_RT_TEST_COMPILER}" MATCHES "clang[+]*$")
|
||||
set(COMPILER_RT_TEST_COMPILER_ID Clang)
|
||||
elseif("${COMPILER_RT_TEST_COMPILER}" MATCHES "clang.*.exe$")
|
||||
set(COMPILER_RT_TEST_COMPILER_ID Clang)
|
||||
else()
|
||||
set(COMPILER_RT_TEST_COMPILER_ID GNU)
|
||||
endif()
|
||||
|
||||
# Tests using XFAIL use the first value in COMPILER_RT_TEST_TARGET_TRIPLE
|
||||
set(COMPILER_RT_TEST_TARGET_TRIPLE ${TARGET_TRIPLE} CACHE STRING
|
||||
"Default triple for cross-compiled executables")
|
||||
string(REPLACE "-" ";" TARGET_TRIPLE_LIST ${COMPILER_RT_TEST_TARGET_TRIPLE})
|
||||
list(GET TARGET_TRIPLE_LIST 0 COMPILER_RT_TEST_TARGET_ARCH)
|
||||
list(GET TARGET_TRIPLE_LIST 1 COMPILER_RT_TEST_TARGET_OS)
|
||||
list(GET TARGET_TRIPLE_LIST 2 COMPILER_RT_TEST_TARGET_ABI)
|
||||
|
||||
if ("${COMPILER_RT_TEST_TARGET_ABI}" STREQUAL "androideabi")
|
||||
set(ANDROID 1)
|
||||
endif()
|
||||
|
||||
string(TOLOWER ${CMAKE_SYSTEM_NAME} COMPILER_RT_OS_DIR)
|
||||
set(COMPILER_RT_LIBRARY_OUTPUT_DIR
|
||||
${COMPILER_RT_OUTPUT_DIR}/lib/${COMPILER_RT_OS_DIR})
|
||||
set(COMPILER_RT_LIBRARY_INSTALL_DIR
|
||||
${COMPILER_RT_INSTALL_PATH}/lib/${COMPILER_RT_OS_DIR})
|
||||
|
||||
# Add path for custom compiler-rt modules.
|
||||
set(CMAKE_MODULE_PATH
|
||||
${CMAKE_MODULE_PATH}
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules"
|
||||
${CMAKE_MODULE_PATH}
|
||||
)
|
||||
include(AddCompilerRT)
|
||||
include(CompilerRTUtils)
|
||||
|
||||
set(COMPILER_RT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
set(COMPILER_RT_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
|
||||
# Setup custom SDK sysroots.
|
||||
set(COMPILER_RT_DARWIN_SDK_SYSROOT ${COMPILER_RT_SOURCE_DIR}/SDKs/darwin)
|
||||
set(COMPILER_RT_LINUX_SDK_SYSROOT ${COMPILER_RT_SOURCE_DIR}/SDKs/linux)
|
||||
include(SanitizerUtils)
|
||||
|
||||
# Detect whether the current target platform is 32-bit or 64-bit, and setup
|
||||
# the correct commandline flags needed to attempt to target 32-bit and 64-bit.
|
||||
@ -59,9 +176,6 @@ else()
|
||||
set(TARGET_32_BIT_CFLAGS "")
|
||||
endif()
|
||||
|
||||
# List of architectures we can target.
|
||||
set(COMPILER_RT_SUPPORTED_ARCH)
|
||||
|
||||
function(get_target_flags_for_arch arch out_var)
|
||||
list(FIND COMPILER_RT_SUPPORTED_ARCH ${arch} ARCH_INDEX)
|
||||
if(ARCH_INDEX EQUAL -1)
|
||||
@ -71,115 +185,103 @@ function(get_target_flags_for_arch arch out_var)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Try to compile a very simple source file to ensure we can target the given
|
||||
# platform. We use the results of these tests to build only the various target
|
||||
# runtime libraries supported by our current compilers cross-compiling
|
||||
# abilities.
|
||||
set(SIMPLE_SOURCE ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/simple.c)
|
||||
file(WRITE ${SIMPLE_SOURCE} "#include <stdlib.h>\nint main() {}")
|
||||
|
||||
# test_target_arch(<arch> <target flags...>)
|
||||
# Sets the target flags for a given architecture and determines if this
|
||||
# architecture is supported by trying to build a simple file.
|
||||
macro(test_target_arch arch)
|
||||
set(TARGET_${arch}_CFLAGS ${ARGN})
|
||||
try_compile(CAN_TARGET_${arch} ${CMAKE_BINARY_DIR} ${SIMPLE_SOURCE}
|
||||
COMPILE_DEFINITIONS "${TARGET_${arch}_CFLAGS}"
|
||||
CMAKE_FLAGS "-DCMAKE_EXE_LINKER_FLAGS:STRING=${TARGET_${arch}_CFLAGS}")
|
||||
if(${CAN_TARGET_${arch}})
|
||||
list(APPEND COMPILER_RT_SUPPORTED_ARCH ${arch})
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
if("${LLVM_NATIVE_ARCH}" STREQUAL "X86")
|
||||
if (NOT MSVC)
|
||||
test_target_arch(x86_64 ${TARGET_64_BIT_CFLAGS})
|
||||
endif()
|
||||
test_target_arch(i386 ${TARGET_32_BIT_CFLAGS})
|
||||
elseif("${LLVM_NATIVE_ARCH}" STREQUAL "PowerPC")
|
||||
test_target_arch(powerpc64 ${TARGET_64_BIT_CFLAGS})
|
||||
endif()
|
||||
|
||||
# We only support running instrumented tests when we're not cross compiling
|
||||
# and target a unix-like system. On Android we define the rules for building
|
||||
# unit tests, but don't execute them.
|
||||
if("${CMAKE_HOST_SYSTEM}" STREQUAL "${CMAKE_SYSTEM}" AND UNIX AND NOT ANDROID)
|
||||
# We support running instrumented tests when we're not cross compiling
|
||||
# and target a UNIX-like system or Windows.
|
||||
# We can run tests on Android even when we are cross-compiling.
|
||||
if(("${CMAKE_HOST_SYSTEM}" STREQUAL "${CMAKE_SYSTEM}" AND (UNIX OR MSVC)) OR ANDROID
|
||||
OR COMPILER_RT_EMULATOR)
|
||||
option(COMPILER_RT_CAN_EXECUTE_TESTS "Can we execute instrumented tests" ON)
|
||||
else()
|
||||
option(COMPILER_RT_CAN_EXECUTE_TESTS "Can we execute instrumented tests" OFF)
|
||||
endif()
|
||||
|
||||
# Check if compiler-rt is built with libc++.
|
||||
find_flag_in_string("${CMAKE_CXX_FLAGS}" "-stdlib=libc++"
|
||||
COMPILER_RT_USES_LIBCXX)
|
||||
|
||||
function(filter_available_targets out_var)
|
||||
set(archs)
|
||||
foreach(arch ${ARGN})
|
||||
list(FIND COMPILER_RT_SUPPORTED_ARCH ${arch} ARCH_INDEX)
|
||||
if(NOT (ARCH_INDEX EQUAL -1) AND CAN_TARGET_${arch})
|
||||
list(APPEND archs ${arch})
|
||||
endif()
|
||||
endforeach()
|
||||
set(${out_var} ${archs} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
option(COMPILER_RT_DEBUG "Build runtimes with full debug info" OFF)
|
||||
|
||||
# COMPILER_RT_DEBUG_PYBOOL is used by lit.common.configured.in.
|
||||
pythonize_bool(COMPILER_RT_DEBUG)
|
||||
|
||||
# Provide some common commmandline flags for Sanitizer runtimes.
|
||||
if (NOT MSVC)
|
||||
set(SANITIZER_COMMON_CFLAGS
|
||||
-fPIC
|
||||
-fno-builtin
|
||||
-fno-exceptions
|
||||
-fomit-frame-pointer
|
||||
-funwind-tables
|
||||
-fno-stack-protector
|
||||
-Wno-gnu # Variadic macros with 0 arguments for ...
|
||||
-fvisibility=hidden
|
||||
)
|
||||
if (NOT COMPILER_RT_DEBUG)
|
||||
list(APPEND SANITIZER_COMMON_CFLAGS -O3)
|
||||
endif()
|
||||
# We have to support both static and dynamic/shared runtime on Windows.
|
||||
# Android only works with dynamic runtime.
|
||||
if(WIN32 OR ANDROID)
|
||||
option(COMPILER_RT_BUILD_SHARED_ASAN "Build shared version of AddressSanitizer runtime" ON)
|
||||
else()
|
||||
set(SANITIZER_COMMON_CFLAGS
|
||||
/MT
|
||||
/Zi
|
||||
/Oy-
|
||||
/GS-
|
||||
/wd4722
|
||||
)
|
||||
option(COMPILER_RT_BUILD_SHARED_ASAN "Build shared version of AddressSanitizer runtime" OFF)
|
||||
endif()
|
||||
# Build sanitizer runtimes with debug info. (MSVC gets /Zi above)
|
||||
if (NOT MSVC)
|
||||
check_cxx_compiler_flag(-gline-tables-only SUPPORTS_GLINE_TABLES_ONLY_FLAG)
|
||||
if(SUPPORTS_GLINE_TABLES_ONLY_FLAG AND NOT COMPILER_RT_DEBUG)
|
||||
list(APPEND SANITIZER_COMMON_CFLAGS -gline-tables-only)
|
||||
else()
|
||||
list(APPEND SANITIZER_COMMON_CFLAGS -g)
|
||||
endif()
|
||||
endif()
|
||||
# Warnings suppressions.
|
||||
check_cxx_compiler_flag(-Wno-variadic-macros SUPPORTS_NO_VARIADIC_MACROS_FLAG)
|
||||
if(SUPPORTS_NO_VARIADIC_MACROS_FLAG)
|
||||
list(APPEND SANITIZER_COMMON_CFLAGS -Wno-variadic-macros)
|
||||
endif()
|
||||
check_cxx_compiler_flag(-Wno-c99-extensions SUPPORTS_NO_C99_EXTENSIONS_FLAG)
|
||||
if(SUPPORTS_NO_C99_EXTENSIONS_FLAG)
|
||||
list(APPEND SANITIZER_COMMON_CFLAGS -Wno-c99-extensions)
|
||||
endif()
|
||||
# Sanitizer may not have libstdc++, so we can have problems with virtual
|
||||
# destructors.
|
||||
check_cxx_compiler_flag(-Wno-non-virtual-dtor SUPPORTS_NO_NON_VIRTUAL_DTOR_FLAG)
|
||||
if (SUPPORTS_NO_NON_VIRTUAL_DTOR_FLAG)
|
||||
list(APPEND SANITIZER_COMMON_CFLAGS -Wno-non-virtual-dtor)
|
||||
endif()
|
||||
check_cxx_compiler_flag(-Wglobal-constructors SUPPORTS_GLOBAL_CONSTRUCTORS_FLAG)
|
||||
# Not all sanitizers forbid global constructors.
|
||||
|
||||
#================================
|
||||
# Setup Compiler Flags
|
||||
#================================
|
||||
include(config-ix)
|
||||
|
||||
if(MSVC)
|
||||
append_string_if(COMPILER_RT_HAS_W3_FLAG /W3 CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
|
||||
else()
|
||||
append_string_if(COMPILER_RT_HAS_WALL_FLAG -Wall CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
|
||||
endif()
|
||||
if(COMPILER_RT_ENABLE_WERROR)
|
||||
append_string_if(COMPILER_RT_HAS_WERROR_FLAG -Werror CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
|
||||
append_string_if(COMPILER_RT_HAS_WX_FLAG /WX CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
|
||||
endif()
|
||||
|
||||
append_string_if(COMPILER_RT_HAS_STD_CXX11_FLAG -std=c++11 CMAKE_CXX_FLAGS)
|
||||
|
||||
# Emulate C99 and C++11's __func__ for MSVC prior to 2013 CTP.
|
||||
if(NOT COMPILER_RT_HAS_FUNC_SYMBOL)
|
||||
add_definitions(-D__func__=__FUNCTION__)
|
||||
endif()
|
||||
|
||||
# Provide some common commmandline flags for Sanitizer runtimes.
|
||||
append_list_if(COMPILER_RT_HAS_FPIC_FLAG -fPIC SANITIZER_COMMON_CFLAGS)
|
||||
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)
|
||||
append_list_if(COMPILER_RT_HAS_FOMIT_FRAME_POINTER_FLAG -fomit-frame-pointer SANITIZER_COMMON_CFLAGS)
|
||||
append_list_if(COMPILER_RT_HAS_FUNWIND_TABLES_FLAG -funwind-tables SANITIZER_COMMON_CFLAGS)
|
||||
append_list_if(COMPILER_RT_HAS_FNO_STACK_PROTECTOR_FLAG -fno-stack-protector SANITIZER_COMMON_CFLAGS)
|
||||
append_list_if(COMPILER_RT_HAS_FVISIBILITY_HIDDEN_FLAG -fvisibility=hidden SANITIZER_COMMON_CFLAGS)
|
||||
append_list_if(COMPILER_RT_HAS_FNO_FUNCTION_SECTIONS_FLAG -fno-function-sections SANITIZER_COMMON_CFLAGS)
|
||||
|
||||
if(MSVC)
|
||||
# Replace the /MD[d] flags with /MT.
|
||||
# FIXME: In fact, sanitizers should support both /MT and /MD, see PR20214.
|
||||
if(COMPILER_RT_HAS_MT_FLAG)
|
||||
foreach(flag_var
|
||||
CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
|
||||
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
|
||||
if(${flag_var} MATCHES "/MD")
|
||||
string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
|
||||
elseif(${flag_var} MATCHES "/MDd")
|
||||
string(REGEX REPLACE "/MDd" "/MT" ${flag_var} "${${flag_var}}")
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
append_list_if(COMPILER_RT_HAS_Oy_FLAG /Oy- SANITIZER_COMMON_CFLAGS)
|
||||
append_list_if(COMPILER_RT_HAS_GS_FLAG /GS- SANITIZER_COMMON_CFLAGS)
|
||||
endif()
|
||||
|
||||
# Build with optimization, unless we're in debug mode. If we're using MSVC,
|
||||
# always respect the optimization flags set by CMAKE_BUILD_TYPE instead.
|
||||
if(NOT COMPILER_RT_DEBUG AND NOT MSVC)
|
||||
list(APPEND SANITIZER_COMMON_CFLAGS -O3)
|
||||
endif()
|
||||
|
||||
# Build sanitizer runtimes with debug info.
|
||||
if(COMPILER_RT_HAS_GLINE_TABLES_ONLY_FLAG)
|
||||
list(APPEND SANITIZER_COMMON_CFLAGS -gline-tables-only)
|
||||
elseif(COMPILER_RT_HAS_G_FLAG)
|
||||
list(APPEND SANITIZER_COMMON_CFLAGS -g)
|
||||
elseif(COMPILER_RT_HAS_Zi_FLAG)
|
||||
list(APPEND SANITIZER_COMMON_CFLAGS /Zi)
|
||||
endif()
|
||||
|
||||
# Turn off several warnings.
|
||||
append_list_if(COMPILER_RT_HAS_WGNU_FLAG -Wno-gnu SANITIZER_COMMON_CFLAGS)
|
||||
append_list_if(COMPILER_RT_HAS_WVARIADIC_MACROS_FLAG -Wno-variadic-macros SANITIZER_COMMON_CFLAGS)
|
||||
append_list_if(COMPILER_RT_HAS_WC99_EXTENSIONS_FLAG -Wno-c99-extensions SANITIZER_COMMON_CFLAGS)
|
||||
append_list_if(COMPILER_RT_HAS_WNON_VIRTUAL_DTOR_FLAG -Wno-non-virtual-dtor SANITIZER_COMMON_CFLAGS)
|
||||
append_list_if(COMPILER_RT_HAS_WD4146_FLAG /wd4146 SANITIZER_COMMON_CFLAGS)
|
||||
append_list_if(COMPILER_RT_HAS_WD4291_FLAG /wd4291 SANITIZER_COMMON_CFLAGS)
|
||||
append_list_if(COMPILER_RT_HAS_WD4391_FLAG /wd4391 SANITIZER_COMMON_CFLAGS)
|
||||
append_list_if(COMPILER_RT_HAS_WD4722_FLAG /wd4722 SANITIZER_COMMON_CFLAGS)
|
||||
append_list_if(COMPILER_RT_HAS_WD4800_FLAG /wd4800 SANITIZER_COMMON_CFLAGS)
|
||||
if(APPLE)
|
||||
# Obtain the iOS Simulator SDK path from xcodebuild.
|
||||
execute_process(
|
||||
@ -187,16 +289,15 @@ if(APPLE)
|
||||
OUTPUT_VARIABLE IOSSIM_SDK_DIR
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
string(REGEX MATCH "-mmacosx-version-min="
|
||||
MACOSX_VERSION_MIN_FLAG "${CMAKE_CXX_FLAGS}")
|
||||
set(SANITIZER_COMMON_SUPPORTED_DARWIN_OS osx)
|
||||
if (IOSSIM_SDK_DIR)
|
||||
if (IOSSIM_SDK_DIR AND NOT MACOSX_VERSION_MIN_FLAG)
|
||||
list(APPEND SANITIZER_COMMON_SUPPORTED_DARWIN_OS iossim)
|
||||
endif()
|
||||
|
||||
if(COMPILER_RT_USES_LIBCXX)
|
||||
set(SANITIZER_MIN_OSX_VERSION 10.7)
|
||||
else()
|
||||
set(SANITIZER_MIN_OSX_VERSION 10.6)
|
||||
endif()
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "") # We're setting the flag manually below.
|
||||
set(DARWIN_osx_CFLAGS -mmacosx-version-min=${SANITIZER_MIN_OSX_VERSION})
|
||||
set(DARWIN_iossim_CFLAGS
|
||||
-mios-simulator-version-min=7.0 -isysroot ${IOSSIM_SDK_DIR})
|
||||
@ -207,26 +308,18 @@ if(APPLE)
|
||||
-isysroot ${IOSSIM_SDK_DIR})
|
||||
endif()
|
||||
|
||||
# Architectures supported by Sanitizer runtimes. Specific sanitizers may
|
||||
# support only subset of these (e.g. TSan works on x86_64 only).
|
||||
filter_available_targets(SANITIZER_COMMON_SUPPORTED_ARCH
|
||||
x86_64 i386 powerpc64)
|
||||
|
||||
add_subdirectory(include)
|
||||
|
||||
set(SANITIZER_COMMON_LIT_TEST_DEPS
|
||||
clang clang-headers FileCheck count not llvm-nm llvm-symbolizer
|
||||
compiler-rt-headers)
|
||||
# Check code style when running lit tests for sanitizers.
|
||||
if(UNIX)
|
||||
list(APPEND SANITIZER_COMMON_LIT_TEST_DEPS SanitizerLintCheck)
|
||||
set(COMPILER_RT_LIBCXX_PATH ${LLVM_MAIN_SRC_DIR}/projects/libcxx)
|
||||
if(EXISTS ${COMPILER_RT_LIBCXX_PATH}/)
|
||||
set(COMPILER_RT_HAS_LIBCXX_SOURCES TRUE)
|
||||
else()
|
||||
set(COMPILER_RT_HAS_LIBCXX_SOURCES FALSE)
|
||||
endif()
|
||||
|
||||
add_subdirectory(lib)
|
||||
|
||||
if(LLVM_INCLUDE_TESTS)
|
||||
# Currently the tests have not been ported to CMake, so disable this
|
||||
# directory.
|
||||
#
|
||||
#add_subdirectory(test)
|
||||
if(COMPILER_RT_INCLUDE_TESTS)
|
||||
add_subdirectory(unittests)
|
||||
endif()
|
||||
add_subdirectory(test)
|
||||
|
57
CODE_OWNERS.TXT
Normal file
57
CODE_OWNERS.TXT
Normal file
@ -0,0 +1,57 @@
|
||||
This file is a list of the people responsible for ensuring that patches for a
|
||||
particular part of compiler-rt are reviewed, either by themself or by
|
||||
someone else. They are also the gatekeepers for their part of compiler-rt, with
|
||||
the final word on what goes in or not.
|
||||
|
||||
The list is sorted by surname and formatted to allow easy grepping and
|
||||
beautification by scripts. The fields are: name (N), email (E), web-address
|
||||
(W), PGP key ID and fingerprint (P), description (D), and snail-mail address
|
||||
(S).
|
||||
|
||||
N: Peter Collingbourne
|
||||
E: peter@pcc.me.uk
|
||||
D: DataFlowSanitizer
|
||||
|
||||
N: Daniel Dunbar
|
||||
E: daniel@zuster.org
|
||||
D: Makefile build
|
||||
|
||||
N: Timur Iskhodzhanov
|
||||
E: timurrrr@google.com
|
||||
D: AddressSanitizer for Windows
|
||||
|
||||
N: Howard Hinnant
|
||||
E: howard.hinnant@gmail.com
|
||||
D: builtins library
|
||||
|
||||
N: Sergey Matveev
|
||||
E: earthdok@google.com
|
||||
D: LeakSanitizer
|
||||
|
||||
N: Alexander Potapenko
|
||||
E: glider@google.com
|
||||
D: MacOS/iOS port of sanitizers
|
||||
|
||||
N: Alexey Samsonov
|
||||
E: samsonov@google.com
|
||||
D: CMake build, test suite
|
||||
|
||||
N: Kostya Serebryany
|
||||
E: kcc@google.com
|
||||
D: AddressSanitizer, sanitizer_common, porting sanitizers to another platforms
|
||||
|
||||
N: Richard Smith
|
||||
E: richard-llvm@metafoo.co.uk
|
||||
D: UndefinedBehaviorSanitizer
|
||||
|
||||
N: Evgeniy Stepanov
|
||||
E: eugenis@google.com
|
||||
D: MemorySanitizer, Android port of sanitizers
|
||||
|
||||
N: Dmitry Vyukov
|
||||
E: dvyukov@google.com
|
||||
D: ThreadSanitizer
|
||||
|
||||
N: Bill Wendling
|
||||
E: isanbard@gmail.com
|
||||
D: Profile runtime library
|
12
CREDITS.TXT
12
CREDITS.TXT
@ -22,3 +22,15 @@ D: Maintain Solaris & AuroraUX ports of Compiler-RT
|
||||
N: Howard Hinnant
|
||||
E: hhinnant@apple.com
|
||||
D: Architect and primary author of compiler-rt
|
||||
|
||||
N: Guan-Hong Liu
|
||||
E: koviankevin@hotmail.com
|
||||
D: IEEE Quad-precision functions
|
||||
|
||||
N: Joerg Sonnenberger
|
||||
E: joerg@NetBSD.org
|
||||
D: Maintains NetBSD port.
|
||||
|
||||
N: Matt Thomas
|
||||
E: matt@NetBSD.org
|
||||
D: ARM improvements.
|
||||
|
10
LICENSE.TXT
10
LICENSE.TXT
@ -14,7 +14,7 @@ Full text of the relevant licenses is included below.
|
||||
University of Illinois/NCSA
|
||||
Open Source License
|
||||
|
||||
Copyright (c) 2009-2013 by the contributors listed in CREDITS.TXT
|
||||
Copyright (c) 2009-2014 by the contributors listed in CREDITS.TXT
|
||||
|
||||
All rights reserved.
|
||||
|
||||
@ -55,7 +55,7 @@ SOFTWARE.
|
||||
|
||||
==============================================================================
|
||||
|
||||
Copyright (c) 2009-2013 by the contributors listed in CREDITS.TXT
|
||||
Copyright (c) 2009-2014 by the contributors listed in CREDITS.TXT
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
@ -89,9 +89,3 @@ other licenses gives permission to use the names of the LLVM Team or the
|
||||
University of Illinois to endorse or promote products derived from this
|
||||
Software.
|
||||
|
||||
The following pieces of software have additional or alternate copyrights,
|
||||
licenses, and/or restrictions:
|
||||
|
||||
Program Directory
|
||||
------- ---------
|
||||
mach_override lib/interception/mach_override
|
||||
|
4
Makefile
4
Makefile
@ -249,10 +249,10 @@ $(call Set,Tmp.CFLAGS,$(strip \
|
||||
|
||||
$(Tmp.ObjPath)/%.o: $(Tmp.SrcPath)/%.s $(Tmp.Dependencies) $(Tmp.ObjPath)/.dir
|
||||
$(Summary) " ASSEMBLE: $(Tmp.Name)/$(Tmp.Config)/$(Tmp.Arch): $$<"
|
||||
$(Verb) $(Tmp.CC) $(Tmp.CFLAGS) -c -o $$@ $$<
|
||||
$(Verb) $(Tmp.CC) $(COMMON_ASMFLAGS) $(Tmp.CFLAGS) -c -o $$@ $$<
|
||||
$(Tmp.ObjPath)/%.o: $(Tmp.SrcPath)/%.S $(Tmp.Dependencies) $(Tmp.ObjPath)/.dir
|
||||
$(Summary) " ASSEMBLE: $(Tmp.Name)/$(Tmp.Config)/$(Tmp.Arch): $$<"
|
||||
$(Verb) $(Tmp.CC) $(Tmp.CFLAGS) -c -o $$@ $$<
|
||||
$(Verb) $(Tmp.CC) $(COMMON_ASMFLAGS) $(Tmp.CFLAGS) -c -o $$@ $$<
|
||||
$(Tmp.ObjPath)/%.o: $(Tmp.SrcPath)/%.c $(Tmp.Dependencies) $(Tmp.ObjPath)/.dir
|
||||
$(Summary) " COMPILE: $(Tmp.Name)/$(Tmp.Config)/$(Tmp.Arch): $$<"
|
||||
$(Verb) $(Tmp.CC) $(COMMON_CFLAGS) $(Tmp.CFLAGS) -c -o $$@ $$<
|
||||
|
332
README.txt
332
README.txt
@ -9,335 +9,3 @@ terms of the license agreement found in LICENSE.txt.
|
||||
|
||||
================================
|
||||
|
||||
This is a replacement library for libgcc. Each function is contained
|
||||
in its own file. Each function has a corresponding unit test under
|
||||
test/Unit.
|
||||
|
||||
A rudimentary script to test each file is in the file called
|
||||
test/Unit/test.
|
||||
|
||||
Here is the specification for this library:
|
||||
|
||||
http://gcc.gnu.org/onlinedocs/gccint/Libgcc.html#Libgcc
|
||||
|
||||
Here is a synopsis of the contents of this library:
|
||||
|
||||
typedef int si_int;
|
||||
typedef unsigned su_int;
|
||||
|
||||
typedef long long di_int;
|
||||
typedef unsigned long long du_int;
|
||||
|
||||
// Integral bit manipulation
|
||||
|
||||
di_int __ashldi3(di_int a, si_int b); // a << b
|
||||
ti_int __ashlti3(ti_int a, si_int b); // a << b
|
||||
|
||||
di_int __ashrdi3(di_int a, si_int b); // a >> b arithmetic (sign fill)
|
||||
ti_int __ashrti3(ti_int a, si_int b); // a >> b arithmetic (sign fill)
|
||||
di_int __lshrdi3(di_int a, si_int b); // a >> b logical (zero fill)
|
||||
ti_int __lshrti3(ti_int a, si_int b); // a >> b logical (zero fill)
|
||||
|
||||
si_int __clzsi2(si_int a); // count leading zeros
|
||||
si_int __clzdi2(di_int a); // count leading zeros
|
||||
si_int __clzti2(ti_int a); // count leading zeros
|
||||
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 __ffsdi2(di_int a); // find least significant 1 bit
|
||||
si_int __ffsti2(ti_int a); // find least significant 1 bit
|
||||
|
||||
si_int __paritysi2(si_int a); // bit parity
|
||||
si_int __paritydi2(di_int a); // bit parity
|
||||
si_int __parityti2(ti_int a); // bit parity
|
||||
|
||||
si_int __popcountsi2(si_int a); // bit population
|
||||
si_int __popcountdi2(di_int a); // bit population
|
||||
si_int __popcountti2(ti_int a); // bit population
|
||||
|
||||
uint32_t __bswapsi2(uint32_t a); // a byteswapped, arm only
|
||||
uint64_t __bswapdi2(uint64_t a); // a byteswapped, arm only
|
||||
|
||||
// Integral arithmetic
|
||||
|
||||
di_int __negdi2 (di_int a); // -a
|
||||
ti_int __negti2 (ti_int a); // -a
|
||||
di_int __muldi3 (di_int a, di_int b); // a * b
|
||||
ti_int __multi3 (ti_int a, ti_int b); // a * b
|
||||
si_int __divsi3 (si_int a, si_int b); // a / b signed
|
||||
di_int __divdi3 (di_int a, di_int b); // a / b signed
|
||||
ti_int __divti3 (ti_int a, ti_int b); // a / b signed
|
||||
su_int __udivsi3 (su_int n, su_int d); // a / b unsigned
|
||||
du_int __udivdi3 (du_int a, du_int b); // a / b unsigned
|
||||
tu_int __udivti3 (tu_int a, tu_int b); // a / b unsigned
|
||||
si_int __modsi3 (si_int a, si_int b); // a % b signed
|
||||
di_int __moddi3 (di_int a, di_int b); // a % b signed
|
||||
ti_int __modti3 (ti_int a, ti_int b); // a % b signed
|
||||
su_int __umodsi3 (su_int a, su_int b); // a % b unsigned
|
||||
du_int __umoddi3 (du_int a, du_int b); // a % b unsigned
|
||||
tu_int __umodti3 (tu_int a, tu_int b); // a % b unsigned
|
||||
du_int __udivmoddi4(du_int a, du_int b, du_int* rem); // a / b, *rem = a % b unsigned
|
||||
tu_int __udivmodti4(tu_int a, tu_int b, tu_int* rem); // a / b, *rem = a % b unsigned
|
||||
su_int __udivmodsi4(su_int a, su_int b, su_int* rem); // a / b, *rem = a % b unsigned
|
||||
si_int __divmodsi4(si_int a, si_int b, si_int* rem); // a / b, *rem = a % b signed
|
||||
|
||||
|
||||
|
||||
// Integral arithmetic with trapping overflow
|
||||
|
||||
si_int __absvsi2(si_int a); // abs(a)
|
||||
di_int __absvdi2(di_int a); // abs(a)
|
||||
ti_int __absvti2(ti_int a); // abs(a)
|
||||
|
||||
si_int __negvsi2(si_int a); // -a
|
||||
di_int __negvdi2(di_int a); // -a
|
||||
ti_int __negvti2(ti_int a); // -a
|
||||
|
||||
si_int __addvsi3(si_int a, si_int b); // a + b
|
||||
di_int __addvdi3(di_int a, di_int b); // a + b
|
||||
ti_int __addvti3(ti_int a, ti_int b); // a + b
|
||||
|
||||
si_int __subvsi3(si_int a, si_int b); // a - b
|
||||
di_int __subvdi3(di_int a, di_int b); // a - b
|
||||
ti_int __subvti3(ti_int a, ti_int b); // a - b
|
||||
|
||||
si_int __mulvsi3(si_int a, si_int b); // a * b
|
||||
di_int __mulvdi3(di_int a, di_int b); // a * b
|
||||
ti_int __mulvti3(ti_int a, ti_int b); // a * b
|
||||
|
||||
|
||||
// Integral arithmetic which returns if overflow
|
||||
|
||||
si_int __mulosi4(si_int a, si_int b, int* overflow); // a * b, overflow set to one if result not in signed range
|
||||
di_int __mulodi4(di_int a, di_int b, int* overflow); // a * b, overflow set to one if result not in signed range
|
||||
ti_int __muloti4(ti_int a, ti_int b, int* overflow); // a * b, overflow set to
|
||||
one if result not in signed range
|
||||
|
||||
|
||||
// Integral comparison: a < b -> 0
|
||||
// a == b -> 1
|
||||
// a > b -> 2
|
||||
|
||||
si_int __cmpdi2 (di_int a, di_int b);
|
||||
si_int __cmpti2 (ti_int a, ti_int b);
|
||||
si_int __ucmpdi2(du_int a, du_int b);
|
||||
si_int __ucmpti2(tu_int a, tu_int b);
|
||||
|
||||
// Integral / floating point conversion
|
||||
|
||||
di_int __fixsfdi( float a);
|
||||
di_int __fixdfdi( double a);
|
||||
di_int __fixxfdi(long double a);
|
||||
|
||||
ti_int __fixsfti( float a);
|
||||
ti_int __fixdfti( double a);
|
||||
ti_int __fixxfti(long double a);
|
||||
uint64_t __fixtfdi(long double input); // ppc only, doesn't match documentation
|
||||
|
||||
su_int __fixunssfsi( float a);
|
||||
su_int __fixunsdfsi( double a);
|
||||
su_int __fixunsxfsi(long double a);
|
||||
|
||||
du_int __fixunssfdi( float a);
|
||||
du_int __fixunsdfdi( double a);
|
||||
du_int __fixunsxfdi(long double a);
|
||||
|
||||
tu_int __fixunssfti( float a);
|
||||
tu_int __fixunsdfti( double a);
|
||||
tu_int __fixunsxfti(long double a);
|
||||
uint64_t __fixunstfdi(long double input); // ppc only
|
||||
|
||||
float __floatdisf(di_int a);
|
||||
double __floatdidf(di_int a);
|
||||
long double __floatdixf(di_int a);
|
||||
long double __floatditf(int64_t a); // ppc only
|
||||
|
||||
float __floattisf(ti_int a);
|
||||
double __floattidf(ti_int a);
|
||||
long double __floattixf(ti_int a);
|
||||
|
||||
float __floatundisf(du_int a);
|
||||
double __floatundidf(du_int a);
|
||||
long double __floatundixf(du_int a);
|
||||
long double __floatunditf(uint64_t a); // ppc only
|
||||
|
||||
float __floatuntisf(tu_int a);
|
||||
double __floatuntidf(tu_int a);
|
||||
long double __floatuntixf(tu_int a);
|
||||
|
||||
// Floating point raised to integer power
|
||||
|
||||
float __powisf2( float a, si_int b); // a ^ b
|
||||
double __powidf2( double a, si_int b); // a ^ b
|
||||
long double __powixf2(long double a, si_int b); // a ^ b
|
||||
long double __powitf2(long double a, si_int b); // ppc only, a ^ b
|
||||
|
||||
// Complex arithmetic
|
||||
|
||||
// (a + ib) * (c + id)
|
||||
|
||||
float _Complex __mulsc3( float a, float b, float c, float d);
|
||||
double _Complex __muldc3(double a, double b, double c, double d);
|
||||
long double _Complex __mulxc3(long double a, long double b,
|
||||
long double c, long double d);
|
||||
long double _Complex __multc3(long double a, long double b,
|
||||
long double c, long double d); // ppc only
|
||||
|
||||
// (a + ib) / (c + id)
|
||||
|
||||
float _Complex __divsc3( float a, float b, float c, float d);
|
||||
double _Complex __divdc3(double a, double b, double c, double d);
|
||||
long double _Complex __divxc3(long double a, long double b,
|
||||
long double c, long double d);
|
||||
long double _Complex __divtc3(long double a, long double b,
|
||||
long double c, long double d); // ppc only
|
||||
|
||||
|
||||
// Runtime support
|
||||
|
||||
// __clear_cache() is used to tell process that new instructions have been
|
||||
// written to an address range. Necessary on processors that do not have
|
||||
// a unified instuction and data cache.
|
||||
void __clear_cache(void* start, void* end);
|
||||
|
||||
// __enable_execute_stack() is used with nested functions when a trampoline
|
||||
// function is written onto the stack and that page range needs to be made
|
||||
// executable.
|
||||
void __enable_execute_stack(void* addr);
|
||||
|
||||
// __gcc_personality_v0() is normally only called by the system unwinder.
|
||||
// C code (as opposed to C++) normally does not need a personality function
|
||||
// because there are no catch clauses or destructors to be run. But there
|
||||
// is a C language extension __attribute__((cleanup(func))) which marks local
|
||||
// variables as needing the cleanup function "func" to be run when the
|
||||
// variable goes out of scope. That includes when an exception is thrown,
|
||||
// so a personality handler is needed.
|
||||
_Unwind_Reason_Code __gcc_personality_v0(int version, _Unwind_Action actions,
|
||||
uint64_t exceptionClass, struct _Unwind_Exception* exceptionObject,
|
||||
_Unwind_Context_t context);
|
||||
|
||||
// for use with some implementations of assert() in <assert.h>
|
||||
void __eprintf(const char* format, const char* assertion_expression,
|
||||
const char* line, const char* file);
|
||||
|
||||
|
||||
|
||||
// Power PC specific functions
|
||||
|
||||
// There is no C interface to the saveFP/restFP functions. They are helper
|
||||
// functions called by the prolog and epilog of functions that need to save
|
||||
// a number of non-volatile float point registers.
|
||||
saveFP
|
||||
restFP
|
||||
|
||||
// PowerPC has a standard template for trampoline functions. This function
|
||||
// generates a custom trampoline function with the specific realFunc
|
||||
// and localsPtr values.
|
||||
void __trampoline_setup(uint32_t* trampOnStack, int trampSizeAllocated,
|
||||
const void* realFunc, void* localsPtr);
|
||||
|
||||
// adds two 128-bit double-double precision values ( x + y )
|
||||
long double __gcc_qadd(long double x, long double y);
|
||||
|
||||
// subtracts two 128-bit double-double precision values ( x - y )
|
||||
long double __gcc_qsub(long double x, long double y);
|
||||
|
||||
// multiples two 128-bit double-double precision values ( x * y )
|
||||
long double __gcc_qmul(long double x, long double y);
|
||||
|
||||
// divides two 128-bit double-double precision values ( x / y )
|
||||
long double __gcc_qdiv(long double a, long double b);
|
||||
|
||||
|
||||
// ARM specific functions
|
||||
|
||||
// There is no C interface to the switch* functions. These helper functions
|
||||
// are only needed by Thumb1 code for efficient switch table generation.
|
||||
switch16
|
||||
switch32
|
||||
switch8
|
||||
switchu8
|
||||
|
||||
// There is no C interface to the *_vfp_d8_d15_regs functions. There are
|
||||
// called in the prolog and epilog of Thumb1 functions. When the C++ ABI use
|
||||
// SJLJ for exceptions, each function with a catch clause or destuctors needs
|
||||
// to save and restore all registers in it prolog and epliog. But there is
|
||||
// no way to access vector and high float registers from thumb1 code, so the
|
||||
// compiler must add call outs to these helper functions in the prolog and
|
||||
// epilog.
|
||||
restore_vfp_d8_d15_regs
|
||||
save_vfp_d8_d15_regs
|
||||
|
||||
|
||||
// Note: long ago ARM processors did not have floating point hardware support.
|
||||
// Floating point was done in software and floating point parameters were
|
||||
// passed in integer registers. When hardware support was added for floating
|
||||
// point, new *vfp functions were added to do the same operations but with
|
||||
// floating point parameters in floating point registers.
|
||||
|
||||
// Undocumented functions
|
||||
|
||||
float __addsf3vfp(float a, float b); // Appears to return a + b
|
||||
double __adddf3vfp(double a, double b); // Appears to return a + b
|
||||
float __divsf3vfp(float a, float b); // Appears to return a / b
|
||||
double __divdf3vfp(double a, double b); // Appears to return a / b
|
||||
int __eqsf2vfp(float a, float b); // Appears to return one
|
||||
// iff a == b and neither is NaN.
|
||||
int __eqdf2vfp(double a, double b); // Appears to return one
|
||||
// iff a == b and neither is NaN.
|
||||
double __extendsfdf2vfp(float a); // Appears to convert from
|
||||
// float to double.
|
||||
int __fixdfsivfp(double a); // Appears to convert from
|
||||
// double to int.
|
||||
int __fixsfsivfp(float a); // Appears to convert from
|
||||
// float to int.
|
||||
unsigned int __fixunssfsivfp(float a); // Appears to convert from
|
||||
// float to unsigned int.
|
||||
unsigned int __fixunsdfsivfp(double a); // Appears to convert from
|
||||
// double to unsigned int.
|
||||
double __floatsidfvfp(int a); // Appears to convert from
|
||||
// int to double.
|
||||
float __floatsisfvfp(int a); // Appears to convert from
|
||||
// int to float.
|
||||
double __floatunssidfvfp(unsigned int a); // Appears to convert from
|
||||
// unisgned int to double.
|
||||
float __floatunssisfvfp(unsigned int a); // Appears to convert from
|
||||
// unisgned int to float.
|
||||
int __gedf2vfp(double a, double b); // Appears to return __gedf2
|
||||
// (a >= b)
|
||||
int __gesf2vfp(float a, float b); // Appears to return __gesf2
|
||||
// (a >= b)
|
||||
int __gtdf2vfp(double a, double b); // Appears to return __gtdf2
|
||||
// (a > b)
|
||||
int __gtsf2vfp(float a, float b); // Appears to return __gtsf2
|
||||
// (a > b)
|
||||
int __ledf2vfp(double a, double b); // Appears to return __ledf2
|
||||
// (a <= b)
|
||||
int __lesf2vfp(float a, float b); // Appears to return __lesf2
|
||||
// (a <= b)
|
||||
int __ltdf2vfp(double a, double b); // Appears to return __ltdf2
|
||||
// (a < b)
|
||||
int __ltsf2vfp(float a, float b); // Appears to return __ltsf2
|
||||
// (a < b)
|
||||
double __muldf3vfp(double a, double b); // Appears to return a * b
|
||||
float __mulsf3vfp(float a, float b); // Appears to return a * b
|
||||
int __nedf2vfp(double a, double b); // Appears to return __nedf2
|
||||
// (a != b)
|
||||
double __negdf2vfp(double a); // Appears to return -a
|
||||
float __negsf2vfp(float a); // Appears to return -a
|
||||
float __negsf2vfp(float a); // Appears to return -a
|
||||
double __subdf3vfp(double a, double b); // Appears to return a - b
|
||||
float __subsf3vfp(float a, float b); // Appears to return a - b
|
||||
float __truncdfsf2vfp(double a); // Appears to convert from
|
||||
// double to float.
|
||||
int __unorddf2vfp(double a, double b); // Appears to return __unorddf2
|
||||
int __unordsf2vfp(float a, float b); // Appears to return __unordsf2
|
||||
|
||||
|
||||
Preconditions are listed for each function at the definition when there are any.
|
||||
Any preconditions reflect the specification at
|
||||
http://gcc.gnu.org/onlinedocs/gccint/Libgcc.html#Libgcc.
|
||||
|
||||
Assumptions are listed in "int_lib.h", and in individual files. Where possible
|
||||
assumptions are checked at compile time.
|
||||
|
@ -1,3 +0,0 @@
|
||||
The Darwin platforms are all similar enough we roll them into one SDK, and use
|
||||
preprocessor tricks to get the right definitions for the few things which
|
||||
diverge between OS X and iOS.
|
@ -1,17 +0,0 @@
|
||||
/* ===-- errno.h - stub SDK header for compiler-rt --------------------------===
|
||||
*
|
||||
* 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 is a stub SDK header file. This file is not part of the interface of
|
||||
* this library nor an official version of the appropriate SDK header. It is
|
||||
* intended only to stub the features of this header required by compiler-rt.
|
||||
*
|
||||
* ===-----------------------------------------------------------------------===
|
||||
*/
|
||||
|
||||
#include <sys/errno.h>
|
@ -1,17 +0,0 @@
|
||||
/* ===-- fcntl.h - stub SDK header for compiler-rt --------------------------===
|
||||
*
|
||||
* 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 is a stub SDK header file. This file is not part of the interface of
|
||||
* this library nor an official version of the appropriate SDK header. It is
|
||||
* intended only to stub the features of this header required by compiler-rt.
|
||||
*
|
||||
* ===-----------------------------------------------------------------------===
|
||||
*/
|
||||
|
||||
#include <sys/fcntl.h>
|
@ -1,23 +0,0 @@
|
||||
/* ===-- limits.h - stub SDK header for compiler-rt -------------------------===
|
||||
*
|
||||
* 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 is a stub SDK header file. This file is not part of the interface of
|
||||
* this library nor an official version of the appropriate SDK header. It is
|
||||
* intended only to stub the features of this header required by compiler-rt.
|
||||
*
|
||||
* ===-----------------------------------------------------------------------===
|
||||
*/
|
||||
|
||||
#ifndef __LIMITS_H__
|
||||
#define __LIMITS_H__
|
||||
|
||||
/* This is only here as a landing pad for the include_next from the compiler's
|
||||
built-in limits.h. */
|
||||
|
||||
#endif /* __LIMITS_H__ */
|
@ -1,89 +0,0 @@
|
||||
/* ===-- stdio.h - stub SDK header for compiler-rt --------------------------===
|
||||
*
|
||||
* 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 is a stub SDK header file. This file is not part of the interface of
|
||||
* this library nor an official version of the appropriate SDK header. It is
|
||||
* intended only to stub the features of this header required by compiler-rt.
|
||||
*
|
||||
* ===-----------------------------------------------------------------------===
|
||||
*/
|
||||
|
||||
#ifndef __STDIO_H__
|
||||
#define __STDIO_H__
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct __sFILE FILE;
|
||||
typedef __SIZE_TYPE__ size_t;
|
||||
|
||||
/* Determine the appropriate fdopen, fopen(), and fwrite() functions. */
|
||||
#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__)
|
||||
# if defined(__i386)
|
||||
# define __FDOPEN_NAME "_fdopen$UNIX2003"
|
||||
# define __FOPEN_NAME "_fopen$UNIX2003"
|
||||
# define __FWRITE_NAME "_fwrite$UNIX2003"
|
||||
# elif defined(__x86_64__)
|
||||
# define __FDOPEN_NAME "_fdopen"
|
||||
# define __FOPEN_NAME "_fopen"
|
||||
# define __FWRITE_NAME "_fwrite"
|
||||
# elif defined(__arm)
|
||||
# define __FDOPEN_NAME "_fdopen"
|
||||
# define __FOPEN_NAME "_fopen"
|
||||
# define __FWRITE_NAME "_fwrite"
|
||||
# else
|
||||
# error "unrecognized architecture for targetting OS X"
|
||||
# endif
|
||||
#elif defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__)
|
||||
# if defined(__i386) || defined (__x86_64)
|
||||
# define __FDOPEN_NAME "_fdopen"
|
||||
# define __FOPEN_NAME "_fopen"
|
||||
# define __FWRITE_NAME "_fwrite"
|
||||
# elif defined(__arm)
|
||||
# define __FDOPEN_NAME "_fdopen"
|
||||
# define __FOPEN_NAME "_fopen"
|
||||
# define __FWRITE_NAME "_fwrite"
|
||||
# else
|
||||
# error "unrecognized architecture for targetting iOS"
|
||||
# endif
|
||||
#else
|
||||
# error "unrecognized architecture for targetting Darwin"
|
||||
#endif
|
||||
|
||||
# define stderr __stderrp
|
||||
extern FILE *__stderrp;
|
||||
|
||||
#ifndef SEEK_SET
|
||||
#define SEEK_SET 0 /* set file offset to offset */
|
||||
#endif
|
||||
#ifndef SEEK_CUR
|
||||
#define SEEK_CUR 1 /* set file offset to current plus offset */
|
||||
#endif
|
||||
#ifndef SEEK_END
|
||||
#define SEEK_END 2 /* set file offset to EOF plus offset */
|
||||
#endif
|
||||
|
||||
int fclose(FILE *);
|
||||
int fflush(FILE *);
|
||||
FILE *fopen(const char * __restrict, const char * __restrict) __asm(__FOPEN_NAME);
|
||||
FILE *fdopen(int, const char *) __asm(__FDOPEN_NAME);
|
||||
int fprintf(FILE * __restrict, const char * __restrict, ...);
|
||||
size_t fwrite(const void * __restrict, size_t, size_t, FILE * __restrict)
|
||||
__asm(__FWRITE_NAME);
|
||||
size_t fread(void * __restrict, size_t, size_t, FILE * __restrict);
|
||||
long ftell(FILE *);
|
||||
int fseek(FILE *, long, int);
|
||||
int snprintf(char * __restrict, size_t, const char * __restrict, ...);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __STDIO_H__ */
|
@ -1,32 +0,0 @@
|
||||
/* ===-- stdlib.h - stub SDK header for compiler-rt -------------------------===
|
||||
*
|
||||
* 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 is a stub SDK header file. This file is not part of the interface of
|
||||
* this library nor an official version of the appropriate SDK header. It is
|
||||
* intended only to stub the features of this header required by compiler-rt.
|
||||
*
|
||||
* ===-----------------------------------------------------------------------===
|
||||
*/
|
||||
|
||||
#ifndef __STDLIB_H__
|
||||
#define __STDLIB_H__
|
||||
|
||||
#define NULL ((void *)0)
|
||||
|
||||
typedef __SIZE_TYPE__ size_t;
|
||||
|
||||
void abort(void) __attribute__((__noreturn__));
|
||||
int atexit(void (*)(void));
|
||||
int atoi(const char *);
|
||||
void free(void *);
|
||||
char *getenv(const char *);
|
||||
void *malloc(size_t);
|
||||
void *realloc(void *, size_t);
|
||||
|
||||
#endif /* __STDLIB_H__ */
|
@ -1,52 +0,0 @@
|
||||
/* ===-- string.h - stub SDK header for compiler-rt -------------------------===
|
||||
*
|
||||
* 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 is a stub SDK header file. This file is not part of the interface of
|
||||
* this library nor an official version of the appropriate SDK header. It is
|
||||
* intended only to stub the features of this header required by compiler-rt.
|
||||
*
|
||||
* ===-----------------------------------------------------------------------===
|
||||
*/
|
||||
|
||||
#ifndef __STRING_H__
|
||||
#define __STRING_H__
|
||||
|
||||
typedef __SIZE_TYPE__ size_t;
|
||||
|
||||
int memcmp(const void *, const void *, size_t);
|
||||
void *memcpy(void *, const void *, size_t);
|
||||
void *memset(void *, int, size_t);
|
||||
char *strcat(char *, const char *);
|
||||
char *strcpy(char *, const char *);
|
||||
char *strdup(const char *);
|
||||
size_t strlen(const char *);
|
||||
char *strncpy(char *, const char *, size_t);
|
||||
|
||||
/* Determine the appropriate strerror() function. */
|
||||
#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__)
|
||||
# if defined(__i386)
|
||||
# define __STRERROR_NAME "_strerror$UNIX2003"
|
||||
# elif defined(__x86_64__) || defined(__arm)
|
||||
# define __STRERROR_NAME "_strerror"
|
||||
# else
|
||||
# error "unrecognized architecture for targetting OS X"
|
||||
# endif
|
||||
#elif defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__)
|
||||
# if defined(__i386) || defined (__x86_64) || defined(__arm)
|
||||
# define __STRERROR_NAME "_strerror"
|
||||
# else
|
||||
# error "unrecognized architecture for targetting iOS"
|
||||
# endif
|
||||
#else
|
||||
# error "unrecognized architecture for targetting Darwin"
|
||||
#endif
|
||||
|
||||
char *strerror(int) __asm(__STRERROR_NAME);
|
||||
|
||||
#endif /* __STRING_H__ */
|
@ -1,31 +0,0 @@
|
||||
/* ===-- errno.h - stub SDK header for compiler-rt --------------------------===
|
||||
*
|
||||
* 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 is a stub SDK header file. This file is not part of the interface of
|
||||
* this library nor an official version of the appropriate SDK header. It is
|
||||
* intended only to stub the features of this header required by compiler-rt.
|
||||
*
|
||||
* ===-----------------------------------------------------------------------===
|
||||
*/
|
||||
|
||||
#ifndef _SYS_ERRNO_H_
|
||||
#define _SYS_ERRNO_H_
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern int *__error(void);
|
||||
#define errno (*__error())
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,52 +0,0 @@
|
||||
/* ===-- fcntl.h - stub SDK header for compiler-rt --------------------------===
|
||||
*
|
||||
* 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 is a stub SDK header file. This file is not part of the interface of
|
||||
* this library nor an official version of the appropriate SDK header. It is
|
||||
* intended only to stub the features of this header required by compiler-rt.
|
||||
*
|
||||
* ===-----------------------------------------------------------------------===
|
||||
*/
|
||||
|
||||
#ifndef _SYS_FCNTL_H_
|
||||
#define _SYS_FCNTL_H_
|
||||
|
||||
/* Determine the appropriate open function. */
|
||||
#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__)
|
||||
# if defined(__i386)
|
||||
# define __OPEN_NAME "_open$UNIX2003"
|
||||
# elif defined(__x86_64__)
|
||||
# define __OPEN_NAME "_open"
|
||||
# elif defined(__arm)
|
||||
# define __OPEN_NAME "_open"
|
||||
# else
|
||||
# error "unrecognized architecture for targetting OS X"
|
||||
# endif
|
||||
#elif defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__)
|
||||
# if defined(__i386) || defined (__x86_64)
|
||||
# define __OPEN_NAME "_open"
|
||||
# elif defined(__arm)
|
||||
# define __OPEN_NAME "_open"
|
||||
# else
|
||||
# error "unrecognized architecture for targetting iOS"
|
||||
# endif
|
||||
#else
|
||||
# error "unrecognized architecture for targetting Darwin"
|
||||
#endif
|
||||
|
||||
#define O_RDONLY 0x0000 /* open for reading only */
|
||||
#define O_WRONLY 0x0001 /* open for writing only */
|
||||
#define O_RDWR 0x0002 /* open for reading and writing */
|
||||
#define O_ACCMODE 0x0003 /* mask for above modes */
|
||||
|
||||
#define O_CREAT 0x0200 /* create if nonexistant */
|
||||
|
||||
int open(const char *, int, ...) __asm(__OPEN_NAME);
|
||||
|
||||
#endif /* !_SYS_FCNTL_H_ */
|
@ -1,42 +0,0 @@
|
||||
/* ===-- mman.h - stub SDK header for compiler-rt ---------------------------===
|
||||
*
|
||||
* 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 is a stub SDK header file. This file is not part of the interface of
|
||||
* this library nor an official version of the appropriate SDK header. It is
|
||||
* intended only to stub the features of this header required by compiler-rt.
|
||||
*
|
||||
* ===-----------------------------------------------------------------------===
|
||||
*/
|
||||
|
||||
#ifndef __SYS_MMAN_H__
|
||||
#define __SYS_MMAN_H__
|
||||
|
||||
typedef __SIZE_TYPE__ size_t;
|
||||
|
||||
#define PROT_NONE 0x00
|
||||
#define PROT_READ 0x01
|
||||
#define PROT_WRITE 0x02
|
||||
#define PROT_EXEC 0x04
|
||||
|
||||
#define MAP_SHARED 0x0001
|
||||
#define MAP_PRIVATE 0x0002
|
||||
|
||||
#define MAP_FILE 0x0000
|
||||
#define MAP_ANON 0x1000
|
||||
|
||||
#define MS_ASYNC 0x0001
|
||||
#define MS_INVALIDATE 0x0002
|
||||
#define MS_SYNC 0x0010
|
||||
|
||||
void *mmap(void *addr, size_t len, int prot, int flags, int fd,
|
||||
long long offset);
|
||||
int munmap(void *addr, size_t len);
|
||||
int msync(void *addr, size_t len, int flags);
|
||||
|
||||
#endif /* __SYS_MMAN_H__ */
|
@ -1,25 +0,0 @@
|
||||
/* ===-- stat.h - stub SDK header for compiler-rt ---------------------------===
|
||||
*
|
||||
* 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 is a stub SDK header file. This file is not part of the interface of
|
||||
* this library nor an official version of the appropriate SDK header. It is
|
||||
* intended only to stub the features of this header required by compiler-rt.
|
||||
*
|
||||
* ===-----------------------------------------------------------------------===
|
||||
*/
|
||||
|
||||
#ifndef __SYS_STAT_H__
|
||||
#define __SYS_STAT_H__
|
||||
|
||||
typedef unsigned short uint16_t;
|
||||
typedef uint16_t mode_t;
|
||||
|
||||
int mkdir(const char *, mode_t);
|
||||
|
||||
#endif /* __SYS_STAT_H__ */
|
@ -1,20 +0,0 @@
|
||||
/* ===-- types.h - stub SDK header for compiler-rt --------------------------===
|
||||
*
|
||||
* 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 is a stub SDK header file. This file is not part of the interface of
|
||||
* this library nor an official version of the appropriate SDK header. It is
|
||||
* intended only to stub the features of this header required by compiler-rt.
|
||||
*
|
||||
* ===-----------------------------------------------------------------------===
|
||||
*/
|
||||
|
||||
#ifndef __SYS_TYPES_H__
|
||||
#define __SYS_TYPES_H__
|
||||
|
||||
#endif /* __SYS_TYPES_H__ */
|
@ -35,6 +35,7 @@ extern int fflush(FILE *);
|
||||
extern FILE *fopen(const char * restrict, const char * restrict);
|
||||
extern FILE *fdopen(int, const char * restrict);
|
||||
extern int fprintf(FILE * restrict, const char * restrict, ...);
|
||||
extern int fputc(int, FILE *);
|
||||
extern size_t fwrite(const void * restrict, size_t, size_t, FILE * restrict);
|
||||
extern size_t fread(void * restrict, size_t, size_t, FILE * restrict);
|
||||
extern long ftell(FILE *);
|
||||
|
@ -1,4 +1,5 @@
|
||||
include(AddLLVM)
|
||||
include(ExternalProject)
|
||||
include(LLVMParseArguments)
|
||||
include(CompilerRTUtils)
|
||||
|
||||
@ -13,7 +14,7 @@ macro(add_compiler_rt_object_library name arch)
|
||||
parse_arguments(LIB "SOURCES;CFLAGS;DEFS" "" ${ARGN})
|
||||
add_library(${name}.${arch} OBJECT ${LIB_SOURCES})
|
||||
set_target_compile_flags(${name}.${arch}
|
||||
${TARGET_${arch}_CFLAGS} ${LIB_CFLAGS})
|
||||
${CMAKE_CXX_FLAGS} ${TARGET_${arch}_CFLAGS} ${LIB_CFLAGS})
|
||||
set_property(TARGET ${name}.${arch} APPEND PROPERTY
|
||||
COMPILE_DEFINITIONS ${LIB_DEFS})
|
||||
else()
|
||||
@ -37,34 +38,47 @@ macro(add_compiler_rt_darwin_object_library name os)
|
||||
COMPILE_DEFINITIONS ${LIB_DEFS})
|
||||
endmacro()
|
||||
|
||||
# Adds static runtime for a given architecture and puts it in the proper
|
||||
# directory in the build and install trees.
|
||||
# add_compiler_rt_static_runtime(<name> <arch>
|
||||
# Adds static or shared runtime for a given architecture and puts it in the
|
||||
# proper directory in the build and install trees.
|
||||
# add_compiler_rt_runtime(<name> <arch> {STATIC,SHARED}
|
||||
# SOURCES <source files>
|
||||
# CFLAGS <compile flags>
|
||||
# DEFS <compile definitions>)
|
||||
macro(add_compiler_rt_static_runtime name arch)
|
||||
# DEFS <compile definitions>
|
||||
# OUTPUT_NAME <output library name>)
|
||||
macro(add_compiler_rt_runtime name arch type)
|
||||
if(CAN_TARGET_${arch})
|
||||
parse_arguments(LIB "SOURCES;CFLAGS;DEFS" "" ${ARGN})
|
||||
add_library(${name} STATIC ${LIB_SOURCES})
|
||||
parse_arguments(LIB "SOURCES;CFLAGS;DEFS;OUTPUT_NAME" "" ${ARGN})
|
||||
add_library(${name} ${type} ${LIB_SOURCES})
|
||||
# Setup compile flags and definitions.
|
||||
set_target_compile_flags(${name}
|
||||
${TARGET_${arch}_CFLAGS} ${LIB_CFLAGS})
|
||||
set_target_link_flags(${name}
|
||||
${TARGET_${arch}_CFLAGS} ${LIB_CFLAGS})
|
||||
set_property(TARGET ${name} APPEND PROPERTY
|
||||
COMPILE_DEFINITIONS ${LIB_DEFS})
|
||||
# Setup correct output directory in the build tree.
|
||||
set_target_properties(${name} PROPERTIES
|
||||
ARCHIVE_OUTPUT_DIRECTORY ${COMPILER_RT_LIBRARY_OUTPUT_DIR})
|
||||
ARCHIVE_OUTPUT_DIRECTORY ${COMPILER_RT_LIBRARY_OUTPUT_DIR}
|
||||
LIBRARY_OUTPUT_DIRECTORY ${COMPILER_RT_LIBRARY_OUTPUT_DIR}
|
||||
RUNTIME_OUTPUT_DIRECTORY ${COMPILER_RT_LIBRARY_OUTPUT_DIR})
|
||||
if ("${LIB_OUTPUT_NAME}" STREQUAL "")
|
||||
set_target_properties(${name} PROPERTIES
|
||||
OUTPUT_NAME ${name}${COMPILER_RT_OS_SUFFIX})
|
||||
else()
|
||||
set_target_properties(${name} PROPERTIES
|
||||
OUTPUT_NAME ${LIB_OUTPUT_NAME})
|
||||
endif()
|
||||
# Add installation command.
|
||||
install(TARGETS ${name}
|
||||
ARCHIVE DESTINATION ${COMPILER_RT_LIBRARY_INSTALL_DIR})
|
||||
add_dependencies(compiler-rt ${name})
|
||||
ARCHIVE DESTINATION ${COMPILER_RT_LIBRARY_INSTALL_DIR}
|
||||
LIBRARY DESTINATION ${COMPILER_RT_LIBRARY_INSTALL_DIR}
|
||||
RUNTIME DESTINATION ${COMPILER_RT_LIBRARY_INSTALL_DIR})
|
||||
else()
|
||||
message(FATAL_ERROR "Archtecture ${arch} can't be targeted")
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
# Same as add_compiler_rt_static_runtime, but creates a universal library
|
||||
# Same as add_compiler_rt_runtime(... STATIC), but creates a universal library
|
||||
# for several architectures.
|
||||
# add_compiler_rt_osx_static_runtime(<name> ARCH <architectures>
|
||||
# SOURCES <source files>
|
||||
@ -81,7 +95,6 @@ macro(add_compiler_rt_osx_static_runtime name)
|
||||
ARCHIVE_OUTPUT_DIRECTORY ${COMPILER_RT_LIBRARY_OUTPUT_DIR})
|
||||
install(TARGETS ${name}
|
||||
ARCHIVE DESTINATION ${COMPILER_RT_LIBRARY_INSTALL_DIR})
|
||||
add_dependencies(compiler-rt ${name})
|
||||
endmacro()
|
||||
|
||||
# Adds dynamic runtime library on osx/iossim, which supports multiple
|
||||
@ -104,20 +117,43 @@ macro(add_compiler_rt_darwin_dynamic_runtime name os)
|
||||
LIBRARY_OUTPUT_DIRECTORY ${COMPILER_RT_LIBRARY_OUTPUT_DIR})
|
||||
install(TARGETS ${name}
|
||||
LIBRARY DESTINATION ${COMPILER_RT_LIBRARY_INSTALL_DIR})
|
||||
add_dependencies(compiler-rt ${name})
|
||||
endmacro()
|
||||
|
||||
set(COMPILER_RT_TEST_CFLAGS)
|
||||
|
||||
# Unittests support.
|
||||
set(COMPILER_RT_GTEST_PATH ${LLVM_MAIN_SRC_DIR}/utils/unittest/googletest)
|
||||
set(COMPILER_RT_GTEST_SOURCE ${COMPILER_RT_GTEST_PATH}/src/gtest-all.cc)
|
||||
set(COMPILER_RT_GTEST_INCLUDE_CFLAGS
|
||||
set(COMPILER_RT_GTEST_CFLAGS
|
||||
-DGTEST_NO_LLVM_RAW_OSTREAM=1
|
||||
-DGTEST_HAS_RTTI=0
|
||||
-I${COMPILER_RT_GTEST_PATH}/include
|
||||
-I${COMPILER_RT_GTEST_PATH}
|
||||
)
|
||||
|
||||
# Use Clang to link objects into a single executable with just-built
|
||||
# Clang, using specific link flags. Make executable a part of provided
|
||||
if(MSVC)
|
||||
# clang doesn't support exceptions on Windows yet.
|
||||
list(APPEND COMPILER_RT_TEST_CFLAGS
|
||||
-D_HAS_EXCEPTIONS=0)
|
||||
|
||||
# We should teach clang to understand "#pragma intrinsic", see PR19898.
|
||||
list(APPEND COMPILER_RT_TEST_CFLAGS -Wno-undefined-inline)
|
||||
|
||||
# Clang doesn't support SEH on Windows yet.
|
||||
list(APPEND COMPILER_RT_GTEST_CFLAGS -DGTEST_HAS_SEH=0)
|
||||
|
||||
# gtest use a lot of stuff marked as deprecated on Windows.
|
||||
list(APPEND COMPILER_RT_GTEST_CFLAGS -Wno-deprecated-declarations)
|
||||
|
||||
# Visual Studio 2012 only supports up to 8 template parameters in
|
||||
# std::tr1::tuple by default, but gtest requires 10
|
||||
if(MSVC_VERSION EQUAL 1700)
|
||||
list(APPEND COMPILER_RT_GTEST_CFLAGS -D_VARIADIC_MAX=10)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Link objects into a single executable with COMPILER_RT_TEST_COMPILER,
|
||||
# using specified link flags. Make executable a part of provided
|
||||
# test_suite.
|
||||
# add_compiler_rt_test(<test_suite> <test_name>
|
||||
# OBJECTS <object files>
|
||||
@ -126,20 +162,98 @@ set(COMPILER_RT_GTEST_INCLUDE_CFLAGS
|
||||
macro(add_compiler_rt_test test_suite test_name)
|
||||
parse_arguments(TEST "OBJECTS;DEPS;LINK_FLAGS" "" ${ARGN})
|
||||
set(output_bin "${CMAKE_CURRENT_BINARY_DIR}/${test_name}")
|
||||
# Use host compiler in a standalone build, and just-built Clang otherwise.
|
||||
if(NOT COMPILER_RT_STANDALONE_BUILD)
|
||||
list(APPEND TEST_DEPS clang)
|
||||
endif()
|
||||
# If we're not on MSVC, include the linker flags from CMAKE but override them
|
||||
# with the provided link flags. This ensures that flags which are required to
|
||||
# link programs at all are included, but the changes needed for the test
|
||||
# trump. With MSVC we can't do that because CMake is set up to run link.exe
|
||||
# when linking, not the compiler. Here, we hack it to use the compiler
|
||||
# because we want to use -fsanitize flags.
|
||||
if(NOT MSVC)
|
||||
set(TEST_LINK_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${TEST_LINK_FLAGS}")
|
||||
separate_arguments(TEST_LINK_FLAGS)
|
||||
endif()
|
||||
add_custom_target(${test_name}
|
||||
COMMAND clang ${TEST_OBJECTS} -o "${output_bin}"
|
||||
COMMAND ${COMPILER_RT_TEST_COMPILER} ${TEST_OBJECTS}
|
||||
-o "${output_bin}"
|
||||
${TEST_LINK_FLAGS}
|
||||
DEPENDS clang ${TEST_DEPS})
|
||||
DEPENDS ${TEST_DEPS})
|
||||
# Make the test suite depend on the binary.
|
||||
add_dependencies(${test_suite} ${test_name})
|
||||
endmacro()
|
||||
|
||||
macro(add_compiler_rt_resource_file target_name file_name)
|
||||
set(src_file "${CMAKE_CURRENT_SOURCE_DIR}/${file_name}")
|
||||
set(dst_file "${CLANG_RESOURCE_DIR}/${file_name}")
|
||||
add_custom_target(${target_name}
|
||||
set(dst_file "${COMPILER_RT_OUTPUT_DIR}/${file_name}")
|
||||
add_custom_command(OUTPUT ${dst_file}
|
||||
DEPENDS ${src_file}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${src_file} ${dst_file}
|
||||
DEPENDS ${file_name})
|
||||
COMMENT "Copying ${file_name}...")
|
||||
add_custom_target(${target_name} DEPENDS ${dst_file})
|
||||
# Install in Clang resource directory.
|
||||
install(FILES ${file_name} DESTINATION ${LIBCLANG_INSTALL_PATH})
|
||||
install(FILES ${file_name} DESTINATION ${COMPILER_RT_INSTALL_PATH})
|
||||
endmacro()
|
||||
|
||||
macro(add_compiler_rt_script name)
|
||||
set(dst ${COMPILER_RT_EXEC_OUTPUT_DIR}/${name})
|
||||
set(src ${CMAKE_CURRENT_SOURCE_DIR}/${name})
|
||||
add_custom_command(OUTPUT ${dst}
|
||||
DEPENDS ${src}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${src} ${dst}
|
||||
COMMENT "Copying ${name}...")
|
||||
add_custom_target(${name} DEPENDS ${dst})
|
||||
install(FILES ${dst}
|
||||
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
|
||||
DESTINATION ${COMPILER_RT_INSTALL_PATH}/bin)
|
||||
endmacro(add_compiler_rt_script src name)
|
||||
|
||||
# Builds custom version of libc++ and installs it in <prefix>.
|
||||
# Can be used to build sanitized versions of libc++ for running unit tests.
|
||||
# add_custom_libcxx(<name> <prefix>
|
||||
# DEPS <list of build deps>
|
||||
# CFLAGS <list of compile flags>)
|
||||
macro(add_custom_libcxx name prefix)
|
||||
if(NOT COMPILER_RT_HAS_LIBCXX_SOURCES)
|
||||
message(FATAL_ERROR "libcxx not found!")
|
||||
endif()
|
||||
|
||||
parse_arguments(LIBCXX "DEPS;CFLAGS" "" ${ARGN})
|
||||
foreach(flag ${LIBCXX_CFLAGS})
|
||||
set(flagstr "${flagstr} ${flag}")
|
||||
endforeach()
|
||||
set(LIBCXX_CFLAGS ${flagstr})
|
||||
|
||||
if(NOT COMPILER_RT_STANDALONE_BUILD)
|
||||
list(APPEND LIBCXX_DEPS clang)
|
||||
endif()
|
||||
|
||||
ExternalProject_Add(${name}
|
||||
PREFIX ${prefix}
|
||||
SOURCE_DIR ${COMPILER_RT_LIBCXX_PATH}
|
||||
CMAKE_ARGS -DCMAKE_C_COMPILER=${COMPILER_RT_TEST_COMPILER}
|
||||
-DCMAKE_CXX_COMPILER=${COMPILER_RT_TEST_COMPILER}
|
||||
-DCMAKE_C_FLAGS=${LIBCXX_CFLAGS}
|
||||
-DCMAKE_CXX_FLAGS=${LIBCXX_CFLAGS}
|
||||
-DCMAKE_BUILD_TYPE=Release
|
||||
-DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
|
||||
LOG_BUILD 1
|
||||
LOG_CONFIGURE 1
|
||||
LOG_INSTALL 1
|
||||
)
|
||||
|
||||
ExternalProject_Add_Step(${name} force-reconfigure
|
||||
DEPENDERS configure
|
||||
ALWAYS 1
|
||||
)
|
||||
|
||||
ExternalProject_Add_Step(${name} clobber
|
||||
COMMAND ${CMAKE_COMMAND} -E remove_directory <BINARY_DIR>
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory <BINARY_DIR>
|
||||
COMMENT "Clobberring ${name} build directory..."
|
||||
DEPENDERS configure
|
||||
DEPENDS ${LIBCXX_DEPS}
|
||||
)
|
||||
endmacro()
|
||||
|
@ -1,6 +1,6 @@
|
||||
include(LLVMParseArguments)
|
||||
|
||||
# Compile a source into an object file with just-built Clang using
|
||||
# Compile a source into an object file with COMPILER_RT_TEST_COMPILER using
|
||||
# a provided compile flags and dependenices.
|
||||
# clang_compile(<object> <source>
|
||||
# CFLAGS <list of compile flags>
|
||||
@ -8,9 +8,74 @@ include(LLVMParseArguments)
|
||||
macro(clang_compile object_file source)
|
||||
parse_arguments(SOURCE "CFLAGS;DEPS" "" ${ARGN})
|
||||
get_filename_component(source_rpath ${source} REALPATH)
|
||||
if(NOT COMPILER_RT_STANDALONE_BUILD)
|
||||
list(APPEND SOURCE_DEPS clang)
|
||||
endif()
|
||||
if (TARGET CompilerRTUnitTestCheckCxx)
|
||||
list(APPEND SOURCE_DEPS CompilerRTUnitTestCheckCxx)
|
||||
endif()
|
||||
string(REGEX MATCH "[.](cc|cpp)$" is_cxx ${source_rpath})
|
||||
if(is_cxx)
|
||||
string(REPLACE " " ";" global_flags "${CMAKE_CXX_FLAGS}")
|
||||
else()
|
||||
string(REPLACE " " ";" global_flags "${CMAKE_C_FLAGS}")
|
||||
endif()
|
||||
# On Windows, CMAKE_*_FLAGS are built for MSVC but we use the GCC clang.exe
|
||||
# which doesn't support flags starting with "/smth". Replace those with
|
||||
# "-smth" equivalents.
|
||||
if(MSVC)
|
||||
string(REGEX REPLACE "^/" "-" global_flags "${global_flags}")
|
||||
string(REPLACE ";/" ";-" global_flags "${global_flags}")
|
||||
endif()
|
||||
# Ignore unknown warnings. CMAKE_CXX_FLAGS may contain GCC-specific options
|
||||
# which are not supported by Clang.
|
||||
list(APPEND global_flags -Wno-unknown-warning-option)
|
||||
set(compile_flags ${global_flags} ${SOURCE_CFLAGS})
|
||||
add_custom_command(
|
||||
OUTPUT ${object_file}
|
||||
COMMAND clang ${SOURCE_CFLAGS} -c -o "${object_file}" ${source_rpath}
|
||||
COMMAND ${COMPILER_RT_TEST_COMPILER} ${compile_flags} -c
|
||||
-o "${object_file}"
|
||||
${source_rpath}
|
||||
MAIN_DEPENDENCY ${source}
|
||||
DEPENDS clang ${SOURCE_DEPS})
|
||||
DEPENDS ${SOURCE_DEPS})
|
||||
endmacro()
|
||||
|
||||
# On Darwin, there are no system-wide C++ headers and the just-built clang is
|
||||
# therefore not able to compile C++ files unless they are copied/symlinked into
|
||||
# ${LLVM_BINARY_DIR}/include/c++
|
||||
# The just-built clang is used to build compiler-rt unit tests. Let's detect
|
||||
# this before we try to build the tests and print out a suggestion how to fix
|
||||
# it.
|
||||
# On other platforms, this is currently not an issue.
|
||||
macro(clang_compiler_add_cxx_check)
|
||||
if (APPLE)
|
||||
set(CMD
|
||||
"echo '#include <iostream>' | ${COMPILER_RT_TEST_COMPILER} -E -x c++ - > /dev/null"
|
||||
"if [ $? != 0 ] "
|
||||
" then echo"
|
||||
" echo 'Your just-built clang cannot find C++ headers, which are needed to build and run compiler-rt tests.'"
|
||||
" echo 'You should copy or symlink your system C++ headers into ${LLVM_BINARY_DIR}/include/c++'"
|
||||
" if [ -d $(dirname $(dirname $(xcrun -f clang)))/include/c++ ]"
|
||||
" then echo 'e.g. with:'"
|
||||
" echo ' cp -r' $(dirname $(dirname $(xcrun -f clang)))/include/c++ '${LLVM_BINARY_DIR}/include/'"
|
||||
" elif [ -d $(dirname $(dirname $(xcrun -f clang)))/lib/c++ ]"
|
||||
" then echo 'e.g. with:'"
|
||||
" echo ' cp -r' $(dirname $(dirname $(xcrun -f clang)))/lib/c++ '${LLVM_BINARY_DIR}/include/'"
|
||||
" fi"
|
||||
" echo 'This can also be fixed by checking out the libcxx project from llvm.org and installing the headers'"
|
||||
" echo 'into your build directory:'"
|
||||
" echo ' cd ${LLVM_SOURCE_DIR}/projects && svn co http://llvm.org/svn/llvm-project/libcxx/trunk libcxx'"
|
||||
" echo ' cd ${LLVM_BINARY_DIR} && make -C ${LLVM_SOURCE_DIR}/projects/libcxx installheaders HEADER_DIR=${LLVM_BINARY_DIR}/include'"
|
||||
" echo"
|
||||
" false"
|
||||
"fi"
|
||||
)
|
||||
add_custom_target(CompilerRTUnitTestCheckCxx
|
||||
COMMAND bash -c "${CMD}"
|
||||
COMMENT "Checking that just-built clang can find C++ headers..."
|
||||
VERBATIM)
|
||||
if (TARGET clang)
|
||||
ADD_DEPENDENCIES(CompilerRTUnitTestCheckCxx clang)
|
||||
endif()
|
||||
endif()
|
||||
endmacro()
|
||||
|
@ -1,14 +1,18 @@
|
||||
include(LLVMParseArguments)
|
||||
|
||||
# Link a shared library with just-built Clang.
|
||||
# Link a shared library with COMPILER_RT_TEST_COMPILER.
|
||||
# clang_link_shared(<output.so>
|
||||
# OBJECTS <list of input objects>
|
||||
# LINKFLAGS <list of link flags>
|
||||
# DEPS <list of dependencies>)
|
||||
macro(clang_link_shared so_file)
|
||||
parse_arguments(SOURCE "OBJECTS;LINKFLAGS;DEPS" "" ${ARGN})
|
||||
if(NOT COMPILER_RT_STANDALONE_BUILD)
|
||||
list(APPEND SOURCE_DEPS clang)
|
||||
endif()
|
||||
add_custom_command(
|
||||
OUTPUT ${so_file}
|
||||
COMMAND clang -o "${so_file}" -shared ${SOURCE_LINKFLAGS} ${SOURCE_OBJECTS}
|
||||
DEPENDS clang ${SOURCE_DEPS})
|
||||
COMMAND ${COMPILER_RT_TEST_COMPILER} -o "${so_file}" -shared
|
||||
${SOURCE_LINKFLAGS} ${SOURCE_OBJECTS}
|
||||
DEPENDS ${SOURCE_DEPS})
|
||||
endmacro()
|
||||
|
@ -2,6 +2,7 @@
|
||||
# define a handy helper function for it. The compile flags setting in CMake
|
||||
# has serious issues that make its syntax challenging at best.
|
||||
function(set_target_compile_flags target)
|
||||
set(argstring "")
|
||||
foreach(arg ${ARGN})
|
||||
set(argstring "${argstring} ${arg}")
|
||||
endforeach()
|
||||
@ -9,24 +10,13 @@ function(set_target_compile_flags target)
|
||||
endfunction()
|
||||
|
||||
function(set_target_link_flags target)
|
||||
set(argstring "")
|
||||
foreach(arg ${ARGN})
|
||||
set(argstring "${argstring} ${arg}")
|
||||
endforeach()
|
||||
set_property(TARGET ${target} PROPERTY LINK_FLAGS "${argstring}")
|
||||
endfunction()
|
||||
|
||||
# Check if a given flag is present in a space-separated flag_string.
|
||||
# Store the result in out_var.
|
||||
function(find_flag_in_string flag_string flag out_var)
|
||||
string(REPLACE " " ";" flag_list ${flag_string})
|
||||
list(FIND flag_list ${flag} flag_pos)
|
||||
if(NOT flag_pos EQUAL -1)
|
||||
set(${out_var} TRUE PARENT_SCOPE)
|
||||
else()
|
||||
set(${out_var} FALSE PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Set the variable var_PYBOOL to True if var holds a true-ish string,
|
||||
# otherwise set it to False.
|
||||
macro(pythonize_bool var)
|
||||
@ -36,3 +26,26 @@ macro(pythonize_bool var)
|
||||
set(${var}_PYBOOL False)
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
# Appends value to all lists in ARGN, if the condition is true.
|
||||
macro(append_list_if condition value)
|
||||
if(${condition})
|
||||
foreach(list ${ARGN})
|
||||
list(APPEND ${list} ${value})
|
||||
endforeach()
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
# Appends value to all strings in ARGN, if the condition is true.
|
||||
macro(append_string_if condition value)
|
||||
if(${condition})
|
||||
foreach(str ${ARGN})
|
||||
set(${str} "${${str}} ${value}")
|
||||
endforeach()
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro(append_no_rtti_flag list)
|
||||
append_list_if(COMPILER_RT_HAS_FNO_RTTI_FLAG -fno-rtti ${list})
|
||||
append_list_if(COMPILER_RT_HAS_GR_FLAG /GR- ${list})
|
||||
endmacro()
|
||||
|
@ -12,21 +12,36 @@ set(SANITIZER_LINT_SCRIPT
|
||||
# symbol names that should be exported as well.
|
||||
# add_sanitizer_rt_symbols(<name> <files with extra symbols to export>)
|
||||
macro(add_sanitizer_rt_symbols name)
|
||||
get_target_property(libfile ${name} LOCATION)
|
||||
set(symsfile "${libfile}.syms")
|
||||
add_custom_command(OUTPUT ${symsfile}
|
||||
set(stamp ${CMAKE_CURRENT_BINARY_DIR}/${name}.syms-stamp)
|
||||
add_custom_command(OUTPUT ${stamp}
|
||||
COMMAND ${PYTHON_EXECUTABLE}
|
||||
${SANITIZER_GEN_DYNAMIC_LIST} ${libfile} ${ARGN}
|
||||
> ${symsfile}
|
||||
${SANITIZER_GEN_DYNAMIC_LIST} $<TARGET_FILE:${name}> ${ARGN}
|
||||
> $<TARGET_FILE:${name}>.syms
|
||||
COMMAND ${CMAKE_COMMAND} -E touch ${stamp}
|
||||
DEPENDS ${name} ${SANITIZER_GEN_DYNAMIC_LIST} ${ARGN}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
COMMENT "Generating exported symbols for ${name}"
|
||||
VERBATIM)
|
||||
add_custom_target(${name}-symbols ALL
|
||||
DEPENDS ${symsfile}
|
||||
DEPENDS ${stamp}
|
||||
SOURCES ${SANITIZER_GEN_DYNAMIC_LIST} ${ARGN})
|
||||
install(FILES ${symsfile} DESTINATION ${COMPILER_RT_LIBRARY_INSTALL_DIR})
|
||||
add_dependencies(compiler-rt ${name}-symbols)
|
||||
|
||||
if(NOT CMAKE_VERSION VERSION_LESS 3.0)
|
||||
install(FILES $<TARGET_FILE:${name}>.syms
|
||||
DESTINATION ${COMPILER_RT_LIBRARY_INSTALL_DIR})
|
||||
else()
|
||||
# Per-config install location.
|
||||
if(CMAKE_CONFIGURATION_TYPES)
|
||||
foreach(c ${CMAKE_CONFIGURATION_TYPES})
|
||||
get_target_property(libfile ${name} LOCATION_${c})
|
||||
install(FILES ${libfile}.syms CONFIGURATIONS ${c}
|
||||
DESTINATION ${COMPILER_RT_LIBRARY_INSTALL_DIR})
|
||||
endforeach()
|
||||
else()
|
||||
get_target_property(libfile ${name} LOCATION_${CMAKE_BUILD_TYPE})
|
||||
install(FILES ${libfile}.syms DESTINATION ${COMPILER_RT_LIBRARY_INSTALL_DIR})
|
||||
endif()
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
# Add target to check code style for sanitizer runtimes.
|
||||
@ -34,6 +49,7 @@ if(UNIX)
|
||||
add_custom_target(SanitizerLintCheck
|
||||
COMMAND LLVM_CHECKOUT=${LLVM_MAIN_SRC_DIR} SILENT=1 TMPDIR=
|
||||
PYTHON_EXECUTABLE=${PYTHON_EXECUTABLE}
|
||||
COMPILER_RT=${COMPILER_RT_SOURCE_DIR}
|
||||
${SANITIZER_LINT_SCRIPT}
|
||||
DEPENDS ${SANITIZER_LINT_SCRIPT}
|
||||
COMMENT "Running lint check for sanitizer sources..."
|
||||
|
258
cmake/config-ix.cmake
Normal file
258
cmake/config-ix.cmake
Normal file
@ -0,0 +1,258 @@
|
||||
include(CheckCXXCompilerFlag)
|
||||
include(CheckLibraryExists)
|
||||
include(CheckSymbolExists)
|
||||
|
||||
# CodeGen options.
|
||||
check_cxx_compiler_flag(-fPIC COMPILER_RT_HAS_FPIC_FLAG)
|
||||
check_cxx_compiler_flag(-fPIE COMPILER_RT_HAS_FPIE_FLAG)
|
||||
check_cxx_compiler_flag(-fno-builtin COMPILER_RT_HAS_FNO_BUILTIN_FLAG)
|
||||
check_cxx_compiler_flag(-fno-exceptions COMPILER_RT_HAS_FNO_EXCEPTIONS_FLAG)
|
||||
check_cxx_compiler_flag(-fomit-frame-pointer COMPILER_RT_HAS_FOMIT_FRAME_POINTER_FLAG)
|
||||
check_cxx_compiler_flag(-funwind-tables COMPILER_RT_HAS_FUNWIND_TABLES_FLAG)
|
||||
check_cxx_compiler_flag(-fno-stack-protector COMPILER_RT_HAS_FNO_STACK_PROTECTOR_FLAG)
|
||||
check_cxx_compiler_flag(-fvisibility=hidden COMPILER_RT_HAS_FVISIBILITY_HIDDEN_FLAG)
|
||||
check_cxx_compiler_flag(-fno-rtti COMPILER_RT_HAS_FNO_RTTI_FLAG)
|
||||
check_cxx_compiler_flag(-ffreestanding COMPILER_RT_HAS_FFREESTANDING_FLAG)
|
||||
check_cxx_compiler_flag("-Werror -fno-function-sections" COMPILER_RT_HAS_FNO_FUNCTION_SECTIONS_FLAG)
|
||||
check_cxx_compiler_flag(-std=c++11 COMPILER_RT_HAS_STD_CXX11_FLAG)
|
||||
check_cxx_compiler_flag(-ftls-model=initial-exec COMPILER_RT_HAS_FTLS_MODEL_INITIAL_EXEC)
|
||||
|
||||
check_cxx_compiler_flag(/GR COMPILER_RT_HAS_GR_FLAG)
|
||||
check_cxx_compiler_flag(/GS COMPILER_RT_HAS_GS_FLAG)
|
||||
check_cxx_compiler_flag(/MT COMPILER_RT_HAS_MT_FLAG)
|
||||
check_cxx_compiler_flag(/Oy COMPILER_RT_HAS_Oy_FLAG)
|
||||
|
||||
# Debug info flags.
|
||||
check_cxx_compiler_flag(-gline-tables-only COMPILER_RT_HAS_GLINE_TABLES_ONLY_FLAG)
|
||||
check_cxx_compiler_flag(-g COMPILER_RT_HAS_G_FLAG)
|
||||
check_cxx_compiler_flag(/Zi COMPILER_RT_HAS_Zi_FLAG)
|
||||
|
||||
# Warnings.
|
||||
check_cxx_compiler_flag(-Wall COMPILER_RT_HAS_WALL_FLAG)
|
||||
check_cxx_compiler_flag(-Werror COMPILER_RT_HAS_WERROR_FLAG)
|
||||
check_cxx_compiler_flag("-Werror -Wframe-larger-than=512" COMPILER_RT_HAS_WFRAME_LARGER_THAN_FLAG)
|
||||
check_cxx_compiler_flag("-Werror -Wglobal-constructors" COMPILER_RT_HAS_WGLOBAL_CONSTRUCTORS_FLAG)
|
||||
check_cxx_compiler_flag("-Werror -Wc99-extensions" COMPILER_RT_HAS_WC99_EXTENSIONS_FLAG)
|
||||
check_cxx_compiler_flag("-Werror -Wgnu" COMPILER_RT_HAS_WGNU_FLAG)
|
||||
check_cxx_compiler_flag("-Werror -Wnon-virtual-dtor" COMPILER_RT_HAS_WNON_VIRTUAL_DTOR_FLAG)
|
||||
check_cxx_compiler_flag("-Werror -Wvariadic-macros" COMPILER_RT_HAS_WVARIADIC_MACROS_FLAG)
|
||||
|
||||
check_cxx_compiler_flag(/W3 COMPILER_RT_HAS_W3_FLAG)
|
||||
check_cxx_compiler_flag(/WX COMPILER_RT_HAS_WX_FLAG)
|
||||
check_cxx_compiler_flag(/wd4146 COMPILER_RT_HAS_WD4146_FLAG)
|
||||
check_cxx_compiler_flag(/wd4291 COMPILER_RT_HAS_WD4291_FLAG)
|
||||
check_cxx_compiler_flag(/wd4391 COMPILER_RT_HAS_WD4391_FLAG)
|
||||
check_cxx_compiler_flag(/wd4722 COMPILER_RT_HAS_WD4722_FLAG)
|
||||
check_cxx_compiler_flag(/wd4800 COMPILER_RT_HAS_WD4800_FLAG)
|
||||
|
||||
# Symbols.
|
||||
check_symbol_exists(__func__ "" COMPILER_RT_HAS_FUNC_SYMBOL)
|
||||
|
||||
# Libraries.
|
||||
check_library_exists(c printf "" COMPILER_RT_HAS_LIBC)
|
||||
check_library_exists(dl dlopen "" COMPILER_RT_HAS_LIBDL)
|
||||
check_library_exists(m pow "" COMPILER_RT_HAS_LIBM)
|
||||
check_library_exists(pthread pthread_create "" COMPILER_RT_HAS_LIBPTHREAD)
|
||||
check_library_exists(stdc++ __cxa_throw "" COMPILER_RT_HAS_LIBSTDCXX)
|
||||
|
||||
# Architectures.
|
||||
|
||||
# List of all architectures we can target.
|
||||
set(COMPILER_RT_SUPPORTED_ARCH)
|
||||
|
||||
# Try to compile a very simple source file to ensure we can target the given
|
||||
# platform. We use the results of these tests to build only the various target
|
||||
# runtime libraries supported by our current compilers cross-compiling
|
||||
# abilities.
|
||||
set(SIMPLE_SOURCE ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/simple.cc)
|
||||
file(WRITE ${SIMPLE_SOURCE} "#include <stdlib.h>\n#include <limits>\nint main() {}\n")
|
||||
|
||||
# test_target_arch(<arch> <target flags...>)
|
||||
# Sets the target flags for a given architecture and determines if this
|
||||
# architecture is supported by trying to build a simple file.
|
||||
macro(test_target_arch arch)
|
||||
set(TARGET_${arch}_CFLAGS ${ARGN})
|
||||
set(argstring "${CMAKE_EXE_LINKER_FLAGS}")
|
||||
foreach(arg ${ARGN})
|
||||
set(argstring "${argstring} ${arg}")
|
||||
endforeach()
|
||||
try_compile(CAN_TARGET_${arch} ${CMAKE_BINARY_DIR} ${SIMPLE_SOURCE}
|
||||
COMPILE_DEFINITIONS "${TARGET_${arch}_CFLAGS}"
|
||||
OUTPUT_VARIABLE TARGET_${arch}_OUTPUT
|
||||
CMAKE_FLAGS "-DCMAKE_EXE_LINKER_FLAGS:STRING=${argstring}")
|
||||
if(${CAN_TARGET_${arch}})
|
||||
list(APPEND COMPILER_RT_SUPPORTED_ARCH ${arch})
|
||||
elseif("${COMPILER_RT_TEST_TARGET_ARCH}" MATCHES "${arch}")
|
||||
# Bail out if we cannot target the architecture we plan to test.
|
||||
message(FATAL_ERROR "Cannot compile for ${arch}:\n${TARGET_${arch}_OUTPUT}")
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
# Add $arch as supported with no additional flags.
|
||||
macro(add_default_target_arch arch)
|
||||
set(TARGET_${arch}_CFLAGS "")
|
||||
set(CAN_TARGET_${arch} 1)
|
||||
list(APPEND COMPILER_RT_SUPPORTED_ARCH ${arch})
|
||||
endmacro()
|
||||
|
||||
macro(detect_target_arch)
|
||||
check_symbol_exists(__arm__ "" __ARM)
|
||||
check_symbol_exists(__aarch64__ "" __AARCH64)
|
||||
check_symbol_exists(__x86_64__ "" __X86_64)
|
||||
check_symbol_exists(__i686__ "" __I686)
|
||||
check_symbol_exists(__i386__ "" __I386)
|
||||
check_symbol_exists(__mips__ "" __MIPS)
|
||||
check_symbol_exists(__mips64__ "" __MIPS64)
|
||||
if(__ARM)
|
||||
add_default_target_arch(arm)
|
||||
elseif(__AARCH64)
|
||||
add_default_target_arch(aarch64)
|
||||
elseif(__X86_64)
|
||||
add_default_target_arch(x86_64)
|
||||
elseif(__I686)
|
||||
add_default_target_arch(i686)
|
||||
elseif(__I386)
|
||||
add_default_target_arch(i386)
|
||||
elseif(__MIPS64) # must be checked before __MIPS
|
||||
add_default_target_arch(mips64)
|
||||
elseif(__MIPS)
|
||||
add_default_target_arch(mips)
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
# Generate the COMPILER_RT_SUPPORTED_ARCH list.
|
||||
if(ANDROID)
|
||||
# Can't rely on LLVM_NATIVE_ARCH in cross-compilation.
|
||||
# Examine compiler output instead.
|
||||
detect_target_arch()
|
||||
set(COMPILER_RT_OS_SUFFIX "-android")
|
||||
else()
|
||||
if("${LLVM_NATIVE_ARCH}" STREQUAL "X86")
|
||||
if (NOT MSVC)
|
||||
test_target_arch(x86_64 ${TARGET_64_BIT_CFLAGS})
|
||||
endif()
|
||||
test_target_arch(i386 ${TARGET_32_BIT_CFLAGS})
|
||||
elseif("${LLVM_NATIVE_ARCH}" STREQUAL "PowerPC")
|
||||
test_target_arch(powerpc64 ${TARGET_64_BIT_CFLAGS})
|
||||
test_target_arch(powerpc64le ${TARGET_64_BIT_CFLAGS})
|
||||
elseif("${LLVM_NATIVE_ARCH}" STREQUAL "Mips")
|
||||
if("${COMPILER_RT_TEST_TARGET_ARCH}" MATCHES "mipsel|mips64el")
|
||||
# regex for mipsel, mips64el
|
||||
test_target_arch(mipsel ${TARGET_32_BIT_CFLAGS})
|
||||
test_target_arch(mips64el ${TARGET_64_BIT_CFLAGS})
|
||||
else()
|
||||
test_target_arch(mips ${TARGET_32_BIT_CFLAGS})
|
||||
test_target_arch(mips64 ${TARGET_64_BIT_CFLAGS})
|
||||
endif()
|
||||
elseif("${COMPILER_RT_TEST_TARGET_ARCH}" MATCHES "arm")
|
||||
test_target_arch(arm "-march=armv7-a")
|
||||
elseif("${COMPILER_RT_TEST_TARGET_ARCH}" MATCHES "aarch32")
|
||||
test_target_arch(aarch32 "-march=armv8-a")
|
||||
elseif("${COMPILER_RT_TEST_TARGET_ARCH}" MATCHES "aarch64")
|
||||
test_target_arch(aarch64 "-march=aarch64")
|
||||
endif()
|
||||
set(COMPILER_RT_OS_SUFFIX "")
|
||||
endif()
|
||||
|
||||
message(STATUS "Compiler-RT supported architectures: ${COMPILER_RT_SUPPORTED_ARCH}")
|
||||
|
||||
# Takes ${ARGN} and puts only supported architectures in @out_var list.
|
||||
function(filter_available_targets out_var)
|
||||
set(archs)
|
||||
foreach(arch ${ARGN})
|
||||
list(FIND COMPILER_RT_SUPPORTED_ARCH ${arch} ARCH_INDEX)
|
||||
if(NOT (ARCH_INDEX EQUAL -1) AND CAN_TARGET_${arch})
|
||||
list(APPEND archs ${arch})
|
||||
endif()
|
||||
endforeach()
|
||||
set(${out_var} ${archs} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Arhcitectures supported by compiler-rt libraries.
|
||||
filter_available_targets(SANITIZER_COMMON_SUPPORTED_ARCH
|
||||
x86_64 i386 i686 powerpc64 powerpc64le arm aarch64 mips mips64 mipsel mips64el)
|
||||
filter_available_targets(ASAN_SUPPORTED_ARCH
|
||||
x86_64 i386 i686 powerpc64 powerpc64le arm mips mipsel mips64 mips64el)
|
||||
filter_available_targets(DFSAN_SUPPORTED_ARCH x86_64 mips64 mips64el)
|
||||
filter_available_targets(LSAN_SUPPORTED_ARCH x86_64)
|
||||
# LSan common files should be available on all architectures supported
|
||||
# by other sanitizers (even if they build into dummy object files).
|
||||
filter_available_targets(LSAN_COMMON_SUPPORTED_ARCH
|
||||
${SANITIZER_COMMON_SUPPORTED_ARCH})
|
||||
filter_available_targets(MSAN_SUPPORTED_ARCH x86_64 mips64 mips64el)
|
||||
filter_available_targets(PROFILE_SUPPORTED_ARCH x86_64 i386 i686 arm mips mips64
|
||||
mipsel mips64el aarch64 powerpc64 powerpc64le)
|
||||
filter_available_targets(TSAN_SUPPORTED_ARCH x86_64)
|
||||
filter_available_targets(UBSAN_SUPPORTED_ARCH x86_64 i386 i686 arm aarch64 mips mipsel)
|
||||
|
||||
if(ANDROID)
|
||||
set(OS_NAME "Android")
|
||||
else()
|
||||
set(OS_NAME "${CMAKE_SYSTEM_NAME}")
|
||||
endif()
|
||||
|
||||
if (SANITIZER_COMMON_SUPPORTED_ARCH AND NOT LLVM_USE_SANITIZER AND
|
||||
(OS_NAME MATCHES "Android|Darwin|Linux|FreeBSD" OR
|
||||
(OS_NAME MATCHES "Windows" AND MSVC AND CMAKE_SIZEOF_VOID_P EQUAL 4)))
|
||||
set(COMPILER_RT_HAS_SANITIZER_COMMON TRUE)
|
||||
else()
|
||||
set(COMPILER_RT_HAS_SANITIZER_COMMON FALSE)
|
||||
endif()
|
||||
|
||||
if (COMPILER_RT_HAS_SANITIZER_COMMON AND ASAN_SUPPORTED_ARCH)
|
||||
set(COMPILER_RT_HAS_ASAN TRUE)
|
||||
else()
|
||||
set(COMPILER_RT_HAS_ASAN FALSE)
|
||||
endif()
|
||||
|
||||
# TODO: Add builtins support.
|
||||
|
||||
if (COMPILER_RT_HAS_SANITIZER_COMMON AND DFSAN_SUPPORTED_ARCH AND
|
||||
OS_NAME MATCHES "Linux")
|
||||
set(COMPILER_RT_HAS_DFSAN TRUE)
|
||||
else()
|
||||
set(COMPILER_RT_HAS_DFSAN FALSE)
|
||||
endif()
|
||||
|
||||
if (COMPILER_RT_HAS_SANITIZER_COMMON AND LSAN_SUPPORTED_ARCH AND
|
||||
OS_NAME MATCHES "Darwin|Linux|FreeBSD")
|
||||
set(COMPILER_RT_HAS_LSAN TRUE)
|
||||
else()
|
||||
set(COMPILER_RT_HAS_LSAN FALSE)
|
||||
endif()
|
||||
|
||||
if (COMPILER_RT_HAS_SANITIZER_COMMON AND LSAN_COMMON_SUPPORTED_ARCH AND
|
||||
OS_NAME MATCHES "Darwin|Linux|FreeBSD|Android")
|
||||
set(COMPILER_RT_HAS_LSAN_COMMON TRUE)
|
||||
else()
|
||||
set(COMPILER_RT_HAS_LSAN_COMMON FALSE)
|
||||
endif()
|
||||
|
||||
if (COMPILER_RT_HAS_SANITIZER_COMMON AND MSAN_SUPPORTED_ARCH AND
|
||||
OS_NAME MATCHES "Linux")
|
||||
set(COMPILER_RT_HAS_MSAN TRUE)
|
||||
else()
|
||||
set(COMPILER_RT_HAS_MSAN FALSE)
|
||||
endif()
|
||||
|
||||
if (PROFILE_SUPPORTED_ARCH AND
|
||||
OS_NAME MATCHES "Darwin|Linux|FreeBSD")
|
||||
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 "Linux|FreeBSD")
|
||||
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")
|
||||
set(COMPILER_RT_HAS_UBSAN TRUE)
|
||||
else()
|
||||
set(COMPILER_RT_HAS_UBSAN FALSE)
|
||||
endif()
|
||||
|
@ -1,16 +1,14 @@
|
||||
set(SANITIZER_HEADERS
|
||||
sanitizer/allocator_interface.h
|
||||
sanitizer/asan_interface.h
|
||||
sanitizer/common_interface_defs.h
|
||||
sanitizer/dfsan_interface.h
|
||||
sanitizer/linux_syscall_hooks.h
|
||||
sanitizer/lsan_interface.h
|
||||
sanitizer/msan_interface.h)
|
||||
sanitizer/msan_interface.h
|
||||
sanitizer/tsan_interface_atomic.h)
|
||||
|
||||
set(output_dir ${LLVM_BINARY_DIR}/lib/clang/${CLANG_VERSION}/include)
|
||||
|
||||
if(MSVC_IDE OR XCODE)
|
||||
set(other_output_dir ${LLVM_BINARY_DIR}/bin/lib/clang/${CLANG_VERSION}/include)
|
||||
endif()
|
||||
set(output_dir ${COMPILER_RT_OUTPUT_DIR}/include)
|
||||
|
||||
# Copy compiler-rt headers to the build tree.
|
||||
set(out_files)
|
||||
@ -22,15 +20,6 @@ foreach( f ${SANITIZER_HEADERS} )
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${src} ${dst}
|
||||
COMMENT "Copying compiler-rt's ${f}...")
|
||||
list(APPEND out_files ${dst})
|
||||
|
||||
if(other_output_dir)
|
||||
set(other_dst ${other_output_dir}/${f})
|
||||
add_custom_command(OUTPUT ${other_dst}
|
||||
DEPENDS ${src}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${src} ${other_dst}
|
||||
COMMENT "Copying compiler-rt's ${f}...")
|
||||
list(APPEND out_files ${other_dst})
|
||||
endif()
|
||||
endforeach( f )
|
||||
|
||||
add_custom_target(compiler-rt-headers ALL DEPENDS ${out_files})
|
||||
@ -39,4 +28,4 @@ add_dependencies(compiler-rt compiler-rt-headers)
|
||||
# Install sanitizer headers.
|
||||
install(FILES ${SANITIZER_HEADERS}
|
||||
PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ
|
||||
DESTINATION ${LIBCLANG_INSTALL_PATH}/include/sanitizer)
|
||||
DESTINATION ${COMPILER_RT_INSTALL_PATH}/include/sanitizer)
|
||||
|
66
include/sanitizer/allocator_interface.h
Normal file
66
include/sanitizer/allocator_interface.h
Normal file
@ -0,0 +1,66 @@
|
||||
//===-- allocator_interface.h ---------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Public interface header for allocator used in sanitizers (ASan/TSan/MSan).
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef SANITIZER_ALLOCATOR_INTERFACE_H
|
||||
#define SANITIZER_ALLOCATOR_INTERFACE_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/* Returns the estimated number of bytes that will be reserved by allocator
|
||||
for request of "size" bytes. If allocator can't allocate that much
|
||||
memory, returns the maximal possible allocation size, otherwise returns
|
||||
"size". */
|
||||
size_t __sanitizer_get_estimated_allocated_size(size_t size);
|
||||
|
||||
/* Returns true if p was returned by the allocator and
|
||||
is not yet freed. */
|
||||
int __sanitizer_get_ownership(const volatile void *p);
|
||||
|
||||
/* Returns the number of bytes reserved for the pointer p.
|
||||
Requires (get_ownership(p) == true) or (p == 0). */
|
||||
size_t __sanitizer_get_allocated_size(const volatile void *p);
|
||||
|
||||
/* Number of bytes, allocated and not yet freed by the application. */
|
||||
size_t __sanitizer_get_current_allocated_bytes();
|
||||
|
||||
/* Number of bytes, mmaped by the allocator to fulfill allocation requests.
|
||||
Generally, for request of X bytes, allocator can reserve and add to free
|
||||
lists a large number of chunks of size X to use them for future requests.
|
||||
All these chunks count toward the heap size. Currently, allocator never
|
||||
releases memory to OS (instead, it just puts freed chunks to free
|
||||
lists). */
|
||||
size_t __sanitizer_get_heap_size();
|
||||
|
||||
/* Number of bytes, mmaped by the allocator, which can be used to fulfill
|
||||
allocation requests. When a user program frees memory chunk, it can first
|
||||
fall into quarantine and will count toward __sanitizer_get_free_bytes()
|
||||
later. */
|
||||
size_t __sanitizer_get_free_bytes();
|
||||
|
||||
/* Number of bytes in unmapped pages, that are released to OS. Currently,
|
||||
always returns 0. */
|
||||
size_t __sanitizer_get_unmapped_bytes();
|
||||
|
||||
/* Malloc hooks that may be optionally provided by user.
|
||||
__sanitizer_malloc_hook(ptr, size) is called immediately after
|
||||
allocation of "size" bytes, which returned "ptr".
|
||||
__sanitizer_free_hook(ptr) is called immediately before
|
||||
deallocation of "ptr". */
|
||||
void __sanitizer_malloc_hook(const volatile void *ptr, size_t size);
|
||||
void __sanitizer_free_hook(const volatile void *ptr);
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif
|
@ -50,22 +50,65 @@ extern "C" {
|
||||
((void)(addr), (void)(size))
|
||||
#endif
|
||||
|
||||
// Returns true iff addr is poisoned (i.e. 1-byte read/write access to this
|
||||
// Returns 1 if addr is poisoned (i.e. 1-byte read/write access to this
|
||||
// address will result in error report from AddressSanitizer).
|
||||
bool __asan_address_is_poisoned(void const volatile *addr);
|
||||
// Otherwise returns 0.
|
||||
int __asan_address_is_poisoned(void const volatile *addr);
|
||||
|
||||
// If at least on byte in [beg, beg+size) is poisoned, return the address
|
||||
// If at least one byte in [beg, beg+size) is poisoned, return the address
|
||||
// of the first such byte. Otherwise return 0.
|
||||
void *__asan_region_is_poisoned(void *beg, size_t size);
|
||||
|
||||
// Print the description of addr (useful when debugging in gdb).
|
||||
void __asan_describe_address(void *addr);
|
||||
|
||||
// Useful for calling from a debugger to get information about an ASan error.
|
||||
// Returns 1 if an error has been (or is being) reported, otherwise returns 0.
|
||||
int __asan_report_present();
|
||||
|
||||
// Useful for calling from a debugger to get information about an ASan error.
|
||||
// If an error has been (or is being) reported, the following functions return
|
||||
// the pc, bp, sp, address, access type (0 = read, 1 = write), access size and
|
||||
// bug description (e.g. "heap-use-after-free"). Otherwise they return 0.
|
||||
void *__asan_get_report_pc();
|
||||
void *__asan_get_report_bp();
|
||||
void *__asan_get_report_sp();
|
||||
void *__asan_get_report_address();
|
||||
int __asan_get_report_access_type();
|
||||
size_t __asan_get_report_access_size();
|
||||
const char *__asan_get_report_description();
|
||||
|
||||
// Useful for calling from the debugger to get information about a pointer.
|
||||
// Returns the category of the given pointer as a constant string.
|
||||
// Possible return values are "global", "stack", "stack-fake", "heap",
|
||||
// "heap-invalid", "shadow-low", "shadow-gap", "shadow-high", "unknown".
|
||||
// If global or stack, tries to also return the variable name, address and
|
||||
// size. If heap, tries to return the chunk address and size. 'name' should
|
||||
// point to an allocated buffer of size 'name_size'.
|
||||
const char *__asan_locate_address(void *addr, char *name, size_t name_size,
|
||||
void **region_address, size_t *region_size);
|
||||
|
||||
// Useful for calling from the debugger to get the allocation stack trace
|
||||
// and thread ID for a heap address. Stores up to 'size' frames into 'trace',
|
||||
// returns the number of stored frames or 0 on error.
|
||||
size_t __asan_get_alloc_stack(void *addr, void **trace, size_t size,
|
||||
int *thread_id);
|
||||
|
||||
// Useful for calling from the debugger to get the free stack trace
|
||||
// and thread ID for a heap address. Stores up to 'size' frames into 'trace',
|
||||
// returns the number of stored frames or 0 on error.
|
||||
size_t __asan_get_free_stack(void *addr, void **trace, size_t size,
|
||||
int *thread_id);
|
||||
|
||||
// Useful for calling from the debugger to get the current shadow memory
|
||||
// mapping.
|
||||
void __asan_get_shadow_mapping(size_t *shadow_scale, size_t *shadow_offset);
|
||||
|
||||
// This is an internal function that is called to report an error.
|
||||
// However it is still a part of the interface because users may want to
|
||||
// set a breakpoint on this function in a debugger.
|
||||
void __asan_report_error(void *pc, void *bp, void *sp,
|
||||
void *addr, bool is_write, size_t access_size);
|
||||
void *addr, int is_write, size_t access_size);
|
||||
|
||||
// Sets the exit code to use when reporting an error.
|
||||
// Returns the old value.
|
||||
@ -82,40 +125,6 @@ extern "C" {
|
||||
// the program crashes before ASan report is printed.
|
||||
void __asan_on_error();
|
||||
|
||||
// User may provide its own implementation for symbolization function.
|
||||
// It should print the description of instruction at address "pc" to
|
||||
// "out_buffer". Description should be at most "out_size" bytes long.
|
||||
// User-specified function should return true if symbolization was
|
||||
// successful.
|
||||
bool __asan_symbolize(const void *pc, char *out_buffer,
|
||||
int out_size);
|
||||
|
||||
// Returns the estimated number of bytes that will be reserved by allocator
|
||||
// for request of "size" bytes. If ASan allocator can't allocate that much
|
||||
// memory, returns the maximal possible allocation size, otherwise returns
|
||||
// "size".
|
||||
size_t __asan_get_estimated_allocated_size(size_t size);
|
||||
// Returns true if p was returned by the ASan allocator and
|
||||
// is not yet freed.
|
||||
bool __asan_get_ownership(const void *p);
|
||||
// Returns the number of bytes reserved for the pointer p.
|
||||
// Requires (get_ownership(p) == true) or (p == 0).
|
||||
size_t __asan_get_allocated_size(const void *p);
|
||||
// Number of bytes, allocated and not yet freed by the application.
|
||||
size_t __asan_get_current_allocated_bytes();
|
||||
// Number of bytes, mmaped by asan allocator to fulfill allocation requests.
|
||||
// Generally, for request of X bytes, allocator can reserve and add to free
|
||||
// lists a large number of chunks of size X to use them for future requests.
|
||||
// All these chunks count toward the heap size. Currently, allocator never
|
||||
// releases memory to OS (instead, it just puts freed chunks to free lists).
|
||||
size_t __asan_get_heap_size();
|
||||
// Number of bytes, mmaped by asan allocator, which can be used to fulfill
|
||||
// allocation requests. When a user program frees memory chunk, it can first
|
||||
// fall into quarantine and will count toward __asan_get_free_bytes() later.
|
||||
size_t __asan_get_free_bytes();
|
||||
// Number of bytes in unmapped pages, that are released to OS. Currently,
|
||||
// always returns 0.
|
||||
size_t __asan_get_unmapped_bytes();
|
||||
// Prints accumulated stats to stderr. Used for debugging.
|
||||
void __asan_print_accumulated_stats();
|
||||
|
||||
@ -123,13 +132,23 @@ extern "C" {
|
||||
// a string containing ASan runtime options. See asan_flags.h for details.
|
||||
const char* __asan_default_options();
|
||||
|
||||
// Malloc hooks that may be optionally provided by user.
|
||||
// __asan_malloc_hook(ptr, size) is called immediately after
|
||||
// allocation of "size" bytes, which returned "ptr".
|
||||
// __asan_free_hook(ptr) is called immediately before
|
||||
// deallocation of "ptr".
|
||||
void __asan_malloc_hook(void *ptr, size_t size);
|
||||
void __asan_free_hook(void *ptr);
|
||||
// The following 2 functions facilitate garbage collection in presence of
|
||||
// asan's fake stack.
|
||||
|
||||
// Returns an opaque handler to be used later in __asan_addr_is_in_fake_stack.
|
||||
// Returns NULL if the current thread does not have a fake stack.
|
||||
void *__asan_get_current_fake_stack();
|
||||
|
||||
// If fake_stack is non-NULL and addr belongs to a fake frame in
|
||||
// fake_stack, returns the address on real stack that corresponds to
|
||||
// the fake frame and sets beg/end to the boundaries of this fake frame.
|
||||
// Otherwise returns NULL and does not touch beg/end.
|
||||
// If beg/end are NULL, they are not touched.
|
||||
// This function may be called from a thread other than the owner of
|
||||
// fake_stack, but the owner thread need to be alive.
|
||||
void *__asan_addr_is_in_fake_stack(void *fake_stack, void *addr, void **beg,
|
||||
void **end);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
@ -24,13 +24,28 @@
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
// Arguments for __sanitizer_sandbox_on_notify() below.
|
||||
typedef struct {
|
||||
// Enable sandbox support in sanitizer coverage.
|
||||
int coverage_sandboxed;
|
||||
// File descriptor to write coverage data to. If -1 is passed, a file will
|
||||
// be pre-opened by __sanitizer_sandobx_on_notify(). This field has no
|
||||
// effect if coverage_sandboxed == 0.
|
||||
intptr_t coverage_fd;
|
||||
// If non-zero, split the coverage data into well-formed blocks. This is
|
||||
// useful when coverage_fd is a socket descriptor. Each block will contain
|
||||
// a header, allowing data from multiple processes to be sent over the same
|
||||
// socket.
|
||||
unsigned int coverage_max_block_size;
|
||||
} __sanitizer_sandbox_arguments;
|
||||
|
||||
// Tell the tools to write their reports to "path.<pid>" instead of stderr.
|
||||
void __sanitizer_set_report_path(const char *path);
|
||||
|
||||
// Notify the tools that the sandbox is going to be turned on. The reserved
|
||||
// parameter will be used in the future to hold a structure with functions
|
||||
// that the tools may call to bypass the sandbox.
|
||||
void __sanitizer_sandbox_on_notify(void *reserved);
|
||||
void __sanitizer_sandbox_on_notify(__sanitizer_sandbox_arguments *args);
|
||||
|
||||
// This function is called by the tool when it has just finished reporting
|
||||
// an error. 'error_summary' is a one-line string that summarizes
|
||||
@ -47,8 +62,17 @@ extern "C" {
|
||||
void __sanitizer_unaligned_store32(void *p, uint32_t x);
|
||||
void __sanitizer_unaligned_store64(void *p, uint64_t x);
|
||||
|
||||
// Initialize coverage.
|
||||
void __sanitizer_cov_init();
|
||||
// Record and dump coverage info.
|
||||
void __sanitizer_cov_dump();
|
||||
// Open <name>.sancov.packed in the coverage directory and return the file
|
||||
// descriptor. Returns -1 on failure, or if coverage dumping is disabled.
|
||||
// This is intended for use by sandboxing code.
|
||||
intptr_t __sanitizer_maybe_open_cov_file(const char *name);
|
||||
// Get the number of total unique covered entities (blocks, edges, calls).
|
||||
// This can be useful for coverage-directed in-process fuzzers.
|
||||
uintptr_t __sanitizer_get_total_unique_coverage();
|
||||
|
||||
// Annotate the current state of a contiguous container, such as
|
||||
// std::vector, std::string or similar.
|
||||
@ -56,7 +80,7 @@ extern "C" {
|
||||
// in a contiguous region of memory. The container owns the region of memory
|
||||
// [beg, end); the memory [beg, mid) is used to store the current elements
|
||||
// and the memory [mid, end) is reserved for future elements;
|
||||
// end <= mid <= end. For example, in "std::vector<> v"
|
||||
// beg <= mid <= end. For example, in "std::vector<> v"
|
||||
// beg = &v[0];
|
||||
// end = beg + v.capacity() * sizeof(v[0]);
|
||||
// mid = beg + v.size() * sizeof(v[0]);
|
||||
@ -70,9 +94,31 @@ extern "C" {
|
||||
//
|
||||
// Use with caution and don't use for anything other than vector-like classes.
|
||||
//
|
||||
// For AddressSanitizer, 'beg' should be 8-aligned.
|
||||
void __sanitizer_annotate_contiguous_container(void *beg, void *end,
|
||||
void *old_mid, void *new_mid);
|
||||
// For AddressSanitizer, 'beg' should be 8-aligned and 'end' should
|
||||
// be either 8-aligned or it should point to the end of a separate heap-,
|
||||
// stack-, or global- allocated buffer. I.e. the following will not work:
|
||||
// int64_t x[2]; // 16 bytes, 8-aligned.
|
||||
// char *beg = (char *)&x[0];
|
||||
// char *end = beg + 12; // Not 8 aligned, not the end of the buffer.
|
||||
// This however will work fine:
|
||||
// int32_t x[3]; // 12 bytes, but 8-aligned under AddressSanitizer.
|
||||
// char *beg = (char*)&x[0];
|
||||
// char *end = beg + 12; // Not 8-aligned, but is the end of the buffer.
|
||||
void __sanitizer_annotate_contiguous_container(const void *beg,
|
||||
const void *end,
|
||||
const void *old_mid,
|
||||
const void *new_mid);
|
||||
// Returns true if the contiguous container [beg, end) is properly poisoned
|
||||
// (e.g. with __sanitizer_annotate_contiguous_container), i.e. if
|
||||
// - [beg, mid) is addressable,
|
||||
// - [mid, end) is unaddressable.
|
||||
// Full verification requires O(end-beg) time; this function tries to avoid
|
||||
// such complexity by touching only parts of the container around beg/mid/end.
|
||||
int __sanitizer_verify_contiguous_container(const void *beg, const void *mid,
|
||||
const void *end);
|
||||
|
||||
// Print the stack trace leading to this call. Useful for debugging user code.
|
||||
void __sanitizer_print_stack_trace();
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
|
@ -39,6 +39,9 @@ struct dfsan_label_info {
|
||||
void *userdata;
|
||||
};
|
||||
|
||||
/// Signature of the callback argument to dfsan_set_write_callback().
|
||||
typedef void (*dfsan_write_callback_t)(int fd, const void *buf, size_t count);
|
||||
|
||||
/// Computes the union of \c l1 and \c l2, possibly creating a union label in
|
||||
/// the process.
|
||||
dfsan_label dfsan_union(dfsan_label l1, dfsan_label l2);
|
||||
@ -74,6 +77,20 @@ int dfsan_has_label(dfsan_label label, dfsan_label elem);
|
||||
/// that label, else returns 0.
|
||||
dfsan_label dfsan_has_label_with_desc(dfsan_label label, const char *desc);
|
||||
|
||||
/// Returns the number of labels allocated.
|
||||
size_t dfsan_get_label_count(void);
|
||||
|
||||
/// Sets a callback to be invoked on calls to write(). The callback is invoked
|
||||
/// before the write is done. The write is not guaranteed to succeed when the
|
||||
/// callback executes. Pass in NULL to remove any callback.
|
||||
void dfsan_set_write_callback(dfsan_write_callback_t labeled_write_callback);
|
||||
|
||||
/// Writes the labels currently used by the program to the given file
|
||||
/// descriptor. The lines of the output have the following format:
|
||||
///
|
||||
/// <label> <parent label 1> <parent label 2> <label description if any>
|
||||
void dfsan_dump_labels(int fd);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
|
||||
|
@ -23,13 +23,24 @@ extern "C" {
|
||||
// be treated as non-leaks. Disable/enable pairs may be nested.
|
||||
void __lsan_disable();
|
||||
void __lsan_enable();
|
||||
|
||||
// The heap object into which p points will be treated as a non-leak.
|
||||
void __lsan_ignore_object(const void *p);
|
||||
// The user may optionally provide this function to disallow leak checking
|
||||
// for the program it is linked into (if the return value is non-zero). This
|
||||
// function must be defined as returning a constant value; any behavior beyond
|
||||
// that is unsupported.
|
||||
int __lsan_is_turned_off();
|
||||
|
||||
// Memory regions registered through this interface will be treated as sources
|
||||
// of live pointers during leak checking. Useful if you store pointers in
|
||||
// mapped memory.
|
||||
// Points of note:
|
||||
// - __lsan_unregister_root_region() must be called with the same pointer and
|
||||
// size that have earlier been passed to __lsan_register_root_region()
|
||||
// - LSan will skip any inaccessible memory when scanning a root region. E.g.,
|
||||
// if you map memory within a larger region that you have mprotect'ed, you can
|
||||
// register the entire large region.
|
||||
// - the implementation is not optimized for performance. This interface is
|
||||
// intended to be used for a small number of relatively static regions.
|
||||
void __lsan_register_root_region(const void *p, size_t size);
|
||||
void __lsan_unregister_root_region(const void *p, size_t size);
|
||||
|
||||
// Calling this function makes LSan enter the leak checking phase immediately.
|
||||
// Use this if normal end-of-process leak checking happens too late (e.g. if
|
||||
// you have intentional memory leaks in your shutdown code). Calling this
|
||||
@ -37,6 +48,16 @@ extern "C" {
|
||||
// most once per process. This function will terminate the process if there
|
||||
// are memory leaks and the exit_code flag is non-zero.
|
||||
void __lsan_do_leak_check();
|
||||
|
||||
// The user may optionally provide this function to disallow leak checking
|
||||
// for the program it is linked into (if the return value is non-zero). This
|
||||
// function must be defined as returning a constant value; any behavior beyond
|
||||
// that is unsupported.
|
||||
int __lsan_is_turned_off();
|
||||
|
||||
// This function may be optionally provided by the user and should return
|
||||
// a string containing LSan suppressions.
|
||||
const char *__lsan_default_suppressions();
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
|
||||
|
@ -19,13 +19,6 @@
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if __has_feature(memory_sanitizer)
|
||||
/* Returns a string describing a stack origin.
|
||||
Return NULL if the origin is invalid, or is not a stack origin. */
|
||||
const char *__msan_get_origin_descr_if_stack(uint32_t id);
|
||||
|
||||
|
||||
/* Set raw origin for the memory range. */
|
||||
void __msan_set_origin(const volatile void *a, size_t size, uint32_t origin);
|
||||
|
||||
@ -41,6 +34,10 @@ extern "C" {
|
||||
/* Make memory region fully initialized (without changing its contents). */
|
||||
void __msan_unpoison(const volatile void *a, size_t size);
|
||||
|
||||
/* Make a null-terminated string fully initialized (without changing its
|
||||
contents). */
|
||||
void __msan_unpoison_string(const volatile char *a);
|
||||
|
||||
/* Make memory region fully uninitialized (without changing its contents). */
|
||||
void __msan_poison(const volatile void *a, size_t size);
|
||||
|
||||
@ -53,6 +50,10 @@ extern "C" {
|
||||
memory range, or -1 if the whole range is good. */
|
||||
intptr_t __msan_test_shadow(const volatile void *x, size_t size);
|
||||
|
||||
/* Checks that memory range is fully initialized, and reports an error if it
|
||||
* is not. */
|
||||
void __msan_check_mem_is_initialized(const volatile void *x, size_t size);
|
||||
|
||||
/* Set exit code when error(s) were detected.
|
||||
Value of 0 means don't change the program exit code. */
|
||||
void __msan_set_exit_code(int exit_code);
|
||||
@ -69,13 +70,13 @@ extern "C" {
|
||||
modules that were compiled without the corresponding compiler flag. */
|
||||
void __msan_set_keep_going(int keep_going);
|
||||
|
||||
/* Print shadow and origin for the memory range to stdout in a human-readable
|
||||
/* Print shadow and origin for the memory range to stderr in a human-readable
|
||||
format. */
|
||||
void __msan_print_shadow(const volatile void *x, size_t size);
|
||||
|
||||
/* Print current function arguments shadow and origin to stdout in a
|
||||
/* Print shadow for the memory range to stderr in a minimalistic
|
||||
human-readable format. */
|
||||
void __msan_print_param_shadow();
|
||||
void __msan_dump_shadow(const volatile void *x, size_t size);
|
||||
|
||||
/* Returns true if running under a dynamic tool (DynamoRio-based). */
|
||||
int __msan_has_dynamic_component();
|
||||
@ -88,72 +89,9 @@ extern "C" {
|
||||
a string containing Msan runtime options. See msan_flags.h for details. */
|
||||
const char* __msan_default_options();
|
||||
|
||||
|
||||
/***********************************/
|
||||
/* Allocator statistics interface. */
|
||||
|
||||
/* Returns the estimated number of bytes that will be reserved by allocator
|
||||
for request of "size" bytes. If Msan allocator can't allocate that much
|
||||
memory, returns the maximal possible allocation size, otherwise returns
|
||||
"size". */
|
||||
size_t __msan_get_estimated_allocated_size(size_t size);
|
||||
|
||||
/* Returns true if p was returned by the Msan allocator and
|
||||
is not yet freed. */
|
||||
int __msan_get_ownership(const volatile void *p);
|
||||
|
||||
/* Returns the number of bytes reserved for the pointer p.
|
||||
Requires (get_ownership(p) == true) or (p == 0). */
|
||||
size_t __msan_get_allocated_size(const volatile void *p);
|
||||
|
||||
/* Number of bytes, allocated and not yet freed by the application. */
|
||||
size_t __msan_get_current_allocated_bytes();
|
||||
|
||||
/* Number of bytes, mmaped by msan allocator to fulfill allocation requests.
|
||||
Generally, for request of X bytes, allocator can reserve and add to free
|
||||
lists a large number of chunks of size X to use them for future requests.
|
||||
All these chunks count toward the heap size. Currently, allocator never
|
||||
releases memory to OS (instead, it just puts freed chunks to free
|
||||
lists). */
|
||||
size_t __msan_get_heap_size();
|
||||
|
||||
/* Number of bytes, mmaped by msan allocator, which can be used to fulfill
|
||||
allocation requests. When a user program frees memory chunk, it can first
|
||||
fall into quarantine and will count toward __msan_get_free_bytes()
|
||||
later. */
|
||||
size_t __msan_get_free_bytes();
|
||||
|
||||
/* Number of bytes in unmapped pages, that are released to OS. Currently,
|
||||
always returns 0. */
|
||||
size_t __msan_get_unmapped_bytes();
|
||||
|
||||
/* Malloc hooks that may be optionally provided by user.
|
||||
__msan_malloc_hook(ptr, size) is called immediately after
|
||||
allocation of "size" bytes, which returned "ptr".
|
||||
__msan_free_hook(ptr) is called immediately before
|
||||
deallocation of "ptr". */
|
||||
void __msan_malloc_hook(const volatile void *ptr, size_t size);
|
||||
void __msan_free_hook(const volatile void *ptr);
|
||||
|
||||
#else // __has_feature(memory_sanitizer)
|
||||
|
||||
#define __msan_get_origin_descr_if_stack(id) ((const char*)0)
|
||||
#define __msan_set_origin(a, size, origin)
|
||||
#define __msan_get_origin(a) ((uint32_t)-1)
|
||||
#define __msan_get_track_origins() (0)
|
||||
#define __msan_get_umr_origin() ((uint32_t)-1)
|
||||
#define __msan_unpoison(a, size)
|
||||
#define __msan_poison(a, size)
|
||||
#define __msan_partial_poison(data, shadow, size)
|
||||
#define __msan_test_shadow(x, size) ((intptr_t)-1)
|
||||
#define __msan_set_exit_code(exit_code)
|
||||
#define __msan_set_expect_umr(expect_umr)
|
||||
#define __msan_print_shadow(x, size)
|
||||
#define __msan_print_param_shadow()
|
||||
#define __msan_has_dynamic_component() (0)
|
||||
#define __msan_allocated_memory(data, size)
|
||||
|
||||
#endif // __has_feature(memory_sanitizer)
|
||||
/* Sets the callback to be called right before death on error.
|
||||
Passing 0 will unset the callback. */
|
||||
void __msan_set_death_callback(void (*callback)(void));
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
|
@ -9,14 +9,11 @@
|
||||
//
|
||||
// This file is a part of ThreadSanitizer (TSan), a race detector.
|
||||
//
|
||||
// Public interface header for TSan atomics.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef TSAN_INTERFACE_ATOMIC_H
|
||||
#define TSAN_INTERFACE_ATOMIC_H
|
||||
|
||||
#ifndef INTERFACE_ATTRIBUTE
|
||||
# define INTERFACE_ATTRIBUTE __attribute__((visibility("default")))
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@ -25,14 +22,12 @@ typedef char __tsan_atomic8;
|
||||
typedef short __tsan_atomic16; // NOLINT
|
||||
typedef int __tsan_atomic32;
|
||||
typedef long __tsan_atomic64; // NOLINT
|
||||
|
||||
#if defined(__SIZEOF_INT128__) \
|
||||
|| (__clang_major__ * 100 + __clang_minor__ >= 302)
|
||||
__extension__ typedef __int128 __tsan_atomic128;
|
||||
#define __TSAN_HAS_INT128 1
|
||||
# define __TSAN_HAS_INT128 1
|
||||
#else
|
||||
typedef char __tsan_atomic128;
|
||||
#define __TSAN_HAS_INT128 0
|
||||
# define __TSAN_HAS_INT128 0
|
||||
#endif
|
||||
|
||||
// Part of ABI, do not change.
|
||||
@ -47,159 +42,181 @@ typedef enum {
|
||||
} __tsan_memory_order;
|
||||
|
||||
__tsan_atomic8 __tsan_atomic8_load(const volatile __tsan_atomic8 *a,
|
||||
__tsan_memory_order mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_memory_order mo);
|
||||
__tsan_atomic16 __tsan_atomic16_load(const volatile __tsan_atomic16 *a,
|
||||
__tsan_memory_order mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_memory_order mo);
|
||||
__tsan_atomic32 __tsan_atomic32_load(const volatile __tsan_atomic32 *a,
|
||||
__tsan_memory_order mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_memory_order mo);
|
||||
__tsan_atomic64 __tsan_atomic64_load(const volatile __tsan_atomic64 *a,
|
||||
__tsan_memory_order mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_memory_order mo);
|
||||
#if __TSAN_HAS_INT128
|
||||
__tsan_atomic128 __tsan_atomic128_load(const volatile __tsan_atomic128 *a,
|
||||
__tsan_memory_order mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_memory_order mo);
|
||||
#endif
|
||||
|
||||
void __tsan_atomic8_store(volatile __tsan_atomic8 *a, __tsan_atomic8 v,
|
||||
__tsan_memory_order mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_memory_order mo);
|
||||
void __tsan_atomic16_store(volatile __tsan_atomic16 *a, __tsan_atomic16 v,
|
||||
__tsan_memory_order mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_memory_order mo);
|
||||
void __tsan_atomic32_store(volatile __tsan_atomic32 *a, __tsan_atomic32 v,
|
||||
__tsan_memory_order mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_memory_order mo);
|
||||
void __tsan_atomic64_store(volatile __tsan_atomic64 *a, __tsan_atomic64 v,
|
||||
__tsan_memory_order mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_memory_order mo);
|
||||
#if __TSAN_HAS_INT128
|
||||
void __tsan_atomic128_store(volatile __tsan_atomic128 *a, __tsan_atomic128 v,
|
||||
__tsan_memory_order mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_memory_order mo);
|
||||
#endif
|
||||
|
||||
__tsan_atomic8 __tsan_atomic8_exchange(volatile __tsan_atomic8 *a,
|
||||
__tsan_atomic8 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic8 v, __tsan_memory_order mo);
|
||||
__tsan_atomic16 __tsan_atomic16_exchange(volatile __tsan_atomic16 *a,
|
||||
__tsan_atomic16 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic16 v, __tsan_memory_order mo);
|
||||
__tsan_atomic32 __tsan_atomic32_exchange(volatile __tsan_atomic32 *a,
|
||||
__tsan_atomic32 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic32 v, __tsan_memory_order mo);
|
||||
__tsan_atomic64 __tsan_atomic64_exchange(volatile __tsan_atomic64 *a,
|
||||
__tsan_atomic64 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic64 v, __tsan_memory_order mo);
|
||||
#if __TSAN_HAS_INT128
|
||||
__tsan_atomic128 __tsan_atomic128_exchange(volatile __tsan_atomic128 *a,
|
||||
__tsan_atomic128 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic128 v, __tsan_memory_order mo);
|
||||
#endif
|
||||
|
||||
__tsan_atomic8 __tsan_atomic8_fetch_add(volatile __tsan_atomic8 *a,
|
||||
__tsan_atomic8 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic8 v, __tsan_memory_order mo);
|
||||
__tsan_atomic16 __tsan_atomic16_fetch_add(volatile __tsan_atomic16 *a,
|
||||
__tsan_atomic16 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic16 v, __tsan_memory_order mo);
|
||||
__tsan_atomic32 __tsan_atomic32_fetch_add(volatile __tsan_atomic32 *a,
|
||||
__tsan_atomic32 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic32 v, __tsan_memory_order mo);
|
||||
__tsan_atomic64 __tsan_atomic64_fetch_add(volatile __tsan_atomic64 *a,
|
||||
__tsan_atomic64 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic64 v, __tsan_memory_order mo);
|
||||
#if __TSAN_HAS_INT128
|
||||
__tsan_atomic128 __tsan_atomic128_fetch_add(volatile __tsan_atomic128 *a,
|
||||
__tsan_atomic128 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic128 v, __tsan_memory_order mo);
|
||||
#endif
|
||||
|
||||
__tsan_atomic8 __tsan_atomic8_fetch_sub(volatile __tsan_atomic8 *a,
|
||||
__tsan_atomic8 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic8 v, __tsan_memory_order mo);
|
||||
__tsan_atomic16 __tsan_atomic16_fetch_sub(volatile __tsan_atomic16 *a,
|
||||
__tsan_atomic16 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic16 v, __tsan_memory_order mo);
|
||||
__tsan_atomic32 __tsan_atomic32_fetch_sub(volatile __tsan_atomic32 *a,
|
||||
__tsan_atomic32 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic32 v, __tsan_memory_order mo);
|
||||
__tsan_atomic64 __tsan_atomic64_fetch_sub(volatile __tsan_atomic64 *a,
|
||||
__tsan_atomic64 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic64 v, __tsan_memory_order mo);
|
||||
#if __TSAN_HAS_INT128
|
||||
__tsan_atomic128 __tsan_atomic128_fetch_sub(volatile __tsan_atomic128 *a,
|
||||
__tsan_atomic128 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic128 v, __tsan_memory_order mo);
|
||||
#endif
|
||||
|
||||
__tsan_atomic8 __tsan_atomic8_fetch_and(volatile __tsan_atomic8 *a,
|
||||
__tsan_atomic8 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic8 v, __tsan_memory_order mo);
|
||||
__tsan_atomic16 __tsan_atomic16_fetch_and(volatile __tsan_atomic16 *a,
|
||||
__tsan_atomic16 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic16 v, __tsan_memory_order mo);
|
||||
__tsan_atomic32 __tsan_atomic32_fetch_and(volatile __tsan_atomic32 *a,
|
||||
__tsan_atomic32 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic32 v, __tsan_memory_order mo);
|
||||
__tsan_atomic64 __tsan_atomic64_fetch_and(volatile __tsan_atomic64 *a,
|
||||
__tsan_atomic64 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic64 v, __tsan_memory_order mo);
|
||||
#if __TSAN_HAS_INT128
|
||||
__tsan_atomic128 __tsan_atomic128_fetch_and(volatile __tsan_atomic128 *a,
|
||||
__tsan_atomic128 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic128 v, __tsan_memory_order mo);
|
||||
#endif
|
||||
|
||||
__tsan_atomic8 __tsan_atomic8_fetch_or(volatile __tsan_atomic8 *a,
|
||||
__tsan_atomic8 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic8 v, __tsan_memory_order mo);
|
||||
__tsan_atomic16 __tsan_atomic16_fetch_or(volatile __tsan_atomic16 *a,
|
||||
__tsan_atomic16 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic16 v, __tsan_memory_order mo);
|
||||
__tsan_atomic32 __tsan_atomic32_fetch_or(volatile __tsan_atomic32 *a,
|
||||
__tsan_atomic32 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic32 v, __tsan_memory_order mo);
|
||||
__tsan_atomic64 __tsan_atomic64_fetch_or(volatile __tsan_atomic64 *a,
|
||||
__tsan_atomic64 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic64 v, __tsan_memory_order mo);
|
||||
#if __TSAN_HAS_INT128
|
||||
__tsan_atomic128 __tsan_atomic128_fetch_or(volatile __tsan_atomic128 *a,
|
||||
__tsan_atomic128 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic128 v, __tsan_memory_order mo);
|
||||
#endif
|
||||
|
||||
__tsan_atomic8 __tsan_atomic8_fetch_xor(volatile __tsan_atomic8 *a,
|
||||
__tsan_atomic8 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic8 v, __tsan_memory_order mo);
|
||||
__tsan_atomic16 __tsan_atomic16_fetch_xor(volatile __tsan_atomic16 *a,
|
||||
__tsan_atomic16 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic16 v, __tsan_memory_order mo);
|
||||
__tsan_atomic32 __tsan_atomic32_fetch_xor(volatile __tsan_atomic32 *a,
|
||||
__tsan_atomic32 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic32 v, __tsan_memory_order mo);
|
||||
__tsan_atomic64 __tsan_atomic64_fetch_xor(volatile __tsan_atomic64 *a,
|
||||
__tsan_atomic64 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic64 v, __tsan_memory_order mo);
|
||||
#if __TSAN_HAS_INT128
|
||||
__tsan_atomic128 __tsan_atomic128_fetch_xor(volatile __tsan_atomic128 *a,
|
||||
__tsan_atomic128 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic128 v, __tsan_memory_order mo);
|
||||
#endif
|
||||
|
||||
__tsan_atomic8 __tsan_atomic8_fetch_nand(volatile __tsan_atomic8 *a,
|
||||
__tsan_atomic8 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic8 v, __tsan_memory_order mo);
|
||||
__tsan_atomic16 __tsan_atomic16_fetch_nand(volatile __tsan_atomic16 *a,
|
||||
__tsan_atomic16 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic16 v, __tsan_memory_order mo);
|
||||
__tsan_atomic32 __tsan_atomic32_fetch_nand(volatile __tsan_atomic32 *a,
|
||||
__tsan_atomic32 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic32 v, __tsan_memory_order mo);
|
||||
__tsan_atomic64 __tsan_atomic64_fetch_nand(volatile __tsan_atomic64 *a,
|
||||
__tsan_atomic64 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic64 v, __tsan_memory_order mo);
|
||||
#if __TSAN_HAS_INT128
|
||||
__tsan_atomic128 __tsan_atomic128_fetch_nand(volatile __tsan_atomic128 *a,
|
||||
__tsan_atomic128 v, __tsan_memory_order mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic128 v, __tsan_memory_order mo);
|
||||
#endif
|
||||
|
||||
int __tsan_atomic8_compare_exchange_weak(volatile __tsan_atomic8 *a,
|
||||
__tsan_atomic8 *c, __tsan_atomic8 v, __tsan_memory_order mo,
|
||||
__tsan_memory_order fail_mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_memory_order fail_mo);
|
||||
int __tsan_atomic16_compare_exchange_weak(volatile __tsan_atomic16 *a,
|
||||
__tsan_atomic16 *c, __tsan_atomic16 v, __tsan_memory_order mo,
|
||||
__tsan_memory_order fail_mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_memory_order fail_mo);
|
||||
int __tsan_atomic32_compare_exchange_weak(volatile __tsan_atomic32 *a,
|
||||
__tsan_atomic32 *c, __tsan_atomic32 v, __tsan_memory_order mo,
|
||||
__tsan_memory_order fail_mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_memory_order fail_mo);
|
||||
int __tsan_atomic64_compare_exchange_weak(volatile __tsan_atomic64 *a,
|
||||
__tsan_atomic64 *c, __tsan_atomic64 v, __tsan_memory_order mo,
|
||||
__tsan_memory_order fail_mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_memory_order fail_mo);
|
||||
#if __TSAN_HAS_INT128
|
||||
int __tsan_atomic128_compare_exchange_weak(volatile __tsan_atomic128 *a,
|
||||
__tsan_atomic128 *c, __tsan_atomic128 v, __tsan_memory_order mo,
|
||||
__tsan_memory_order fail_mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_memory_order fail_mo);
|
||||
#endif
|
||||
|
||||
int __tsan_atomic8_compare_exchange_strong(volatile __tsan_atomic8 *a,
|
||||
__tsan_atomic8 *c, __tsan_atomic8 v, __tsan_memory_order mo,
|
||||
__tsan_memory_order fail_mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_memory_order fail_mo);
|
||||
int __tsan_atomic16_compare_exchange_strong(volatile __tsan_atomic16 *a,
|
||||
__tsan_atomic16 *c, __tsan_atomic16 v, __tsan_memory_order mo,
|
||||
__tsan_memory_order fail_mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_memory_order fail_mo);
|
||||
int __tsan_atomic32_compare_exchange_strong(volatile __tsan_atomic32 *a,
|
||||
__tsan_atomic32 *c, __tsan_atomic32 v, __tsan_memory_order mo,
|
||||
__tsan_memory_order fail_mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_memory_order fail_mo);
|
||||
int __tsan_atomic64_compare_exchange_strong(volatile __tsan_atomic64 *a,
|
||||
__tsan_atomic64 *c, __tsan_atomic64 v, __tsan_memory_order mo,
|
||||
__tsan_memory_order fail_mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_memory_order fail_mo);
|
||||
#if __TSAN_HAS_INT128
|
||||
int __tsan_atomic128_compare_exchange_strong(volatile __tsan_atomic128 *a,
|
||||
__tsan_atomic128 *c, __tsan_atomic128 v, __tsan_memory_order mo,
|
||||
__tsan_memory_order fail_mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_memory_order fail_mo);
|
||||
#endif
|
||||
|
||||
__tsan_atomic8 __tsan_atomic8_compare_exchange_val(
|
||||
volatile __tsan_atomic8 *a, __tsan_atomic8 c, __tsan_atomic8 v,
|
||||
__tsan_memory_order mo, __tsan_memory_order fail_mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_memory_order mo, __tsan_memory_order fail_mo);
|
||||
__tsan_atomic16 __tsan_atomic16_compare_exchange_val(
|
||||
volatile __tsan_atomic16 *a, __tsan_atomic16 c, __tsan_atomic16 v,
|
||||
__tsan_memory_order mo, __tsan_memory_order fail_mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_memory_order mo, __tsan_memory_order fail_mo);
|
||||
__tsan_atomic32 __tsan_atomic32_compare_exchange_val(
|
||||
volatile __tsan_atomic32 *a, __tsan_atomic32 c, __tsan_atomic32 v,
|
||||
__tsan_memory_order mo, __tsan_memory_order fail_mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_memory_order mo, __tsan_memory_order fail_mo);
|
||||
__tsan_atomic64 __tsan_atomic64_compare_exchange_val(
|
||||
volatile __tsan_atomic64 *a, __tsan_atomic64 c, __tsan_atomic64 v,
|
||||
__tsan_memory_order mo, __tsan_memory_order fail_mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_memory_order mo, __tsan_memory_order fail_mo);
|
||||
#if __TSAN_HAS_INT128
|
||||
__tsan_atomic128 __tsan_atomic128_compare_exchange_val(
|
||||
volatile __tsan_atomic128 *a, __tsan_atomic128 c, __tsan_atomic128 v,
|
||||
__tsan_memory_order mo, __tsan_memory_order fail_mo) INTERFACE_ATTRIBUTE;
|
||||
__tsan_memory_order mo, __tsan_memory_order fail_mo);
|
||||
#endif
|
||||
|
||||
void __tsan_atomic_thread_fence(__tsan_memory_order mo) INTERFACE_ATTRIBUTE;
|
||||
void __tsan_atomic_signal_fence(__tsan_memory_order mo) INTERFACE_ATTRIBUTE;
|
||||
void __tsan_atomic_thread_fence(__tsan_memory_order mo);
|
||||
void __tsan_atomic_signal_fence(__tsan_memory_order mo);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#undef INTERFACE_ATTRIBUTE
|
||||
|
||||
#endif // #ifndef TSAN_INTERFACE_ATOMIC_H
|
||||
#endif // TSAN_INTERFACE_ATOMIC_H
|
@ -1,216 +1,42 @@
|
||||
# First, add the subdirectories which contain feature-based runtime libraries
|
||||
# and several convenience helper libraries.
|
||||
|
||||
# Don't build sanitizers in the bootstrap build.
|
||||
if(LLVM_USE_SANITIZER STREQUAL "")
|
||||
# AddressSanitizer is supported on Linux and Mac OS X.
|
||||
# 32-bit Windows support is experimental.
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "Darwin|Linux")
|
||||
set(SUPPORTS_BUILDING_ASAN TRUE)
|
||||
elseif(CMAKE_SYSTEM_NAME MATCHES "Windows"
|
||||
AND MSVC AND CMAKE_SIZEOF_VOID_P EQUAL 4)
|
||||
set(SUPPORTS_BUILDING_ASAN TRUE)
|
||||
else()
|
||||
set(SUPPORTS_BUILDING_ASAN FALSE)
|
||||
endif()
|
||||
if(SUPPORTS_BUILDING_ASAN)
|
||||
add_subdirectory(asan)
|
||||
include(AddCompilerRT)
|
||||
include(SanitizerUtils)
|
||||
|
||||
if(COMPILER_RT_HAS_SANITIZER_COMMON)
|
||||
add_subdirectory(interception)
|
||||
add_subdirectory(sanitizer_common)
|
||||
endif()
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "Darwin|Linux" AND NOT ANDROID)
|
||||
# LSan, UBsan and profile can be built on Mac OS and Linux.
|
||||
add_subdirectory(lsan)
|
||||
add_subdirectory(profile)
|
||||
add_subdirectory(ubsan)
|
||||
endif()
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "Linux" AND NOT ANDROID)
|
||||
# ThreadSanitizer and MemorySanitizer are supported on Linux only.
|
||||
add_subdirectory(tsan)
|
||||
add_subdirectory(msan)
|
||||
add_subdirectory(msandr)
|
||||
endif()
|
||||
|
||||
if(COMPILER_RT_HAS_ASAN)
|
||||
add_subdirectory(asan)
|
||||
endif()
|
||||
|
||||
add_subdirectory(builtins)
|
||||
|
||||
if(COMPILER_RT_HAS_DFSAN)
|
||||
add_subdirectory(dfsan)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# The top-level lib directory contains a large amount of C code which provides
|
||||
# generic implementations of the core runtime library along with optimized
|
||||
# architecture-specific code in various subdirectories.
|
||||
|
||||
set(GENERIC_SOURCES
|
||||
absvdi2.c
|
||||
absvsi2.c
|
||||
absvti2.c
|
||||
adddf3.c
|
||||
addsf3.c
|
||||
addvdi3.c
|
||||
addvsi3.c
|
||||
addvti3.c
|
||||
apple_versioning.c
|
||||
ashldi3.c
|
||||
ashlti3.c
|
||||
ashrdi3.c
|
||||
ashrti3.c
|
||||
# FIXME: atomic.c may only be compiled if host compiler understands _Atomic
|
||||
# atomic.c
|
||||
clear_cache.c
|
||||
clzdi2.c
|
||||
clzsi2.c
|
||||
clzti2.c
|
||||
cmpdi2.c
|
||||
cmpti2.c
|
||||
comparedf2.c
|
||||
comparesf2.c
|
||||
ctzdi2.c
|
||||
ctzsi2.c
|
||||
ctzti2.c
|
||||
divdc3.c
|
||||
divdf3.c
|
||||
divdi3.c
|
||||
divmoddi4.c
|
||||
divmodsi4.c
|
||||
divsc3.c
|
||||
divsf3.c
|
||||
divsi3.c
|
||||
divti3.c
|
||||
divxc3.c
|
||||
enable_execute_stack.c
|
||||
eprintf.c
|
||||
extendsfdf2.c
|
||||
ffsdi2.c
|
||||
ffsti2.c
|
||||
fixdfdi.c
|
||||
fixdfsi.c
|
||||
fixdfti.c
|
||||
fixsfdi.c
|
||||
fixsfsi.c
|
||||
fixsfti.c
|
||||
fixunsdfdi.c
|
||||
fixunsdfsi.c
|
||||
fixunsdfti.c
|
||||
fixunssfdi.c
|
||||
fixunssfsi.c
|
||||
fixunssfti.c
|
||||
fixunsxfdi.c
|
||||
fixunsxfsi.c
|
||||
fixunsxfti.c
|
||||
fixxfdi.c
|
||||
fixxfti.c
|
||||
floatdidf.c
|
||||
floatdisf.c
|
||||
floatdixf.c
|
||||
floatsidf.c
|
||||
floatsisf.c
|
||||
floattidf.c
|
||||
floattisf.c
|
||||
floattixf.c
|
||||
floatundidf.c
|
||||
floatundisf.c
|
||||
floatundixf.c
|
||||
floatunsidf.c
|
||||
floatunsisf.c
|
||||
floatuntidf.c
|
||||
floatuntisf.c
|
||||
floatuntixf.c
|
||||
gcc_personality_v0.c
|
||||
int_util.c
|
||||
lshrdi3.c
|
||||
lshrti3.c
|
||||
moddi3.c
|
||||
modsi3.c
|
||||
modti3.c
|
||||
muldc3.c
|
||||
muldf3.c
|
||||
muldi3.c
|
||||
mulodi4.c
|
||||
mulosi4.c
|
||||
muloti4.c
|
||||
mulsc3.c
|
||||
mulsf3.c
|
||||
multi3.c
|
||||
mulvdi3.c
|
||||
mulvsi3.c
|
||||
mulvti3.c
|
||||
mulxc3.c
|
||||
negdf2.c
|
||||
negdi2.c
|
||||
negsf2.c
|
||||
negti2.c
|
||||
negvdi2.c
|
||||
negvsi2.c
|
||||
negvti2.c
|
||||
paritydi2.c
|
||||
paritysi2.c
|
||||
parityti2.c
|
||||
popcountdi2.c
|
||||
popcountsi2.c
|
||||
popcountti2.c
|
||||
powidf2.c
|
||||
powisf2.c
|
||||
powitf2.c
|
||||
powixf2.c
|
||||
subdf3.c
|
||||
subsf3.c
|
||||
subvdi3.c
|
||||
subvsi3.c
|
||||
subvti3.c
|
||||
trampoline_setup.c
|
||||
truncdfsf2.c
|
||||
ucmpdi2.c
|
||||
ucmpti2.c
|
||||
udivdi3.c
|
||||
udivmoddi4.c
|
||||
udivmodsi4.c
|
||||
udivmodti4.c
|
||||
udivsi3.c
|
||||
udivti3.c
|
||||
umoddi3.c
|
||||
umodsi3.c
|
||||
umodti3.c
|
||||
)
|
||||
|
||||
set(x86_64_SOURCES
|
||||
x86_64/floatdidf.c
|
||||
x86_64/floatdisf.c
|
||||
x86_64/floatdixf.c
|
||||
x86_64/floatundidf.S
|
||||
x86_64/floatundisf.S
|
||||
x86_64/floatundixf.S
|
||||
${GENERIC_SOURCES})
|
||||
|
||||
set(i386_SOURCES
|
||||
i386/ashldi3.S
|
||||
i386/ashrdi3.S
|
||||
i386/divdi3.S
|
||||
i386/floatdidf.S
|
||||
i386/floatdisf.S
|
||||
i386/floatdixf.S
|
||||
i386/floatundidf.S
|
||||
i386/floatundisf.S
|
||||
i386/floatundixf.S
|
||||
i386/lshrdi3.S
|
||||
i386/moddi3.S
|
||||
i386/muldi3.S
|
||||
i386/udivdi3.S
|
||||
i386/umoddi3.S
|
||||
${GENERIC_SOURCES})
|
||||
|
||||
if (NOT WIN32)
|
||||
foreach(arch x86_64 i386)
|
||||
if(CAN_TARGET_${arch})
|
||||
add_compiler_rt_static_runtime(clang_rt.${arch} ${arch}
|
||||
SOURCES ${${arch}_SOURCES}
|
||||
CFLAGS "-std=c99")
|
||||
endif()
|
||||
endforeach()
|
||||
if(COMPILER_RT_HAS_LSAN OR COMPILER_RT_HAS_LSAN_COMMON)
|
||||
add_subdirectory(lsan)
|
||||
endif()
|
||||
|
||||
# Generate configs for running lit and unit tests.
|
||||
configure_lit_site_cfg(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/lit.common.configured.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/lit.common.configured)
|
||||
if(COMPILER_RT_HAS_MSAN)
|
||||
add_subdirectory(msan)
|
||||
endif()
|
||||
|
||||
configure_lit_site_cfg(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/lit.common.unit.configured.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/lit.common.unit.configured)
|
||||
if(COMPILER_RT_HAS_PROFILE)
|
||||
add_subdirectory(profile)
|
||||
endif()
|
||||
|
||||
if(COMPILER_RT_HAS_TSAN)
|
||||
add_subdirectory(tsan)
|
||||
add_subdirectory(tsan/dd)
|
||||
endif()
|
||||
|
||||
if(COMPILER_RT_HAS_UBSAN)
|
||||
add_subdirectory(ubsan)
|
||||
endif()
|
||||
|
||||
|
@ -7,27 +7,16 @@
|
||||
#
|
||||
#===------------------------------------------------------------------------===#
|
||||
|
||||
ModuleName := builtins
|
||||
SubDirs :=
|
||||
|
||||
# Add arch specific optimized implementations.
|
||||
SubDirs += i386 ppc x86_64 arm
|
||||
|
||||
# Add other submodules.
|
||||
# Add submodules.
|
||||
SubDirs += asan
|
||||
SubDirs += builtins
|
||||
SubDirs += dfsan
|
||||
SubDirs += interception
|
||||
SubDirs += lsan
|
||||
SubDirs += msan
|
||||
SubDirs += profile
|
||||
SubDirs += sanitizer_common
|
||||
SubDirs += tsan
|
||||
SubDirs += msan
|
||||
SubDirs += ubsan
|
||||
SubDirs += lsan
|
||||
SubDirs += dfsan
|
||||
|
||||
# Define the variables for this specific directory.
|
||||
Sources := $(foreach file,$(wildcard $(Dir)/*.c),$(notdir $(file)))
|
||||
ObjNames := $(Sources:%.c=%.o)
|
||||
Implementation := Generic
|
||||
|
||||
# FIXME: use automatic dependencies?
|
||||
Dependencies := $(wildcard $(Dir)/*.h)
|
||||
|
152
lib/adddf3.c
152
lib/adddf3.c
@ -1,152 +0,0 @@
|
||||
//===-- lib/adddf3.c - Double-precision addition ------------------*- C -*-===//
|
||||
//
|
||||
// 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 double-precision soft-float addition with the IEEE-754
|
||||
// default rounding (to nearest, ties to even).
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#define DOUBLE_PRECISION
|
||||
#include "fp_lib.h"
|
||||
|
||||
ARM_EABI_FNALIAS(dadd, adddf3)
|
||||
|
||||
COMPILER_RT_ABI fp_t
|
||||
__adddf3(fp_t a, fp_t b) {
|
||||
|
||||
rep_t aRep = toRep(a);
|
||||
rep_t bRep = toRep(b);
|
||||
const rep_t aAbs = aRep & absMask;
|
||||
const rep_t bAbs = bRep & absMask;
|
||||
|
||||
// Detect if a or b is zero, infinity, or NaN.
|
||||
if (aAbs - 1U >= infRep - 1U || bAbs - 1U >= infRep - 1U) {
|
||||
|
||||
// NaN + anything = qNaN
|
||||
if (aAbs > infRep) return fromRep(toRep(a) | quietBit);
|
||||
// anything + NaN = qNaN
|
||||
if (bAbs > infRep) return fromRep(toRep(b) | quietBit);
|
||||
|
||||
if (aAbs == infRep) {
|
||||
// +/-infinity + -/+infinity = qNaN
|
||||
if ((toRep(a) ^ toRep(b)) == signBit) return fromRep(qnanRep);
|
||||
// +/-infinity + anything remaining = +/- infinity
|
||||
else return a;
|
||||
}
|
||||
|
||||
// anything remaining + +/-infinity = +/-infinity
|
||||
if (bAbs == infRep) return b;
|
||||
|
||||
// zero + anything = anything
|
||||
if (!aAbs) {
|
||||
// but we need to get the sign right for zero + zero
|
||||
if (!bAbs) return fromRep(toRep(a) & toRep(b));
|
||||
else return b;
|
||||
}
|
||||
|
||||
// anything + zero = anything
|
||||
if (!bAbs) return a;
|
||||
}
|
||||
|
||||
// Swap a and b if necessary so that a has the larger absolute value.
|
||||
if (bAbs > aAbs) {
|
||||
const rep_t temp = aRep;
|
||||
aRep = bRep;
|
||||
bRep = temp;
|
||||
}
|
||||
|
||||
// Extract the exponent and significand from the (possibly swapped) a and b.
|
||||
int aExponent = aRep >> significandBits & maxExponent;
|
||||
int bExponent = bRep >> significandBits & maxExponent;
|
||||
rep_t aSignificand = aRep & significandMask;
|
||||
rep_t bSignificand = bRep & significandMask;
|
||||
|
||||
// Normalize any denormals, and adjust the exponent accordingly.
|
||||
if (aExponent == 0) aExponent = normalize(&aSignificand);
|
||||
if (bExponent == 0) bExponent = normalize(&bSignificand);
|
||||
|
||||
// The sign of the result is the sign of the larger operand, a. If they
|
||||
// have opposite signs, we are performing a subtraction; otherwise addition.
|
||||
const rep_t resultSign = aRep & signBit;
|
||||
const bool subtraction = (aRep ^ bRep) & signBit;
|
||||
|
||||
// Shift the significands to give us round, guard and sticky, and or in the
|
||||
// implicit significand bit. (If we fell through from the denormal path it
|
||||
// was already set by normalize( ), but setting it twice won't hurt
|
||||
// anything.)
|
||||
aSignificand = (aSignificand | implicitBit) << 3;
|
||||
bSignificand = (bSignificand | implicitBit) << 3;
|
||||
|
||||
// Shift the significand of b by the difference in exponents, with a sticky
|
||||
// bottom bit to get rounding correct.
|
||||
const unsigned int align = aExponent - bExponent;
|
||||
if (align) {
|
||||
if (align < typeWidth) {
|
||||
const bool sticky = bSignificand << (typeWidth - align);
|
||||
bSignificand = bSignificand >> align | sticky;
|
||||
} else {
|
||||
bSignificand = 1; // sticky; b is known to be non-zero.
|
||||
}
|
||||
}
|
||||
|
||||
if (subtraction) {
|
||||
aSignificand -= bSignificand;
|
||||
|
||||
// If a == -b, return +zero.
|
||||
if (aSignificand == 0) return fromRep(0);
|
||||
|
||||
// If partial cancellation occured, we need to left-shift the result
|
||||
// and adjust the exponent:
|
||||
if (aSignificand < implicitBit << 3) {
|
||||
const int shift = rep_clz(aSignificand) - rep_clz(implicitBit << 3);
|
||||
aSignificand <<= shift;
|
||||
aExponent -= shift;
|
||||
}
|
||||
}
|
||||
|
||||
else /* addition */ {
|
||||
aSignificand += bSignificand;
|
||||
|
||||
// If the addition carried up, we need to right-shift the result and
|
||||
// adjust the exponent:
|
||||
if (aSignificand & implicitBit << 4) {
|
||||
const bool sticky = aSignificand & 1;
|
||||
aSignificand = aSignificand >> 1 | sticky;
|
||||
aExponent += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// If we have overflowed the type, return +/- infinity:
|
||||
if (aExponent >= maxExponent) return fromRep(infRep | resultSign);
|
||||
|
||||
if (aExponent <= 0) {
|
||||
// Result is denormal before rounding; the exponent is zero and we
|
||||
// need to shift the significand.
|
||||
const int shift = 1 - aExponent;
|
||||
const bool sticky = aSignificand << (typeWidth - shift);
|
||||
aSignificand = aSignificand >> shift | sticky;
|
||||
aExponent = 0;
|
||||
}
|
||||
|
||||
// Low three bits are round, guard, and sticky.
|
||||
const int roundGuardSticky = aSignificand & 0x7;
|
||||
|
||||
// Shift the significand into place, and mask off the implicit bit.
|
||||
rep_t result = aSignificand >> 3 & significandMask;
|
||||
|
||||
// Insert the exponent and sign.
|
||||
result |= (rep_t)aExponent << significandBits;
|
||||
result |= resultSign;
|
||||
|
||||
// Final rounding. The result may overflow to infinity, but that is the
|
||||
// correct result in that case.
|
||||
if (roundGuardSticky > 0x4) result++;
|
||||
if (roundGuardSticky == 0x4) result += result & 1;
|
||||
return fromRep(result);
|
||||
}
|
@ -1,96 +0,0 @@
|
||||
/*===-- udivmodsi4.S - 32-bit unsigned integer divide and modulus ---------===//
|
||||
*
|
||||
* 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 __udivmodsi4 (32-bit unsigned integer divide and
|
||||
* modulus) function for the ARM architecture. A naive digit-by-digit
|
||||
* computation is employed for simplicity.
|
||||
*
|
||||
*===----------------------------------------------------------------------===*/
|
||||
|
||||
#include "../assembly.h"
|
||||
|
||||
#define ESTABLISH_FRAME \
|
||||
push {r4, r7, lr} ;\
|
||||
add r7, sp, #4
|
||||
#define CLEAR_FRAME_AND_RETURN \
|
||||
pop {r4, r7, pc}
|
||||
|
||||
#define a r0
|
||||
#define b r1
|
||||
#define i r3
|
||||
#define r r4
|
||||
#define q ip
|
||||
#define one lr
|
||||
|
||||
.syntax unified
|
||||
.align 3
|
||||
DEFINE_COMPILERRT_FUNCTION(__udivmodsi4)
|
||||
#if __ARM_ARCH_EXT_IDIV__
|
||||
tst r1, r1
|
||||
beq LOCAL_LABEL(divzero)
|
||||
mov r3, r0
|
||||
udiv r0, r3, r1
|
||||
mls r1, r0, r1, r3
|
||||
str r1, [r2]
|
||||
bx lr
|
||||
LOCAL_LABEL(divzero):
|
||||
mov r0, #0
|
||||
bx lr
|
||||
#else
|
||||
// We use a simple digit by digit algorithm; before we get into the actual
|
||||
// divide loop, we must calculate the left-shift amount necessary to align
|
||||
// the MSB of the divisor with that of the dividend (If this shift is
|
||||
// negative, then the result is zero, and we early out). We also conjure a
|
||||
// bit mask of 1 to use in constructing the quotient, and initialize the
|
||||
// quotient to zero.
|
||||
ESTABLISH_FRAME
|
||||
clz r4, a
|
||||
tst b, b // detect divide-by-zero
|
||||
clz r3, b
|
||||
mov q, #0
|
||||
beq LOCAL_LABEL(return) // return 0 if b is zero.
|
||||
mov one, #1
|
||||
subs i, r3, r4
|
||||
blt LOCAL_LABEL(return) // return 0 if MSB(a) < MSB(b)
|
||||
|
||||
LOCAL_LABEL(mainLoop):
|
||||
// This loop basically implements the following:
|
||||
//
|
||||
// do {
|
||||
// if (a >= b << i) {
|
||||
// a -= b << i;
|
||||
// q |= 1 << i;
|
||||
// if (a == 0) break;
|
||||
// }
|
||||
// } while (--i)
|
||||
//
|
||||
// Note that this does not perform the final iteration (i == 0); by doing it
|
||||
// this way, we can merge the two branches which is a substantial win for
|
||||
// such a tight loop on current ARM architectures.
|
||||
subs r, a, b, lsl i
|
||||
itt hs
|
||||
orrhs q, q,one, lsl i
|
||||
movhs a, r
|
||||
it ne
|
||||
subsne i, i, #1
|
||||
bhi LOCAL_LABEL(mainLoop)
|
||||
|
||||
// Do the final test subtraction and update of quotient (i == 0), as it is
|
||||
// not performed in the main loop.
|
||||
subs r, a, b
|
||||
itt hs
|
||||
orrhs q, #1
|
||||
movhs a, r
|
||||
|
||||
LOCAL_LABEL(return):
|
||||
// Store the remainder, and move the quotient to r0, then return.
|
||||
str a, [r2]
|
||||
mov r0, q
|
||||
CLEAR_FRAME_AND_RETURN
|
||||
#endif
|
@ -1,93 +0,0 @@
|
||||
/*===-- udivsi3.S - 32-bit unsigned integer divide ------------------------===//
|
||||
*
|
||||
* 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 __udivsi3 (32-bit unsigned integer divide)
|
||||
* function for the ARM architecture. A naive digit-by-digit computation is
|
||||
* employed for simplicity.
|
||||
*
|
||||
*===----------------------------------------------------------------------===*/
|
||||
|
||||
#include "../assembly.h"
|
||||
|
||||
#define ESTABLISH_FRAME \
|
||||
push {r7, lr} ;\
|
||||
mov r7, sp
|
||||
#define CLEAR_FRAME_AND_RETURN \
|
||||
pop {r7, pc}
|
||||
|
||||
#define a r0
|
||||
#define b r1
|
||||
#define r r2
|
||||
#define i r3
|
||||
#define q ip
|
||||
#define one lr
|
||||
|
||||
.syntax unified
|
||||
.align 3
|
||||
// Ok, APCS and AAPCS agree on 32 bit args, so it's safe to use the same routine.
|
||||
DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_uidiv, __udivsi3)
|
||||
DEFINE_COMPILERRT_FUNCTION(__udivsi3)
|
||||
#if __ARM_ARCH_EXT_IDIV__
|
||||
tst r1,r1
|
||||
beq LOCAL_LABEL(divzero)
|
||||
udiv r0, r0, r1
|
||||
bx lr
|
||||
LOCAL_LABEL(divzero):
|
||||
mov r0,#0
|
||||
bx lr
|
||||
#else
|
||||
// We use a simple digit by digit algorithm; before we get into the actual
|
||||
// divide loop, we must calculate the left-shift amount necessary to align
|
||||
// the MSB of the divisor with that of the dividend (If this shift is
|
||||
// negative, then the result is zero, and we early out). We also conjure a
|
||||
// bit mask of 1 to use in constructing the quotient, and initialize the
|
||||
// quotient to zero.
|
||||
ESTABLISH_FRAME
|
||||
clz r2, a
|
||||
tst b, b // detect divide-by-zero
|
||||
clz r3, b
|
||||
mov q, #0
|
||||
beq LOCAL_LABEL(return) // return 0 if b is zero.
|
||||
mov one, #1
|
||||
subs i, r3, r2
|
||||
blt LOCAL_LABEL(return) // return 0 if MSB(a) < MSB(b)
|
||||
|
||||
LOCAL_LABEL(mainLoop):
|
||||
// This loop basically implements the following:
|
||||
//
|
||||
// do {
|
||||
// if (a >= b << i) {
|
||||
// a -= b << i;
|
||||
// q |= 1 << i;
|
||||
// if (a == 0) break;
|
||||
// }
|
||||
// } while (--i)
|
||||
//
|
||||
// Note that this does not perform the final iteration (i == 0); by doing it
|
||||
// this way, we can merge the two branches which is a substantial win for
|
||||
// such a tight loop on current ARM architectures.
|
||||
subs r, a, b, lsl i
|
||||
itt hs
|
||||
orrhs q, q,one, lsl i
|
||||
movhs a, r
|
||||
it ne
|
||||
subsne i, i, #1
|
||||
bhi LOCAL_LABEL(mainLoop)
|
||||
|
||||
// Do the final test subtraction and update of quotient (i == 0), as it is
|
||||
// not performed in the main loop.
|
||||
subs r, a, b
|
||||
it hs
|
||||
orrhs q, #1
|
||||
|
||||
LOCAL_LABEL(return):
|
||||
// Move the quotient to r0 and return.
|
||||
mov r0, q
|
||||
CLEAR_FRAME_AND_RETURN
|
||||
#endif
|
@ -1,72 +0,0 @@
|
||||
/*===-- umodsi3.S - 32-bit unsigned integer modulus -----------------------===//
|
||||
*
|
||||
* 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 __umodsi3 (32-bit unsigned integer modulus)
|
||||
* function for the ARM architecture. A naive digit-by-digit computation is
|
||||
* employed for simplicity.
|
||||
*
|
||||
*===----------------------------------------------------------------------===*/
|
||||
|
||||
#include "../assembly.h"
|
||||
|
||||
#define a r0
|
||||
#define b r1
|
||||
#define r r2
|
||||
#define i r3
|
||||
|
||||
.syntax unified
|
||||
.align 3
|
||||
DEFINE_COMPILERRT_FUNCTION(__umodsi3)
|
||||
#if __ARM_ARCH_EXT_IDIV__
|
||||
tst r1, r1
|
||||
beq LOCAL_LABEL(divzero)
|
||||
udiv r2, r0, r1
|
||||
mls r0, r2, r1, r0
|
||||
bx lr
|
||||
LOCAL_LABEL(divzero):
|
||||
mov r0, #0
|
||||
bx lr
|
||||
#else
|
||||
// We use a simple digit by digit algorithm; before we get into the actual
|
||||
// divide loop, we must calculate the left-shift amount necessary to align
|
||||
// the MSB of the divisor with that of the dividend.
|
||||
clz r2, a
|
||||
tst b, b // detect b == 0
|
||||
clz r3, b
|
||||
bxeq lr // return a if b == 0
|
||||
subs i, r3, r2
|
||||
bxlt lr // return a if MSB(a) < MSB(b)
|
||||
|
||||
LOCAL_LABEL(mainLoop):
|
||||
// This loop basically implements the following:
|
||||
//
|
||||
// do {
|
||||
// if (a >= b << i) {
|
||||
// a -= b << i;
|
||||
// if (a == 0) break;
|
||||
// }
|
||||
// } while (--i)
|
||||
//
|
||||
// Note that this does not perform the final iteration (i == 0); by doing it
|
||||
// this way, we can merge the two branches which is a substantial win for
|
||||
// such a tight loop on current ARM architectures.
|
||||
subs r, a, b, lsl i
|
||||
it hs
|
||||
movhs a, r
|
||||
it ne
|
||||
subsne i, i, #1
|
||||
bhi LOCAL_LABEL(mainLoop)
|
||||
|
||||
// Do the final test subtraction and update of remainder (i == 0), as it is
|
||||
// not performed in the main loop.
|
||||
subs r, a, b
|
||||
it hs
|
||||
movhs a, r
|
||||
bx lr
|
||||
#endif
|
@ -2,6 +2,8 @@
|
||||
|
||||
set(ASAN_SOURCES
|
||||
asan_allocator2.cc
|
||||
asan_activation.cc
|
||||
asan_debugging.cc
|
||||
asan_fake_stack.cc
|
||||
asan_globals.cc
|
||||
asan_interceptors.cc
|
||||
@ -10,81 +12,85 @@ set(ASAN_SOURCES
|
||||
asan_malloc_linux.cc
|
||||
asan_malloc_mac.cc
|
||||
asan_malloc_win.cc
|
||||
asan_new_delete.cc
|
||||
asan_poisoning.cc
|
||||
asan_posix.cc
|
||||
asan_preinit.cc
|
||||
asan_report.cc
|
||||
asan_rtl.cc
|
||||
asan_stack.cc
|
||||
asan_stats.cc
|
||||
asan_suppressions.cc
|
||||
asan_thread.cc
|
||||
asan_win.cc)
|
||||
|
||||
set(ASAN_CXX_SOURCES
|
||||
asan_new_delete.cc)
|
||||
|
||||
set(ASAN_PREINIT_SOURCES
|
||||
asan_preinit.cc)
|
||||
|
||||
include_directories(..)
|
||||
|
||||
if (NOT MSVC)
|
||||
set(ASAN_CFLAGS
|
||||
${SANITIZER_COMMON_CFLAGS}
|
||||
-fno-rtti)
|
||||
else()
|
||||
set(ASAN_CFLAGS
|
||||
${SANITIZER_COMMON_CFLAGS}
|
||||
/GR-)
|
||||
endif()
|
||||
set(ASAN_CFLAGS ${SANITIZER_COMMON_CFLAGS})
|
||||
append_no_rtti_flag(ASAN_CFLAGS)
|
||||
|
||||
set(ASAN_COMMON_DEFINITIONS
|
||||
ASAN_HAS_EXCEPTIONS=1)
|
||||
|
||||
if(ANDROID)
|
||||
list(APPEND ASAN_COMMON_DEFINITIONS
|
||||
ASAN_FLEXIBLE_MAPPING_AND_OFFSET=0
|
||||
ASAN_NEEDS_SEGV=0
|
||||
ASAN_LOW_MEMORY=1)
|
||||
elseif(MSVC)
|
||||
list(APPEND ASAN_COMMON_DEFINITIONS
|
||||
ASAN_FLEXIBLE_MAPPING_AND_OFFSET=0
|
||||
ASAN_NEEDS_SEGV=0)
|
||||
else()
|
||||
list(APPEND ASAN_COMMON_DEFINITIONS
|
||||
ASAN_FLEXIBLE_MAPPING_AND_OFFSET=1
|
||||
ASAN_NEEDS_SEGV=1)
|
||||
endif()
|
||||
|
||||
# Architectures supported by ASan.
|
||||
filter_available_targets(ASAN_SUPPORTED_ARCH
|
||||
x86_64 i386 powerpc64)
|
||||
set(ASAN_DYNAMIC_DEFINITIONS
|
||||
${ASAN_COMMON_DEFINITIONS} ASAN_DYNAMIC=1)
|
||||
append_list_if(WIN32 INTERCEPTION_DYNAMIC_CRT ASAN_DYNAMIC_DEFINITIONS)
|
||||
|
||||
set(ASAN_DYNAMIC_CFLAGS ${ASAN_CFLAGS})
|
||||
append_list_if(COMPILER_RT_HAS_FTLS_MODEL_INITIAL_EXEC
|
||||
-ftls-model=initial-exec ASAN_DYNAMIC_CFLAGS)
|
||||
append_list_if(MSVC /DEBUG ASAN_DYNAMIC_CFLAGS)
|
||||
|
||||
append_list_if(COMPILER_RT_HAS_LIBC c ASAN_DYNAMIC_LIBS)
|
||||
append_list_if(COMPILER_RT_HAS_LIBDL dl ASAN_DYNAMIC_LIBS)
|
||||
append_list_if(COMPILER_RT_HAS_LIBM m ASAN_DYNAMIC_LIBS)
|
||||
append_list_if(COMPILER_RT_HAS_LIBPTHREAD pthread ASAN_DYNAMIC_LIBS)
|
||||
append_list_if(COMPILER_RT_HAS_LIBSTDCXX stdc++ ASAN_DYNAMIC_LIBS)
|
||||
|
||||
append_list_if(ANDROID log ASAN_DYNAMIC_LIBS)
|
||||
|
||||
# Compile ASan sources into an object library.
|
||||
if(APPLE)
|
||||
foreach(os ${SANITIZER_COMMON_SUPPORTED_DARWIN_OS})
|
||||
add_compiler_rt_darwin_object_library(RTAsan ${os}
|
||||
ARCH ${ASAN_SUPPORTED_ARCH}
|
||||
SOURCES ${ASAN_SOURCES}
|
||||
SOURCES ${ASAN_SOURCES} ${ASAN_CXX_SOURCES}
|
||||
CFLAGS ${ASAN_CFLAGS}
|
||||
DEFS ${ASAN_COMMON_DEFINITIONS})
|
||||
endforeach()
|
||||
elseif(ANDROID)
|
||||
add_library(RTAsan.arm.android OBJECT ${ASAN_SOURCES})
|
||||
set_target_compile_flags(RTAsan.arm.android ${ASAN_CFLAGS})
|
||||
set_property(TARGET RTAsan.arm.android APPEND PROPERTY
|
||||
COMPILE_DEFINITIONS ${ASAN_COMMON_DEFINITIONS})
|
||||
else()
|
||||
foreach(arch ${ASAN_SUPPORTED_ARCH})
|
||||
add_compiler_rt_object_library(RTAsan ${arch}
|
||||
SOURCES ${ASAN_SOURCES} CFLAGS ${ASAN_CFLAGS}
|
||||
DEFS ${ASAN_COMMON_DEFINITIONS})
|
||||
add_compiler_rt_object_library(RTAsan_cxx ${arch}
|
||||
SOURCES ${ASAN_CXX_SOURCES} CFLAGS ${ASAN_CFLAGS}
|
||||
DEFS ${ASAN_COMMON_DEFINITIONS})
|
||||
add_compiler_rt_object_library(RTAsan_preinit ${arch}
|
||||
SOURCES ${ASAN_PREINIT_SOURCES} CFLAGS ${ASAN_CFLAGS}
|
||||
DEFS ${ASAN_COMMON_DEFINITIONS})
|
||||
if (COMPILER_RT_BUILD_SHARED_ASAN)
|
||||
add_compiler_rt_object_library(RTAsan_dynamic ${arch}
|
||||
SOURCES ${ASAN_SOURCES} ${ASAN_CXX_SOURCES}
|
||||
CFLAGS ${ASAN_DYNAMIC_CFLAGS}
|
||||
DEFS ${ASAN_DYNAMIC_DEFINITIONS})
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
# Build ASan runtimes shipped with Clang.
|
||||
set(ASAN_RUNTIME_LIBRARIES)
|
||||
add_custom_target(asan)
|
||||
if(APPLE)
|
||||
foreach (os ${SANITIZER_COMMON_SUPPORTED_DARWIN_OS})
|
||||
# Dynamic lookup is needed because shadow scale and offset are
|
||||
# provided by the instrumented modules.
|
||||
set(ASAN_RUNTIME_LDFLAGS
|
||||
"-undefined dynamic_lookup")
|
||||
add_compiler_rt_darwin_dynamic_runtime(clang_rt.asan_${os}_dynamic ${os}
|
||||
ARCH ${ASAN_SUPPORTED_ARCH}
|
||||
SOURCES $<TARGET_OBJECTS:RTAsan.${os}>
|
||||
@ -92,63 +98,89 @@ if(APPLE)
|
||||
$<TARGET_OBJECTS:RTSanitizerCommon.${os}>
|
||||
$<TARGET_OBJECTS:RTLSanCommon.${os}>
|
||||
CFLAGS ${ASAN_CFLAGS}
|
||||
DEFS ${ASAN_COMMON_DEFINITIONS}
|
||||
LINKFLAGS ${ASAN_RUNTIME_LDFLAGS})
|
||||
list(APPEND ASAN_RUNTIME_LIBRARIES clang_rt.asan_${os}_dynamic)
|
||||
DEFS ${ASAN_COMMON_DEFINITIONS})
|
||||
add_dependencies(asan clang_rt.asan_${os}_dynamic)
|
||||
endforeach()
|
||||
|
||||
elseif(ANDROID)
|
||||
add_library(clang_rt.asan-arm-android SHARED
|
||||
$<TARGET_OBJECTS:RTAsan.arm.android>
|
||||
$<TARGET_OBJECTS:RTInterception.arm.android>
|
||||
$<TARGET_OBJECTS:RTSanitizerCommon.arm.android>)
|
||||
set_target_compile_flags(clang_rt.asan-arm-android
|
||||
${ASAN_CFLAGS})
|
||||
set_property(TARGET clang_rt.asan-arm-android APPEND PROPERTY
|
||||
COMPILE_DEFINITIONS ${ASAN_COMMON_DEFINITIONS})
|
||||
target_link_libraries(clang_rt.asan-arm-android dl)
|
||||
list(APPEND ASAN_RUNTIME_LIBRARIES clang_rt.asan-arm-android)
|
||||
else()
|
||||
# Build separate libraries for each target.
|
||||
foreach(arch ${ASAN_SUPPORTED_ARCH})
|
||||
set(ASAN_RUNTIME_OBJECTS
|
||||
$<TARGET_OBJECTS:RTAsan.${arch}>
|
||||
set(ASAN_COMMON_RUNTIME_OBJECTS
|
||||
$<TARGET_OBJECTS:RTInterception.${arch}>
|
||||
$<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
|
||||
$<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>)
|
||||
if (NOT WIN32)
|
||||
if(NOT WIN32)
|
||||
# We can't build Leak Sanitizer on Windows yet.
|
||||
list(APPEND ASAN_RUNTIME_OBJECTS $<TARGET_OBJECTS:RTLSanCommon.${arch}>)
|
||||
list(APPEND ASAN_COMMON_RUNTIME_OBJECTS
|
||||
$<TARGET_OBJECTS:RTLSanCommon.${arch}>)
|
||||
endif()
|
||||
|
||||
add_compiler_rt_static_runtime(clang_rt.asan-${arch} ${arch}
|
||||
SOURCES ${ASAN_RUNTIME_OBJECTS}
|
||||
add_compiler_rt_runtime(clang_rt.asan-${arch} ${arch} STATIC
|
||||
SOURCES $<TARGET_OBJECTS:RTAsan_preinit.${arch}>
|
||||
$<TARGET_OBJECTS:RTAsan.${arch}>
|
||||
${ASAN_COMMON_RUNTIME_OBJECTS}
|
||||
CFLAGS ${ASAN_CFLAGS}
|
||||
DEFS ${ASAN_COMMON_DEFINITIONS})
|
||||
list(APPEND ASAN_RUNTIME_LIBRARIES clang_rt.asan-${arch})
|
||||
if (UNIX AND NOT ${arch} STREQUAL "i386")
|
||||
add_dependencies(asan clang_rt.asan-${arch})
|
||||
|
||||
add_compiler_rt_runtime(clang_rt.asan_cxx-${arch} ${arch} STATIC
|
||||
SOURCES $<TARGET_OBJECTS:RTAsan_cxx.${arch}>
|
||||
CFLAGS ${ASAN_CFLAGS}
|
||||
DEFS ${ASAN_COMMON_DEFINITIONS})
|
||||
add_dependencies(asan clang_rt.asan_cxx-${arch})
|
||||
|
||||
if (COMPILER_RT_BUILD_SHARED_ASAN)
|
||||
add_compiler_rt_runtime(clang_rt.asan-preinit-${arch} ${arch} STATIC
|
||||
SOURCES $<TARGET_OBJECTS:RTAsan_preinit.${arch}>
|
||||
CFLAGS ${ASAN_CFLAGS}
|
||||
DEFS ${ASAN_COMMON_DEFINITIONS})
|
||||
add_dependencies(asan clang_rt.asan-preinit-${arch})
|
||||
|
||||
if (WIN32)
|
||||
set(SHARED_ASAN_NAME clang_rt.asan_dynamic-${arch}${COMPILER_RT_OS_SUFFIX})
|
||||
else()
|
||||
set(SHARED_ASAN_NAME clang_rt.asan-${arch}${COMPILER_RT_OS_SUFFIX})
|
||||
endif()
|
||||
|
||||
add_compiler_rt_runtime(clang_rt.asan-dynamic-${arch} ${arch} SHARED
|
||||
OUTPUT_NAME ${SHARED_ASAN_NAME}
|
||||
SOURCES $<TARGET_OBJECTS:RTAsan_dynamic.${arch}>
|
||||
${ASAN_COMMON_RUNTIME_OBJECTS}
|
||||
CFLAGS ${ASAN_DYNAMIC_CFLAGS}
|
||||
DEFS ${ASAN_DYNAMIC_DEFINITIONS})
|
||||
target_link_libraries(clang_rt.asan-dynamic-${arch} ${ASAN_DYNAMIC_LIBS})
|
||||
add_dependencies(asan clang_rt.asan-dynamic-${arch})
|
||||
endif()
|
||||
|
||||
if (UNIX AND NOT ${arch} STREQUAL "i386" AND NOT ${arch} STREQUAL "i686")
|
||||
add_sanitizer_rt_symbols(clang_rt.asan_cxx-${arch})
|
||||
add_dependencies(asan clang_rt.asan_cxx-${arch}-symbols)
|
||||
add_sanitizer_rt_symbols(clang_rt.asan-${arch} asan.syms.extra)
|
||||
list(APPEND ASAN_RUNTIME_LIBRARIES clang_rt.asan-${arch}-symbols)
|
||||
add_dependencies(asan clang_rt.asan-${arch}-symbols)
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
add_compiler_rt_static_runtime(clang_rt.asan_dll_thunk-${arch} ${arch}
|
||||
SOURCES asan_dll_thunk.cc
|
||||
add_compiler_rt_runtime(clang_rt.asan_dll_thunk-${arch} ${arch} STATIC
|
||||
SOURCES asan_win_dll_thunk.cc
|
||||
$<TARGET_OBJECTS:RTInterception.${arch}>
|
||||
CFLAGS ${ASAN_CFLAGS} -DASAN_DLL_THUNK
|
||||
DEFS ${ASAN_COMMON_DEFINITIONS})
|
||||
list(APPEND ASAN_RUNTIME_LIBRARIES clang_rt.asan_dll_thunk-${arch})
|
||||
add_dependencies(asan clang_rt.asan_dll_thunk-${arch})
|
||||
add_compiler_rt_runtime(clang_rt.asan_dynamic_runtime_thunk-${arch} ${arch}
|
||||
STATIC
|
||||
SOURCES asan_win_dynamic_runtime_thunk.cc
|
||||
CFLAGS ${ASAN_CFLAGS} -DASAN_DYNAMIC_RUNTIME_THUNK -Zl
|
||||
DEFS ${ASAN_COMMON_DEFINITIONS})
|
||||
add_dependencies(asan clang_rt.asan_dynamic_runtime_thunk-${arch})
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
add_compiler_rt_resource_file(asan_blacklist asan_blacklist.txt)
|
||||
add_dependencies(asan asan_blacklist)
|
||||
add_dependencies(compiler-rt asan)
|
||||
|
||||
# All ASan runtime dependencies.
|
||||
add_custom_target(asan_runtime_libraries
|
||||
DEPENDS asan_blacklist ${ASAN_RUNTIME_LIBRARIES})
|
||||
add_subdirectory(scripts)
|
||||
|
||||
if(LLVM_INCLUDE_TESTS)
|
||||
if(COMPILER_RT_INCLUDE_TESTS)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
||||
add_subdirectory(lit_tests)
|
||||
|
@ -10,8 +10,12 @@
|
||||
ModuleName := asan
|
||||
SubDirs :=
|
||||
|
||||
Sources := $(foreach file,$(wildcard $(Dir)/*.cc),$(notdir $(file)))
|
||||
ObjNames := $(Sources:%.cc=%.o)
|
||||
CCSources := $(foreach file,$(wildcard $(Dir)/*.cc),$(notdir $(file)))
|
||||
CXXOnlySources := asan_new_delete.cc
|
||||
COnlySources := $(filter-out $(CXXOnlySources),$(CCSources))
|
||||
SSources := $(foreach file,$(wildcard $(Dir)/*.S),$(notdir $(file)))
|
||||
Sources := $(CCSources) $(SSources)
|
||||
ObjNames := $(CCSources:%.cc=%.o) $(SSources:%.S=%.o)
|
||||
|
||||
Implementation := Generic
|
||||
|
||||
@ -21,4 +25,5 @@ Dependencies += $(wildcard $(Dir)/../interception/*.h)
|
||||
Dependencies += $(wildcard $(Dir)/../sanitizer_common/*.h)
|
||||
|
||||
# Define a convenience variable for all the asan functions.
|
||||
AsanFunctions := $(Sources:%.cc=%)
|
||||
AsanFunctions := $(COnlySources:%.cc=%) $(SSources:%.S=%)
|
||||
AsanCXXFunctions := $(CXXOnlySources:%.cc=%)
|
||||
|
@ -1,16 +1,15 @@
|
||||
AddressSanitizer RT
|
||||
================================
|
||||
This directory contains sources of the AddressSanitizer (asan) run-time library.
|
||||
This directory contains sources of the AddressSanitizer (asan) runtime library.
|
||||
We are in the process of integrating AddressSanitizer with LLVM, stay tuned.
|
||||
|
||||
Directory structre:
|
||||
Directory structure:
|
||||
README.txt : This file.
|
||||
Makefile.mk : File for make-based build.
|
||||
CMakeLists.txt : File for cmake-based build.
|
||||
asan_*.{cc,h} : Sources of the asan run-time lirbary.
|
||||
asan_*.{cc,h} : Sources of the asan runtime library.
|
||||
scripts/* : Helper scripts.
|
||||
tests/* : ASan unit tests.
|
||||
lit_tests/* : ASan output tests.
|
||||
|
||||
Also ASan runtime needs the following libraries:
|
||||
lib/interception/ : Machinery used to intercept function calls.
|
||||
|
88
lib/asan/asan_activation.cc
Normal file
88
lib/asan/asan_activation.cc
Normal file
@ -0,0 +1,88 @@
|
||||
//===-- asan_activation.cc --------------------------------------*- 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 AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// ASan activation/deactivation logic.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "asan_activation.h"
|
||||
#include "asan_allocator.h"
|
||||
#include "asan_flags.h"
|
||||
#include "asan_internal.h"
|
||||
#include "sanitizer_common/sanitizer_flags.h"
|
||||
|
||||
namespace __asan {
|
||||
|
||||
static struct AsanDeactivatedFlags {
|
||||
int quarantine_size;
|
||||
int max_redzone;
|
||||
int malloc_context_size;
|
||||
bool poison_heap;
|
||||
bool alloc_dealloc_mismatch;
|
||||
bool allocator_may_return_null;
|
||||
} asan_deactivated_flags;
|
||||
|
||||
static bool asan_is_deactivated;
|
||||
|
||||
void AsanStartDeactivated() {
|
||||
VReport(1, "Deactivating ASan\n");
|
||||
// Save flag values.
|
||||
asan_deactivated_flags.quarantine_size = flags()->quarantine_size;
|
||||
asan_deactivated_flags.max_redzone = flags()->max_redzone;
|
||||
asan_deactivated_flags.poison_heap = flags()->poison_heap;
|
||||
asan_deactivated_flags.malloc_context_size =
|
||||
common_flags()->malloc_context_size;
|
||||
asan_deactivated_flags.alloc_dealloc_mismatch =
|
||||
flags()->alloc_dealloc_mismatch;
|
||||
asan_deactivated_flags.allocator_may_return_null =
|
||||
common_flags()->allocator_may_return_null;
|
||||
|
||||
flags()->quarantine_size = 0;
|
||||
flags()->max_redzone = 16;
|
||||
flags()->poison_heap = false;
|
||||
common_flags()->malloc_context_size = 0;
|
||||
flags()->alloc_dealloc_mismatch = false;
|
||||
common_flags()->allocator_may_return_null = true;
|
||||
|
||||
asan_is_deactivated = true;
|
||||
}
|
||||
|
||||
void AsanActivate() {
|
||||
if (!asan_is_deactivated) return;
|
||||
VReport(1, "Activating ASan\n");
|
||||
|
||||
// Restore flag values.
|
||||
// FIXME: this is not atomic, and there may be other threads alive.
|
||||
flags()->quarantine_size = asan_deactivated_flags.quarantine_size;
|
||||
flags()->max_redzone = asan_deactivated_flags.max_redzone;
|
||||
flags()->poison_heap = asan_deactivated_flags.poison_heap;
|
||||
common_flags()->malloc_context_size =
|
||||
asan_deactivated_flags.malloc_context_size;
|
||||
flags()->alloc_dealloc_mismatch =
|
||||
asan_deactivated_flags.alloc_dealloc_mismatch;
|
||||
common_flags()->allocator_may_return_null =
|
||||
asan_deactivated_flags.allocator_may_return_null;
|
||||
|
||||
ParseExtraActivationFlags();
|
||||
|
||||
ReInitializeAllocator();
|
||||
|
||||
asan_is_deactivated = false;
|
||||
VReport(
|
||||
1,
|
||||
"quarantine_size %d, max_redzone %d, poison_heap %d, "
|
||||
"malloc_context_size %d, alloc_dealloc_mismatch %d, "
|
||||
"allocator_may_return_null %d\n",
|
||||
flags()->quarantine_size, flags()->max_redzone, flags()->poison_heap,
|
||||
common_flags()->malloc_context_size, flags()->alloc_dealloc_mismatch,
|
||||
common_flags()->allocator_may_return_null);
|
||||
}
|
||||
|
||||
} // namespace __asan
|
@ -1,4 +1,4 @@
|
||||
//===----------- shared-lib-test-so.cc --------------------------*- C++ -*-===//
|
||||
//===-- asan_activation.h ---------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -9,18 +9,15 @@
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// ASan activation/deactivation logic.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include <stdio.h>
|
||||
|
||||
int pad[10];
|
||||
int GLOB[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
#ifndef ASAN_ACTIVATION_H
|
||||
#define ASAN_ACTIVATION_H
|
||||
|
||||
extern "C"
|
||||
void inc(int index) {
|
||||
GLOB[index]++;
|
||||
}
|
||||
namespace __asan {
|
||||
void AsanStartDeactivated();
|
||||
void AsanActivate();
|
||||
} // namespace __asan
|
||||
|
||||
extern "C"
|
||||
void inc2(int *a, int index) {
|
||||
a[index]++;
|
||||
}
|
||||
#endif // ASAN_ACTIVATION_H
|
@ -17,6 +17,7 @@
|
||||
|
||||
#include "asan_internal.h"
|
||||
#include "asan_interceptors.h"
|
||||
#include "sanitizer_common/sanitizer_allocator.h"
|
||||
#include "sanitizer_common/sanitizer_list.h"
|
||||
|
||||
namespace __asan {
|
||||
@ -31,6 +32,7 @@ static const uptr kNumberOfSizeClasses = 255;
|
||||
struct AsanChunk;
|
||||
|
||||
void InitializeAllocator();
|
||||
void ReInitializeAllocator();
|
||||
|
||||
class AsanChunkView {
|
||||
public:
|
||||
@ -42,8 +44,9 @@ class AsanChunkView {
|
||||
uptr UsedSize(); // Size requested by the user.
|
||||
uptr AllocTid();
|
||||
uptr FreeTid();
|
||||
void GetAllocStack(StackTrace *stack);
|
||||
void GetFreeStack(StackTrace *stack);
|
||||
bool Eq(const AsanChunkView &c) const { return chunk_ == c.chunk_; }
|
||||
StackTrace GetAllocStack();
|
||||
StackTrace GetFreeStack();
|
||||
bool AddrIsInside(uptr addr, uptr access_size, sptr *offset) {
|
||||
if (addr >= Beg() && (addr + access_size) <= End()) {
|
||||
*offset = addr - Beg();
|
||||
@ -90,31 +93,66 @@ class AsanChunkFifoList: public IntrusiveList<AsanChunk> {
|
||||
uptr size_;
|
||||
};
|
||||
|
||||
struct AsanThreadLocalMallocStorage {
|
||||
explicit AsanThreadLocalMallocStorage(LinkerInitialized x)
|
||||
{ }
|
||||
AsanThreadLocalMallocStorage() {
|
||||
CHECK(REAL(memset));
|
||||
REAL(memset)(this, 0, sizeof(AsanThreadLocalMallocStorage));
|
||||
}
|
||||
|
||||
uptr quarantine_cache[16];
|
||||
uptr allocator2_cache[96 * (512 * 8 + 16)]; // Opaque.
|
||||
void CommitBack();
|
||||
struct AsanMapUnmapCallback {
|
||||
void OnMap(uptr p, uptr size) const;
|
||||
void OnUnmap(uptr p, uptr size) const;
|
||||
};
|
||||
|
||||
void *asan_memalign(uptr alignment, uptr size, StackTrace *stack,
|
||||
AllocType alloc_type);
|
||||
void asan_free(void *ptr, StackTrace *stack, AllocType alloc_type);
|
||||
#if SANITIZER_CAN_USE_ALLOCATOR64
|
||||
# if defined(__powerpc64__)
|
||||
const uptr kAllocatorSpace = 0xa0000000000ULL;
|
||||
const uptr kAllocatorSize = 0x20000000000ULL; // 2T.
|
||||
# else
|
||||
const uptr kAllocatorSpace = 0x600000000000ULL;
|
||||
const uptr kAllocatorSize = 0x40000000000ULL; // 4T.
|
||||
# endif
|
||||
typedef DefaultSizeClassMap SizeClassMap;
|
||||
typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, 0 /*metadata*/,
|
||||
SizeClassMap, AsanMapUnmapCallback> PrimaryAllocator;
|
||||
#else // Fallback to SizeClassAllocator32.
|
||||
static const uptr kRegionSizeLog = 20;
|
||||
static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog;
|
||||
# if SANITIZER_WORDSIZE == 32
|
||||
typedef FlatByteMap<kNumRegions> ByteMap;
|
||||
# elif SANITIZER_WORDSIZE == 64
|
||||
typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap;
|
||||
# endif
|
||||
typedef CompactSizeClassMap SizeClassMap;
|
||||
typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, 16,
|
||||
SizeClassMap, kRegionSizeLog,
|
||||
ByteMap,
|
||||
AsanMapUnmapCallback> PrimaryAllocator;
|
||||
#endif // SANITIZER_CAN_USE_ALLOCATOR64
|
||||
|
||||
void *asan_malloc(uptr size, StackTrace *stack);
|
||||
void *asan_calloc(uptr nmemb, uptr size, StackTrace *stack);
|
||||
void *asan_realloc(void *p, uptr size, StackTrace *stack);
|
||||
void *asan_valloc(uptr size, StackTrace *stack);
|
||||
void *asan_pvalloc(uptr size, StackTrace *stack);
|
||||
typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
|
||||
typedef LargeMmapAllocator<AsanMapUnmapCallback> SecondaryAllocator;
|
||||
typedef CombinedAllocator<PrimaryAllocator, AllocatorCache,
|
||||
SecondaryAllocator> Allocator;
|
||||
|
||||
|
||||
struct AsanThreadLocalMallocStorage {
|
||||
uptr quarantine_cache[16];
|
||||
AllocatorCache allocator2_cache;
|
||||
void CommitBack();
|
||||
private:
|
||||
// These objects are allocated via mmap() and are zero-initialized.
|
||||
AsanThreadLocalMallocStorage() {}
|
||||
};
|
||||
|
||||
void *asan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack,
|
||||
AllocType alloc_type);
|
||||
void asan_free(void *ptr, BufferedStackTrace *stack, AllocType alloc_type);
|
||||
void asan_sized_free(void *ptr, uptr size, BufferedStackTrace *stack,
|
||||
AllocType alloc_type);
|
||||
|
||||
void *asan_malloc(uptr size, BufferedStackTrace *stack);
|
||||
void *asan_calloc(uptr nmemb, uptr size, BufferedStackTrace *stack);
|
||||
void *asan_realloc(void *p, uptr size, BufferedStackTrace *stack);
|
||||
void *asan_valloc(uptr size, BufferedStackTrace *stack);
|
||||
void *asan_pvalloc(uptr size, BufferedStackTrace *stack);
|
||||
|
||||
int asan_posix_memalign(void **memptr, uptr alignment, uptr size,
|
||||
StackTrace *stack);
|
||||
BufferedStackTrace *stack);
|
||||
uptr asan_malloc_usable_size(void *ptr, uptr pc, uptr bp);
|
||||
|
||||
uptr asan_mz_size(const void *ptr);
|
||||
|
@ -19,8 +19,9 @@
|
||||
#include "asan_mapping.h"
|
||||
#include "asan_poisoning.h"
|
||||
#include "asan_report.h"
|
||||
#include "asan_stack.h"
|
||||
#include "asan_thread.h"
|
||||
#include "sanitizer_common/sanitizer_allocator.h"
|
||||
#include "sanitizer_common/sanitizer_allocator_interface.h"
|
||||
#include "sanitizer_common/sanitizer_flags.h"
|
||||
#include "sanitizer_common/sanitizer_internal_defs.h"
|
||||
#include "sanitizer_common/sanitizer_list.h"
|
||||
@ -30,65 +31,30 @@
|
||||
|
||||
namespace __asan {
|
||||
|
||||
struct AsanMapUnmapCallback {
|
||||
void OnMap(uptr p, uptr size) const {
|
||||
void AsanMapUnmapCallback::OnMap(uptr p, uptr size) const {
|
||||
PoisonShadow(p, size, kAsanHeapLeftRedzoneMagic);
|
||||
// Statistics.
|
||||
AsanStats &thread_stats = GetCurrentThreadStats();
|
||||
thread_stats.mmaps++;
|
||||
thread_stats.mmaped += size;
|
||||
}
|
||||
void OnUnmap(uptr p, uptr size) const {
|
||||
}
|
||||
void AsanMapUnmapCallback::OnUnmap(uptr p, uptr size) const {
|
||||
PoisonShadow(p, size, 0);
|
||||
// We are about to unmap a chunk of user memory.
|
||||
// Mark the corresponding shadow memory as not needed.
|
||||
// Since asan's mapping is compacting, the shadow chunk may be
|
||||
// not page-aligned, so we only flush the page-aligned portion.
|
||||
uptr page_size = GetPageSizeCached();
|
||||
uptr shadow_beg = RoundUpTo(MemToShadow(p), page_size);
|
||||
uptr shadow_end = RoundDownTo(MemToShadow(p + size), page_size);
|
||||
FlushUnneededShadowMemory(shadow_beg, shadow_end - shadow_beg);
|
||||
FlushUnneededASanShadowMemory(p, size);
|
||||
// Statistics.
|
||||
AsanStats &thread_stats = GetCurrentThreadStats();
|
||||
thread_stats.munmaps++;
|
||||
thread_stats.munmaped += size;
|
||||
}
|
||||
};
|
||||
|
||||
#if SANITIZER_WORDSIZE == 64
|
||||
#if defined(__powerpc64__)
|
||||
const uptr kAllocatorSpace = 0xa0000000000ULL;
|
||||
const uptr kAllocatorSize = 0x20000000000ULL; // 2T.
|
||||
#else
|
||||
const uptr kAllocatorSpace = 0x600000000000ULL;
|
||||
const uptr kAllocatorSize = 0x40000000000ULL; // 4T.
|
||||
#endif
|
||||
typedef DefaultSizeClassMap SizeClassMap;
|
||||
typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, 0 /*metadata*/,
|
||||
SizeClassMap, AsanMapUnmapCallback> PrimaryAllocator;
|
||||
#elif SANITIZER_WORDSIZE == 32
|
||||
static const u64 kAddressSpaceSize = 1ULL << 32;
|
||||
typedef CompactSizeClassMap SizeClassMap;
|
||||
static const uptr kRegionSizeLog = 20;
|
||||
static const uptr kFlatByteMapSize = kAddressSpaceSize >> kRegionSizeLog;
|
||||
typedef SizeClassAllocator32<0, kAddressSpaceSize, 16,
|
||||
SizeClassMap, kRegionSizeLog,
|
||||
FlatByteMap<kFlatByteMapSize>,
|
||||
AsanMapUnmapCallback> PrimaryAllocator;
|
||||
#endif
|
||||
|
||||
typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
|
||||
typedef LargeMmapAllocator<AsanMapUnmapCallback> SecondaryAllocator;
|
||||
typedef CombinedAllocator<PrimaryAllocator, AllocatorCache,
|
||||
SecondaryAllocator> Allocator;
|
||||
}
|
||||
|
||||
// We can not use THREADLOCAL because it is not supported on some of the
|
||||
// platforms we care about (OSX 10.6, Android).
|
||||
// static THREADLOCAL AllocatorCache cache;
|
||||
AllocatorCache *GetAllocatorCache(AsanThreadLocalMallocStorage *ms) {
|
||||
CHECK(ms);
|
||||
CHECK_LE(sizeof(AllocatorCache), sizeof(ms->allocator2_cache));
|
||||
return reinterpret_cast<AllocatorCache *>(ms->allocator2_cache);
|
||||
return &ms->allocator2_cache;
|
||||
}
|
||||
|
||||
static Allocator allocator;
|
||||
@ -134,7 +100,8 @@ static uptr ComputeRZLog(uptr user_requested_size) {
|
||||
user_requested_size <= (1 << 14) - 256 ? 4 :
|
||||
user_requested_size <= (1 << 15) - 512 ? 5 :
|
||||
user_requested_size <= (1 << 16) - 1024 ? 6 : 7;
|
||||
return Max(rz_log, RZSize2Log(flags()->redzone));
|
||||
return Min(Max(rz_log, RZSize2Log(flags()->redzone)),
|
||||
RZSize2Log(flags()->max_redzone));
|
||||
}
|
||||
|
||||
// The memory chunk allocated from the underlying allocator looks like this:
|
||||
@ -201,23 +168,6 @@ struct AsanChunk: ChunkBase {
|
||||
}
|
||||
return reinterpret_cast<void*>(Beg() - RZLog2Size(rz_log));
|
||||
}
|
||||
// If we don't use stack depot, we store the alloc/free stack traces
|
||||
// in the chunk itself.
|
||||
u32 *AllocStackBeg() {
|
||||
return (u32*)(Beg() - RZLog2Size(rz_log));
|
||||
}
|
||||
uptr AllocStackSize() {
|
||||
CHECK_LE(RZLog2Size(rz_log), kChunkHeaderSize);
|
||||
return (RZLog2Size(rz_log) - kChunkHeaderSize) / sizeof(u32);
|
||||
}
|
||||
u32 *FreeStackBeg() {
|
||||
return (u32*)(Beg() + kChunkHeader2Size);
|
||||
}
|
||||
uptr FreeStackSize() {
|
||||
if (user_requested_size < kChunkHeader2Size) return 0;
|
||||
uptr available = RoundUpTo(user_requested_size, SHADOW_GRANULARITY);
|
||||
return (available - kChunkHeader2Size) / sizeof(u32);
|
||||
}
|
||||
bool AddrIsInside(uptr addr, bool locked_version = false) {
|
||||
return (addr >= Beg()) && (addr < Beg() + UsedSize(locked_version));
|
||||
}
|
||||
@ -232,20 +182,19 @@ uptr AsanChunkView::UsedSize() { return chunk_->UsedSize(); }
|
||||
uptr AsanChunkView::AllocTid() { return chunk_->alloc_tid; }
|
||||
uptr AsanChunkView::FreeTid() { return chunk_->free_tid; }
|
||||
|
||||
static void GetStackTraceFromId(u32 id, StackTrace *stack) {
|
||||
static StackTrace GetStackTraceFromId(u32 id) {
|
||||
CHECK(id);
|
||||
uptr size = 0;
|
||||
const uptr *trace = StackDepotGet(id, &size);
|
||||
CHECK(trace);
|
||||
stack->CopyFrom(trace, size);
|
||||
StackTrace res = StackDepotGet(id);
|
||||
CHECK(res.trace);
|
||||
return res;
|
||||
}
|
||||
|
||||
void AsanChunkView::GetAllocStack(StackTrace *stack) {
|
||||
GetStackTraceFromId(chunk_->alloc_context_id, stack);
|
||||
StackTrace AsanChunkView::GetAllocStack() {
|
||||
return GetStackTraceFromId(chunk_->alloc_context_id);
|
||||
}
|
||||
|
||||
void AsanChunkView::GetFreeStack(StackTrace *stack) {
|
||||
GetStackTraceFromId(chunk_->free_context_id, stack);
|
||||
StackTrace AsanChunkView::GetFreeStack() {
|
||||
return GetStackTraceFromId(chunk_->free_context_id);
|
||||
}
|
||||
|
||||
struct QuarantineCallback;
|
||||
@ -309,10 +258,14 @@ void InitializeAllocator() {
|
||||
quarantine.Init((uptr)flags()->quarantine_size, kMaxThreadLocalQuarantine);
|
||||
}
|
||||
|
||||
static void *Allocate(uptr size, uptr alignment, StackTrace *stack,
|
||||
void ReInitializeAllocator() {
|
||||
quarantine.Init((uptr)flags()->quarantine_size, kMaxThreadLocalQuarantine);
|
||||
}
|
||||
|
||||
static void *Allocate(uptr size, uptr alignment, BufferedStackTrace *stack,
|
||||
AllocType alloc_type, bool can_fill) {
|
||||
if (!asan_inited)
|
||||
__asan_init();
|
||||
if (UNLIKELY(!asan_inited))
|
||||
AsanInitFromRtl();
|
||||
Flags &fl = *flags();
|
||||
CHECK(stack);
|
||||
const uptr min_alignment = SHADOW_GRANULARITY;
|
||||
@ -357,6 +310,16 @@ static void *Allocate(uptr size, uptr alignment, StackTrace *stack,
|
||||
AllocatorCache *cache = &fallback_allocator_cache;
|
||||
allocated = allocator.Allocate(cache, needed_size, 8, false);
|
||||
}
|
||||
|
||||
if (*(u8 *)MEM_TO_SHADOW((uptr)allocated) == 0 && flags()->poison_heap) {
|
||||
// Heap poisoning is enabled, but the allocator provides an unpoisoned
|
||||
// chunk. This is possible if flags()->poison_heap was disabled for some
|
||||
// time, for example, due to flags()->start_disabled.
|
||||
// Anyway, poison the block before using it for anything else.
|
||||
uptr allocated_size = allocator.GetActuallyAllocatedSize(allocated);
|
||||
PoisonShadow((uptr)allocated, allocated_size, kAsanHeapLeftRedzoneMagic);
|
||||
}
|
||||
|
||||
uptr alloc_beg = reinterpret_cast<uptr>(allocated);
|
||||
uptr alloc_end = alloc_beg + needed_size;
|
||||
uptr beg_plus_redzone = alloc_beg + rz_size;
|
||||
@ -391,7 +354,7 @@ static void *Allocate(uptr size, uptr alignment, StackTrace *stack,
|
||||
meta[1] = chunk_beg;
|
||||
}
|
||||
|
||||
m->alloc_context_id = StackDepotPut(stack->trace, stack->size);
|
||||
m->alloc_context_id = StackDepotPut(*stack);
|
||||
|
||||
uptr size_rounded_down_to_granularity = RoundDownTo(size, SHADOW_GRANULARITY);
|
||||
// Unpoison the bulk of the memory region.
|
||||
@ -427,15 +390,16 @@ static void *Allocate(uptr size, uptr alignment, StackTrace *stack,
|
||||
return res;
|
||||
}
|
||||
|
||||
static void ReportInvalidFree(void *ptr, u8 chunk_state, StackTrace *stack) {
|
||||
static void ReportInvalidFree(void *ptr, u8 chunk_state,
|
||||
BufferedStackTrace *stack) {
|
||||
if (chunk_state == CHUNK_QUARANTINE)
|
||||
ReportDoubleFree((uptr)ptr, stack);
|
||||
else
|
||||
ReportFreeNotMalloced((uptr)ptr, stack);
|
||||
}
|
||||
|
||||
static void AtomicallySetQuarantineFlag(AsanChunk *m,
|
||||
void *ptr, StackTrace *stack) {
|
||||
static void AtomicallySetQuarantineFlag(AsanChunk *m, void *ptr,
|
||||
BufferedStackTrace *stack) {
|
||||
u8 old_chunk_state = CHUNK_ALLOCATED;
|
||||
// Flip the chunk_state atomically to avoid race on double-free.
|
||||
if (!atomic_compare_exchange_strong((atomic_uint8_t*)m, &old_chunk_state,
|
||||
@ -446,8 +410,8 @@ static void AtomicallySetQuarantineFlag(AsanChunk *m,
|
||||
|
||||
// Expects the chunk to already be marked as quarantined by using
|
||||
// AtomicallySetQuarantineFlag.
|
||||
static void QuarantineChunk(AsanChunk *m, void *ptr,
|
||||
StackTrace *stack, AllocType alloc_type) {
|
||||
static void QuarantineChunk(AsanChunk *m, void *ptr, BufferedStackTrace *stack,
|
||||
AllocType alloc_type) {
|
||||
CHECK_EQ(m->chunk_state, CHUNK_QUARANTINE);
|
||||
|
||||
if (m->alloc_type != alloc_type && flags()->alloc_dealloc_mismatch)
|
||||
@ -459,7 +423,7 @@ static void QuarantineChunk(AsanChunk *m, void *ptr,
|
||||
CHECK_EQ(m->free_tid, kInvalidTid);
|
||||
AsanThread *t = GetCurrentThread();
|
||||
m->free_tid = t ? t->tid() : 0;
|
||||
m->free_context_id = StackDepotPut(stack->trace, stack->size);
|
||||
m->free_context_id = StackDepotPut(*stack);
|
||||
// Poison the region.
|
||||
PoisonShadow(m->Beg(),
|
||||
RoundUpTo(m->UsedSize(), SHADOW_GRANULARITY),
|
||||
@ -483,19 +447,25 @@ static void QuarantineChunk(AsanChunk *m, void *ptr,
|
||||
}
|
||||
}
|
||||
|
||||
static void Deallocate(void *ptr, StackTrace *stack, AllocType alloc_type) {
|
||||
static void Deallocate(void *ptr, uptr delete_size, BufferedStackTrace *stack,
|
||||
AllocType alloc_type) {
|
||||
uptr p = reinterpret_cast<uptr>(ptr);
|
||||
if (p == 0) return;
|
||||
|
||||
uptr chunk_beg = p - kChunkHeaderSize;
|
||||
AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg);
|
||||
if (delete_size && flags()->new_delete_type_mismatch &&
|
||||
delete_size != m->UsedSize()) {
|
||||
ReportNewDeleteSizeMismatch(p, delete_size, stack);
|
||||
}
|
||||
ASAN_FREE_HOOK(ptr);
|
||||
// Must mark the chunk as quarantined before any changes to its metadata.
|
||||
AtomicallySetQuarantineFlag(m, ptr, stack);
|
||||
QuarantineChunk(m, ptr, stack, alloc_type);
|
||||
}
|
||||
|
||||
static void *Reallocate(void *old_ptr, uptr new_size, StackTrace *stack) {
|
||||
static void *Reallocate(void *old_ptr, uptr new_size,
|
||||
BufferedStackTrace *stack) {
|
||||
CHECK(old_ptr && new_size);
|
||||
uptr p = reinterpret_cast<uptr>(old_ptr);
|
||||
uptr chunk_beg = p - kChunkHeaderSize;
|
||||
@ -515,7 +485,7 @@ static void *Reallocate(void *old_ptr, uptr new_size, StackTrace *stack) {
|
||||
// If realloc() races with free(), we may start copying freed memory.
|
||||
// However, we will report racy double-free later anyway.
|
||||
REAL(memcpy)(new_ptr, old_ptr, memcpy_size);
|
||||
Deallocate(old_ptr, stack, FROM_MALLOC);
|
||||
Deallocate(old_ptr, 0, stack, FROM_MALLOC);
|
||||
}
|
||||
return new_ptr;
|
||||
}
|
||||
@ -608,20 +578,25 @@ void PrintInternalAllocatorStats() {
|
||||
allocator.PrintStats();
|
||||
}
|
||||
|
||||
void *asan_memalign(uptr alignment, uptr size, StackTrace *stack,
|
||||
void *asan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack,
|
||||
AllocType alloc_type) {
|
||||
return Allocate(size, alignment, stack, alloc_type, true);
|
||||
}
|
||||
|
||||
void asan_free(void *ptr, StackTrace *stack, AllocType alloc_type) {
|
||||
Deallocate(ptr, stack, alloc_type);
|
||||
void asan_free(void *ptr, BufferedStackTrace *stack, AllocType alloc_type) {
|
||||
Deallocate(ptr, 0, stack, alloc_type);
|
||||
}
|
||||
|
||||
void *asan_malloc(uptr size, StackTrace *stack) {
|
||||
void asan_sized_free(void *ptr, uptr size, BufferedStackTrace *stack,
|
||||
AllocType alloc_type) {
|
||||
Deallocate(ptr, size, stack, alloc_type);
|
||||
}
|
||||
|
||||
void *asan_malloc(uptr size, BufferedStackTrace *stack) {
|
||||
return Allocate(size, 8, stack, FROM_MALLOC, true);
|
||||
}
|
||||
|
||||
void *asan_calloc(uptr nmemb, uptr size, StackTrace *stack) {
|
||||
void *asan_calloc(uptr nmemb, uptr size, BufferedStackTrace *stack) {
|
||||
if (CallocShouldReturnNullDueToOverflow(size, nmemb))
|
||||
return AllocatorReturnNull();
|
||||
void *ptr = Allocate(nmemb * size, 8, stack, FROM_MALLOC, false);
|
||||
@ -632,21 +607,21 @@ void *asan_calloc(uptr nmemb, uptr size, StackTrace *stack) {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *asan_realloc(void *p, uptr size, StackTrace *stack) {
|
||||
void *asan_realloc(void *p, uptr size, BufferedStackTrace *stack) {
|
||||
if (p == 0)
|
||||
return Allocate(size, 8, stack, FROM_MALLOC, true);
|
||||
if (size == 0) {
|
||||
Deallocate(p, stack, FROM_MALLOC);
|
||||
Deallocate(p, 0, stack, FROM_MALLOC);
|
||||
return 0;
|
||||
}
|
||||
return Reallocate(p, size, stack);
|
||||
}
|
||||
|
||||
void *asan_valloc(uptr size, StackTrace *stack) {
|
||||
void *asan_valloc(uptr size, BufferedStackTrace *stack) {
|
||||
return Allocate(size, GetPageSizeCached(), stack, FROM_MALLOC, true);
|
||||
}
|
||||
|
||||
void *asan_pvalloc(uptr size, StackTrace *stack) {
|
||||
void *asan_pvalloc(uptr size, BufferedStackTrace *stack) {
|
||||
uptr PageSize = GetPageSizeCached();
|
||||
size = RoundUpTo(size, PageSize);
|
||||
if (size == 0) {
|
||||
@ -657,7 +632,7 @@ void *asan_pvalloc(uptr size, StackTrace *stack) {
|
||||
}
|
||||
|
||||
int asan_posix_memalign(void **memptr, uptr alignment, uptr size,
|
||||
StackTrace *stack) {
|
||||
BufferedStackTrace *stack) {
|
||||
void *ptr = Allocate(size, alignment, stack, FROM_MALLOC, true);
|
||||
CHECK(IsAligned((uptr)ptr, alignment));
|
||||
*memptr = ptr;
|
||||
@ -710,8 +685,12 @@ uptr PointsIntoChunk(void* p) {
|
||||
__asan::AsanChunk *m = __asan::GetAsanChunkByAddrFastLocked(addr);
|
||||
if (!m) return 0;
|
||||
uptr chunk = m->Beg();
|
||||
if ((m->chunk_state == __asan::CHUNK_ALLOCATED) &&
|
||||
m->AddrIsInside(addr, /*locked_version=*/true))
|
||||
if (m->chunk_state != __asan::CHUNK_ALLOCATED)
|
||||
return 0;
|
||||
if (m->AddrIsInside(addr, /*locked_version=*/true))
|
||||
return chunk;
|
||||
if (IsSpecialCaseOfOperatorNew0(chunk, m->UsedSize(/*locked_version*/ true),
|
||||
addr))
|
||||
return chunk;
|
||||
return 0;
|
||||
}
|
||||
@ -776,23 +755,23 @@ using namespace __asan; // NOLINT
|
||||
|
||||
// ASan allocator doesn't reserve extra bytes, so normally we would
|
||||
// just return "size". We don't want to expose our redzone sizes, etc here.
|
||||
uptr __asan_get_estimated_allocated_size(uptr size) {
|
||||
uptr __sanitizer_get_estimated_allocated_size(uptr size) {
|
||||
return size;
|
||||
}
|
||||
|
||||
bool __asan_get_ownership(const void *p) {
|
||||
int __sanitizer_get_ownership(const void *p) {
|
||||
uptr ptr = reinterpret_cast<uptr>(p);
|
||||
return (AllocationSize(ptr) > 0);
|
||||
}
|
||||
|
||||
uptr __asan_get_allocated_size(const void *p) {
|
||||
uptr __sanitizer_get_allocated_size(const void *p) {
|
||||
if (p == 0) return 0;
|
||||
uptr ptr = reinterpret_cast<uptr>(p);
|
||||
uptr allocated_size = AllocationSize(ptr);
|
||||
// Die if p is not malloced or if it is already freed.
|
||||
if (allocated_size == 0) {
|
||||
GET_STACK_TRACE_FATAL_HERE;
|
||||
ReportAsanGetAllocatedSizeNotOwned(ptr, &stack);
|
||||
ReportSanitizerGetAllocatedSizeNotOwned(ptr, &stack);
|
||||
}
|
||||
return allocated_size;
|
||||
}
|
||||
@ -801,12 +780,12 @@ uptr __asan_get_allocated_size(const void *p) {
|
||||
// Provide default (no-op) implementation of malloc hooks.
|
||||
extern "C" {
|
||||
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
|
||||
void __asan_malloc_hook(void *ptr, uptr size) {
|
||||
void __sanitizer_malloc_hook(void *ptr, uptr size) {
|
||||
(void)ptr;
|
||||
(void)size;
|
||||
}
|
||||
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
|
||||
void __asan_free_hook(void *ptr) {
|
||||
void __sanitizer_free_hook(void *ptr) {
|
||||
(void)ptr;
|
||||
}
|
||||
} // extern "C"
|
||||
|
@ -8,3 +8,6 @@
|
||||
# global:*global_with_bad_access_or_initialization*
|
||||
# global:*global_with_initialization_issues*=init
|
||||
# type:*Namespace::ClassName*=init
|
||||
|
||||
# Stack buffer overflow in VC/INCLUDE/xlocnum, see http://goo.gl/L4qqUG
|
||||
fun:*_Find_elem@*@std*
|
||||
|
141
lib/asan/asan_debugging.cc
Normal file
141
lib/asan/asan_debugging.cc
Normal file
@ -0,0 +1,141 @@
|
||||
//===-- asan_debugging.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 AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// This file contains various functions that are generally useful to call when
|
||||
// using a debugger (LLDB, GDB).
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "asan_allocator.h"
|
||||
#include "asan_flags.h"
|
||||
#include "asan_internal.h"
|
||||
#include "asan_mapping.h"
|
||||
#include "asan_report.h"
|
||||
#include "asan_thread.h"
|
||||
|
||||
namespace __asan {
|
||||
|
||||
void GetInfoForStackVar(uptr addr, AddressDescription *descr, AsanThread *t) {
|
||||
descr->name[0] = 0;
|
||||
descr->region_address = 0;
|
||||
descr->region_size = 0;
|
||||
descr->region_kind = "stack";
|
||||
|
||||
AsanThread::StackFrameAccess access;
|
||||
if (!t->GetStackFrameAccessByAddr(addr, &access))
|
||||
return;
|
||||
InternalMmapVector<StackVarDescr> vars(16);
|
||||
if (!ParseFrameDescription(access.frame_descr, &vars)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uptr i = 0; i < vars.size(); i++) {
|
||||
if (access.offset <= vars[i].beg + vars[i].size) {
|
||||
internal_strncat(descr->name, vars[i].name_pos,
|
||||
Min(descr->name_size, vars[i].name_len));
|
||||
descr->region_address = addr - (access.offset - vars[i].beg);
|
||||
descr->region_size = vars[i].size;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GetInfoForHeapAddress(uptr addr, AddressDescription *descr) {
|
||||
AsanChunkView chunk = FindHeapChunkByAddress(addr);
|
||||
|
||||
descr->name[0] = 0;
|
||||
descr->region_address = 0;
|
||||
descr->region_size = 0;
|
||||
|
||||
if (!chunk.IsValid()) {
|
||||
descr->region_kind = "heap-invalid";
|
||||
return;
|
||||
}
|
||||
|
||||
descr->region_address = chunk.Beg();
|
||||
descr->region_size = chunk.UsedSize();
|
||||
descr->region_kind = "heap";
|
||||
}
|
||||
|
||||
void AsanLocateAddress(uptr addr, AddressDescription *descr) {
|
||||
if (DescribeAddressIfShadow(addr, descr, /* print */ false)) {
|
||||
return;
|
||||
}
|
||||
if (GetInfoForAddressIfGlobal(addr, descr)) {
|
||||
return;
|
||||
}
|
||||
asanThreadRegistry().Lock();
|
||||
AsanThread *thread = FindThreadByStackAddress(addr);
|
||||
asanThreadRegistry().Unlock();
|
||||
if (thread) {
|
||||
GetInfoForStackVar(addr, descr, thread);
|
||||
return;
|
||||
}
|
||||
GetInfoForHeapAddress(addr, descr);
|
||||
}
|
||||
|
||||
uptr AsanGetStack(uptr addr, uptr *trace, uptr size, u32 *thread_id,
|
||||
bool alloc_stack) {
|
||||
AsanChunkView chunk = FindHeapChunkByAddress(addr);
|
||||
if (!chunk.IsValid()) return 0;
|
||||
|
||||
StackTrace stack(nullptr, 0);
|
||||
if (alloc_stack) {
|
||||
if (chunk.AllocTid() == kInvalidTid) return 0;
|
||||
stack = chunk.GetAllocStack();
|
||||
if (thread_id) *thread_id = chunk.AllocTid();
|
||||
} else {
|
||||
if (chunk.FreeTid() == kInvalidTid) return 0;
|
||||
stack = chunk.GetFreeStack();
|
||||
if (thread_id) *thread_id = chunk.FreeTid();
|
||||
}
|
||||
|
||||
if (trace && size) {
|
||||
size = Min(size, Min(stack.size, kStackTraceMax));
|
||||
for (uptr i = 0; i < size; i++)
|
||||
trace[i] = StackTrace::GetPreviousInstructionPc(stack.trace[i]);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
using namespace __asan;
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
const char *__asan_locate_address(uptr addr, char *name, uptr name_size,
|
||||
uptr *region_address, uptr *region_size) {
|
||||
AddressDescription descr = { name, name_size, 0, 0, 0 };
|
||||
AsanLocateAddress(addr, &descr);
|
||||
if (region_address) *region_address = descr.region_address;
|
||||
if (region_size) *region_size = descr.region_size;
|
||||
return descr.region_kind;
|
||||
}
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
uptr __asan_get_alloc_stack(uptr addr, uptr *trace, uptr size, u32 *thread_id) {
|
||||
return AsanGetStack(addr, trace, size, thread_id, /* alloc_stack */ true);
|
||||
}
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
uptr __asan_get_free_stack(uptr addr, uptr *trace, uptr size, u32 *thread_id) {
|
||||
return AsanGetStack(addr, trace, size, thread_id, /* alloc_stack */ false);
|
||||
}
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void __asan_get_shadow_mapping(uptr *shadow_scale, uptr *shadow_offset) {
|
||||
if (shadow_scale)
|
||||
*shadow_scale = SHADOW_SCALE;
|
||||
if (shadow_offset)
|
||||
*shadow_offset = SHADOW_OFFSET;
|
||||
}
|
@ -1,196 +0,0 @@
|
||||
//===-- asan_dll_thunk.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 AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// This file defines a family of thunks that should be statically linked into
|
||||
// the DLLs that have ASan instrumentation in order to delegate the calls to the
|
||||
// shared runtime that lives in the main binary.
|
||||
// See https://code.google.com/p/address-sanitizer/issues/detail?id=209 for the
|
||||
// details.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Only compile this code when buidling asan_dll_thunk.lib
|
||||
// Using #ifdef rather than relying on Makefiles etc.
|
||||
// simplifies the build procedure.
|
||||
#ifdef ASAN_DLL_THUNK
|
||||
|
||||
// ----------------- Helper functions and macros --------------------- {{{1
|
||||
extern "C" {
|
||||
void *__stdcall GetModuleHandleA(const char *module_name);
|
||||
void *__stdcall GetProcAddress(void *module, const char *proc_name);
|
||||
void abort();
|
||||
}
|
||||
|
||||
static void *getRealProcAddressOrDie(const char *name) {
|
||||
void *ret = GetProcAddress(GetModuleHandleA(0), name);
|
||||
if (!ret)
|
||||
abort();
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define WRAP_V_V(name) \
|
||||
extern "C" void name() { \
|
||||
typedef void (*fntype)(); \
|
||||
static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
|
||||
fn(); \
|
||||
}
|
||||
|
||||
#define WRAP_V_W(name) \
|
||||
extern "C" void name(void *arg) { \
|
||||
typedef void (*fntype)(void *arg); \
|
||||
static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
|
||||
fn(arg); \
|
||||
}
|
||||
|
||||
#define WRAP_V_WW(name) \
|
||||
extern "C" void name(void *arg1, void *arg2) { \
|
||||
typedef void (*fntype)(void *, void *); \
|
||||
static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
|
||||
fn(arg1, arg2); \
|
||||
}
|
||||
|
||||
#define WRAP_V_WWW(name) \
|
||||
extern "C" void name(void *arg1, void *arg2, void *arg3) { \
|
||||
typedef void *(*fntype)(void *, void *, void *); \
|
||||
static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
|
||||
fn(arg1, arg2, arg3); \
|
||||
}
|
||||
|
||||
#define WRAP_W_V(name) \
|
||||
extern "C" void *name() { \
|
||||
typedef void *(*fntype)(); \
|
||||
static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
|
||||
return fn(); \
|
||||
}
|
||||
|
||||
#define WRAP_W_W(name) \
|
||||
extern "C" void *name(void *arg) { \
|
||||
typedef void *(*fntype)(void *arg); \
|
||||
static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
|
||||
return fn(arg); \
|
||||
}
|
||||
|
||||
#define WRAP_W_WW(name) \
|
||||
extern "C" void *name(void *arg1, void *arg2) { \
|
||||
typedef void *(*fntype)(void *, void *); \
|
||||
static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
|
||||
return fn(arg1, arg2); \
|
||||
}
|
||||
|
||||
#define WRAP_W_WWW(name) \
|
||||
extern "C" void *name(void *arg1, void *arg2, void *arg3) { \
|
||||
typedef void *(*fntype)(void *, void *, void *); \
|
||||
static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
|
||||
return fn(arg1, arg2, arg3); \
|
||||
}
|
||||
|
||||
#define WRAP_W_WWWW(name) \
|
||||
extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4) { \
|
||||
typedef void *(*fntype)(void *, void *, void *, void *); \
|
||||
static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
|
||||
return fn(arg1, arg2, arg3, arg4); \
|
||||
}
|
||||
|
||||
#define WRAP_W_WWWWW(name) \
|
||||
extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4, \
|
||||
void *arg5) { \
|
||||
typedef void *(*fntype)(void *, void *, void *, void *, void *); \
|
||||
static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
|
||||
return fn(arg1, arg2, arg3, arg4, arg5); \
|
||||
}
|
||||
|
||||
#define WRAP_W_WWWWWW(name) \
|
||||
extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4, \
|
||||
void *arg5, void *arg6) { \
|
||||
typedef void *(*fntype)(void *, void *, void *, void *, void *, void *); \
|
||||
static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
|
||||
return fn(arg1, arg2, arg3, arg4, arg5, arg6); \
|
||||
}
|
||||
// }}}
|
||||
|
||||
// ----------------- ASan own interface functions --------------------
|
||||
WRAP_W_V(__asan_should_detect_stack_use_after_return)
|
||||
|
||||
extern "C" {
|
||||
int __asan_option_detect_stack_use_after_return;
|
||||
|
||||
// Manually wrap __asan_init as we need to initialize
|
||||
// __asan_option_detect_stack_use_after_return afterwards.
|
||||
void __asan_init_v3() {
|
||||
typedef void (*fntype)();
|
||||
static fntype fn = (fntype)getRealProcAddressOrDie("__asan_init_v3");
|
||||
fn();
|
||||
__asan_option_detect_stack_use_after_return =
|
||||
(__asan_should_detect_stack_use_after_return() != 0);
|
||||
}
|
||||
}
|
||||
|
||||
WRAP_V_W(__asan_report_store1)
|
||||
WRAP_V_W(__asan_report_store2)
|
||||
WRAP_V_W(__asan_report_store4)
|
||||
WRAP_V_W(__asan_report_store8)
|
||||
WRAP_V_W(__asan_report_store16)
|
||||
WRAP_V_WW(__asan_report_store_n)
|
||||
|
||||
WRAP_V_W(__asan_report_load1)
|
||||
WRAP_V_W(__asan_report_load2)
|
||||
WRAP_V_W(__asan_report_load4)
|
||||
WRAP_V_W(__asan_report_load8)
|
||||
WRAP_V_W(__asan_report_load16)
|
||||
WRAP_V_WW(__asan_report_load_n)
|
||||
|
||||
WRAP_V_WW(__asan_register_globals)
|
||||
WRAP_V_WW(__asan_unregister_globals)
|
||||
|
||||
WRAP_W_WW(__asan_stack_malloc_0)
|
||||
WRAP_W_WW(__asan_stack_malloc_1)
|
||||
WRAP_W_WW(__asan_stack_malloc_2)
|
||||
WRAP_W_WW(__asan_stack_malloc_3)
|
||||
WRAP_W_WW(__asan_stack_malloc_4)
|
||||
WRAP_W_WW(__asan_stack_malloc_5)
|
||||
WRAP_W_WW(__asan_stack_malloc_6)
|
||||
WRAP_W_WW(__asan_stack_malloc_7)
|
||||
WRAP_W_WW(__asan_stack_malloc_8)
|
||||
WRAP_W_WW(__asan_stack_malloc_9)
|
||||
WRAP_W_WW(__asan_stack_malloc_10)
|
||||
|
||||
WRAP_V_WWW(__asan_stack_free_0)
|
||||
WRAP_V_WWW(__asan_stack_free_1)
|
||||
WRAP_V_WWW(__asan_stack_free_2)
|
||||
WRAP_V_WWW(__asan_stack_free_4)
|
||||
WRAP_V_WWW(__asan_stack_free_5)
|
||||
WRAP_V_WWW(__asan_stack_free_6)
|
||||
WRAP_V_WWW(__asan_stack_free_7)
|
||||
WRAP_V_WWW(__asan_stack_free_8)
|
||||
WRAP_V_WWW(__asan_stack_free_9)
|
||||
WRAP_V_WWW(__asan_stack_free_10)
|
||||
|
||||
// TODO(timurrrr): Add more interface functions on the as-needed basis.
|
||||
|
||||
// ----------------- Memory allocation functions ---------------------
|
||||
WRAP_V_W(free)
|
||||
WRAP_V_WW(_free_dbg)
|
||||
|
||||
WRAP_W_W(malloc)
|
||||
WRAP_W_WWWW(_malloc_dbg)
|
||||
|
||||
WRAP_W_WW(calloc)
|
||||
WRAP_W_WWWWW(_calloc_dbg)
|
||||
WRAP_W_WWW(_calloc_impl)
|
||||
|
||||
WRAP_W_WW(realloc)
|
||||
WRAP_W_WWW(_realloc_dbg)
|
||||
WRAP_W_WWW(_recalloc)
|
||||
|
||||
WRAP_W_W(_msize)
|
||||
|
||||
// TODO(timurrrr): Do we need to add _Crt* stuff here? (see asan_malloc_win.cc).
|
||||
|
||||
#endif // ASAN_DLL_THUNK
|
@ -27,8 +27,10 @@ ALWAYS_INLINE void SetShadow(uptr ptr, uptr size, uptr class_id, u64 magic) {
|
||||
CHECK_EQ(SHADOW_SCALE, 3); // This code expects SHADOW_SCALE=3.
|
||||
u64 *shadow = reinterpret_cast<u64*>(MemToShadow(ptr));
|
||||
if (class_id <= 6) {
|
||||
for (uptr i = 0; i < (1U << class_id); i++)
|
||||
for (uptr i = 0; i < (1U << class_id); i++) {
|
||||
shadow[i] = magic;
|
||||
SanitizerBreakOptimization(0); // Make sure this does not become memset.
|
||||
}
|
||||
} else {
|
||||
// The size class is too big, it's cheaper to poison only size bytes.
|
||||
PoisonShadow(ptr, size, static_cast<u8>(magic));
|
||||
@ -42,21 +44,32 @@ FakeStack *FakeStack::Create(uptr stack_size_log) {
|
||||
stack_size_log = kMinStackSizeLog;
|
||||
if (stack_size_log > kMaxStackSizeLog)
|
||||
stack_size_log = kMaxStackSizeLog;
|
||||
uptr size = RequiredSize(stack_size_log);
|
||||
FakeStack *res = reinterpret_cast<FakeStack *>(
|
||||
MmapOrDie(RequiredSize(stack_size_log), "FakeStack"));
|
||||
flags()->uar_noreserve ? MmapNoReserveOrDie(size, "FakeStack")
|
||||
: MmapOrDie(size, "FakeStack"));
|
||||
res->stack_size_log_ = stack_size_log;
|
||||
if (common_flags()->verbosity) {
|
||||
u8 *p = reinterpret_cast<u8 *>(res);
|
||||
Report("T%d: FakeStack created: %p -- %p stack_size_log: %zd \n",
|
||||
VReport(1, "T%d: FakeStack created: %p -- %p stack_size_log: %zd; "
|
||||
"mmapped %zdK, noreserve=%d \n",
|
||||
GetCurrentTidOrInvalid(), p,
|
||||
p + FakeStack::RequiredSize(stack_size_log), stack_size_log);
|
||||
}
|
||||
p + FakeStack::RequiredSize(stack_size_log), stack_size_log,
|
||||
size >> 10, flags()->uar_noreserve);
|
||||
return res;
|
||||
}
|
||||
|
||||
void FakeStack::Destroy() {
|
||||
void FakeStack::Destroy(int tid) {
|
||||
PoisonAll(0);
|
||||
UnmapOrDie(this, RequiredSize(stack_size_log_));
|
||||
if (common_flags()->verbosity >= 2) {
|
||||
InternalScopedString str(kNumberOfSizeClasses * 50);
|
||||
for (uptr class_id = 0; class_id < kNumberOfSizeClasses; class_id++)
|
||||
str.append("%zd: %zd/%zd; ", class_id, hint_position_[class_id],
|
||||
NumberOfFrames(stack_size_log(), class_id));
|
||||
Report("T%d: FakeStack destroyed: %s\n", tid, str.data());
|
||||
}
|
||||
uptr size = RequiredSize(stack_size_log_);
|
||||
FlushUnneededASanShadowMemory(reinterpret_cast<uptr>(this), size);
|
||||
UnmapOrDie(this, size);
|
||||
}
|
||||
|
||||
void FakeStack::PoisonAll(u8 magic) {
|
||||
@ -93,7 +106,7 @@ FakeFrame *FakeStack::Allocate(uptr stack_size_log, uptr class_id,
|
||||
return 0; // We are out of fake stack.
|
||||
}
|
||||
|
||||
uptr FakeStack::AddrIsInFakeStack(uptr ptr) {
|
||||
uptr FakeStack::AddrIsInFakeStack(uptr ptr, uptr *frame_beg, uptr *frame_end) {
|
||||
uptr stack_size_log = this->stack_size_log();
|
||||
uptr beg = reinterpret_cast<uptr>(GetFrame(stack_size_log, 0, 0));
|
||||
uptr end = reinterpret_cast<uptr>(this) + RequiredSize(stack_size_log);
|
||||
@ -103,7 +116,10 @@ uptr FakeStack::AddrIsInFakeStack(uptr ptr) {
|
||||
CHECK_LE(base, ptr);
|
||||
CHECK_LT(ptr, base + (1UL << stack_size_log));
|
||||
uptr pos = (ptr - base) >> (kMinStackFrameSizeLog + class_id);
|
||||
return base + pos * BytesInSizeClass(class_id);
|
||||
uptr res = base + pos * BytesInSizeClass(class_id);
|
||||
*frame_end = res + BytesInSizeClass(class_id);
|
||||
*frame_beg = res + sizeof(FakeFrame);
|
||||
return res;
|
||||
}
|
||||
|
||||
void FakeStack::HandleNoReturn() {
|
||||
@ -197,14 +213,15 @@ ALWAYS_INLINE void OnFree(uptr ptr, uptr class_id, uptr size, uptr real_stack) {
|
||||
} // namespace __asan
|
||||
|
||||
// ---------------------- Interface ---------------- {{{1
|
||||
using namespace __asan;
|
||||
#define DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(class_id) \
|
||||
extern "C" SANITIZER_INTERFACE_ATTRIBUTE uptr \
|
||||
__asan_stack_malloc_##class_id(uptr size, uptr real_stack) { \
|
||||
return __asan::OnMalloc(class_id, size, real_stack); \
|
||||
return OnMalloc(class_id, size, real_stack); \
|
||||
} \
|
||||
extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __asan_stack_free_##class_id( \
|
||||
uptr ptr, uptr size, uptr real_stack) { \
|
||||
__asan::OnFree(ptr, class_id, size, real_stack); \
|
||||
OnFree(ptr, class_id, size, real_stack); \
|
||||
}
|
||||
|
||||
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(0)
|
||||
@ -218,3 +235,23 @@ DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(7)
|
||||
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(8)
|
||||
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(9)
|
||||
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(10)
|
||||
extern "C" {
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void *__asan_get_current_fake_stack() { return GetFakeStackFast(); }
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void *__asan_addr_is_in_fake_stack(void *fake_stack, void *addr, void **beg,
|
||||
void **end) {
|
||||
FakeStack *fs = reinterpret_cast<FakeStack*>(fake_stack);
|
||||
if (!fs) return 0;
|
||||
uptr frame_beg, frame_end;
|
||||
FakeFrame *frame = reinterpret_cast<FakeFrame *>(fs->AddrIsInFakeStack(
|
||||
reinterpret_cast<uptr>(addr), &frame_beg, &frame_end));
|
||||
if (!frame) return 0;
|
||||
if (frame->magic != kCurrentStackFrameMagic)
|
||||
return 0;
|
||||
if (beg) *beg = reinterpret_cast<void*>(frame_beg);
|
||||
if (end) *end = reinterpret_cast<void*>(frame_end);
|
||||
return reinterpret_cast<void*>(frame->real_stack);
|
||||
}
|
||||
} // extern "C"
|
||||
|
@ -65,7 +65,7 @@ class FakeStack {
|
||||
// CTOR: create the FakeStack as a single mmap-ed object.
|
||||
static FakeStack *Create(uptr stack_size_log);
|
||||
|
||||
void Destroy();
|
||||
void Destroy(int tid);
|
||||
|
||||
// stack_size_log is at least 15 (stack_size >= 32K).
|
||||
static uptr SizeRequiredForFlags(uptr stack_size_log) {
|
||||
@ -129,7 +129,11 @@ class FakeStack {
|
||||
void PoisonAll(u8 magic);
|
||||
|
||||
// Return the beginning of the FakeFrame or 0 if the address is not ours.
|
||||
uptr AddrIsInFakeStack(uptr addr);
|
||||
uptr AddrIsInFakeStack(uptr addr, uptr *frame_beg, uptr *frame_end);
|
||||
USED uptr AddrIsInFakeStack(uptr addr) {
|
||||
uptr t1, t2;
|
||||
return AddrIsInFakeStack(addr, &t1, &t2);
|
||||
}
|
||||
|
||||
// Number of bytes in a fake frame of this size class.
|
||||
static uptr BytesInSizeClass(uptr class_id) {
|
||||
|
@ -28,88 +28,44 @@
|
||||
namespace __asan {
|
||||
|
||||
struct Flags {
|
||||
// Size (in bytes) of quarantine used to detect use-after-free errors.
|
||||
// Lower value may reduce memory usage but increase the chance of
|
||||
// false negatives.
|
||||
// Flag descriptions are in asan_rtl.cc.
|
||||
int quarantine_size;
|
||||
// Size (in bytes) of redzones around heap objects.
|
||||
// Requirement: redzone >= 32, is a power of two.
|
||||
int redzone;
|
||||
// If set, prints some debugging information and does additional checks.
|
||||
int max_redzone;
|
||||
bool debug;
|
||||
// Controls the way to handle globals (0 - don't detect buffer overflow
|
||||
// on globals, 1 - detect buffer overflow, 2 - print data about registered
|
||||
// globals).
|
||||
int report_globals;
|
||||
// If set, attempts to catch initialization order issues.
|
||||
bool check_initialization_order;
|
||||
// If set, uses custom wrappers and replacements for libc string functions
|
||||
// to find more errors.
|
||||
bool replace_str;
|
||||
// If set, uses custom wrappers for memset/memcpy/memmove intinsics.
|
||||
bool replace_intrin;
|
||||
// Used on Mac only.
|
||||
bool mac_ignore_invalid_free;
|
||||
// Enables stack-use-after-return checking at run-time.
|
||||
bool detect_stack_use_after_return;
|
||||
// The minimal fake stack size log.
|
||||
int uar_stack_size_log;
|
||||
// ASan allocator flag. max_malloc_fill_size is the maximal amount of bytes
|
||||
// that will be filled with malloc_fill_byte on malloc.
|
||||
int min_uar_stack_size_log;
|
||||
int max_uar_stack_size_log;
|
||||
bool uar_noreserve;
|
||||
int max_malloc_fill_size, malloc_fill_byte;
|
||||
// Override exit status if something was reported.
|
||||
int exitcode;
|
||||
// If set, user may manually mark memory regions as poisoned or unpoisoned.
|
||||
bool allow_user_poisoning;
|
||||
// Number of seconds to sleep between printing an error report and
|
||||
// terminating application. Useful for debug purposes (when one needs
|
||||
// to attach gdb, for example).
|
||||
int sleep_before_dying;
|
||||
// If set, registers ASan custom segv handler.
|
||||
bool handle_segv;
|
||||
// If set, allows user register segv handler even if ASan registers one.
|
||||
bool allow_user_segv_handler;
|
||||
// If set, uses alternate stack for signal handling.
|
||||
bool use_sigaltstack;
|
||||
// Allow the users to work around the bug in Nvidia drivers prior to 295.*.
|
||||
bool check_malloc_usable_size;
|
||||
// If set, explicitly unmaps (huge) shadow at exit.
|
||||
bool unmap_shadow_on_exit;
|
||||
// If set, calls abort() instead of _exit() after printing an error report.
|
||||
bool abort_on_error;
|
||||
// Print various statistics after printing an error message or if atexit=1.
|
||||
bool print_stats;
|
||||
// Print the legend for the shadow bytes.
|
||||
bool print_legend;
|
||||
// If set, prints ASan exit stats even after program terminates successfully.
|
||||
bool atexit;
|
||||
// If set, coverage information will be dumped at shutdown time if the
|
||||
// appropriate instrumentation was enabled.
|
||||
bool coverage;
|
||||
// By default, disable core dumper on 64-bit - it makes little sense
|
||||
// to dump 16T+ core.
|
||||
bool disable_core;
|
||||
// Allow the tool to re-exec the program. This may interfere badly with the
|
||||
// debugger.
|
||||
bool allow_reexec;
|
||||
// If set, prints not only thread creation stacks for threads in error report,
|
||||
// but also thread creation stacks for threads that created those threads,
|
||||
// etc. up to main thread.
|
||||
bool print_full_thread_history;
|
||||
// Poison (or not) the heap memory on [de]allocation. Zero value is useful
|
||||
// for benchmarking the allocator or instrumentator.
|
||||
bool poison_heap;
|
||||
// If true, poison partially addressable 8-byte aligned words (default=true).
|
||||
// This flag affects heap and global buffers, but not stack buffers.
|
||||
bool poison_partial;
|
||||
// Report errors on malloc/delete, new/free, new/delete[], etc.
|
||||
bool poison_array_cookie;
|
||||
bool alloc_dealloc_mismatch;
|
||||
// If true, assume that memcmp(p1, p2, n) always reads n bytes before
|
||||
// comparing p1 and p2.
|
||||
bool new_delete_type_mismatch;
|
||||
bool strict_memcmp;
|
||||
// If true, assume that dynamic initializers can never access globals from
|
||||
// other modules, even if the latter are already initialized.
|
||||
bool strict_init_order;
|
||||
bool start_deactivated;
|
||||
int detect_invalid_pointer_pairs;
|
||||
bool detect_container_overflow;
|
||||
int detect_odr_violation;
|
||||
bool dump_instruction_bytes;
|
||||
};
|
||||
|
||||
extern Flags asan_flags_dont_use_directly;
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "sanitizer_common/sanitizer_common.h"
|
||||
#include "sanitizer_common/sanitizer_mutex.h"
|
||||
#include "sanitizer_common/sanitizer_placement_new.h"
|
||||
#include "sanitizer_common/sanitizer_stackdepot.h"
|
||||
|
||||
namespace __asan {
|
||||
|
||||
@ -45,6 +46,14 @@ typedef InternalMmapVector<DynInitGlobal> VectorOfGlobals;
|
||||
// Lazy-initialized and never deleted.
|
||||
static VectorOfGlobals *dynamic_init_globals;
|
||||
|
||||
// We want to remember where a certain range of globals was registered.
|
||||
struct GlobalRegistrationSite {
|
||||
u32 stack_id;
|
||||
Global *g_first, *g_last;
|
||||
};
|
||||
typedef InternalMmapVector<GlobalRegistrationSite> GlobalRegistrationSiteVector;
|
||||
static GlobalRegistrationSiteVector *global_registration_site_vector;
|
||||
|
||||
ALWAYS_INLINE void PoisonShadowForGlobal(const Global *g, u8 value) {
|
||||
FastPoisonShadow(g->beg, g->size_with_redzone, value);
|
||||
}
|
||||
@ -62,25 +71,74 @@ ALWAYS_INLINE void PoisonRedZones(const Global &g) {
|
||||
}
|
||||
}
|
||||
|
||||
static void ReportGlobal(const Global &g, const char *prefix) {
|
||||
Report("%s Global: beg=%p size=%zu/%zu name=%s module=%s dyn_init=%zu\n",
|
||||
prefix, (void*)g.beg, g.size, g.size_with_redzone, g.name,
|
||||
g.module_name, g.has_dynamic_init);
|
||||
const uptr kMinimalDistanceFromAnotherGlobal = 64;
|
||||
|
||||
bool IsAddressNearGlobal(uptr addr, const __asan_global &g) {
|
||||
if (addr <= g.beg - kMinimalDistanceFromAnotherGlobal) return false;
|
||||
if (addr >= g.beg + g.size_with_redzone) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DescribeAddressIfGlobal(uptr addr, uptr size) {
|
||||
static void ReportGlobal(const Global &g, const char *prefix) {
|
||||
Report("%s Global[%p]: beg=%p size=%zu/%zu name=%s module=%s dyn_init=%zu\n",
|
||||
prefix, &g, (void *)g.beg, g.size, g.size_with_redzone, g.name,
|
||||
g.module_name, g.has_dynamic_init);
|
||||
if (g.location) {
|
||||
Report(" location (%p): name=%s[%p], %d %d\n", g.location,
|
||||
g.location->filename, g.location->filename, g.location->line_no,
|
||||
g.location->column_no);
|
||||
}
|
||||
}
|
||||
|
||||
static bool DescribeOrGetInfoIfGlobal(uptr addr, uptr size, bool print,
|
||||
Global *output_global) {
|
||||
if (!flags()->report_globals) return false;
|
||||
BlockingMutexLock lock(&mu_for_globals);
|
||||
bool res = false;
|
||||
for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
|
||||
const Global &g = *l->g;
|
||||
if (print) {
|
||||
if (flags()->report_globals >= 2)
|
||||
ReportGlobal(g, "Search");
|
||||
res |= DescribeAddressRelativeToGlobal(addr, size, g);
|
||||
} else {
|
||||
if (IsAddressNearGlobal(addr, g)) {
|
||||
CHECK(output_global);
|
||||
*output_global = g;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool DescribeAddressIfGlobal(uptr addr, uptr size) {
|
||||
return DescribeOrGetInfoIfGlobal(addr, size, /* print */ true,
|
||||
/* output_global */ nullptr);
|
||||
}
|
||||
|
||||
bool GetInfoForAddressIfGlobal(uptr addr, AddressDescription *descr) {
|
||||
Global g = {};
|
||||
if (DescribeOrGetInfoIfGlobal(addr, /* size */ 1, /* print */ false, &g)) {
|
||||
internal_strncpy(descr->name, g.name, descr->name_size);
|
||||
descr->region_address = g.beg;
|
||||
descr->region_size = g.size;
|
||||
descr->region_kind = "global";
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
u32 FindRegistrationSite(const Global *g) {
|
||||
CHECK(global_registration_site_vector);
|
||||
for (uptr i = 0, n = global_registration_site_vector->size(); i < n; i++) {
|
||||
GlobalRegistrationSite &grs = (*global_registration_site_vector)[i];
|
||||
if (g >= grs.g_first && g <= grs.g_last)
|
||||
return grs.stack_id;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Register a global variable.
|
||||
// This function may be called more than once for every global
|
||||
// so we store the globals in a map.
|
||||
@ -92,6 +150,20 @@ static void RegisterGlobal(const Global *g) {
|
||||
CHECK(AddrIsInMem(g->beg));
|
||||
CHECK(AddrIsAlignedByGranularity(g->beg));
|
||||
CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
|
||||
if (flags()->detect_odr_violation) {
|
||||
// Try detecting ODR (One Definition Rule) violation, i.e. the situation
|
||||
// where two globals with the same name are defined in different modules.
|
||||
if (__asan_region_is_poisoned(g->beg, g->size_with_redzone)) {
|
||||
// This check may not be enough: if the first global is much larger
|
||||
// the entire redzone of the second global may be within the first global.
|
||||
for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
|
||||
if (g->beg == l->g->beg &&
|
||||
(flags()->detect_odr_violation >= 2 || g->size != l->g->size))
|
||||
ReportODRViolation(g, FindRegistrationSite(g),
|
||||
l->g, FindRegistrationSite(l->g));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (flags()->poison_heap)
|
||||
PoisonRedZones(*g);
|
||||
ListOfGlobals *l = new(allocator_for_globals) ListOfGlobals;
|
||||
@ -144,7 +216,18 @@ using namespace __asan; // NOLINT
|
||||
// Register an array of globals.
|
||||
void __asan_register_globals(__asan_global *globals, uptr n) {
|
||||
if (!flags()->report_globals) return;
|
||||
GET_STACK_TRACE_FATAL_HERE;
|
||||
u32 stack_id = StackDepotPut(stack);
|
||||
BlockingMutexLock lock(&mu_for_globals);
|
||||
if (!global_registration_site_vector)
|
||||
global_registration_site_vector =
|
||||
new(allocator_for_globals) GlobalRegistrationSiteVector(128);
|
||||
GlobalRegistrationSite site = {stack_id, &globals[0], &globals[n - 1]};
|
||||
global_registration_site_vector->push_back(site);
|
||||
if (flags()->report_globals >= 2) {
|
||||
PRINT_CURRENT_STACK();
|
||||
Printf("=== ID %d; %p %p\n", stack_id, &globals[0], &globals[n - 1]);
|
||||
}
|
||||
for (uptr i = 0; i < n; i++) {
|
||||
RegisterGlobal(&globals[i]);
|
||||
}
|
||||
|
32
lib/asan/asan_init_version.h
Normal file
32
lib/asan/asan_init_version.h
Normal file
@ -0,0 +1,32 @@
|
||||
//===-- asan_init_version.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 AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// This header defines a versioned __asan_init function to be called at the
|
||||
// startup of the instrumented program.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef ASAN_INIT_VERSION_H
|
||||
#define ASAN_INIT_VERSION_H
|
||||
|
||||
extern "C" {
|
||||
// Every time the ASan ABI changes we also change the version number in the
|
||||
// __asan_init function name. Objects built with incompatible ASan ABI
|
||||
// versions will not link with run-time.
|
||||
// Changes between ABI versions:
|
||||
// v1=>v2: added 'module_name' to __asan_global
|
||||
// v2=>v3: stack frame description (created by the compiler)
|
||||
// contains the function PC as the 3-rd field (see
|
||||
// DescribeAddressIfStack).
|
||||
// v3=>v4: added '__asan_global_source_location' to __asan_global.
|
||||
#define __asan_init __asan_init_v4
|
||||
#define __asan_init_name "__asan_init_v4"
|
||||
}
|
||||
|
||||
#endif // ASAN_INIT_VERSION_H
|
@ -1,79 +0,0 @@
|
||||
//===-- asan_intercepted_functions.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 AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// ASan-private header containing prototypes for wrapper functions and wrappers
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef ASAN_INTERCEPTED_FUNCTIONS_H
|
||||
#define ASAN_INTERCEPTED_FUNCTIONS_H
|
||||
|
||||
#include "sanitizer_common/sanitizer_platform_interceptors.h"
|
||||
|
||||
// Use macro to describe if specific function should be
|
||||
// intercepted on a given platform.
|
||||
#if !SANITIZER_WINDOWS
|
||||
# define ASAN_INTERCEPT_ATOLL_AND_STRTOLL 1
|
||||
# define ASAN_INTERCEPT__LONGJMP 1
|
||||
# define ASAN_INTERCEPT_STRDUP 1
|
||||
# define ASAN_INTERCEPT_INDEX 1
|
||||
# define ASAN_INTERCEPT_PTHREAD_CREATE 1
|
||||
# define ASAN_INTERCEPT_MLOCKX 1
|
||||
#else
|
||||
# define ASAN_INTERCEPT_ATOLL_AND_STRTOLL 0
|
||||
# define ASAN_INTERCEPT__LONGJMP 0
|
||||
# define ASAN_INTERCEPT_STRDUP 0
|
||||
# define ASAN_INTERCEPT_INDEX 0
|
||||
# define ASAN_INTERCEPT_PTHREAD_CREATE 0
|
||||
# define ASAN_INTERCEPT_MLOCKX 0
|
||||
#endif
|
||||
|
||||
#if SANITIZER_LINUX
|
||||
# define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 1
|
||||
#else
|
||||
# define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 0
|
||||
#endif
|
||||
|
||||
#if !SANITIZER_MAC
|
||||
# define ASAN_INTERCEPT_STRNLEN 1
|
||||
#else
|
||||
# define ASAN_INTERCEPT_STRNLEN 0
|
||||
#endif
|
||||
|
||||
#if SANITIZER_LINUX && !SANITIZER_ANDROID
|
||||
# define ASAN_INTERCEPT_SWAPCONTEXT 1
|
||||
#else
|
||||
# define ASAN_INTERCEPT_SWAPCONTEXT 0
|
||||
#endif
|
||||
|
||||
#if !SANITIZER_ANDROID && !SANITIZER_WINDOWS
|
||||
# define ASAN_INTERCEPT_SIGNAL_AND_SIGACTION 1
|
||||
#else
|
||||
# define ASAN_INTERCEPT_SIGNAL_AND_SIGACTION 0
|
||||
#endif
|
||||
|
||||
#if !SANITIZER_WINDOWS
|
||||
# define ASAN_INTERCEPT_SIGLONGJMP 1
|
||||
#else
|
||||
# define ASAN_INTERCEPT_SIGLONGJMP 0
|
||||
#endif
|
||||
|
||||
#if ASAN_HAS_EXCEPTIONS && !SANITIZER_WINDOWS
|
||||
# define ASAN_INTERCEPT___CXA_THROW 1
|
||||
#else
|
||||
# define ASAN_INTERCEPT___CXA_THROW 0
|
||||
#endif
|
||||
|
||||
#if !SANITIZER_WINDOWS
|
||||
# define ASAN_INTERCEPT___CXA_ATEXIT 1
|
||||
#else
|
||||
# define ASAN_INTERCEPT___CXA_ATEXIT 0
|
||||
#endif
|
||||
|
||||
#endif // ASAN_INTERCEPTED_FUNCTIONS_H
|
@ -14,14 +14,13 @@
|
||||
#include "asan_interceptors.h"
|
||||
|
||||
#include "asan_allocator.h"
|
||||
#include "asan_intercepted_functions.h"
|
||||
#include "asan_internal.h"
|
||||
#include "asan_mapping.h"
|
||||
#include "asan_poisoning.h"
|
||||
#include "asan_report.h"
|
||||
#include "asan_stack.h"
|
||||
#include "asan_stats.h"
|
||||
#include "interception/interception.h"
|
||||
#include "asan_suppressions.h"
|
||||
#include "sanitizer_common/sanitizer_libc.h"
|
||||
|
||||
namespace __asan {
|
||||
@ -36,24 +35,45 @@ static inline bool QuickCheckForUnpoisonedRegion(uptr beg, uptr size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct AsanInterceptorContext {
|
||||
const char *interceptor_name;
|
||||
};
|
||||
|
||||
// We implement ACCESS_MEMORY_RANGE, ASAN_READ_RANGE,
|
||||
// and ASAN_WRITE_RANGE as macro instead of function so
|
||||
// that no extra frames are created, and stack trace contains
|
||||
// relevant information only.
|
||||
// We check all shadow bytes.
|
||||
#define ACCESS_MEMORY_RANGE(offset, size, isWrite) do { \
|
||||
#define ACCESS_MEMORY_RANGE(ctx, offset, size, isWrite) do { \
|
||||
uptr __offset = (uptr)(offset); \
|
||||
uptr __size = (uptr)(size); \
|
||||
uptr __bad = 0; \
|
||||
if (__offset > __offset + __size) { \
|
||||
GET_STACK_TRACE_FATAL_HERE; \
|
||||
ReportStringFunctionSizeOverflow(__offset, __size, &stack); \
|
||||
} \
|
||||
if (!QuickCheckForUnpoisonedRegion(__offset, __size) && \
|
||||
(__bad = __asan_region_is_poisoned(__offset, __size))) { \
|
||||
AsanInterceptorContext *_ctx = (AsanInterceptorContext *)ctx; \
|
||||
bool suppressed = false; \
|
||||
if (_ctx) { \
|
||||
suppressed = IsInterceptorSuppressed(_ctx->interceptor_name); \
|
||||
if (!suppressed && HaveStackTraceBasedSuppressions()) { \
|
||||
GET_STACK_TRACE_FATAL_HERE; \
|
||||
suppressed = IsStackTraceSuppressed(&stack); \
|
||||
} \
|
||||
} \
|
||||
if (!suppressed) { \
|
||||
GET_CURRENT_PC_BP_SP; \
|
||||
__asan_report_error(pc, bp, sp, __bad, isWrite, __size); \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ASAN_READ_RANGE(offset, size) ACCESS_MEMORY_RANGE(offset, size, false)
|
||||
#define ASAN_WRITE_RANGE(offset, size) ACCESS_MEMORY_RANGE(offset, size, true)
|
||||
#define ASAN_READ_RANGE(ctx, offset, size) \
|
||||
ACCESS_MEMORY_RANGE(ctx, offset, size, false)
|
||||
#define ASAN_WRITE_RANGE(ctx, offset, size) \
|
||||
ACCESS_MEMORY_RANGE(ctx, offset, size, true)
|
||||
|
||||
// Behavior of functions like "memcpy" or "strcpy" is undefined
|
||||
// if memory intervals overlap. We report error in this case.
|
||||
@ -72,13 +92,6 @@ static inline bool RangesOverlap(const char *offset1, uptr length1,
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ENSURE_ASAN_INITED() do { \
|
||||
CHECK(!asan_init_is_running); \
|
||||
if (!asan_inited) { \
|
||||
__asan_init(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static inline uptr MaybeRealStrnlen(const char *s, uptr maxlen) {
|
||||
#if ASAN_INTERCEPT_STRNLEN
|
||||
if (REAL(strnlen) != 0) {
|
||||
@ -110,28 +123,31 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)
|
||||
#if !SANITIZER_MAC
|
||||
#define ASAN_INTERCEPT_FUNC(name) \
|
||||
do { \
|
||||
if ((!INTERCEPT_FUNCTION(name) || !REAL(name)) && \
|
||||
common_flags()->verbosity > 0) \
|
||||
Report("AddressSanitizer: failed to intercept '" #name "'\n"); \
|
||||
if ((!INTERCEPT_FUNCTION(name) || !REAL(name))) \
|
||||
VReport(1, "AddressSanitizer: failed to intercept '" #name "'\n"); \
|
||||
} while (0)
|
||||
#else
|
||||
// OS X interceptors don't need to be initialized with INTERCEPT_FUNCTION.
|
||||
#define ASAN_INTERCEPT_FUNC(name)
|
||||
#endif // SANITIZER_MAC
|
||||
|
||||
#define ASAN_INTERCEPTOR_ENTER(ctx, func) \
|
||||
AsanInterceptorContext _ctx = {#func}; \
|
||||
ctx = (void *)&_ctx; \
|
||||
(void) ctx; \
|
||||
|
||||
#define COMMON_INTERCEPT_FUNCTION(name) ASAN_INTERCEPT_FUNC(name)
|
||||
#define COMMON_INTERCEPTOR_UNPOISON_PARAM(ctx, count) \
|
||||
do { \
|
||||
} while (false)
|
||||
#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \
|
||||
ASAN_WRITE_RANGE(ptr, size)
|
||||
#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) ASAN_READ_RANGE(ptr, size)
|
||||
ASAN_WRITE_RANGE(ctx, ptr, size)
|
||||
#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \
|
||||
ASAN_READ_RANGE(ctx, ptr, size)
|
||||
#define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \
|
||||
do { \
|
||||
if (asan_init_is_running) return REAL(func)(__VA_ARGS__); \
|
||||
ctx = 0; \
|
||||
(void) ctx; \
|
||||
if (SANITIZER_MAC && !asan_inited) return REAL(func)(__VA_ARGS__); \
|
||||
if (asan_init_is_running) \
|
||||
return REAL(func)(__VA_ARGS__); \
|
||||
ASAN_INTERCEPTOR_ENTER(ctx, func); \
|
||||
if (SANITIZER_MAC && UNLIKELY(!asan_inited)) \
|
||||
return REAL(func)(__VA_ARGS__); \
|
||||
ENSURE_ASAN_INITED(); \
|
||||
} while (false)
|
||||
#define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \
|
||||
@ -153,10 +169,15 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)
|
||||
} while (false)
|
||||
#define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name)
|
||||
#define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit()
|
||||
#define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, res) CovUpdateMapping()
|
||||
#define COMMON_INTERCEPTOR_LIBRARY_UNLOADED() CovUpdateMapping()
|
||||
#define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (!asan_inited)
|
||||
#include "sanitizer_common/sanitizer_common_interceptors.inc"
|
||||
|
||||
#define COMMON_SYSCALL_PRE_READ_RANGE(p, s) ASAN_READ_RANGE(p, s)
|
||||
#define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) ASAN_WRITE_RANGE(p, s)
|
||||
// Syscall interceptors don't have contexts, we don't support suppressions
|
||||
// for them.
|
||||
#define COMMON_SYSCALL_PRE_READ_RANGE(p, s) ASAN_READ_RANGE(nullptr, p, s)
|
||||
#define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) ASAN_WRITE_RANGE(nullptr, p, s)
|
||||
#define COMMON_SYSCALL_POST_READ_RANGE(p, s) \
|
||||
do { \
|
||||
(void)(p); \
|
||||
@ -169,47 +190,90 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)
|
||||
} while (false)
|
||||
#include "sanitizer_common/sanitizer_common_syscalls.inc"
|
||||
|
||||
struct ThreadStartParam {
|
||||
atomic_uintptr_t t;
|
||||
atomic_uintptr_t is_registered;
|
||||
};
|
||||
|
||||
static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {
|
||||
AsanThread *t = (AsanThread*)arg;
|
||||
ThreadStartParam *param = reinterpret_cast<ThreadStartParam *>(arg);
|
||||
AsanThread *t = nullptr;
|
||||
while ((t = reinterpret_cast<AsanThread *>(
|
||||
atomic_load(¶m->t, memory_order_acquire))) == 0)
|
||||
internal_sched_yield();
|
||||
SetCurrentThread(t);
|
||||
return t->ThreadStart(GetTid());
|
||||
return t->ThreadStart(GetTid(), ¶m->is_registered);
|
||||
}
|
||||
|
||||
#if ASAN_INTERCEPT_PTHREAD_CREATE
|
||||
INTERCEPTOR(int, pthread_create, void *thread,
|
||||
void *attr, void *(*start_routine)(void*), void *arg) {
|
||||
EnsureMainThreadIDIsCorrect();
|
||||
// Strict init-order checking in thread-hostile.
|
||||
// Strict init-order checking is thread-hostile.
|
||||
if (flags()->strict_init_order)
|
||||
StopInitOrderChecking();
|
||||
GET_STACK_TRACE_THREAD;
|
||||
int detached = 0;
|
||||
if (attr != 0)
|
||||
REAL(pthread_attr_getdetachstate)(attr, &detached);
|
||||
|
||||
ThreadStartParam param;
|
||||
atomic_store(¶m.t, 0, memory_order_relaxed);
|
||||
atomic_store(¶m.is_registered, 0, memory_order_relaxed);
|
||||
int result = REAL(pthread_create)(thread, attr, asan_thread_start, ¶m);
|
||||
if (result == 0) {
|
||||
u32 current_tid = GetCurrentTidOrInvalid();
|
||||
AsanThread *t = AsanThread::Create(start_routine, arg);
|
||||
CreateThreadContextArgs args = { t, &stack };
|
||||
asanThreadRegistry().CreateThread(*(uptr*)t, detached, current_tid, &args);
|
||||
return REAL(pthread_create)(thread, attr, asan_thread_start, t);
|
||||
AsanThread *t =
|
||||
AsanThread::Create(start_routine, arg, current_tid, &stack, detached);
|
||||
atomic_store(¶m.t, reinterpret_cast<uptr>(t), memory_order_release);
|
||||
// Wait until the AsanThread object is initialized and the ThreadRegistry
|
||||
// entry is in "started" state. One reason for this is that after this
|
||||
// interceptor exits, the child thread's stack may be the only thing holding
|
||||
// the |arg| pointer. This may cause LSan to report a leak if leak checking
|
||||
// happens at a point when the interceptor has already exited, but the stack
|
||||
// range for the child thread is not yet known.
|
||||
while (atomic_load(¶m.is_registered, memory_order_acquire) == 0)
|
||||
internal_sched_yield();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#endif // ASAN_INTERCEPT_PTHREAD_CREATE
|
||||
|
||||
#if ASAN_INTERCEPT_SIGNAL_AND_SIGACTION
|
||||
|
||||
#if SANITIZER_ANDROID
|
||||
INTERCEPTOR(void*, bsd_signal, int signum, void *handler) {
|
||||
if (!AsanInterceptsSignal(signum) ||
|
||||
common_flags()->allow_user_segv_handler) {
|
||||
return REAL(bsd_signal)(signum, handler);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
INTERCEPTOR(void*, signal, int signum, void *handler) {
|
||||
if (!AsanInterceptsSignal(signum) || flags()->allow_user_segv_handler) {
|
||||
if (!AsanInterceptsSignal(signum) ||
|
||||
common_flags()->allow_user_segv_handler) {
|
||||
return REAL(signal)(signum, handler);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
INTERCEPTOR(int, sigaction, int signum, const struct sigaction *act,
|
||||
struct sigaction *oldact) {
|
||||
if (!AsanInterceptsSignal(signum) || flags()->allow_user_segv_handler) {
|
||||
if (!AsanInterceptsSignal(signum) ||
|
||||
common_flags()->allow_user_segv_handler) {
|
||||
return REAL(sigaction)(signum, act, oldact);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
namespace __sanitizer {
|
||||
int real_sigaction(int signum, const void *act, void *oldact) {
|
||||
return REAL(sigaction)(signum, (const struct sigaction *)act,
|
||||
(struct sigaction *)oldact);
|
||||
}
|
||||
} // namespace __sanitizer
|
||||
|
||||
#elif SANITIZER_POSIX
|
||||
// We need to have defined REAL(sigaction) on posix systems.
|
||||
DEFINE_REAL(int, sigaction, int signum, const struct sigaction *act,
|
||||
@ -279,52 +343,45 @@ INTERCEPTOR(void, __cxa_throw, void *a, void *b, void *c) {
|
||||
}
|
||||
#endif
|
||||
|
||||
// intercept mlock and friends.
|
||||
// Since asan maps 16T of RAM, mlock is completely unfriendly to asan.
|
||||
// All functions return 0 (success).
|
||||
static void MlockIsUnsupported() {
|
||||
static bool printed = false;
|
||||
if (printed) return;
|
||||
printed = true;
|
||||
if (common_flags()->verbosity > 0) {
|
||||
Printf("INFO: AddressSanitizer ignores "
|
||||
"mlock/mlockall/munlock/munlockall\n");
|
||||
}
|
||||
#if SANITIZER_WINDOWS
|
||||
INTERCEPTOR_WINAPI(void, RaiseException, void *a, void *b, void *c, void *d) {
|
||||
CHECK(REAL(RaiseException));
|
||||
__asan_handle_no_return();
|
||||
REAL(RaiseException)(a, b, c, d);
|
||||
}
|
||||
|
||||
INTERCEPTOR(int, mlock, const void *addr, uptr len) {
|
||||
MlockIsUnsupported();
|
||||
return 0;
|
||||
INTERCEPTOR(int, _except_handler3, void *a, void *b, void *c, void *d) {
|
||||
CHECK(REAL(_except_handler3));
|
||||
__asan_handle_no_return();
|
||||
return REAL(_except_handler3)(a, b, c, d);
|
||||
}
|
||||
|
||||
INTERCEPTOR(int, munlock, const void *addr, uptr len) {
|
||||
MlockIsUnsupported();
|
||||
return 0;
|
||||
}
|
||||
|
||||
INTERCEPTOR(int, mlockall, int flags) {
|
||||
MlockIsUnsupported();
|
||||
return 0;
|
||||
}
|
||||
|
||||
INTERCEPTOR(int, munlockall, void) {
|
||||
MlockIsUnsupported();
|
||||
return 0;
|
||||
#if ASAN_DYNAMIC
|
||||
// This handler is named differently in -MT and -MD CRTs.
|
||||
#define _except_handler4 _except_handler4_common
|
||||
#endif
|
||||
INTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) {
|
||||
CHECK(REAL(_except_handler4));
|
||||
__asan_handle_no_return();
|
||||
return REAL(_except_handler4)(a, b, c, d);
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline int CharCmp(unsigned char c1, unsigned char c2) {
|
||||
return (c1 == c2) ? 0 : (c1 < c2) ? -1 : 1;
|
||||
}
|
||||
|
||||
INTERCEPTOR(int, memcmp, const void *a1, const void *a2, uptr size) {
|
||||
if (!asan_inited) return internal_memcmp(a1, a2, size);
|
||||
void *ctx;
|
||||
ASAN_INTERCEPTOR_ENTER(ctx, memcmp);
|
||||
if (UNLIKELY(!asan_inited)) return internal_memcmp(a1, a2, size);
|
||||
ENSURE_ASAN_INITED();
|
||||
if (flags()->replace_intrin) {
|
||||
if (flags()->strict_memcmp) {
|
||||
// Check the entire regions even if the first bytes of the buffers are
|
||||
// different.
|
||||
ASAN_READ_RANGE(a1, size);
|
||||
ASAN_READ_RANGE(a2, size);
|
||||
ASAN_READ_RANGE(ctx, a1, size);
|
||||
ASAN_READ_RANGE(ctx, a2, size);
|
||||
// Fallthrough to REAL(memcmp) below.
|
||||
} else {
|
||||
unsigned char c1 = 0, c2 = 0;
|
||||
@ -336,51 +393,81 @@ INTERCEPTOR(int, memcmp, const void *a1, const void *a2, uptr size) {
|
||||
c2 = s2[i];
|
||||
if (c1 != c2) break;
|
||||
}
|
||||
ASAN_READ_RANGE(s1, Min(i + 1, size));
|
||||
ASAN_READ_RANGE(s2, Min(i + 1, size));
|
||||
ASAN_READ_RANGE(ctx, s1, Min(i + 1, size));
|
||||
ASAN_READ_RANGE(ctx, s2, Min(i + 1, size));
|
||||
return CharCmp(c1, c2);
|
||||
}
|
||||
}
|
||||
return REAL(memcmp(a1, a2, size));
|
||||
}
|
||||
|
||||
#define MEMMOVE_BODY { \
|
||||
if (!asan_inited) return internal_memmove(to, from, size); \
|
||||
// memcpy is called during __asan_init() from the internals of printf(...).
|
||||
// We do not treat memcpy with to==from as a bug.
|
||||
// See http://llvm.org/bugs/show_bug.cgi?id=11763.
|
||||
#define ASAN_MEMCPY_IMPL(ctx, to, from, size) do { \
|
||||
if (UNLIKELY(!asan_inited)) return internal_memcpy(to, from, size); \
|
||||
if (asan_init_is_running) { \
|
||||
return REAL(memmove)(to, from, size); \
|
||||
return REAL(memcpy)(to, from, size); \
|
||||
} \
|
||||
ENSURE_ASAN_INITED(); \
|
||||
if (flags()->replace_intrin) { \
|
||||
ASAN_READ_RANGE(from, size); \
|
||||
ASAN_WRITE_RANGE(to, size); \
|
||||
if (to != from) { \
|
||||
CHECK_RANGES_OVERLAP("memcpy", to, size, from, size); \
|
||||
} \
|
||||
return internal_memmove(to, from, size); \
|
||||
ASAN_READ_RANGE(ctx, from, size); \
|
||||
ASAN_WRITE_RANGE(ctx, to, size); \
|
||||
} \
|
||||
return REAL(memcpy)(to, from, size); \
|
||||
} while (0)
|
||||
|
||||
|
||||
void *__asan_memcpy(void *to, const void *from, uptr size) {
|
||||
ASAN_MEMCPY_IMPL(nullptr, to, from, size);
|
||||
}
|
||||
|
||||
INTERCEPTOR(void*, memmove, void *to, const void *from, uptr size) MEMMOVE_BODY
|
||||
// memset is called inside Printf.
|
||||
#define ASAN_MEMSET_IMPL(ctx, block, c, size) do { \
|
||||
if (UNLIKELY(!asan_inited)) return internal_memset(block, c, size); \
|
||||
if (asan_init_is_running) { \
|
||||
return REAL(memset)(block, c, size); \
|
||||
} \
|
||||
ENSURE_ASAN_INITED(); \
|
||||
if (flags()->replace_intrin) { \
|
||||
ASAN_WRITE_RANGE(ctx, block, size); \
|
||||
} \
|
||||
return REAL(memset)(block, c, size); \
|
||||
} while (0)
|
||||
|
||||
void *__asan_memset(void *block, int c, uptr size) {
|
||||
ASAN_MEMSET_IMPL(nullptr, block, c, size);
|
||||
}
|
||||
|
||||
#define ASAN_MEMMOVE_IMPL(ctx, to, from, size) do { \
|
||||
if (UNLIKELY(!asan_inited)) \
|
||||
return internal_memmove(to, from, size); \
|
||||
ENSURE_ASAN_INITED(); \
|
||||
if (flags()->replace_intrin) { \
|
||||
ASAN_READ_RANGE(ctx, from, size); \
|
||||
ASAN_WRITE_RANGE(ctx, to, size); \
|
||||
} \
|
||||
return internal_memmove(to, from, size); \
|
||||
} while (0)
|
||||
|
||||
void *__asan_memmove(void *to, const void *from, uptr size) {
|
||||
ASAN_MEMMOVE_IMPL(nullptr, to, from, size);
|
||||
}
|
||||
|
||||
INTERCEPTOR(void*, memmove, void *to, const void *from, uptr size) {
|
||||
void *ctx;
|
||||
ASAN_INTERCEPTOR_ENTER(ctx, memmove);
|
||||
ASAN_MEMMOVE_IMPL(ctx, to, from, size);
|
||||
}
|
||||
|
||||
INTERCEPTOR(void*, memcpy, void *to, const void *from, uptr size) {
|
||||
void *ctx;
|
||||
ASAN_INTERCEPTOR_ENTER(ctx, memcpy);
|
||||
#if !SANITIZER_MAC
|
||||
if (!asan_inited) return internal_memcpy(to, from, size);
|
||||
// memcpy is called during __asan_init() from the internals
|
||||
// of printf(...).
|
||||
if (asan_init_is_running) {
|
||||
return REAL(memcpy)(to, from, size);
|
||||
}
|
||||
ENSURE_ASAN_INITED();
|
||||
if (flags()->replace_intrin) {
|
||||
if (to != from) {
|
||||
// We do not treat memcpy with to==from as a bug.
|
||||
// See http://llvm.org/bugs/show_bug.cgi?id=11763.
|
||||
CHECK_RANGES_OVERLAP("memcpy", to, size, from, size);
|
||||
}
|
||||
ASAN_READ_RANGE(from, size);
|
||||
ASAN_WRITE_RANGE(to, size);
|
||||
}
|
||||
// Interposing of resolver functions is broken on Mac OS 10.7 and 10.8, so
|
||||
// calling REAL(memcpy) here leads to infinite recursion.
|
||||
// See also http://code.google.com/p/address-sanitizer/issues/detail?id=116.
|
||||
return internal_memcpy(to, from, size);
|
||||
ASAN_MEMCPY_IMPL(ctx, to, from, size);
|
||||
#else
|
||||
// At least on 10.7 and 10.8 both memcpy() and memmove() are being replaced
|
||||
// with WRAP(memcpy). As a result, false positives are reported for memmove()
|
||||
@ -388,25 +475,20 @@ INTERCEPTOR(void*, memcpy, void *to, const void *from, uptr size) {
|
||||
// ASAN_OPTIONS=replace_intrin=0, memmove() is still replaced with
|
||||
// internal_memcpy(), which may lead to crashes, see
|
||||
// http://llvm.org/bugs/show_bug.cgi?id=16362.
|
||||
MEMMOVE_BODY
|
||||
ASAN_MEMMOVE_IMPL(ctx, to, from, size);
|
||||
#endif // !SANITIZER_MAC
|
||||
}
|
||||
|
||||
INTERCEPTOR(void*, memset, void *block, int c, uptr size) {
|
||||
if (!asan_inited) return internal_memset(block, c, size);
|
||||
// memset is called inside Printf.
|
||||
if (asan_init_is_running) {
|
||||
return REAL(memset)(block, c, size);
|
||||
}
|
||||
ENSURE_ASAN_INITED();
|
||||
if (flags()->replace_intrin) {
|
||||
ASAN_WRITE_RANGE(block, size);
|
||||
}
|
||||
return REAL(memset)(block, c, size);
|
||||
void *ctx;
|
||||
ASAN_INTERCEPTOR_ENTER(ctx, memset);
|
||||
ASAN_MEMSET_IMPL(ctx, block, c, size);
|
||||
}
|
||||
|
||||
INTERCEPTOR(char*, strchr, const char *str, int c) {
|
||||
if (!asan_inited) return internal_strchr(str, c);
|
||||
void *ctx;
|
||||
ASAN_INTERCEPTOR_ENTER(ctx, strchr);
|
||||
if (UNLIKELY(!asan_inited)) return internal_strchr(str, c);
|
||||
// strchr is called inside create_purgeable_zone() when MallocGuardEdges=1 is
|
||||
// used.
|
||||
if (asan_init_is_running) {
|
||||
@ -416,7 +498,7 @@ INTERCEPTOR(char*, strchr, const char *str, int c) {
|
||||
char *result = REAL(strchr)(str, c);
|
||||
if (flags()->replace_str) {
|
||||
uptr bytes_read = (result ? result - str : REAL(strlen)(str)) + 1;
|
||||
ASAN_READ_RANGE(str, bytes_read);
|
||||
ASAN_READ_RANGE(ctx, str, bytes_read);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -438,13 +520,15 @@ DEFINE_REAL(char*, index, const char *string, int c)
|
||||
// For both strcat() and strncat() we need to check the validity of |to|
|
||||
// argument irrespective of the |from| length.
|
||||
INTERCEPTOR(char*, strcat, char *to, const char *from) { // NOLINT
|
||||
void *ctx;
|
||||
ASAN_INTERCEPTOR_ENTER(ctx, strcat); // NOLINT
|
||||
ENSURE_ASAN_INITED();
|
||||
if (flags()->replace_str) {
|
||||
uptr from_length = REAL(strlen)(from);
|
||||
ASAN_READ_RANGE(from, from_length + 1);
|
||||
ASAN_READ_RANGE(ctx, from, from_length + 1);
|
||||
uptr to_length = REAL(strlen)(to);
|
||||
ASAN_READ_RANGE(to, to_length);
|
||||
ASAN_WRITE_RANGE(to + to_length, from_length + 1);
|
||||
ASAN_READ_RANGE(ctx, to, to_length);
|
||||
ASAN_WRITE_RANGE(ctx, to + to_length, from_length + 1);
|
||||
// If the copying actually happens, the |from| string should not overlap
|
||||
// with the resulting string starting at |to|, which has a length of
|
||||
// to_length + from_length + 1.
|
||||
@ -457,14 +541,16 @@ INTERCEPTOR(char*, strcat, char *to, const char *from) { // NOLINT
|
||||
}
|
||||
|
||||
INTERCEPTOR(char*, strncat, char *to, const char *from, uptr size) {
|
||||
void *ctx;
|
||||
ASAN_INTERCEPTOR_ENTER(ctx, strncat);
|
||||
ENSURE_ASAN_INITED();
|
||||
if (flags()->replace_str) {
|
||||
uptr from_length = MaybeRealStrnlen(from, size);
|
||||
uptr copy_length = Min(size, from_length + 1);
|
||||
ASAN_READ_RANGE(from, copy_length);
|
||||
ASAN_READ_RANGE(ctx, from, copy_length);
|
||||
uptr to_length = REAL(strlen)(to);
|
||||
ASAN_READ_RANGE(to, to_length);
|
||||
ASAN_WRITE_RANGE(to + to_length, from_length + 1);
|
||||
ASAN_READ_RANGE(ctx, to, to_length);
|
||||
ASAN_WRITE_RANGE(ctx, to + to_length, from_length + 1);
|
||||
if (from_length > 0) {
|
||||
CHECK_RANGES_OVERLAP("strncat", to, to_length + copy_length + 1,
|
||||
from, copy_length);
|
||||
@ -474,8 +560,10 @@ INTERCEPTOR(char*, strncat, char *to, const char *from, uptr size) {
|
||||
}
|
||||
|
||||
INTERCEPTOR(char*, strcpy, char *to, const char *from) { // NOLINT
|
||||
void *ctx;
|
||||
ASAN_INTERCEPTOR_ENTER(ctx, strcpy); // NOLINT
|
||||
#if SANITIZER_MAC
|
||||
if (!asan_inited) return REAL(strcpy)(to, from); // NOLINT
|
||||
if (UNLIKELY(!asan_inited)) return REAL(strcpy)(to, from); // NOLINT
|
||||
#endif
|
||||
// strcpy is called from malloc_default_purgeable_zone()
|
||||
// in __asan::ReplaceSystemAlloc() on Mac.
|
||||
@ -486,19 +574,21 @@ INTERCEPTOR(char*, strcpy, char *to, const char *from) { // NOLINT
|
||||
if (flags()->replace_str) {
|
||||
uptr from_size = REAL(strlen)(from) + 1;
|
||||
CHECK_RANGES_OVERLAP("strcpy", to, from_size, from, from_size);
|
||||
ASAN_READ_RANGE(from, from_size);
|
||||
ASAN_WRITE_RANGE(to, from_size);
|
||||
ASAN_READ_RANGE(ctx, from, from_size);
|
||||
ASAN_WRITE_RANGE(ctx, to, from_size);
|
||||
}
|
||||
return REAL(strcpy)(to, from); // NOLINT
|
||||
}
|
||||
|
||||
#if ASAN_INTERCEPT_STRDUP
|
||||
INTERCEPTOR(char*, strdup, const char *s) {
|
||||
if (!asan_inited) return internal_strdup(s);
|
||||
void *ctx;
|
||||
ASAN_INTERCEPTOR_ENTER(ctx, strdup);
|
||||
if (UNLIKELY(!asan_inited)) return internal_strdup(s);
|
||||
ENSURE_ASAN_INITED();
|
||||
uptr length = REAL(strlen)(s);
|
||||
if (flags()->replace_str) {
|
||||
ASAN_READ_RANGE(s, length + 1);
|
||||
ASAN_READ_RANGE(ctx, s, length + 1);
|
||||
}
|
||||
GET_STACK_TRACE_MALLOC;
|
||||
void *new_mem = asan_malloc(length + 1, &stack);
|
||||
@ -507,47 +597,55 @@ INTERCEPTOR(char*, strdup, const char *s) {
|
||||
}
|
||||
#endif
|
||||
|
||||
INTERCEPTOR(uptr, strlen, const char *s) {
|
||||
if (!asan_inited) return internal_strlen(s);
|
||||
INTERCEPTOR(SIZE_T, strlen, const char *s) {
|
||||
void *ctx;
|
||||
ASAN_INTERCEPTOR_ENTER(ctx, strlen);
|
||||
if (UNLIKELY(!asan_inited)) return internal_strlen(s);
|
||||
// strlen is called from malloc_default_purgeable_zone()
|
||||
// in __asan::ReplaceSystemAlloc() on Mac.
|
||||
if (asan_init_is_running) {
|
||||
return REAL(strlen)(s);
|
||||
}
|
||||
ENSURE_ASAN_INITED();
|
||||
uptr length = REAL(strlen)(s);
|
||||
SIZE_T length = REAL(strlen)(s);
|
||||
if (flags()->replace_str) {
|
||||
ASAN_READ_RANGE(s, length + 1);
|
||||
ASAN_READ_RANGE(ctx, s, length + 1);
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
INTERCEPTOR(uptr, wcslen, const wchar_t *s) {
|
||||
uptr length = REAL(wcslen)(s);
|
||||
INTERCEPTOR(SIZE_T, wcslen, const wchar_t *s) {
|
||||
void *ctx;
|
||||
ASAN_INTERCEPTOR_ENTER(ctx, wcslen);
|
||||
SIZE_T length = REAL(wcslen)(s);
|
||||
if (!asan_init_is_running) {
|
||||
ENSURE_ASAN_INITED();
|
||||
ASAN_READ_RANGE(s, (length + 1) * sizeof(wchar_t));
|
||||
ASAN_READ_RANGE(ctx, s, (length + 1) * sizeof(wchar_t));
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
INTERCEPTOR(char*, strncpy, char *to, const char *from, uptr size) {
|
||||
void *ctx;
|
||||
ASAN_INTERCEPTOR_ENTER(ctx, strncpy);
|
||||
ENSURE_ASAN_INITED();
|
||||
if (flags()->replace_str) {
|
||||
uptr from_size = Min(size, MaybeRealStrnlen(from, size) + 1);
|
||||
CHECK_RANGES_OVERLAP("strncpy", to, from_size, from, from_size);
|
||||
ASAN_READ_RANGE(from, from_size);
|
||||
ASAN_WRITE_RANGE(to, size);
|
||||
ASAN_READ_RANGE(ctx, from, from_size);
|
||||
ASAN_WRITE_RANGE(ctx, to, size);
|
||||
}
|
||||
return REAL(strncpy)(to, from, size);
|
||||
}
|
||||
|
||||
#if ASAN_INTERCEPT_STRNLEN
|
||||
INTERCEPTOR(uptr, strnlen, const char *s, uptr maxlen) {
|
||||
void *ctx;
|
||||
ASAN_INTERCEPTOR_ENTER(ctx, strnlen);
|
||||
ENSURE_ASAN_INITED();
|
||||
uptr length = REAL(strnlen)(s, maxlen);
|
||||
if (flags()->replace_str) {
|
||||
ASAN_READ_RANGE(s, Min(length + 1, maxlen));
|
||||
ASAN_READ_RANGE(ctx, s, Min(length + 1, maxlen));
|
||||
}
|
||||
return length;
|
||||
}
|
||||
@ -565,13 +663,15 @@ static inline void FixRealStrtolEndptr(const char *nptr, char **endptr) {
|
||||
// We get this symbol by skipping leading blanks and optional +/- sign.
|
||||
while (IsSpace(*nptr)) nptr++;
|
||||
if (*nptr == '+' || *nptr == '-') nptr++;
|
||||
*endptr = (char*)nptr;
|
||||
*endptr = const_cast<char *>(nptr);
|
||||
}
|
||||
CHECK(*endptr >= nptr);
|
||||
}
|
||||
|
||||
INTERCEPTOR(long, strtol, const char *nptr, // NOLINT
|
||||
char **endptr, int base) {
|
||||
void *ctx;
|
||||
ASAN_INTERCEPTOR_ENTER(ctx, strtol);
|
||||
ENSURE_ASAN_INITED();
|
||||
if (!flags()->replace_str) {
|
||||
return REAL(strtol)(nptr, endptr, base);
|
||||
@ -583,14 +683,16 @@ INTERCEPTOR(long, strtol, const char *nptr, // NOLINT
|
||||
}
|
||||
if (IsValidStrtolBase(base)) {
|
||||
FixRealStrtolEndptr(nptr, &real_endptr);
|
||||
ASAN_READ_RANGE(nptr, (real_endptr - nptr) + 1);
|
||||
ASAN_READ_RANGE(ctx, nptr, (real_endptr - nptr) + 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
INTERCEPTOR(int, atoi, const char *nptr) {
|
||||
void *ctx;
|
||||
ASAN_INTERCEPTOR_ENTER(ctx, atoi);
|
||||
#if SANITIZER_MAC
|
||||
if (!asan_inited) return REAL(atoi)(nptr);
|
||||
if (UNLIKELY(!asan_inited)) return REAL(atoi)(nptr);
|
||||
#endif
|
||||
ENSURE_ASAN_INITED();
|
||||
if (!flags()->replace_str) {
|
||||
@ -603,13 +705,15 @@ INTERCEPTOR(int, atoi, const char *nptr) {
|
||||
// different from int). So, we just imitate this behavior.
|
||||
int result = REAL(strtol)(nptr, &real_endptr, 10);
|
||||
FixRealStrtolEndptr(nptr, &real_endptr);
|
||||
ASAN_READ_RANGE(nptr, (real_endptr - nptr) + 1);
|
||||
ASAN_READ_RANGE(ctx, nptr, (real_endptr - nptr) + 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
INTERCEPTOR(long, atol, const char *nptr) { // NOLINT
|
||||
void *ctx;
|
||||
ASAN_INTERCEPTOR_ENTER(ctx, atol);
|
||||
#if SANITIZER_MAC
|
||||
if (!asan_inited) return REAL(atol)(nptr);
|
||||
if (UNLIKELY(!asan_inited)) return REAL(atol)(nptr);
|
||||
#endif
|
||||
ENSURE_ASAN_INITED();
|
||||
if (!flags()->replace_str) {
|
||||
@ -618,13 +722,15 @@ INTERCEPTOR(long, atol, const char *nptr) { // NOLINT
|
||||
char *real_endptr;
|
||||
long result = REAL(strtol)(nptr, &real_endptr, 10); // NOLINT
|
||||
FixRealStrtolEndptr(nptr, &real_endptr);
|
||||
ASAN_READ_RANGE(nptr, (real_endptr - nptr) + 1);
|
||||
ASAN_READ_RANGE(ctx, nptr, (real_endptr - nptr) + 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
#if ASAN_INTERCEPT_ATOLL_AND_STRTOLL
|
||||
INTERCEPTOR(long long, strtoll, const char *nptr, // NOLINT
|
||||
char **endptr, int base) {
|
||||
void *ctx;
|
||||
ASAN_INTERCEPTOR_ENTER(ctx, strtoll);
|
||||
ENSURE_ASAN_INITED();
|
||||
if (!flags()->replace_str) {
|
||||
return REAL(strtoll)(nptr, endptr, base);
|
||||
@ -639,12 +745,14 @@ INTERCEPTOR(long long, strtoll, const char *nptr, // NOLINT
|
||||
// if base is valid.
|
||||
if (IsValidStrtolBase(base)) {
|
||||
FixRealStrtolEndptr(nptr, &real_endptr);
|
||||
ASAN_READ_RANGE(nptr, (real_endptr - nptr) + 1);
|
||||
ASAN_READ_RANGE(ctx, nptr, (real_endptr - nptr) + 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
INTERCEPTOR(long long, atoll, const char *nptr) { // NOLINT
|
||||
void *ctx;
|
||||
ASAN_INTERCEPTOR_ENTER(ctx, atoll);
|
||||
ENSURE_ASAN_INITED();
|
||||
if (!flags()->replace_str) {
|
||||
return REAL(atoll)(nptr);
|
||||
@ -652,7 +760,7 @@ INTERCEPTOR(long long, atoll, const char *nptr) { // NOLINT
|
||||
char *real_endptr;
|
||||
long long result = REAL(strtoll)(nptr, &real_endptr, 10); // NOLINT
|
||||
FixRealStrtolEndptr(nptr, &real_endptr);
|
||||
ASAN_READ_RANGE(nptr, (real_endptr - nptr) + 1);
|
||||
ASAN_READ_RANGE(ctx, nptr, (real_endptr - nptr) + 1);
|
||||
return result;
|
||||
}
|
||||
#endif // ASAN_INTERCEPT_ATOLL_AND_STRTOLL
|
||||
@ -666,7 +774,7 @@ static void AtCxaAtexit(void *unused) {
|
||||
INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
|
||||
void *dso_handle) {
|
||||
#if SANITIZER_MAC
|
||||
if (!asan_inited) return REAL(__cxa_atexit)(func, arg, dso_handle);
|
||||
if (UNLIKELY(!asan_inited)) return REAL(__cxa_atexit)(func, arg, dso_handle);
|
||||
#endif
|
||||
ENSURE_ASAN_INITED();
|
||||
int res = REAL(__cxa_atexit)(func, arg, dso_handle);
|
||||
@ -675,27 +783,50 @@ INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
|
||||
}
|
||||
#endif // ASAN_INTERCEPT___CXA_ATEXIT
|
||||
|
||||
#if ASAN_INTERCEPT_FORK
|
||||
INTERCEPTOR(int, fork, void) {
|
||||
ENSURE_ASAN_INITED();
|
||||
if (common_flags()->coverage) CovBeforeFork();
|
||||
int pid = REAL(fork)();
|
||||
if (common_flags()->coverage) CovAfterFork(pid);
|
||||
return pid;
|
||||
}
|
||||
#endif // ASAN_INTERCEPT_FORK
|
||||
|
||||
#if SANITIZER_WINDOWS
|
||||
INTERCEPTOR_WINAPI(DWORD, CreateThread,
|
||||
void* security, uptr stack_size,
|
||||
DWORD (__stdcall *start_routine)(void*), void* arg,
|
||||
DWORD thr_flags, void* tid) {
|
||||
// Strict init-order checking in thread-hostile.
|
||||
// Strict init-order checking is thread-hostile.
|
||||
if (flags()->strict_init_order)
|
||||
StopInitOrderChecking();
|
||||
GET_STACK_TRACE_THREAD;
|
||||
u32 current_tid = GetCurrentTidOrInvalid();
|
||||
AsanThread *t = AsanThread::Create(start_routine, arg);
|
||||
CreateThreadContextArgs args = { t, &stack };
|
||||
bool detached = false; // FIXME: how can we determine it on Windows?
|
||||
asanThreadRegistry().CreateThread(*(uptr*)t, detached, current_tid, &args);
|
||||
return REAL(CreateThread)(security, stack_size,
|
||||
asan_thread_start, t, thr_flags, tid);
|
||||
ThreadStartParam param;
|
||||
atomic_store(¶m.t, 0, memory_order_relaxed);
|
||||
atomic_store(¶m.is_registered, 0, memory_order_relaxed);
|
||||
DWORD result = REAL(CreateThread)(security, stack_size, asan_thread_start,
|
||||
¶m, thr_flags, tid);
|
||||
if (result) {
|
||||
u32 current_tid = GetCurrentTidOrInvalid();
|
||||
AsanThread *t =
|
||||
AsanThread::Create(start_routine, arg, current_tid, &stack, detached);
|
||||
atomic_store(¶m.t, reinterpret_cast<uptr>(t), memory_order_release);
|
||||
// The pthread_create interceptor waits here, so we do the same for
|
||||
// consistency.
|
||||
while (atomic_load(¶m.is_registered, memory_order_acquire) == 0)
|
||||
internal_sched_yield();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
namespace __asan {
|
||||
void InitializeWindowsInterceptors() {
|
||||
ASAN_INTERCEPT_FUNC(CreateThread);
|
||||
ASAN_INTERCEPT_FUNC(RaiseException);
|
||||
ASAN_INTERCEPT_FUNC(_except_handler3);
|
||||
ASAN_INTERCEPT_FUNC(_except_handler4);
|
||||
}
|
||||
|
||||
} // namespace __asan
|
||||
@ -707,7 +838,7 @@ void InitializeAsanInterceptors() {
|
||||
static bool was_called_once;
|
||||
CHECK(was_called_once == false);
|
||||
was_called_once = true;
|
||||
SANITIZER_COMMON_INTERCEPTORS_INIT;
|
||||
InitializeCommonInterceptors();
|
||||
|
||||
// Intercept mem* functions.
|
||||
ASAN_INTERCEPT_FUNC(memcmp);
|
||||
@ -743,20 +874,16 @@ void InitializeAsanInterceptors() {
|
||||
ASAN_INTERCEPT_FUNC(strtoll);
|
||||
#endif
|
||||
|
||||
#if ASAN_INTERCEPT_MLOCKX
|
||||
// Intercept mlock/munlock.
|
||||
ASAN_INTERCEPT_FUNC(mlock);
|
||||
ASAN_INTERCEPT_FUNC(munlock);
|
||||
ASAN_INTERCEPT_FUNC(mlockall);
|
||||
ASAN_INTERCEPT_FUNC(munlockall);
|
||||
#endif
|
||||
|
||||
// Intecept signal- and jump-related functions.
|
||||
ASAN_INTERCEPT_FUNC(longjmp);
|
||||
#if ASAN_INTERCEPT_SIGNAL_AND_SIGACTION
|
||||
ASAN_INTERCEPT_FUNC(sigaction);
|
||||
#if SANITIZER_ANDROID
|
||||
ASAN_INTERCEPT_FUNC(bsd_signal);
|
||||
#else
|
||||
ASAN_INTERCEPT_FUNC(signal);
|
||||
#endif
|
||||
#endif
|
||||
#if ASAN_INTERCEPT_SWAPCONTEXT
|
||||
ASAN_INTERCEPT_FUNC(swapcontext);
|
||||
#endif
|
||||
@ -769,7 +896,7 @@ void InitializeAsanInterceptors() {
|
||||
|
||||
// Intercept exception handling functions.
|
||||
#if ASAN_INTERCEPT___CXA_THROW
|
||||
INTERCEPT_FUNCTION(__cxa_throw);
|
||||
ASAN_INTERCEPT_FUNC(__cxa_throw);
|
||||
#endif
|
||||
|
||||
// Intercept threading-related functions
|
||||
@ -782,14 +909,16 @@ void InitializeAsanInterceptors() {
|
||||
ASAN_INTERCEPT_FUNC(__cxa_atexit);
|
||||
#endif
|
||||
|
||||
#if ASAN_INTERCEPT_FORK
|
||||
ASAN_INTERCEPT_FUNC(fork);
|
||||
#endif
|
||||
|
||||
// Some Windows-specific interceptors.
|
||||
#if SANITIZER_WINDOWS
|
||||
InitializeWindowsInterceptors();
|
||||
#endif
|
||||
|
||||
if (common_flags()->verbosity > 0) {
|
||||
Report("AddressSanitizer: libc interceptors initialized\n");
|
||||
}
|
||||
VReport(1, "AddressSanitizer: libc interceptors initialized\n");
|
||||
}
|
||||
|
||||
} // namespace __asan
|
||||
|
@ -16,12 +16,75 @@
|
||||
|
||||
#include "asan_internal.h"
|
||||
#include "interception/interception.h"
|
||||
#include "sanitizer_common/sanitizer_platform_interceptors.h"
|
||||
|
||||
// Use macro to describe if specific function should be
|
||||
// intercepted on a given platform.
|
||||
#if !SANITIZER_WINDOWS
|
||||
# define ASAN_INTERCEPT_ATOLL_AND_STRTOLL 1
|
||||
# define ASAN_INTERCEPT__LONGJMP 1
|
||||
# define ASAN_INTERCEPT_STRDUP 1
|
||||
# define ASAN_INTERCEPT_INDEX 1
|
||||
# define ASAN_INTERCEPT_PTHREAD_CREATE 1
|
||||
# define ASAN_INTERCEPT_FORK 1
|
||||
#else
|
||||
# define ASAN_INTERCEPT_ATOLL_AND_STRTOLL 0
|
||||
# define ASAN_INTERCEPT__LONGJMP 0
|
||||
# define ASAN_INTERCEPT_STRDUP 0
|
||||
# define ASAN_INTERCEPT_INDEX 0
|
||||
# define ASAN_INTERCEPT_PTHREAD_CREATE 0
|
||||
# define ASAN_INTERCEPT_FORK 0
|
||||
#endif
|
||||
|
||||
#if SANITIZER_FREEBSD || SANITIZER_LINUX
|
||||
# define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 1
|
||||
#else
|
||||
# define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 0
|
||||
#endif
|
||||
|
||||
#if !SANITIZER_MAC
|
||||
# define ASAN_INTERCEPT_STRNLEN 1
|
||||
#else
|
||||
# define ASAN_INTERCEPT_STRNLEN 0
|
||||
#endif
|
||||
|
||||
#if SANITIZER_LINUX && !SANITIZER_ANDROID
|
||||
# define ASAN_INTERCEPT_SWAPCONTEXT 1
|
||||
#else
|
||||
# define ASAN_INTERCEPT_SWAPCONTEXT 0
|
||||
#endif
|
||||
|
||||
#if !SANITIZER_WINDOWS
|
||||
# define ASAN_INTERCEPT_SIGNAL_AND_SIGACTION 1
|
||||
#else
|
||||
# define ASAN_INTERCEPT_SIGNAL_AND_SIGACTION 0
|
||||
#endif
|
||||
|
||||
#if !SANITIZER_WINDOWS
|
||||
# define ASAN_INTERCEPT_SIGLONGJMP 1
|
||||
#else
|
||||
# define ASAN_INTERCEPT_SIGLONGJMP 0
|
||||
#endif
|
||||
|
||||
// Android bug: https://code.google.com/p/android/issues/detail?id=61799
|
||||
#if ASAN_HAS_EXCEPTIONS && !SANITIZER_WINDOWS && \
|
||||
!(SANITIZER_ANDROID && defined(__i386))
|
||||
# define ASAN_INTERCEPT___CXA_THROW 1
|
||||
#else
|
||||
# define ASAN_INTERCEPT___CXA_THROW 0
|
||||
#endif
|
||||
|
||||
#if !SANITIZER_WINDOWS
|
||||
# define ASAN_INTERCEPT___CXA_ATEXIT 1
|
||||
#else
|
||||
# define ASAN_INTERCEPT___CXA_ATEXIT 0
|
||||
#endif
|
||||
|
||||
DECLARE_REAL(int, memcmp, const void *a1, const void *a2, uptr size)
|
||||
DECLARE_REAL(void*, memcpy, void *to, const void *from, uptr size)
|
||||
DECLARE_REAL(void*, memset, void *block, int c, uptr size)
|
||||
DECLARE_REAL(char*, strchr, const char *str, int c)
|
||||
DECLARE_REAL(uptr, strlen, const char *s)
|
||||
DECLARE_REAL(SIZE_T, strlen, const char *s)
|
||||
DECLARE_REAL(char*, strncpy, char *to, const char *from, uptr size)
|
||||
DECLARE_REAL(uptr, strnlen, const char *s, uptr maxlen)
|
||||
DECLARE_REAL(char*, strstr, const char *s1, const char *s2)
|
||||
@ -33,6 +96,13 @@ namespace __asan {
|
||||
|
||||
void InitializeAsanInterceptors();
|
||||
|
||||
#define ENSURE_ASAN_INITED() do { \
|
||||
CHECK(!asan_init_is_running); \
|
||||
if (UNLIKELY(!asan_inited)) { \
|
||||
AsanInitFromRtl(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
#endif // ASAN_INTERCEPTORS_H
|
||||
|
@ -17,21 +17,24 @@
|
||||
|
||||
#include "sanitizer_common/sanitizer_internal_defs.h"
|
||||
|
||||
#include "asan_init_version.h"
|
||||
|
||||
using __sanitizer::uptr;
|
||||
|
||||
extern "C" {
|
||||
// This function should be called at the very beginning of the process,
|
||||
// before any instrumented code is executed and before any call to malloc.
|
||||
// Everytime the asan ABI changes we also change the version number in this
|
||||
// name. Objects build with incompatible asan ABI version
|
||||
// will not link with run-time.
|
||||
// Changes between ABI versions:
|
||||
// v1=>v2: added 'module_name' to __asan_global
|
||||
// v2=>v3: stack frame description (created by the compiler)
|
||||
// contains the function PC as the 3-rd field (see
|
||||
// DescribeAddressIfStack).
|
||||
SANITIZER_INTERFACE_ATTRIBUTE void __asan_init_v3();
|
||||
#define __asan_init __asan_init_v3
|
||||
// Please note that __asan_init is a macro that is replaced with
|
||||
// __asan_init_vXXX at compile-time.
|
||||
SANITIZER_INTERFACE_ATTRIBUTE void __asan_init();
|
||||
|
||||
// This structure is used to describe the source location of a place where
|
||||
// global was defined.
|
||||
struct __asan_global_source_location {
|
||||
const char *filename;
|
||||
int line_no;
|
||||
int column_no;
|
||||
};
|
||||
|
||||
// This structure describes an instrumented global variable.
|
||||
struct __asan_global {
|
||||
@ -42,6 +45,8 @@ extern "C" {
|
||||
const char *module_name; // Module name as a C string. This pointer is a
|
||||
// unique identifier of a module.
|
||||
uptr has_dynamic_init; // Non-zero if the global has dynamic initializer.
|
||||
__asan_global_source_location *location; // Source location of a global,
|
||||
// or NULL if it is unknown.
|
||||
};
|
||||
|
||||
// These two functions should be called by the instrumented code.
|
||||
@ -77,7 +82,7 @@ extern "C" {
|
||||
void __asan_unpoison_memory_region(void const volatile *addr, uptr size);
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
bool __asan_address_is_poisoned(void const volatile *addr);
|
||||
int __asan_address_is_poisoned(void const volatile *addr);
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
uptr __asan_region_is_poisoned(uptr beg, uptr size);
|
||||
@ -85,9 +90,42 @@ extern "C" {
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void __asan_describe_address(uptr addr);
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
int __asan_report_present();
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
uptr __asan_get_report_pc();
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
uptr __asan_get_report_bp();
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
uptr __asan_get_report_sp();
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
uptr __asan_get_report_address();
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
int __asan_get_report_access_type();
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
uptr __asan_get_report_access_size();
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
const char * __asan_get_report_description();
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
const char * __asan_locate_address(uptr addr, char *name, uptr name_size,
|
||||
uptr *region_address, uptr *region_size);
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
uptr __asan_get_alloc_stack(uptr addr, uptr *trace, uptr size,
|
||||
u32 *thread_id);
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
uptr __asan_get_free_stack(uptr addr, uptr *trace, uptr size,
|
||||
u32 *thread_id);
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void __asan_get_shadow_mapping(uptr *shadow_scale, uptr *shadow_offset);
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void __asan_report_error(uptr pc, uptr bp, uptr sp,
|
||||
uptr addr, bool is_write, uptr access_size);
|
||||
uptr addr, int is_write, uptr access_size);
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
int __asan_set_error_exit_code(int exit_code);
|
||||
@ -99,32 +137,46 @@ extern "C" {
|
||||
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
|
||||
/* OPTIONAL */ void __asan_on_error();
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
|
||||
/* OPTIONAL */ bool __asan_symbolize(const void *pc, char *out_buffer,
|
||||
int out_size);
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
uptr __asan_get_estimated_allocated_size(uptr size);
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE bool __asan_get_ownership(const void *p);
|
||||
SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_allocated_size(const void *p);
|
||||
SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_current_allocated_bytes();
|
||||
SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_heap_size();
|
||||
SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_free_bytes();
|
||||
SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_unmapped_bytes();
|
||||
SANITIZER_INTERFACE_ATTRIBUTE void __asan_print_accumulated_stats();
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
|
||||
/* OPTIONAL */ const char* __asan_default_options();
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
|
||||
/* OPTIONAL */ void __asan_malloc_hook(void *ptr, uptr size);
|
||||
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
|
||||
/* OPTIONAL */ void __asan_free_hook(void *ptr);
|
||||
|
||||
// Global flag, copy of ASAN_OPTIONS=detect_stack_use_after_return
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
extern int __asan_option_detect_stack_use_after_return;
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
extern uptr *__asan_test_only_reported_buggy_pointer;
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE void __asan_load1(uptr p);
|
||||
SANITIZER_INTERFACE_ATTRIBUTE void __asan_load2(uptr p);
|
||||
SANITIZER_INTERFACE_ATTRIBUTE void __asan_load4(uptr p);
|
||||
SANITIZER_INTERFACE_ATTRIBUTE void __asan_load8(uptr p);
|
||||
SANITIZER_INTERFACE_ATTRIBUTE void __asan_load16(uptr p);
|
||||
SANITIZER_INTERFACE_ATTRIBUTE void __asan_store1(uptr p);
|
||||
SANITIZER_INTERFACE_ATTRIBUTE void __asan_store2(uptr p);
|
||||
SANITIZER_INTERFACE_ATTRIBUTE void __asan_store4(uptr p);
|
||||
SANITIZER_INTERFACE_ATTRIBUTE void __asan_store8(uptr p);
|
||||
SANITIZER_INTERFACE_ATTRIBUTE void __asan_store16(uptr p);
|
||||
SANITIZER_INTERFACE_ATTRIBUTE void __asan_loadN(uptr p, uptr size);
|
||||
SANITIZER_INTERFACE_ATTRIBUTE void __asan_storeN(uptr p, uptr size);
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void* __asan_memcpy(void *dst, const void *src, uptr size);
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void* __asan_memset(void *s, int c, uptr n);
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void* __asan_memmove(void* dest, const void* src, uptr n);
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void __asan_poison_cxx_array_cookie(uptr p);
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
uptr __asan_load_cxx_array_cookie(uptr *p);
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void __asan_poison_intra_object_redzone(uptr p, uptr size);
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void __asan_unpoison_intra_object_redzone(uptr p, uptr size);
|
||||
} // extern "C"
|
||||
|
||||
#endif // ASAN_INTERFACE_INTERNAL_H
|
||||
|
@ -30,26 +30,11 @@
|
||||
|
||||
// Build-time configuration options.
|
||||
|
||||
// If set, asan will install its own SEGV signal handler.
|
||||
#ifndef ASAN_NEEDS_SEGV
|
||||
# if SANITIZER_ANDROID == 1
|
||||
# define ASAN_NEEDS_SEGV 0
|
||||
# else
|
||||
# define ASAN_NEEDS_SEGV 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// If set, asan will intercept C++ exception api call(s).
|
||||
#ifndef ASAN_HAS_EXCEPTIONS
|
||||
# define ASAN_HAS_EXCEPTIONS 1
|
||||
#endif
|
||||
|
||||
// If set, asan uses the values of SHADOW_SCALE and SHADOW_OFFSET
|
||||
// provided by the instrumented objects. Otherwise constants are used.
|
||||
#ifndef ASAN_FLEXIBLE_MAPPING_AND_OFFSET
|
||||
# define ASAN_FLEXIBLE_MAPPING_AND_OFFSET 0
|
||||
#endif
|
||||
|
||||
// If set, values like allocator chunk size, as well as defaults for some flags
|
||||
// will be changed towards less memory overhead.
|
||||
#ifndef ASAN_LOW_MEMORY
|
||||
@ -60,36 +45,56 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef ASAN_USE_PREINIT_ARRAY
|
||||
# define ASAN_USE_PREINIT_ARRAY (SANITIZER_LINUX && !SANITIZER_ANDROID)
|
||||
#ifndef ASAN_DYNAMIC
|
||||
# ifdef PIC
|
||||
# define ASAN_DYNAMIC 1
|
||||
# else
|
||||
# define ASAN_DYNAMIC 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// All internal functions in asan reside inside the __asan namespace
|
||||
// to avoid namespace collisions with the user programs.
|
||||
// Seperate namespace also makes it simpler to distinguish the asan run-time
|
||||
// Separate namespace also makes it simpler to distinguish the asan run-time
|
||||
// functions from the instrumented user code in a profile.
|
||||
namespace __asan {
|
||||
|
||||
class AsanThread;
|
||||
using __sanitizer::StackTrace;
|
||||
|
||||
struct SignalContext {
|
||||
void *context;
|
||||
uptr addr;
|
||||
uptr pc;
|
||||
uptr sp;
|
||||
uptr bp;
|
||||
|
||||
SignalContext(void *context, uptr addr, uptr pc, uptr sp, uptr bp) :
|
||||
context(context), addr(addr), pc(pc), sp(sp), bp(bp) {
|
||||
}
|
||||
|
||||
// Creates signal context in a platform-specific manner.
|
||||
static SignalContext Create(void *siginfo, void *context);
|
||||
};
|
||||
|
||||
void AsanInitFromRtl();
|
||||
|
||||
// asan_rtl.cc
|
||||
void NORETURN ShowStatsAndAbort();
|
||||
|
||||
void ReplaceOperatorsNewAndDelete();
|
||||
// asan_malloc_linux.cc / asan_malloc_mac.cc
|
||||
void ReplaceSystemMalloc();
|
||||
|
||||
// asan_linux.cc / asan_mac.cc / asan_win.cc
|
||||
void *AsanDoesNotSupportStaticLinkage();
|
||||
void AsanCheckDynamicRTPrereqs();
|
||||
void AsanCheckIncompatibleRT();
|
||||
|
||||
void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp);
|
||||
void AsanOnSIGSEGV(int, void *siginfo, void *context);
|
||||
|
||||
void MaybeReexec();
|
||||
bool AsanInterceptsSignal(int signum);
|
||||
void SetAlternateSignalStack();
|
||||
void UnsetAlternateSignalStack();
|
||||
void InstallSignalHandlers();
|
||||
void ReadContextStack(void *context, uptr *stack, uptr *ssize);
|
||||
void AsanPlatformThreadInit();
|
||||
void StopInitOrderChecking();
|
||||
@ -102,7 +107,11 @@ void PlatformTSDDtor(void *tsd);
|
||||
|
||||
void AppendToErrorMessageBuffer(const char *buffer);
|
||||
|
||||
// Platfrom-specific options.
|
||||
void ParseExtraActivationFlags();
|
||||
|
||||
void *AsanDlSymNext(const char *sym);
|
||||
|
||||
// Platform-specific options.
|
||||
#if SANITIZER_MAC
|
||||
bool PlatformHasDifferentMemcpyAndMemmove();
|
||||
# define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE \
|
||||
@ -114,9 +123,9 @@ bool PlatformHasDifferentMemcpyAndMemmove();
|
||||
// Add convenient macro for interface functions that may be represented as
|
||||
// weak hooks.
|
||||
#define ASAN_MALLOC_HOOK(ptr, size) \
|
||||
if (&__asan_malloc_hook) __asan_malloc_hook(ptr, size)
|
||||
if (&__sanitizer_malloc_hook) __sanitizer_malloc_hook(ptr, size)
|
||||
#define ASAN_FREE_HOOK(ptr) \
|
||||
if (&__asan_free_hook) __asan_free_hook(ptr)
|
||||
if (&__sanitizer_free_hook) __sanitizer_free_hook(ptr)
|
||||
#define ASAN_ON_ERROR() \
|
||||
if (&__asan_on_error) __asan_on_error()
|
||||
|
||||
@ -136,9 +145,14 @@ const int kAsanStackPartialRedzoneMagic = 0xf4;
|
||||
const int kAsanStackAfterReturnMagic = 0xf5;
|
||||
const int kAsanInitializationOrderMagic = 0xf6;
|
||||
const int kAsanUserPoisonedMemoryMagic = 0xf7;
|
||||
const int kAsanContiguousContainerOOBMagic = 0xfc;
|
||||
const int kAsanStackUseAfterScopeMagic = 0xf8;
|
||||
const int kAsanGlobalRedzoneMagic = 0xf9;
|
||||
const int kAsanInternalHeapMagic = 0xfe;
|
||||
const int kAsanArrayCookieMagic = 0xac;
|
||||
const int kAsanIntraObjectRedzone = 0xbb;
|
||||
const int kAsanAllocaLeftMagic = 0xca;
|
||||
const int kAsanAllocaRightMagic = 0xcb;
|
||||
|
||||
static const uptr kCurrentStackFrameMagic = 0x41B58AB3;
|
||||
static const uptr kRetiredStackFrameMagic = 0x45E0360E;
|
||||
|
@ -13,11 +13,13 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "sanitizer_common/sanitizer_platform.h"
|
||||
#if SANITIZER_LINUX
|
||||
#if SANITIZER_FREEBSD || SANITIZER_LINUX
|
||||
|
||||
#include "asan_interceptors.h"
|
||||
#include "asan_internal.h"
|
||||
#include "asan_thread.h"
|
||||
#include "sanitizer_common/sanitizer_flags.h"
|
||||
#include "sanitizer_common/sanitizer_freebsd.h"
|
||||
#include "sanitizer_common/sanitizer_libc.h"
|
||||
#include "sanitizer_common/sanitizer_procmaps.h"
|
||||
|
||||
@ -26,18 +28,43 @@
|
||||
#include <sys/mman.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/types.h>
|
||||
#include <dlfcn.h>
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <unwind.h>
|
||||
|
||||
#if !SANITIZER_ANDROID
|
||||
// FIXME: where to get ucontext on Android?
|
||||
#include <sys/ucontext.h>
|
||||
#if SANITIZER_FREEBSD
|
||||
#include <sys/link_elf.h>
|
||||
#endif
|
||||
|
||||
#if SANITIZER_ANDROID || SANITIZER_FREEBSD
|
||||
#include <ucontext.h>
|
||||
extern "C" void* _DYNAMIC;
|
||||
#else
|
||||
#include <sys/ucontext.h>
|
||||
#include <link.h>
|
||||
#endif
|
||||
|
||||
// x86-64 FreeBSD 9.2 and older define 'ucontext_t' incorrectly in
|
||||
// 32-bit mode.
|
||||
#if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32) && \
|
||||
__FreeBSD_version <= 902001 // v9.2
|
||||
#define ucontext_t xucontext_t
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
ASAN_RT_VERSION_UNDEFINED = 0,
|
||||
ASAN_RT_VERSION_DYNAMIC,
|
||||
ASAN_RT_VERSION_STATIC,
|
||||
} asan_rt_version_t;
|
||||
|
||||
// FIXME: perhaps also store abi version here?
|
||||
extern "C" {
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
asan_rt_version_t __asan_rt_version;
|
||||
}
|
||||
|
||||
namespace __asan {
|
||||
|
||||
@ -50,38 +77,126 @@ void *AsanDoesNotSupportStaticLinkage() {
|
||||
return &_DYNAMIC; // defined in link.h
|
||||
}
|
||||
|
||||
void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
|
||||
#if SANITIZER_ANDROID
|
||||
*pc = *sp = *bp = 0;
|
||||
#elif defined(__arm__)
|
||||
// FIXME: should we do anything for Android?
|
||||
void AsanCheckDynamicRTPrereqs() {}
|
||||
void AsanCheckIncompatibleRT() {}
|
||||
#else
|
||||
static int FindFirstDSOCallback(struct dl_phdr_info *info, size_t size,
|
||||
void *data) {
|
||||
// Continue until the first dynamic library is found
|
||||
if (!info->dlpi_name || info->dlpi_name[0] == 0)
|
||||
return 0;
|
||||
|
||||
// Ignore vDSO
|
||||
if (internal_strncmp(info->dlpi_name, "linux-", sizeof("linux-") - 1) == 0)
|
||||
return 0;
|
||||
|
||||
*(const char **)data = info->dlpi_name;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool IsDynamicRTName(const char *libname) {
|
||||
return internal_strstr(libname, "libclang_rt.asan") ||
|
||||
internal_strstr(libname, "libasan.so");
|
||||
}
|
||||
|
||||
static void ReportIncompatibleRT() {
|
||||
Report("Your application is linked against incompatible ASan runtimes.\n");
|
||||
Die();
|
||||
}
|
||||
|
||||
void AsanCheckDynamicRTPrereqs() {
|
||||
// Ensure that dynamic RT is the first DSO in the list
|
||||
const char *first_dso_name = 0;
|
||||
dl_iterate_phdr(FindFirstDSOCallback, &first_dso_name);
|
||||
if (first_dso_name && !IsDynamicRTName(first_dso_name)) {
|
||||
Report("ASan runtime does not come first in initial library list; "
|
||||
"you should either link runtime to your application or "
|
||||
"manually preload it with LD_PRELOAD.\n");
|
||||
Die();
|
||||
}
|
||||
}
|
||||
|
||||
void AsanCheckIncompatibleRT() {
|
||||
if (ASAN_DYNAMIC) {
|
||||
if (__asan_rt_version == ASAN_RT_VERSION_UNDEFINED) {
|
||||
__asan_rt_version = ASAN_RT_VERSION_DYNAMIC;
|
||||
} else if (__asan_rt_version != ASAN_RT_VERSION_DYNAMIC) {
|
||||
ReportIncompatibleRT();
|
||||
}
|
||||
} else {
|
||||
if (__asan_rt_version == ASAN_RT_VERSION_UNDEFINED) {
|
||||
// Ensure that dynamic runtime is not present. We should detect it
|
||||
// as early as possible, otherwise ASan interceptors could bind to
|
||||
// the functions in dynamic ASan runtime instead of the functions in
|
||||
// system libraries, causing crashes later in ASan initialization.
|
||||
MemoryMappingLayout proc_maps(/*cache_enabled*/true);
|
||||
char filename[128];
|
||||
while (proc_maps.Next(0, 0, 0, filename, sizeof(filename), 0)) {
|
||||
if (IsDynamicRTName(filename)) {
|
||||
Report("Your application is linked against "
|
||||
"incompatible ASan runtimes.\n");
|
||||
Die();
|
||||
}
|
||||
}
|
||||
__asan_rt_version = ASAN_RT_VERSION_STATIC;
|
||||
} else if (__asan_rt_version != ASAN_RT_VERSION_STATIC) {
|
||||
ReportIncompatibleRT();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // SANITIZER_ANDROID
|
||||
|
||||
void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
|
||||
#if defined(__arm__)
|
||||
ucontext_t *ucontext = (ucontext_t*)context;
|
||||
*pc = ucontext->uc_mcontext.arm_pc;
|
||||
*bp = ucontext->uc_mcontext.arm_fp;
|
||||
*sp = ucontext->uc_mcontext.arm_sp;
|
||||
# elif defined(__hppa__)
|
||||
#elif defined(__aarch64__)
|
||||
ucontext_t *ucontext = (ucontext_t*)context;
|
||||
*pc = ucontext->uc_mcontext.pc;
|
||||
*bp = ucontext->uc_mcontext.regs[29];
|
||||
*sp = ucontext->uc_mcontext.sp;
|
||||
#elif defined(__hppa__)
|
||||
ucontext_t *ucontext = (ucontext_t*)context;
|
||||
*pc = ucontext->uc_mcontext.sc_iaoq[0];
|
||||
/* GCC uses %r3 whenever a frame pointer is needed. */
|
||||
*bp = ucontext->uc_mcontext.sc_gr[3];
|
||||
*sp = ucontext->uc_mcontext.sc_gr[30];
|
||||
# elif defined(__x86_64__)
|
||||
#elif defined(__x86_64__)
|
||||
# if SANITIZER_FREEBSD
|
||||
ucontext_t *ucontext = (ucontext_t*)context;
|
||||
*pc = ucontext->uc_mcontext.mc_rip;
|
||||
*bp = ucontext->uc_mcontext.mc_rbp;
|
||||
*sp = ucontext->uc_mcontext.mc_rsp;
|
||||
# else
|
||||
ucontext_t *ucontext = (ucontext_t*)context;
|
||||
*pc = ucontext->uc_mcontext.gregs[REG_RIP];
|
||||
*bp = ucontext->uc_mcontext.gregs[REG_RBP];
|
||||
*sp = ucontext->uc_mcontext.gregs[REG_RSP];
|
||||
# elif defined(__i386__)
|
||||
# endif
|
||||
#elif defined(__i386__)
|
||||
# if SANITIZER_FREEBSD
|
||||
ucontext_t *ucontext = (ucontext_t*)context;
|
||||
*pc = ucontext->uc_mcontext.mc_eip;
|
||||
*bp = ucontext->uc_mcontext.mc_ebp;
|
||||
*sp = ucontext->uc_mcontext.mc_esp;
|
||||
# else
|
||||
ucontext_t *ucontext = (ucontext_t*)context;
|
||||
*pc = ucontext->uc_mcontext.gregs[REG_EIP];
|
||||
*bp = ucontext->uc_mcontext.gregs[REG_EBP];
|
||||
*sp = ucontext->uc_mcontext.gregs[REG_ESP];
|
||||
# elif defined(__powerpc__) || defined(__powerpc64__)
|
||||
# endif
|
||||
#elif defined(__powerpc__) || defined(__powerpc64__)
|
||||
ucontext_t *ucontext = (ucontext_t*)context;
|
||||
*pc = ucontext->uc_mcontext.regs->nip;
|
||||
*sp = ucontext->uc_mcontext.regs->gpr[PT_R1];
|
||||
// The powerpc{,64}-linux ABIs do not specify r31 as the frame
|
||||
// pointer, but GCC always uses r31 when we need a frame pointer.
|
||||
*bp = ucontext->uc_mcontext.regs->gpr[PT_R31];
|
||||
# elif defined(__sparc__)
|
||||
#elif defined(__sparc__)
|
||||
ucontext_t *ucontext = (ucontext_t*)context;
|
||||
uptr *stk_ptr;
|
||||
# if defined (__arch64__)
|
||||
@ -95,7 +210,7 @@ void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
|
||||
stk_ptr = (uptr *) *sp;
|
||||
*bp = stk_ptr[15];
|
||||
# endif
|
||||
# elif defined(__mips__)
|
||||
#elif defined(__mips__)
|
||||
ucontext_t *ucontext = (ucontext_t*)context;
|
||||
*pc = ucontext->uc_mcontext.gregs[31];
|
||||
*bp = ucontext->uc_mcontext.gregs[30];
|
||||
@ -106,7 +221,7 @@ void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
|
||||
}
|
||||
|
||||
bool AsanInterceptsSignal(int signum) {
|
||||
return signum == SIGSEGV && flags()->handle_segv;
|
||||
return signum == SIGSEGV && common_flags()->handle_segv;
|
||||
}
|
||||
|
||||
void AsanPlatformThreadInit() {
|
||||
@ -125,6 +240,10 @@ void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
|
||||
}
|
||||
#endif
|
||||
|
||||
void *AsanDlSymNext(const char *sym) {
|
||||
return dlsym(RTLD_NEXT, sym);
|
||||
}
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
#endif // SANITIZER_LINUX
|
||||
#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
|
||||
|
@ -17,12 +17,12 @@
|
||||
|
||||
#include "asan_interceptors.h"
|
||||
#include "asan_internal.h"
|
||||
#include "asan_mac.h"
|
||||
#include "asan_mapping.h"
|
||||
#include "asan_stack.h"
|
||||
#include "asan_thread.h"
|
||||
#include "sanitizer_common/sanitizer_atomic.h"
|
||||
#include "sanitizer_common/sanitizer_libc.h"
|
||||
#include "sanitizer_common/sanitizer_mac.h"
|
||||
|
||||
#include <crt_externs.h> // for _NSGetArgv
|
||||
#include <dlfcn.h> // for dladdr()
|
||||
@ -53,43 +53,6 @@ void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
|
||||
# endif // SANITIZER_WORDSIZE
|
||||
}
|
||||
|
||||
MacosVersion cached_macos_version = MACOS_VERSION_UNINITIALIZED;
|
||||
|
||||
MacosVersion GetMacosVersionInternal() {
|
||||
int mib[2] = { CTL_KERN, KERN_OSRELEASE };
|
||||
char version[100];
|
||||
uptr len = 0, maxlen = sizeof(version) / sizeof(version[0]);
|
||||
for (uptr i = 0; i < maxlen; i++) version[i] = '\0';
|
||||
// Get the version length.
|
||||
CHECK_NE(sysctl(mib, 2, 0, &len, 0, 0), -1);
|
||||
CHECK_LT(len, maxlen);
|
||||
CHECK_NE(sysctl(mib, 2, version, &len, 0, 0), -1);
|
||||
switch (version[0]) {
|
||||
case '9': return MACOS_VERSION_LEOPARD;
|
||||
case '1': {
|
||||
switch (version[1]) {
|
||||
case '0': return MACOS_VERSION_SNOW_LEOPARD;
|
||||
case '1': return MACOS_VERSION_LION;
|
||||
case '2': return MACOS_VERSION_MOUNTAIN_LION;
|
||||
case '3': return MACOS_VERSION_MAVERICKS;
|
||||
default: return MACOS_VERSION_UNKNOWN;
|
||||
}
|
||||
}
|
||||
default: return MACOS_VERSION_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
MacosVersion GetMacosVersion() {
|
||||
atomic_uint32_t *cache =
|
||||
reinterpret_cast<atomic_uint32_t*>(&cached_macos_version);
|
||||
MacosVersion result =
|
||||
static_cast<MacosVersion>(atomic_load(cache, memory_order_acquire));
|
||||
if (result == MACOS_VERSION_UNINITIALIZED) {
|
||||
result = GetMacosVersionInternal();
|
||||
atomic_store(cache, result, memory_order_release);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool PlatformHasDifferentMemcpyAndMemmove() {
|
||||
// On OS X 10.7 memcpy() and memmove() are both resolved
|
||||
@ -151,7 +114,7 @@ void MaybeReexec() {
|
||||
internal_strlen(dyld_insert_libraries) : 0;
|
||||
uptr fname_len = internal_strlen(info.dli_fname);
|
||||
if (!dyld_insert_libraries ||
|
||||
!REAL(strstr)(dyld_insert_libraries, info.dli_fname)) {
|
||||
!REAL(strstr)(dyld_insert_libraries, StripModuleName(info.dli_fname))) {
|
||||
// DYLD_INSERT_LIBRARIES is not set or does not contain the runtime
|
||||
// library.
|
||||
char program_name[1024];
|
||||
@ -174,12 +137,10 @@ void MaybeReexec() {
|
||||
// Set DYLD_INSERT_LIBRARIES equal to the runtime dylib name.
|
||||
setenv(kDyldInsertLibraries, info.dli_fname, /*overwrite*/0);
|
||||
}
|
||||
if (common_flags()->verbosity >= 1) {
|
||||
Report("exec()-ing the program with\n");
|
||||
Report("%s=%s\n", kDyldInsertLibraries, new_env);
|
||||
Report("to enable ASan wrappers.\n");
|
||||
Report("Set ASAN_OPTIONS=allow_reexec=0 to disable this.\n");
|
||||
}
|
||||
VReport(1, "exec()-ing the program with\n");
|
||||
VReport(1, "%s=%s\n", kDyldInsertLibraries, new_env);
|
||||
VReport(1, "to enable ASan wrappers.\n");
|
||||
VReport(1, "Set ASAN_OPTIONS=allow_reexec=0 to disable this.\n");
|
||||
execv(program_name, *_NSGetArgv());
|
||||
} else {
|
||||
// DYLD_INSERT_LIBRARIES is set and contains the runtime library.
|
||||
@ -238,8 +199,15 @@ void *AsanDoesNotSupportStaticLinkage() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// No-op. Mac does not support static linkage anyway.
|
||||
void AsanCheckDynamicRTPrereqs() {}
|
||||
|
||||
// No-op. Mac does not support static linkage anyway.
|
||||
void AsanCheckIncompatibleRT() {}
|
||||
|
||||
bool AsanInterceptsSignal(int signum) {
|
||||
return (signum == SIGSEGV || signum == SIGBUS) && flags()->handle_segv;
|
||||
return (signum == SIGSEGV || signum == SIGBUS) &&
|
||||
common_flags()->handle_segv;
|
||||
}
|
||||
|
||||
void AsanPlatformThreadInit() {
|
||||
@ -296,9 +264,8 @@ ALWAYS_INLINE
|
||||
void asan_register_worker_thread(int parent_tid, StackTrace *stack) {
|
||||
AsanThread *t = GetCurrentThread();
|
||||
if (!t) {
|
||||
t = AsanThread::Create(0, 0);
|
||||
CreateThreadContextArgs args = { t, stack };
|
||||
asanThreadRegistry().CreateThread(*(uptr*)t, true, parent_tid, &args);
|
||||
t = AsanThread::Create(/* start_routine */ nullptr, /* arg */ nullptr,
|
||||
parent_tid, stack, /* detached */ true);
|
||||
t->Init();
|
||||
asanThreadRegistry().StartThread(t->tid(), 0, 0);
|
||||
SetCurrentThread(t);
|
||||
@ -311,11 +278,10 @@ extern "C"
|
||||
void asan_dispatch_call_block_and_release(void *block) {
|
||||
GET_STACK_TRACE_THREAD;
|
||||
asan_block_context_t *context = (asan_block_context_t*)block;
|
||||
if (common_flags()->verbosity >= 2) {
|
||||
Report("asan_dispatch_call_block_and_release(): "
|
||||
VReport(2,
|
||||
"asan_dispatch_call_block_and_release(): "
|
||||
"context: %p, pthread_self: %p\n",
|
||||
block, pthread_self());
|
||||
}
|
||||
asan_register_worker_thread(context->parent_tid, &stack);
|
||||
// Call the original dispatcher for the block.
|
||||
context->func(context->block);
|
||||
@ -330,7 +296,7 @@ using namespace __asan; // NOLINT
|
||||
// The caller retains control of the allocated context.
|
||||
extern "C"
|
||||
asan_block_context_t *alloc_asan_context(void *ctxt, dispatch_function_t func,
|
||||
StackTrace *stack) {
|
||||
BufferedStackTrace *stack) {
|
||||
asan_block_context_t *asan_ctxt =
|
||||
(asan_block_context_t*) asan_malloc(sizeof(asan_block_context_t), stack);
|
||||
asan_ctxt->block = ctxt;
|
||||
@ -388,7 +354,6 @@ INTERCEPTOR(void, dispatch_group_async_f, dispatch_group_t group,
|
||||
|
||||
#if !defined(MISSING_BLOCKS_SUPPORT)
|
||||
extern "C" {
|
||||
// FIXME: consolidate these declarations with asan_intercepted_functions.h.
|
||||
void dispatch_async(dispatch_queue_t dq, void(^work)(void));
|
||||
void dispatch_group_async(dispatch_group_t dg, dispatch_queue_t dq,
|
||||
void(^work)(void));
|
||||
@ -408,32 +373,44 @@ void dispatch_source_set_event_handler(dispatch_source_t ds, void(^work)(void));
|
||||
work(); \
|
||||
}
|
||||
|
||||
// Forces the compiler to generate a frame pointer in the function.
|
||||
#define ENABLE_FRAME_POINTER \
|
||||
do { \
|
||||
volatile uptr enable_fp; \
|
||||
enable_fp = GET_CURRENT_FRAME(); \
|
||||
} while (0)
|
||||
|
||||
INTERCEPTOR(void, dispatch_async,
|
||||
dispatch_queue_t dq, void(^work)(void)) {
|
||||
ENABLE_FRAME_POINTER;
|
||||
GET_ASAN_BLOCK(work);
|
||||
REAL(dispatch_async)(dq, asan_block);
|
||||
}
|
||||
|
||||
INTERCEPTOR(void, dispatch_group_async,
|
||||
dispatch_group_t dg, dispatch_queue_t dq, void(^work)(void)) {
|
||||
ENABLE_FRAME_POINTER;
|
||||
GET_ASAN_BLOCK(work);
|
||||
REAL(dispatch_group_async)(dg, dq, asan_block);
|
||||
}
|
||||
|
||||
INTERCEPTOR(void, dispatch_after,
|
||||
dispatch_time_t when, dispatch_queue_t queue, void(^work)(void)) {
|
||||
ENABLE_FRAME_POINTER;
|
||||
GET_ASAN_BLOCK(work);
|
||||
REAL(dispatch_after)(when, queue, asan_block);
|
||||
}
|
||||
|
||||
INTERCEPTOR(void, dispatch_source_set_cancel_handler,
|
||||
dispatch_source_t ds, void(^work)(void)) {
|
||||
ENABLE_FRAME_POINTER;
|
||||
GET_ASAN_BLOCK(work);
|
||||
REAL(dispatch_source_set_cancel_handler)(ds, asan_block);
|
||||
}
|
||||
|
||||
INTERCEPTOR(void, dispatch_source_set_event_handler,
|
||||
dispatch_source_t ds, void(^work)(void)) {
|
||||
ENABLE_FRAME_POINTER;
|
||||
GET_ASAN_BLOCK(work);
|
||||
REAL(dispatch_source_set_event_handler)(ds, asan_block);
|
||||
}
|
||||
|
@ -1,59 +0,0 @@
|
||||
//===-- asan_mac.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 AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// Mac-specific ASan definitions.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef ASAN_MAC_H
|
||||
#define ASAN_MAC_H
|
||||
|
||||
// CF_RC_BITS, the layout of CFRuntimeBase and __CFStrIsConstant are internal
|
||||
// and subject to change in further CoreFoundation versions. Apple does not
|
||||
// guarantee any binary compatibility from release to release.
|
||||
|
||||
// See http://opensource.apple.com/source/CF/CF-635.15/CFInternal.h
|
||||
#if defined(__BIG_ENDIAN__)
|
||||
#define CF_RC_BITS 0
|
||||
#endif
|
||||
|
||||
#if defined(__LITTLE_ENDIAN__)
|
||||
#define CF_RC_BITS 3
|
||||
#endif
|
||||
|
||||
// See http://opensource.apple.com/source/CF/CF-635.15/CFRuntime.h
|
||||
typedef struct __CFRuntimeBase {
|
||||
uptr _cfisa;
|
||||
u8 _cfinfo[4];
|
||||
#if __LP64__
|
||||
u32 _rc;
|
||||
#endif
|
||||
} CFRuntimeBase;
|
||||
|
||||
enum MacosVersion {
|
||||
MACOS_VERSION_UNINITIALIZED = 0,
|
||||
MACOS_VERSION_UNKNOWN,
|
||||
MACOS_VERSION_LEOPARD,
|
||||
MACOS_VERSION_SNOW_LEOPARD,
|
||||
MACOS_VERSION_LION,
|
||||
MACOS_VERSION_MOUNTAIN_LION,
|
||||
MACOS_VERSION_MAVERICKS
|
||||
};
|
||||
|
||||
// Used by asan_malloc_mac.cc and asan_mac.cc
|
||||
extern "C" void __CFInitialize();
|
||||
|
||||
namespace __asan {
|
||||
|
||||
MacosVersion GetMacosVersion();
|
||||
void MaybeReplaceCFAllocator();
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
#endif // ASAN_MAC_H
|
@ -15,48 +15,14 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "sanitizer_common/sanitizer_platform.h"
|
||||
#if SANITIZER_LINUX
|
||||
#if SANITIZER_FREEBSD || SANITIZER_LINUX
|
||||
|
||||
#include "sanitizer_common/sanitizer_tls_get_addr.h"
|
||||
#include "asan_allocator.h"
|
||||
#include "asan_interceptors.h"
|
||||
#include "asan_internal.h"
|
||||
#include "asan_stack.h"
|
||||
|
||||
#if SANITIZER_ANDROID
|
||||
DECLARE_REAL_AND_INTERCEPTOR(void*, malloc, uptr size)
|
||||
DECLARE_REAL_AND_INTERCEPTOR(void, free, void *ptr)
|
||||
DECLARE_REAL_AND_INTERCEPTOR(void*, calloc, uptr nmemb, uptr size)
|
||||
DECLARE_REAL_AND_INTERCEPTOR(void*, realloc, void *ptr, uptr size)
|
||||
DECLARE_REAL_AND_INTERCEPTOR(void*, memalign, uptr boundary, uptr size)
|
||||
|
||||
struct MallocDebug {
|
||||
void* (*malloc)(uptr bytes);
|
||||
void (*free)(void* mem);
|
||||
void* (*calloc)(uptr n_elements, uptr elem_size);
|
||||
void* (*realloc)(void* oldMem, uptr bytes);
|
||||
void* (*memalign)(uptr alignment, uptr bytes);
|
||||
};
|
||||
|
||||
const MallocDebug asan_malloc_dispatch ALIGNED(32) = {
|
||||
WRAP(malloc), WRAP(free), WRAP(calloc), WRAP(realloc), WRAP(memalign)
|
||||
};
|
||||
|
||||
extern "C" const MallocDebug* __libc_malloc_dispatch;
|
||||
|
||||
namespace __asan {
|
||||
void ReplaceSystemMalloc() {
|
||||
__libc_malloc_dispatch = &asan_malloc_dispatch;
|
||||
}
|
||||
} // namespace __asan
|
||||
|
||||
#else // ANDROID
|
||||
|
||||
namespace __asan {
|
||||
void ReplaceSystemMalloc() {
|
||||
}
|
||||
} // namespace __asan
|
||||
#endif // ANDROID
|
||||
|
||||
// ---------------------- Replacement functions ---------------- {{{1
|
||||
using namespace __asan; // NOLINT
|
||||
|
||||
@ -76,7 +42,7 @@ INTERCEPTOR(void*, malloc, uptr size) {
|
||||
}
|
||||
|
||||
INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
|
||||
if (!asan_inited) {
|
||||
if (UNLIKELY(!asan_inited)) {
|
||||
// Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
|
||||
const uptr kCallocPoolSize = 1024;
|
||||
static uptr calloc_memory_for_dlsym[kCallocPoolSize];
|
||||
@ -101,8 +67,17 @@ INTERCEPTOR(void*, memalign, uptr boundary, uptr size) {
|
||||
return asan_memalign(boundary, size, &stack, FROM_MALLOC);
|
||||
}
|
||||
|
||||
INTERCEPTOR(void*, __libc_memalign, uptr align, uptr s)
|
||||
ALIAS("memalign");
|
||||
INTERCEPTOR(void*, aligned_alloc, uptr boundary, uptr size) {
|
||||
GET_STACK_TRACE_MALLOC;
|
||||
return asan_memalign(boundary, size, &stack, FROM_MALLOC);
|
||||
}
|
||||
|
||||
INTERCEPTOR(void*, __libc_memalign, uptr boundary, uptr size) {
|
||||
GET_STACK_TRACE_MALLOC;
|
||||
void *res = asan_memalign(boundary, size, &stack, FROM_MALLOC);
|
||||
DTLS_on_libc_memalign(res, size * boundary);
|
||||
return res;
|
||||
}
|
||||
|
||||
INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {
|
||||
GET_CURRENT_PC_BP_SP;
|
||||
@ -148,4 +123,64 @@ INTERCEPTOR(void, malloc_stats, void) {
|
||||
__asan_print_accumulated_stats();
|
||||
}
|
||||
|
||||
#endif // SANITIZER_LINUX
|
||||
#if SANITIZER_ANDROID
|
||||
// Format of __libc_malloc_dispatch has changed in Android L.
|
||||
// While we are moving towards a solution that does not depend on bionic
|
||||
// internals, here is something to support both K* and L releases.
|
||||
struct MallocDebugK {
|
||||
void *(*malloc)(uptr bytes);
|
||||
void (*free)(void *mem);
|
||||
void *(*calloc)(uptr n_elements, uptr elem_size);
|
||||
void *(*realloc)(void *oldMem, uptr bytes);
|
||||
void *(*memalign)(uptr alignment, uptr bytes);
|
||||
uptr (*malloc_usable_size)(void *mem);
|
||||
};
|
||||
|
||||
struct MallocDebugL {
|
||||
void *(*calloc)(uptr n_elements, uptr elem_size);
|
||||
void (*free)(void *mem);
|
||||
fake_mallinfo (*mallinfo)(void);
|
||||
void *(*malloc)(uptr bytes);
|
||||
uptr (*malloc_usable_size)(void *mem);
|
||||
void *(*memalign)(uptr alignment, uptr bytes);
|
||||
int (*posix_memalign)(void **memptr, uptr alignment, uptr size);
|
||||
void* (*pvalloc)(uptr size);
|
||||
void *(*realloc)(void *oldMem, uptr bytes);
|
||||
void* (*valloc)(uptr size);
|
||||
};
|
||||
|
||||
ALIGNED(32) const MallocDebugK asan_malloc_dispatch_k = {
|
||||
WRAP(malloc), WRAP(free), WRAP(calloc),
|
||||
WRAP(realloc), WRAP(memalign), WRAP(malloc_usable_size)};
|
||||
|
||||
ALIGNED(32) const MallocDebugL asan_malloc_dispatch_l = {
|
||||
WRAP(calloc), WRAP(free), WRAP(mallinfo),
|
||||
WRAP(malloc), WRAP(malloc_usable_size), WRAP(memalign),
|
||||
WRAP(posix_memalign), WRAP(pvalloc), WRAP(realloc),
|
||||
WRAP(valloc)};
|
||||
|
||||
namespace __asan {
|
||||
void ReplaceSystemMalloc() {
|
||||
void **__libc_malloc_dispatch_p =
|
||||
(void **)AsanDlSymNext("__libc_malloc_dispatch");
|
||||
if (__libc_malloc_dispatch_p) {
|
||||
// Decide on K vs L dispatch format by the presence of
|
||||
// __libc_malloc_default_dispatch export in libc.
|
||||
void *default_dispatch_p = AsanDlSymNext("__libc_malloc_default_dispatch");
|
||||
if (default_dispatch_p)
|
||||
*__libc_malloc_dispatch_p = (void *)&asan_malloc_dispatch_k;
|
||||
else
|
||||
*__libc_malloc_dispatch_p = (void *)&asan_malloc_dispatch_l;
|
||||
}
|
||||
}
|
||||
} // namespace __asan
|
||||
|
||||
#else // SANITIZER_ANDROID
|
||||
|
||||
namespace __asan {
|
||||
void ReplaceSystemMalloc() {
|
||||
}
|
||||
} // namespace __asan
|
||||
#endif // SANITIZER_ANDROID
|
||||
|
||||
#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
|
||||
|
@ -24,10 +24,10 @@
|
||||
#include "asan_allocator.h"
|
||||
#include "asan_interceptors.h"
|
||||
#include "asan_internal.h"
|
||||
#include "asan_mac.h"
|
||||
#include "asan_report.h"
|
||||
#include "asan_stack.h"
|
||||
#include "asan_stats.h"
|
||||
#include "sanitizer_common/sanitizer_mac.h"
|
||||
|
||||
// Similar code is used in Google Perftools,
|
||||
// http://code.google.com/p/google-perftools.
|
||||
@ -41,7 +41,7 @@ static malloc_zone_t asan_zone;
|
||||
|
||||
INTERCEPTOR(malloc_zone_t *, malloc_create_zone,
|
||||
vm_size_t start_size, unsigned zone_flags) {
|
||||
if (!asan_inited) __asan_init();
|
||||
ENSURE_ASAN_INITED();
|
||||
GET_STACK_TRACE_MALLOC;
|
||||
uptr page_size = GetPageSizeCached();
|
||||
uptr allocated_size = RoundUpTo(sizeof(asan_zone), page_size);
|
||||
@ -60,39 +60,39 @@ INTERCEPTOR(malloc_zone_t *, malloc_create_zone,
|
||||
}
|
||||
|
||||
INTERCEPTOR(malloc_zone_t *, malloc_default_zone, void) {
|
||||
if (!asan_inited) __asan_init();
|
||||
ENSURE_ASAN_INITED();
|
||||
return &asan_zone;
|
||||
}
|
||||
|
||||
INTERCEPTOR(malloc_zone_t *, malloc_default_purgeable_zone, void) {
|
||||
// FIXME: ASan should support purgeable allocations.
|
||||
// https://code.google.com/p/address-sanitizer/issues/detail?id=139
|
||||
if (!asan_inited) __asan_init();
|
||||
ENSURE_ASAN_INITED();
|
||||
return &asan_zone;
|
||||
}
|
||||
|
||||
INTERCEPTOR(void, malloc_make_purgeable, void *ptr) {
|
||||
// FIXME: ASan should support purgeable allocations. Ignoring them is fine
|
||||
// for now.
|
||||
if (!asan_inited) __asan_init();
|
||||
ENSURE_ASAN_INITED();
|
||||
}
|
||||
|
||||
INTERCEPTOR(int, malloc_make_nonpurgeable, void *ptr) {
|
||||
// FIXME: ASan should support purgeable allocations. Ignoring them is fine
|
||||
// for now.
|
||||
if (!asan_inited) __asan_init();
|
||||
ENSURE_ASAN_INITED();
|
||||
// Must return 0 if the contents were not purged since the last call to
|
||||
// malloc_make_purgeable().
|
||||
return 0;
|
||||
}
|
||||
|
||||
INTERCEPTOR(void, malloc_set_zone_name, malloc_zone_t *zone, const char *name) {
|
||||
if (!asan_inited) __asan_init();
|
||||
ENSURE_ASAN_INITED();
|
||||
// Allocate |strlen("asan-") + 1 + internal_strlen(name)| bytes.
|
||||
size_t buflen = 6 + (name ? internal_strlen(name) : 0);
|
||||
InternalScopedBuffer<char> new_name(buflen);
|
||||
InternalScopedString new_name(buflen);
|
||||
if (name && zone->introspect == asan_zone.introspect) {
|
||||
internal_snprintf(new_name.data(), buflen, "asan-%s", name);
|
||||
new_name.append("asan-%s", name);
|
||||
name = new_name.data();
|
||||
}
|
||||
|
||||
@ -102,44 +102,44 @@ INTERCEPTOR(void, malloc_set_zone_name, malloc_zone_t *zone, const char *name) {
|
||||
}
|
||||
|
||||
INTERCEPTOR(void *, malloc, size_t size) {
|
||||
if (!asan_inited) __asan_init();
|
||||
ENSURE_ASAN_INITED();
|
||||
GET_STACK_TRACE_MALLOC;
|
||||
void *res = asan_malloc(size, &stack);
|
||||
return res;
|
||||
}
|
||||
|
||||
INTERCEPTOR(void, free, void *ptr) {
|
||||
if (!asan_inited) __asan_init();
|
||||
ENSURE_ASAN_INITED();
|
||||
if (!ptr) return;
|
||||
GET_STACK_TRACE_FREE;
|
||||
asan_free(ptr, &stack, FROM_MALLOC);
|
||||
}
|
||||
|
||||
INTERCEPTOR(void *, realloc, void *ptr, size_t size) {
|
||||
if (!asan_inited) __asan_init();
|
||||
ENSURE_ASAN_INITED();
|
||||
GET_STACK_TRACE_MALLOC;
|
||||
return asan_realloc(ptr, size, &stack);
|
||||
}
|
||||
|
||||
INTERCEPTOR(void *, calloc, size_t nmemb, size_t size) {
|
||||
if (!asan_inited) __asan_init();
|
||||
ENSURE_ASAN_INITED();
|
||||
GET_STACK_TRACE_MALLOC;
|
||||
return asan_calloc(nmemb, size, &stack);
|
||||
}
|
||||
|
||||
INTERCEPTOR(void *, valloc, size_t size) {
|
||||
if (!asan_inited) __asan_init();
|
||||
ENSURE_ASAN_INITED();
|
||||
GET_STACK_TRACE_MALLOC;
|
||||
return asan_memalign(GetPageSizeCached(), size, &stack, FROM_MALLOC);
|
||||
}
|
||||
|
||||
INTERCEPTOR(size_t, malloc_good_size, size_t size) {
|
||||
if (!asan_inited) __asan_init();
|
||||
ENSURE_ASAN_INITED();
|
||||
return asan_zone.introspect->good_size(&asan_zone, size);
|
||||
}
|
||||
|
||||
INTERCEPTOR(int, posix_memalign, void **memptr, size_t alignment, size_t size) {
|
||||
if (!asan_inited) __asan_init();
|
||||
ENSURE_ASAN_INITED();
|
||||
CHECK(memptr);
|
||||
GET_STACK_TRACE_MALLOC;
|
||||
void *result = asan_memalign(alignment, size, &stack, FROM_MALLOC);
|
||||
@ -159,7 +159,7 @@ size_t mz_size(malloc_zone_t* zone, const void* ptr) {
|
||||
}
|
||||
|
||||
void *mz_malloc(malloc_zone_t *zone, size_t size) {
|
||||
if (!asan_inited) {
|
||||
if (UNLIKELY(!asan_inited)) {
|
||||
CHECK(system_malloc_zone);
|
||||
return malloc_zone_malloc(system_malloc_zone, size);
|
||||
}
|
||||
@ -168,7 +168,7 @@ void *mz_malloc(malloc_zone_t *zone, size_t size) {
|
||||
}
|
||||
|
||||
void *mz_calloc(malloc_zone_t *zone, size_t nmemb, size_t size) {
|
||||
if (!asan_inited) {
|
||||
if (UNLIKELY(!asan_inited)) {
|
||||
// Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
|
||||
const size_t kCallocPoolSize = 1024;
|
||||
static uptr calloc_memory_for_dlsym[kCallocPoolSize];
|
||||
@ -184,7 +184,7 @@ void *mz_calloc(malloc_zone_t *zone, size_t nmemb, size_t size) {
|
||||
}
|
||||
|
||||
void *mz_valloc(malloc_zone_t *zone, size_t size) {
|
||||
if (!asan_inited) {
|
||||
if (UNLIKELY(!asan_inited)) {
|
||||
CHECK(system_malloc_zone);
|
||||
return malloc_zone_valloc(system_malloc_zone, size);
|
||||
}
|
||||
@ -242,7 +242,7 @@ void mz_destroy(malloc_zone_t* zone) {
|
||||
#if defined(MAC_OS_X_VERSION_10_6) && \
|
||||
MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
|
||||
void *mz_memalign(malloc_zone_t *zone, size_t align, size_t size) {
|
||||
if (!asan_inited) {
|
||||
if (UNLIKELY(!asan_inited)) {
|
||||
CHECK(system_malloc_zone);
|
||||
return malloc_zone_memalign(system_malloc_zone, align, size);
|
||||
}
|
||||
|
@ -23,71 +23,77 @@
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
// ---------------------- Replacement functions ---------------- {{{1
|
||||
using namespace __asan; // NOLINT
|
||||
|
||||
// FIXME: Simply defining functions with the same signature in *.obj
|
||||
// files overrides the standard functions in *.lib
|
||||
// This works well for simple helloworld-like tests but might need to be
|
||||
// revisited in the future.
|
||||
// MT: Simply defining functions with the same signature in *.obj
|
||||
// files overrides the standard functions in the CRT.
|
||||
// MD: Memory allocation functions are defined in the CRT .dll,
|
||||
// so we have to intercept them before they are called for the first time.
|
||||
|
||||
#if ASAN_DYNAMIC
|
||||
# define ALLOCATION_FUNCTION_ATTRIBUTE
|
||||
#else
|
||||
# define ALLOCATION_FUNCTION_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
ALLOCATION_FUNCTION_ATTRIBUTE
|
||||
void free(void *ptr) {
|
||||
GET_STACK_TRACE_FREE;
|
||||
return asan_free(ptr, &stack, FROM_MALLOC);
|
||||
}
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void _free_dbg(void* ptr, int) {
|
||||
ALLOCATION_FUNCTION_ATTRIBUTE
|
||||
void _free_dbg(void *ptr, int) {
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
ALLOCATION_FUNCTION_ATTRIBUTE
|
||||
void cfree(void *ptr) {
|
||||
CHECK(!"cfree() should not be used on Windows?");
|
||||
CHECK(!"cfree() should not be used on Windows");
|
||||
}
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
ALLOCATION_FUNCTION_ATTRIBUTE
|
||||
void *malloc(size_t size) {
|
||||
GET_STACK_TRACE_MALLOC;
|
||||
return asan_malloc(size, &stack);
|
||||
}
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void* _malloc_dbg(size_t size, int , const char*, int) {
|
||||
ALLOCATION_FUNCTION_ATTRIBUTE
|
||||
void *_malloc_dbg(size_t size, int, const char *, int) {
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
ALLOCATION_FUNCTION_ATTRIBUTE
|
||||
void *calloc(size_t nmemb, size_t size) {
|
||||
GET_STACK_TRACE_MALLOC;
|
||||
return asan_calloc(nmemb, size, &stack);
|
||||
}
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void* _calloc_dbg(size_t n, size_t size, int, const char*, int) {
|
||||
return calloc(n, size);
|
||||
ALLOCATION_FUNCTION_ATTRIBUTE
|
||||
void *_calloc_dbg(size_t nmemb, size_t size, int, const char *, int) {
|
||||
return calloc(nmemb, size);
|
||||
}
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
ALLOCATION_FUNCTION_ATTRIBUTE
|
||||
void *_calloc_impl(size_t nmemb, size_t size, int *errno_tmp) {
|
||||
return calloc(nmemb, size);
|
||||
}
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
ALLOCATION_FUNCTION_ATTRIBUTE
|
||||
void *realloc(void *ptr, size_t size) {
|
||||
GET_STACK_TRACE_MALLOC;
|
||||
return asan_realloc(ptr, size, &stack);
|
||||
}
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
ALLOCATION_FUNCTION_ATTRIBUTE
|
||||
void *_realloc_dbg(void *ptr, size_t size, int) {
|
||||
CHECK(!"_realloc_dbg should not exist!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void* _recalloc(void* p, size_t n, size_t elem_size) {
|
||||
ALLOCATION_FUNCTION_ATTRIBUTE
|
||||
void *_recalloc(void *p, size_t n, size_t elem_size) {
|
||||
if (!p)
|
||||
return calloc(n, elem_size);
|
||||
const size_t size = n * elem_size;
|
||||
@ -96,13 +102,28 @@ void* _recalloc(void* p, size_t n, size_t elem_size) {
|
||||
return realloc(p, size);
|
||||
}
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
ALLOCATION_FUNCTION_ATTRIBUTE
|
||||
size_t _msize(void *ptr) {
|
||||
GET_CURRENT_PC_BP_SP;
|
||||
(void)sp;
|
||||
return asan_malloc_usable_size(ptr, pc, bp);
|
||||
}
|
||||
|
||||
ALLOCATION_FUNCTION_ATTRIBUTE
|
||||
void *_expand(void *memblock, size_t size) {
|
||||
// _expand is used in realloc-like functions to resize the buffer if possible.
|
||||
// We don't want memory to stand still while resizing buffers, so return 0.
|
||||
return 0;
|
||||
}
|
||||
|
||||
ALLOCATION_FUNCTION_ATTRIBUTE
|
||||
void *_expand_dbg(void *memblock, size_t size) {
|
||||
return _expand(memblock, size);
|
||||
}
|
||||
|
||||
// TODO(timurrrr): Might want to add support for _aligned_* allocation
|
||||
// functions to detect a bit more bugs. Those functions seem to wrap malloc().
|
||||
|
||||
int _CrtDbgReport(int, const char*, int,
|
||||
const char*, const char*, ...) {
|
||||
ShowStatsAndAbort();
|
||||
@ -118,37 +139,38 @@ int _CrtSetReportMode(int, int) {
|
||||
}
|
||||
} // extern "C"
|
||||
|
||||
using __interception::GetRealFunctionAddress;
|
||||
|
||||
// We don't want to include "windows.h" in this file to avoid extra attributes
|
||||
// set on malloc/free etc (e.g. dllimport), so declare a few things manually:
|
||||
extern "C" int __stdcall VirtualProtect(void* addr, size_t size,
|
||||
DWORD prot, DWORD *old_prot);
|
||||
const int PAGE_EXECUTE_READWRITE = 0x40;
|
||||
|
||||
namespace __asan {
|
||||
void ReplaceSystemMalloc() {
|
||||
#if defined(_DLL)
|
||||
# ifdef _WIN64
|
||||
# error ReplaceSystemMalloc was not tested on x64
|
||||
# endif
|
||||
char *crt_malloc;
|
||||
if (GetRealFunctionAddress("malloc", (void**)&crt_malloc)) {
|
||||
// Replace malloc in the CRT dll with a jump to our malloc.
|
||||
DWORD old_prot, unused;
|
||||
CHECK(VirtualProtect(crt_malloc, 16, PAGE_EXECUTE_READWRITE, &old_prot));
|
||||
REAL(memset)(crt_malloc, 0xCC /* int 3 */, 16); // just in case.
|
||||
#if defined(ASAN_DYNAMIC)
|
||||
// We don't check the result because CRT might not be used in the process.
|
||||
__interception::OverrideFunction("free", (uptr)free);
|
||||
__interception::OverrideFunction("malloc", (uptr)malloc);
|
||||
__interception::OverrideFunction("_malloc_crt", (uptr)malloc);
|
||||
__interception::OverrideFunction("calloc", (uptr)calloc);
|
||||
__interception::OverrideFunction("_calloc_crt", (uptr)calloc);
|
||||
__interception::OverrideFunction("realloc", (uptr)realloc);
|
||||
__interception::OverrideFunction("_realloc_crt", (uptr)realloc);
|
||||
__interception::OverrideFunction("_recalloc", (uptr)_recalloc);
|
||||
__interception::OverrideFunction("_recalloc_crt", (uptr)_recalloc);
|
||||
__interception::OverrideFunction("_msize", (uptr)_msize);
|
||||
__interception::OverrideFunction("_expand", (uptr)_expand);
|
||||
|
||||
ptrdiff_t jmp_offset = (char*)malloc - (char*)crt_malloc - 5;
|
||||
crt_malloc[0] = 0xE9; // jmp, should be followed by an offset.
|
||||
REAL(memcpy)(crt_malloc + 1, &jmp_offset, sizeof(jmp_offset));
|
||||
|
||||
CHECK(VirtualProtect(crt_malloc, 16, old_prot, &unused));
|
||||
|
||||
// FYI: FlushInstructionCache is needed on Itanium etc but not on x86/x64.
|
||||
}
|
||||
|
||||
// FIXME: investigate whether anything else is needed.
|
||||
// Override different versions of 'operator new' and 'operator delete'.
|
||||
// No need to override the nothrow versions as they just wrap the throw
|
||||
// versions.
|
||||
// FIXME: Unfortunately, MSVC miscompiles the statements that take the
|
||||
// addresses of the array versions of these operators,
|
||||
// see https://connect.microsoft.com/VisualStudio/feedbackdetail/view/946992
|
||||
// We might want to try to work around this by [inline] assembly or compiling
|
||||
// parts of the RTL with Clang.
|
||||
void *(*op_new)(size_t sz) = operator new;
|
||||
void (*op_delete)(void *p) = operator delete;
|
||||
void *(*op_array_new)(size_t sz) = operator new[];
|
||||
void (*op_array_delete)(void *p) = operator delete[];
|
||||
__interception::OverrideFunction("??2@YAPAXI@Z", (uptr)op_new);
|
||||
__interception::OverrideFunction("??3@YAXPAX@Z", (uptr)op_delete);
|
||||
__interception::OverrideFunction("??_U@YAPAXI@Z", (uptr)op_array_new);
|
||||
__interception::OverrideFunction("??_V@YAXPAX@Z", (uptr)op_array_delete);
|
||||
#endif
|
||||
}
|
||||
} // namespace __asan
|
||||
|
@ -43,54 +43,87 @@
|
||||
// || `[0x00007fff8000, 0x00008fff6fff]` || LowShadow ||
|
||||
// || `[0x000000000000, 0x00007fff7fff]` || LowMem ||
|
||||
//
|
||||
// Default Linux/i386 mapping:
|
||||
// Default Linux/i386 mapping on x86_64 machine:
|
||||
// || `[0x40000000, 0xffffffff]` || HighMem ||
|
||||
// || `[0x28000000, 0x3fffffff]` || HighShadow ||
|
||||
// || `[0x24000000, 0x27ffffff]` || ShadowGap ||
|
||||
// || `[0x20000000, 0x23ffffff]` || LowShadow ||
|
||||
// || `[0x00000000, 0x1fffffff]` || LowMem ||
|
||||
//
|
||||
// Default Linux/i386 mapping on i386 machine
|
||||
// (addresses starting with 0xc0000000 are reserved
|
||||
// for kernel and thus not sanitized):
|
||||
// || `[0x38000000, 0xbfffffff]` || HighMem ||
|
||||
// || `[0x27000000, 0x37ffffff]` || HighShadow ||
|
||||
// || `[0x24000000, 0x26ffffff]` || ShadowGap ||
|
||||
// || `[0x20000000, 0x23ffffff]` || LowShadow ||
|
||||
// || `[0x00000000, 0x1fffffff]` || LowMem ||
|
||||
//
|
||||
// Default Linux/MIPS mapping:
|
||||
// || `[0x2aaa8000, 0xffffffff]` || HighMem ||
|
||||
// || `[0x0fffd000, 0x2aaa7fff]` || HighShadow ||
|
||||
// || `[0x0bffd000, 0x0fffcfff]` || ShadowGap ||
|
||||
// || `[0x0aaa8000, 0x0bffcfff]` || LowShadow ||
|
||||
// || `[0x00000000, 0x0aaa7fff]` || LowMem ||
|
||||
// || `[0x2aaa0000, 0xffffffff]` || HighMem ||
|
||||
// || `[0x0fff4000, 0x2aa9ffff]` || HighShadow ||
|
||||
// || `[0x0bff4000, 0x0fff3fff]` || ShadowGap ||
|
||||
// || `[0x0aaa0000, 0x0bff3fff]` || LowShadow ||
|
||||
// || `[0x00000000, 0x0aa9ffff]` || LowMem ||
|
||||
//
|
||||
// Shadow mapping on FreeBSD/x86-64 with SHADOW_OFFSET == 0x400000000000:
|
||||
// || `[0x500000000000, 0x7fffffffffff]` || HighMem ||
|
||||
// || `[0x4a0000000000, 0x4fffffffffff]` || HighShadow ||
|
||||
// || `[0x480000000000, 0x49ffffffffff]` || ShadowGap ||
|
||||
// || `[0x400000000000, 0x47ffffffffff]` || LowShadow ||
|
||||
// || `[0x000000000000, 0x3fffffffffff]` || LowMem ||
|
||||
//
|
||||
// Shadow mapping on FreeBSD/i386 with SHADOW_OFFSET == 0x40000000:
|
||||
// || `[0x60000000, 0xffffffff]` || HighMem ||
|
||||
// || `[0x4c000000, 0x5fffffff]` || HighShadow ||
|
||||
// || `[0x48000000, 0x4bffffff]` || ShadowGap ||
|
||||
// || `[0x40000000, 0x47ffffff]` || LowShadow ||
|
||||
// || `[0x00000000, 0x3fffffff]` || LowMem ||
|
||||
|
||||
static const u64 kDefaultShadowScale = 3;
|
||||
static const u64 kDefaultShadowOffset32 = 1ULL << 29;
|
||||
static const u64 kDefaultShadowOffset32 = 1ULL << 29; // 0x20000000
|
||||
static const u64 kIosShadowOffset32 = 1ULL << 30; // 0x40000000
|
||||
static const u64 kDefaultShadowOffset64 = 1ULL << 44;
|
||||
static const u64 kDefaultShort64bitShadowOffset = 0x7FFF8000; // < 2G.
|
||||
static const u64 kAArch64_ShadowOffset64 = 1ULL << 36;
|
||||
static const u64 kMIPS32_ShadowOffset32 = 0x0aaa0000;
|
||||
static const u64 kMIPS64_ShadowOffset64 = 1ULL << 36;
|
||||
static const u64 kPPC64_ShadowOffset64 = 1ULL << 41;
|
||||
static const u64 kMIPS32_ShadowOffset32 = 0x0aaa8000;
|
||||
static const u64 kFreeBSD_ShadowOffset32 = 1ULL << 30; // 0x40000000
|
||||
static const u64 kFreeBSD_ShadowOffset64 = 1ULL << 46; // 0x400000000000
|
||||
|
||||
#if ASAN_FLEXIBLE_MAPPING_AND_OFFSET == 1
|
||||
extern SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_mapping_scale;
|
||||
extern SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_mapping_offset;
|
||||
# define SHADOW_SCALE (__asan_mapping_scale)
|
||||
# define SHADOW_OFFSET (__asan_mapping_offset)
|
||||
#else
|
||||
# define SHADOW_SCALE kDefaultShadowScale
|
||||
# if SANITIZER_ANDROID
|
||||
#define SHADOW_SCALE kDefaultShadowScale
|
||||
#if SANITIZER_ANDROID
|
||||
# define SHADOW_OFFSET (0)
|
||||
# else
|
||||
#else
|
||||
# if SANITIZER_WORDSIZE == 32
|
||||
# if defined(__mips__)
|
||||
# define SHADOW_OFFSET kMIPS32_ShadowOffset32
|
||||
# elif SANITIZER_FREEBSD
|
||||
# define SHADOW_OFFSET kFreeBSD_ShadowOffset32
|
||||
# else
|
||||
# if SANITIZER_IOS
|
||||
# define SHADOW_OFFSET kIosShadowOffset32
|
||||
# else
|
||||
# define SHADOW_OFFSET kDefaultShadowOffset32
|
||||
# endif
|
||||
# endif
|
||||
# else
|
||||
# if defined(__powerpc64__)
|
||||
# if defined(__aarch64__)
|
||||
# define SHADOW_OFFSET kAArch64_ShadowOffset64
|
||||
# elif defined(__powerpc64__)
|
||||
# define SHADOW_OFFSET kPPC64_ShadowOffset64
|
||||
# elif SANITIZER_FREEBSD
|
||||
# define SHADOW_OFFSET kFreeBSD_ShadowOffset64
|
||||
# elif SANITIZER_MAC
|
||||
# define SHADOW_OFFSET kDefaultShadowOffset64
|
||||
# elif defined(__mips64)
|
||||
# define SHADOW_OFFSET kMIPS64_ShadowOffset64
|
||||
# else
|
||||
# define SHADOW_OFFSET kDefaultShort64bitShadowOffset
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
#endif // ASAN_FLEXIBLE_MAPPING_AND_OFFSET
|
||||
#endif
|
||||
|
||||
#define SHADOW_GRANULARITY (1ULL << SHADOW_SCALE)
|
||||
#define MEM_TO_SHADOW(mem) (((mem) >> SHADOW_SCALE) + (SHADOW_OFFSET))
|
||||
|
@ -16,20 +16,21 @@
|
||||
#include "asan_internal.h"
|
||||
#include "asan_stack.h"
|
||||
|
||||
#include "interception/interception.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace __asan {
|
||||
// This function is a no-op. We need it to make sure that object file
|
||||
// with our replacements will actually be loaded from static ASan
|
||||
// run-time library at link-time.
|
||||
void ReplaceOperatorsNewAndDelete() { }
|
||||
}
|
||||
// C++ operators can't have visibility attributes on Windows.
|
||||
#if SANITIZER_WINDOWS
|
||||
# define CXX_OPERATOR_ATTRIBUTE
|
||||
#else
|
||||
# define CXX_OPERATOR_ATTRIBUTE INTERCEPTOR_ATTRIBUTE
|
||||
#endif
|
||||
|
||||
using namespace __asan; // NOLINT
|
||||
|
||||
// On Android new() goes through malloc interceptors.
|
||||
// See also https://code.google.com/p/address-sanitizer/issues/detail?id=131.
|
||||
#if !SANITIZER_ANDROID
|
||||
// This code has issues on OSX.
|
||||
// See https://code.google.com/p/address-sanitizer/issues/detail?id=131.
|
||||
|
||||
// Fake std::nothrow_t to avoid including <new>.
|
||||
namespace std {
|
||||
@ -48,14 +49,23 @@ struct nothrow_t {};
|
||||
// To make sure that C++ allocation/deallocation operators are overridden on
|
||||
// OS X we need to intercept them using their mangled names.
|
||||
#if !SANITIZER_MAC
|
||||
INTERCEPTOR_ATTRIBUTE
|
||||
// FreeBSD prior v9.2 have wrong definition of 'size_t'.
|
||||
// http://svnweb.freebsd.org/base?view=revision&revision=232261
|
||||
#if SANITIZER_FREEBSD && SANITIZER_WORDSIZE == 32
|
||||
#include <sys/param.h>
|
||||
#if __FreeBSD_version <= 902001 // v9.2
|
||||
#define size_t unsigned
|
||||
#endif // __FreeBSD_version
|
||||
#endif // SANITIZER_FREEBSD && SANITIZER_WORDSIZE == 32
|
||||
|
||||
CXX_OPERATOR_ATTRIBUTE
|
||||
void *operator new(size_t size) { OPERATOR_NEW_BODY(FROM_NEW); }
|
||||
INTERCEPTOR_ATTRIBUTE
|
||||
CXX_OPERATOR_ATTRIBUTE
|
||||
void *operator new[](size_t size) { OPERATOR_NEW_BODY(FROM_NEW_BR); }
|
||||
INTERCEPTOR_ATTRIBUTE
|
||||
CXX_OPERATOR_ATTRIBUTE
|
||||
void *operator new(size_t size, std::nothrow_t const&)
|
||||
{ OPERATOR_NEW_BODY(FROM_NEW); }
|
||||
INTERCEPTOR_ATTRIBUTE
|
||||
CXX_OPERATOR_ATTRIBUTE
|
||||
void *operator new[](size_t size, std::nothrow_t const&)
|
||||
{ OPERATOR_NEW_BODY(FROM_NEW_BR); }
|
||||
|
||||
@ -79,16 +89,32 @@ INTERCEPTOR(void *, _ZnamRKSt9nothrow_t, size_t size, std::nothrow_t const&) {
|
||||
asan_free(ptr, &stack, type);
|
||||
|
||||
#if !SANITIZER_MAC
|
||||
INTERCEPTOR_ATTRIBUTE
|
||||
void operator delete(void *ptr) { OPERATOR_DELETE_BODY(FROM_NEW); }
|
||||
INTERCEPTOR_ATTRIBUTE
|
||||
void operator delete[](void *ptr) { OPERATOR_DELETE_BODY(FROM_NEW_BR); }
|
||||
INTERCEPTOR_ATTRIBUTE
|
||||
void operator delete(void *ptr, std::nothrow_t const&)
|
||||
{ OPERATOR_DELETE_BODY(FROM_NEW); }
|
||||
INTERCEPTOR_ATTRIBUTE
|
||||
void operator delete[](void *ptr, std::nothrow_t const&)
|
||||
{ OPERATOR_DELETE_BODY(FROM_NEW_BR); }
|
||||
CXX_OPERATOR_ATTRIBUTE
|
||||
void operator delete(void *ptr) throw() {
|
||||
OPERATOR_DELETE_BODY(FROM_NEW);
|
||||
}
|
||||
CXX_OPERATOR_ATTRIBUTE
|
||||
void operator delete[](void *ptr) throw() {
|
||||
OPERATOR_DELETE_BODY(FROM_NEW_BR);
|
||||
}
|
||||
CXX_OPERATOR_ATTRIBUTE
|
||||
void operator delete(void *ptr, std::nothrow_t const&) {
|
||||
OPERATOR_DELETE_BODY(FROM_NEW);
|
||||
}
|
||||
CXX_OPERATOR_ATTRIBUTE
|
||||
void operator delete[](void *ptr, std::nothrow_t const&) {
|
||||
OPERATOR_DELETE_BODY(FROM_NEW_BR);
|
||||
}
|
||||
CXX_OPERATOR_ATTRIBUTE
|
||||
void operator delete(void *ptr, size_t size) throw() {
|
||||
GET_STACK_TRACE_FREE;
|
||||
asan_sized_free(ptr, size, &stack, FROM_NEW);
|
||||
}
|
||||
CXX_OPERATOR_ATTRIBUTE
|
||||
void operator delete[](void *ptr, size_t size) throw() {
|
||||
GET_STACK_TRACE_FREE;
|
||||
asan_sized_free(ptr, size, &stack, FROM_NEW_BR);
|
||||
}
|
||||
|
||||
#else // SANITIZER_MAC
|
||||
INTERCEPTOR(void, _ZdlPv, void *ptr) {
|
||||
@ -104,5 +130,3 @@ INTERCEPTOR(void, _ZdaPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&) {
|
||||
OPERATOR_DELETE_BODY(FROM_NEW_BR);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -13,6 +13,8 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "asan_poisoning.h"
|
||||
#include "asan_report.h"
|
||||
#include "asan_stack.h"
|
||||
#include "sanitizer_common/sanitizer_libc.h"
|
||||
#include "sanitizer_common/sanitizer_flags.h"
|
||||
|
||||
@ -50,6 +52,36 @@ struct ShadowSegmentEndpoint {
|
||||
}
|
||||
};
|
||||
|
||||
void FlushUnneededASanShadowMemory(uptr p, uptr size) {
|
||||
// Since asan's mapping is compacting, the shadow chunk may be
|
||||
// not page-aligned, so we only flush the page-aligned portion.
|
||||
uptr page_size = GetPageSizeCached();
|
||||
uptr shadow_beg = RoundUpTo(MemToShadow(p), page_size);
|
||||
uptr shadow_end = RoundDownTo(MemToShadow(p + size), page_size);
|
||||
FlushUnneededShadowMemory(shadow_beg, shadow_end - shadow_beg);
|
||||
}
|
||||
|
||||
void AsanPoisonOrUnpoisonIntraObjectRedzone(uptr ptr, uptr size, bool poison) {
|
||||
uptr end = ptr + size;
|
||||
if (common_flags()->verbosity) {
|
||||
Printf("__asan_%spoison_intra_object_redzone [%p,%p) %zd\n",
|
||||
poison ? "" : "un", ptr, end, size);
|
||||
if (common_flags()->verbosity >= 2)
|
||||
PRINT_CURRENT_STACK();
|
||||
}
|
||||
CHECK(size);
|
||||
CHECK_LE(size, 4096);
|
||||
CHECK(IsAligned(end, SHADOW_GRANULARITY));
|
||||
if (!IsAligned(ptr, SHADOW_GRANULARITY)) {
|
||||
*(u8 *)MemToShadow(ptr) =
|
||||
poison ? static_cast<u8>(ptr % SHADOW_GRANULARITY) : 0;
|
||||
ptr |= SHADOW_GRANULARITY - 1;
|
||||
ptr++;
|
||||
}
|
||||
for (; ptr < end; ptr += SHADOW_GRANULARITY)
|
||||
*(u8*)MemToShadow(ptr) = poison ? kAsanIntraObjectRedzone : 0;
|
||||
}
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
// ---------------------- Interface ---------------- {{{1
|
||||
@ -69,10 +101,8 @@ void __asan_poison_memory_region(void const volatile *addr, uptr size) {
|
||||
if (!flags()->allow_user_poisoning || size == 0) return;
|
||||
uptr beg_addr = (uptr)addr;
|
||||
uptr end_addr = beg_addr + size;
|
||||
if (common_flags()->verbosity >= 1) {
|
||||
Printf("Trying to poison memory region [%p, %p)\n",
|
||||
(void*)beg_addr, (void*)end_addr);
|
||||
}
|
||||
VPrintf(1, "Trying to poison memory region [%p, %p)\n", (void *)beg_addr,
|
||||
(void *)end_addr);
|
||||
ShadowSegmentEndpoint beg(beg_addr);
|
||||
ShadowSegmentEndpoint end(end_addr);
|
||||
if (beg.chunk == end.chunk) {
|
||||
@ -111,10 +141,8 @@ void __asan_unpoison_memory_region(void const volatile *addr, uptr size) {
|
||||
if (!flags()->allow_user_poisoning || size == 0) return;
|
||||
uptr beg_addr = (uptr)addr;
|
||||
uptr end_addr = beg_addr + size;
|
||||
if (common_flags()->verbosity >= 1) {
|
||||
Printf("Trying to unpoison memory region [%p, %p)\n",
|
||||
(void*)beg_addr, (void*)end_addr);
|
||||
}
|
||||
VPrintf(1, "Trying to unpoison memory region [%p, %p)\n", (void *)beg_addr,
|
||||
(void *)end_addr);
|
||||
ShadowSegmentEndpoint beg(beg_addr);
|
||||
ShadowSegmentEndpoint end(end_addr);
|
||||
if (beg.chunk == end.chunk) {
|
||||
@ -139,7 +167,7 @@ void __asan_unpoison_memory_region(void const volatile *addr, uptr size) {
|
||||
}
|
||||
}
|
||||
|
||||
bool __asan_address_is_poisoned(void const volatile *addr) {
|
||||
int __asan_address_is_poisoned(void const volatile *addr) {
|
||||
return __asan::AddressIsPoisoned((uptr)addr);
|
||||
}
|
||||
|
||||
@ -148,6 +176,7 @@ uptr __asan_region_is_poisoned(uptr beg, uptr size) {
|
||||
uptr end = beg + size;
|
||||
if (!AddrIsInMem(beg)) return beg;
|
||||
if (!AddrIsInMem(end)) return end;
|
||||
CHECK_LT(beg, end);
|
||||
uptr aligned_b = RoundUpTo(beg, SHADOW_GRANULARITY);
|
||||
uptr aligned_e = RoundDownTo(end, SHADOW_GRANULARITY);
|
||||
uptr shadow_beg = MemToShadow(aligned_b);
|
||||
@ -219,6 +248,36 @@ void __sanitizer_unaligned_store64(uu64 *p, u64 x) {
|
||||
*p = x;
|
||||
}
|
||||
|
||||
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void __asan_poison_cxx_array_cookie(uptr p) {
|
||||
if (SANITIZER_WORDSIZE != 64) return;
|
||||
if (!flags()->poison_array_cookie) return;
|
||||
uptr s = MEM_TO_SHADOW(p);
|
||||
*reinterpret_cast<u8*>(s) = kAsanArrayCookieMagic;
|
||||
}
|
||||
|
||||
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
|
||||
uptr __asan_load_cxx_array_cookie(uptr *p) {
|
||||
if (SANITIZER_WORDSIZE != 64) return *p;
|
||||
if (!flags()->poison_array_cookie) return *p;
|
||||
uptr s = MEM_TO_SHADOW(reinterpret_cast<uptr>(p));
|
||||
u8 sval = *reinterpret_cast<u8*>(s);
|
||||
if (sval == kAsanArrayCookieMagic) return *p;
|
||||
// If sval is not kAsanArrayCookieMagic it can only be freed memory,
|
||||
// which means that we are going to get double-free. So, return 0 to avoid
|
||||
// infinite loop of destructors. We don't want to report a double-free here
|
||||
// though, so print a warning just in case.
|
||||
// CHECK_EQ(sval, kAsanHeapFreeMagic);
|
||||
if (sval == kAsanHeapFreeMagic) {
|
||||
Report("AddressSanitizer: loaded array cookie from free-d memory; "
|
||||
"expect a double-free report\n");
|
||||
return 0;
|
||||
}
|
||||
// The cookie may remain unpoisoned if e.g. it comes from a custom
|
||||
// operator new defined inside a class.
|
||||
return *p;
|
||||
}
|
||||
|
||||
// This is a simplified version of __asan_(un)poison_memory_region, which
|
||||
// assumes that left border of region to be poisoned is properly aligned.
|
||||
static void PoisonAlignedStackMemory(uptr addr, uptr size, bool do_poison) {
|
||||
@ -245,55 +304,113 @@ static void PoisonAlignedStackMemory(uptr addr, uptr size, bool do_poison) {
|
||||
}
|
||||
|
||||
void __asan_poison_stack_memory(uptr addr, uptr size) {
|
||||
if (common_flags()->verbosity > 0)
|
||||
Report("poisoning: %p %zx\n", (void*)addr, size);
|
||||
VReport(1, "poisoning: %p %zx\n", (void *)addr, size);
|
||||
PoisonAlignedStackMemory(addr, size, true);
|
||||
}
|
||||
|
||||
void __asan_unpoison_stack_memory(uptr addr, uptr size) {
|
||||
if (common_flags()->verbosity > 0)
|
||||
Report("unpoisoning: %p %zx\n", (void*)addr, size);
|
||||
VReport(1, "unpoisoning: %p %zx\n", (void *)addr, size);
|
||||
PoisonAlignedStackMemory(addr, size, false);
|
||||
}
|
||||
|
||||
void __sanitizer_annotate_contiguous_container(void *beg_p, void *end_p,
|
||||
void *old_mid_p,
|
||||
void *new_mid_p) {
|
||||
void __sanitizer_annotate_contiguous_container(const void *beg_p,
|
||||
const void *end_p,
|
||||
const void *old_mid_p,
|
||||
const void *new_mid_p) {
|
||||
if (!flags()->detect_container_overflow) return;
|
||||
VPrintf(2, "contiguous_container: %p %p %p %p\n", beg_p, end_p, old_mid_p,
|
||||
new_mid_p);
|
||||
uptr beg = reinterpret_cast<uptr>(beg_p);
|
||||
uptr end= reinterpret_cast<uptr>(end_p);
|
||||
uptr end = reinterpret_cast<uptr>(end_p);
|
||||
uptr old_mid = reinterpret_cast<uptr>(old_mid_p);
|
||||
uptr new_mid = reinterpret_cast<uptr>(new_mid_p);
|
||||
uptr granularity = SHADOW_GRANULARITY;
|
||||
CHECK(beg <= end && beg <= old_mid && beg <= new_mid && old_mid <= end &&
|
||||
new_mid <= end && IsAligned(beg, granularity));
|
||||
if (!(beg <= old_mid && beg <= new_mid && old_mid <= end && new_mid <= end &&
|
||||
IsAligned(beg, granularity))) {
|
||||
GET_STACK_TRACE_FATAL_HERE;
|
||||
ReportBadParamsToAnnotateContiguousContainer(beg, end, old_mid, new_mid,
|
||||
&stack);
|
||||
}
|
||||
CHECK_LE(end - beg,
|
||||
FIRST_32_SECOND_64(1UL << 30, 1UL << 34)); // Sanity check.
|
||||
|
||||
uptr a = RoundDownTo(Min(old_mid, new_mid), granularity);
|
||||
uptr c = RoundUpTo(Max(old_mid, new_mid), granularity);
|
||||
uptr b = new_mid;
|
||||
uptr b1 = RoundDownTo(b, granularity);
|
||||
uptr b2 = RoundUpTo(b, granularity);
|
||||
uptr d = old_mid;
|
||||
uptr d1 = RoundDownTo(d, granularity);
|
||||
uptr d2 = RoundUpTo(d, granularity);
|
||||
uptr d1 = RoundDownTo(old_mid, granularity);
|
||||
// uptr d2 = RoundUpTo(old_mid, granularity);
|
||||
// Currently we should be in this state:
|
||||
// [a, d1) is good, [d2, c) is bad, [d1, d2) is partially good.
|
||||
// Make a quick sanity check that we are indeed in this state.
|
||||
if (d1 != d2)
|
||||
CHECK_EQ(*(u8*)MemToShadow(d1), d - d1);
|
||||
//
|
||||
// FIXME: Two of these three checks are disabled until we fix
|
||||
// https://code.google.com/p/address-sanitizer/issues/detail?id=258.
|
||||
// if (d1 != d2)
|
||||
// CHECK_EQ(*(u8*)MemToShadow(d1), old_mid - d1);
|
||||
if (a + granularity <= d1)
|
||||
CHECK_EQ(*(u8*)MemToShadow(a), 0);
|
||||
if (d2 + granularity <= c && c <= end)
|
||||
CHECK_EQ(*(u8 *)MemToShadow(c - granularity), kAsanUserPoisonedMemoryMagic);
|
||||
// if (d2 + granularity <= c && c <= end)
|
||||
// CHECK_EQ(*(u8 *)MemToShadow(c - granularity),
|
||||
// kAsanContiguousContainerOOBMagic);
|
||||
|
||||
uptr b1 = RoundDownTo(new_mid, granularity);
|
||||
uptr b2 = RoundUpTo(new_mid, granularity);
|
||||
// New state:
|
||||
// [a, b1) is good, [b2, c) is bad, [b1, b2) is partially good.
|
||||
// FIXME: we may want to have a separate poison magic value.
|
||||
PoisonShadow(a, b1 - a, 0);
|
||||
PoisonShadow(b2, c - b2, kAsanUserPoisonedMemoryMagic);
|
||||
PoisonShadow(b2, c - b2, kAsanContiguousContainerOOBMagic);
|
||||
if (b1 != b2) {
|
||||
CHECK_EQ(b2 - b1, granularity);
|
||||
*(u8*)MemToShadow(b1) = static_cast<u8>(b - b1);
|
||||
*(u8*)MemToShadow(b1) = static_cast<u8>(new_mid - b1);
|
||||
}
|
||||
}
|
||||
|
||||
int __sanitizer_verify_contiguous_container(const void *beg_p,
|
||||
const void *mid_p,
|
||||
const void *end_p) {
|
||||
if (!flags()->detect_container_overflow) return 1;
|
||||
uptr beg = reinterpret_cast<uptr>(beg_p);
|
||||
uptr end = reinterpret_cast<uptr>(end_p);
|
||||
uptr mid = reinterpret_cast<uptr>(mid_p);
|
||||
CHECK_LE(beg, mid);
|
||||
CHECK_LE(mid, end);
|
||||
// Check some bytes starting from beg, some bytes around mid, and some bytes
|
||||
// ending with end.
|
||||
uptr kMaxRangeToCheck = 32;
|
||||
uptr r1_beg = beg;
|
||||
uptr r1_end = Min(end + kMaxRangeToCheck, mid);
|
||||
uptr r2_beg = Max(beg, mid - kMaxRangeToCheck);
|
||||
uptr r2_end = Min(end, mid + kMaxRangeToCheck);
|
||||
uptr r3_beg = Max(end - kMaxRangeToCheck, mid);
|
||||
uptr r3_end = end;
|
||||
for (uptr i = r1_beg; i < r1_end; i++)
|
||||
if (AddressIsPoisoned(i))
|
||||
return 0;
|
||||
for (uptr i = r2_beg; i < mid; i++)
|
||||
if (AddressIsPoisoned(i))
|
||||
return 0;
|
||||
for (uptr i = mid; i < r2_end; i++)
|
||||
if (!AddressIsPoisoned(i))
|
||||
return 0;
|
||||
for (uptr i = r3_beg; i < r3_end; i++)
|
||||
if (!AddressIsPoisoned(i))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void __asan_poison_intra_object_redzone(uptr ptr, uptr size) {
|
||||
AsanPoisonOrUnpoisonIntraObjectRedzone(ptr, size, true);
|
||||
}
|
||||
|
||||
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void __asan_unpoison_intra_object_redzone(uptr ptr, uptr size) {
|
||||
AsanPoisonOrUnpoisonIntraObjectRedzone(ptr, size, false);
|
||||
}
|
||||
|
||||
// --- Implementation of LSan-specific functions --- {{{1
|
||||
namespace __lsan {
|
||||
bool WordIsPoisoned(uptr addr) {
|
||||
return (__asan_region_is_poisoned(addr, sizeof(uptr)) != 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "asan_interceptors.h"
|
||||
#include "asan_internal.h"
|
||||
#include "asan_mapping.h"
|
||||
#include "sanitizer_common/sanitizer_flags.h"
|
||||
|
||||
namespace __asan {
|
||||
|
||||
@ -37,7 +38,32 @@ ALWAYS_INLINE void FastPoisonShadow(uptr aligned_beg, uptr aligned_size,
|
||||
uptr shadow_beg = MEM_TO_SHADOW(aligned_beg);
|
||||
uptr shadow_end = MEM_TO_SHADOW(
|
||||
aligned_beg + aligned_size - SHADOW_GRANULARITY) + 1;
|
||||
// FIXME: Page states are different on Windows, so using the same interface
|
||||
// for mapping shadow and zeroing out pages doesn't "just work", so we should
|
||||
// probably provide higher-level interface for these operations.
|
||||
// For now, just memset on Windows.
|
||||
if (value ||
|
||||
SANITIZER_WINDOWS == 1 ||
|
||||
shadow_end - shadow_beg < common_flags()->clear_shadow_mmap_threshold) {
|
||||
REAL(memset)((void*)shadow_beg, value, shadow_end - shadow_beg);
|
||||
} else {
|
||||
uptr page_size = GetPageSizeCached();
|
||||
uptr page_beg = RoundUpTo(shadow_beg, page_size);
|
||||
uptr page_end = RoundDownTo(shadow_end, page_size);
|
||||
|
||||
if (page_beg >= page_end) {
|
||||
REAL(memset)((void *)shadow_beg, 0, shadow_end - shadow_beg);
|
||||
} else {
|
||||
if (page_beg != shadow_beg) {
|
||||
REAL(memset)((void *)shadow_beg, 0, page_beg - shadow_beg);
|
||||
}
|
||||
if (page_end != shadow_end) {
|
||||
REAL(memset)((void *)page_end, 0, shadow_end - page_end);
|
||||
}
|
||||
void *res = MmapFixedNoReserve(page_beg, page_end - page_beg);
|
||||
CHECK_EQ(page_beg, res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void FastPoisonShadowPartialRightRedzone(
|
||||
@ -57,4 +83,8 @@ ALWAYS_INLINE void FastPoisonShadowPartialRightRedzone(
|
||||
}
|
||||
}
|
||||
|
||||
// Calls __sanitizer::FlushUnneededShadowMemory() on
|
||||
// [MemToShadow(p), MemToShadow(p+size)] with proper rounding.
|
||||
void FlushUnneededASanShadowMemory(uptr p, uptr size);
|
||||
|
||||
} // namespace __asan
|
||||
|
@ -13,7 +13,7 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "sanitizer_common/sanitizer_platform.h"
|
||||
#if SANITIZER_LINUX || SANITIZER_MAC
|
||||
#if SANITIZER_POSIX
|
||||
|
||||
#include "asan_internal.h"
|
||||
#include "asan_interceptors.h"
|
||||
@ -30,70 +30,59 @@
|
||||
#include <sys/resource.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static const uptr kAltStackSize = SIGSTKSZ * 4; // SIGSTKSZ is not enough.
|
||||
|
||||
namespace __asan {
|
||||
|
||||
static void MaybeInstallSigaction(int signum,
|
||||
void (*handler)(int, siginfo_t *, void *)) {
|
||||
if (!AsanInterceptsSignal(signum))
|
||||
return;
|
||||
struct sigaction sigact;
|
||||
REAL(memset)(&sigact, 0, sizeof(sigact));
|
||||
sigact.sa_sigaction = handler;
|
||||
sigact.sa_flags = SA_SIGINFO;
|
||||
if (flags()->use_sigaltstack) sigact.sa_flags |= SA_ONSTACK;
|
||||
CHECK_EQ(0, REAL(sigaction)(signum, &sigact, 0));
|
||||
if (common_flags()->verbosity >= 1) {
|
||||
Report("Installed the sigaction for signal %d\n", signum);
|
||||
}
|
||||
}
|
||||
|
||||
static void ASAN_OnSIGSEGV(int, siginfo_t *siginfo, void *context) {
|
||||
uptr addr = (uptr)siginfo->si_addr;
|
||||
// Write the first message using the bullet-proof write.
|
||||
if (13 != internal_write(2, "ASAN:SIGSEGV\n", 13)) Die();
|
||||
SignalContext SignalContext::Create(void *siginfo, void *context) {
|
||||
uptr addr = (uptr)((siginfo_t*)siginfo)->si_addr;
|
||||
uptr pc, sp, bp;
|
||||
GetPcSpBp(context, &pc, &sp, &bp);
|
||||
ReportSIGSEGV(pc, sp, bp, addr);
|
||||
return SignalContext(context, addr, pc, sp, bp);
|
||||
}
|
||||
|
||||
void SetAlternateSignalStack() {
|
||||
stack_t altstack, oldstack;
|
||||
CHECK_EQ(0, sigaltstack(0, &oldstack));
|
||||
// If the alternate stack is already in place, do nothing.
|
||||
if ((oldstack.ss_flags & SS_DISABLE) == 0) return;
|
||||
// TODO(glider): the mapped stack should have the MAP_STACK flag in the
|
||||
// future. It is not required by man 2 sigaltstack now (they're using
|
||||
// malloc()).
|
||||
void* base = MmapOrDie(kAltStackSize, __FUNCTION__);
|
||||
altstack.ss_sp = base;
|
||||
altstack.ss_flags = 0;
|
||||
altstack.ss_size = kAltStackSize;
|
||||
CHECK_EQ(0, sigaltstack(&altstack, 0));
|
||||
if (common_flags()->verbosity > 0) {
|
||||
Report("Alternative stack for T%d set: [%p,%p)\n",
|
||||
GetCurrentTidOrInvalid(),
|
||||
altstack.ss_sp, (char*)altstack.ss_sp + altstack.ss_size);
|
||||
void AsanOnSIGSEGV(int, void *siginfo, void *context) {
|
||||
ScopedDeadlySignal signal_scope(GetCurrentThread());
|
||||
int code = (int)((siginfo_t*)siginfo)->si_code;
|
||||
// Write the first message using the bullet-proof write.
|
||||
if (13 != internal_write(2, "ASAN:SIGSEGV\n", 13)) Die();
|
||||
SignalContext sig = SignalContext::Create(siginfo, context);
|
||||
|
||||
// Access at a reasonable offset above SP, or slightly below it (to account
|
||||
// for x86_64 or PowerPC redzone, ARM push of multiple registers, etc) is
|
||||
// probably a stack overflow.
|
||||
bool IsStackAccess = sig.addr + 512 > sig.sp && sig.addr < sig.sp + 0xFFFF;
|
||||
|
||||
#if __powerpc__
|
||||
// Large stack frames can be allocated with e.g.
|
||||
// lis r0,-10000
|
||||
// stdux r1,r1,r0 # store sp to [sp-10000] and update sp by -10000
|
||||
// If the store faults then sp will not have been updated, so test above
|
||||
// will not work, becase the fault address will be more than just "slightly"
|
||||
// below sp.
|
||||
if (!IsStackAccess && IsAccessibleMemoryRange(sig.pc, 4)) {
|
||||
u32 inst = *(unsigned *)sig.pc;
|
||||
u32 ra = (inst >> 16) & 0x1F;
|
||||
u32 opcd = inst >> 26;
|
||||
u32 xo = (inst >> 1) & 0x3FF;
|
||||
// Check for store-with-update to sp. The instructions we accept are:
|
||||
// stbu rs,d(ra) stbux rs,ra,rb
|
||||
// sthu rs,d(ra) sthux rs,ra,rb
|
||||
// stwu rs,d(ra) stwux rs,ra,rb
|
||||
// stdu rs,ds(ra) stdux rs,ra,rb
|
||||
// where ra is r1 (the stack pointer).
|
||||
if (ra == 1 &&
|
||||
(opcd == 39 || opcd == 45 || opcd == 37 || opcd == 62 ||
|
||||
(opcd == 31 && (xo == 247 || xo == 439 || xo == 183 || xo == 181))))
|
||||
IsStackAccess = true;
|
||||
}
|
||||
}
|
||||
#endif // __powerpc__
|
||||
|
||||
void UnsetAlternateSignalStack() {
|
||||
stack_t altstack, oldstack;
|
||||
altstack.ss_sp = 0;
|
||||
altstack.ss_flags = SS_DISABLE;
|
||||
altstack.ss_size = 0;
|
||||
CHECK_EQ(0, sigaltstack(&altstack, &oldstack));
|
||||
UnmapOrDie(oldstack.ss_sp, oldstack.ss_size);
|
||||
}
|
||||
|
||||
void InstallSignalHandlers() {
|
||||
// Set the alternate signal stack for the main thread.
|
||||
// This will cause SetAlternateSignalStack to be called twice, but the stack
|
||||
// will be actually set only once.
|
||||
if (flags()->use_sigaltstack) SetAlternateSignalStack();
|
||||
MaybeInstallSigaction(SIGSEGV, ASAN_OnSIGSEGV);
|
||||
MaybeInstallSigaction(SIGBUS, ASAN_OnSIGSEGV);
|
||||
// We also check si_code to filter out SEGV caused by something else other
|
||||
// then hitting the guard page or unmapped memory, like, for example,
|
||||
// unaligned memory access.
|
||||
if (IsStackAccess && (code == si_SEGV_MAPERR || code == si_SEGV_ACCERR))
|
||||
ReportStackOverflow(sig);
|
||||
else
|
||||
ReportSIGSEGV("SEGV", sig);
|
||||
}
|
||||
|
||||
// ---------------------- TSD ---------------- {{{1
|
||||
@ -127,4 +116,4 @@ void PlatformTSDDtor(void *tsd) {
|
||||
}
|
||||
} // namespace __asan
|
||||
|
||||
#endif // SANITIZER_LINUX || SANITIZER_MAC
|
||||
#endif // SANITIZER_POSIX
|
||||
|
@ -10,22 +10,16 @@
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// Call __asan_init at the very early stage of process startup.
|
||||
// On Linux we use .preinit_array section (unless PIC macro is defined).
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "asan_internal.h"
|
||||
|
||||
#if ASAN_USE_PREINIT_ARRAY && !defined(PIC)
|
||||
// On Linux, we force __asan_init to be called before anyone else
|
||||
// by placing it into .preinit_array section.
|
||||
// FIXME: do we have anything like this on Mac?
|
||||
using namespace __asan;
|
||||
|
||||
#if SANITIZER_CAN_USE_PREINIT_ARRAY
|
||||
// The symbol is called __local_asan_preinit, because it's not intended to be
|
||||
// exported.
|
||||
// This code linked into the main executable when -fsanitize=address is in
|
||||
// the link flags. It can only use exported interface functions.
|
||||
__attribute__((section(".preinit_array"), used))
|
||||
void (*__local_asan_preinit)(void) = __asan_init;
|
||||
#elif SANITIZER_WINDOWS && defined(_DLL)
|
||||
// On Windows, when using dynamic CRT (/MD), we can put a pointer
|
||||
// to __asan_init into the global list of C initializers.
|
||||
// See crt0dat.c in the CRT sources for the details.
|
||||
#pragma section(".CRT$XIB", long, read) // NOLINT
|
||||
__declspec(allocate(".CRT$XIB")) void (*__asan_preinit)() = __asan_init;
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -18,13 +18,33 @@
|
||||
|
||||
namespace __asan {
|
||||
|
||||
struct StackVarDescr {
|
||||
uptr beg;
|
||||
uptr size;
|
||||
const char *name_pos;
|
||||
uptr name_len;
|
||||
};
|
||||
|
||||
struct AddressDescription {
|
||||
char *name;
|
||||
uptr name_size;
|
||||
uptr region_address;
|
||||
uptr region_size;
|
||||
const char *region_kind;
|
||||
};
|
||||
|
||||
// The following functions prints address description depending
|
||||
// on the memory type (shadow/heap/stack/global).
|
||||
void DescribeHeapAddress(uptr addr, uptr access_size);
|
||||
bool DescribeAddressIfGlobal(uptr addr, uptr access_size);
|
||||
bool DescribeAddressRelativeToGlobal(uptr addr, uptr access_size,
|
||||
const __asan_global &g);
|
||||
bool DescribeAddressIfShadow(uptr addr);
|
||||
bool IsAddressNearGlobal(uptr addr, const __asan_global &g);
|
||||
bool GetInfoForAddressIfGlobal(uptr addr, AddressDescription *descr);
|
||||
bool DescribeAddressIfShadow(uptr addr, AddressDescription *descr = nullptr,
|
||||
bool print = true);
|
||||
bool ParseFrameDescription(const char *frame_descr,
|
||||
InternalMmapVector<StackVarDescr> *vars);
|
||||
bool DescribeAddressIfStack(uptr addr, uptr access_size);
|
||||
// Determines memory type on its own.
|
||||
void DescribeAddress(uptr addr, uptr access_size);
|
||||
@ -32,26 +52,44 @@ void DescribeAddress(uptr addr, uptr access_size);
|
||||
void DescribeThread(AsanThreadContext *context);
|
||||
|
||||
// Different kinds of error reports.
|
||||
void NORETURN ReportSIGSEGV(uptr pc, uptr sp, uptr bp, uptr addr);
|
||||
void NORETURN ReportDoubleFree(uptr addr, StackTrace *free_stack);
|
||||
void NORETURN ReportFreeNotMalloced(uptr addr, StackTrace *free_stack);
|
||||
void NORETURN ReportAllocTypeMismatch(uptr addr, StackTrace *free_stack,
|
||||
void NORETURN ReportStackOverflow(const SignalContext &sig);
|
||||
void NORETURN ReportSIGSEGV(const char *description, const SignalContext &sig);
|
||||
void NORETURN ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size,
|
||||
BufferedStackTrace *free_stack);
|
||||
void NORETURN ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack);
|
||||
void NORETURN ReportFreeNotMalloced(uptr addr, BufferedStackTrace *free_stack);
|
||||
void NORETURN ReportAllocTypeMismatch(uptr addr, BufferedStackTrace *free_stack,
|
||||
AllocType alloc_type,
|
||||
AllocType dealloc_type);
|
||||
void NORETURN ReportMallocUsableSizeNotOwned(uptr addr,
|
||||
StackTrace *stack);
|
||||
void NORETURN ReportAsanGetAllocatedSizeNotOwned(uptr addr,
|
||||
StackTrace *stack);
|
||||
void NORETURN ReportStringFunctionMemoryRangesOverlap(
|
||||
const char *function, const char *offset1, uptr length1,
|
||||
const char *offset2, uptr length2, StackTrace *stack);
|
||||
void NORETURN
|
||||
ReportMallocUsableSizeNotOwned(uptr addr, BufferedStackTrace *stack);
|
||||
void NORETURN
|
||||
ReportSanitizerGetAllocatedSizeNotOwned(uptr addr,
|
||||
BufferedStackTrace *stack);
|
||||
void NORETURN
|
||||
ReportStringFunctionMemoryRangesOverlap(const char *function,
|
||||
const char *offset1, uptr length1,
|
||||
const char *offset2, uptr length2,
|
||||
BufferedStackTrace *stack);
|
||||
void NORETURN ReportStringFunctionSizeOverflow(uptr offset, uptr size,
|
||||
BufferedStackTrace *stack);
|
||||
void NORETURN
|
||||
ReportBadParamsToAnnotateContiguousContainer(uptr beg, uptr end,
|
||||
uptr old_mid, uptr new_mid,
|
||||
BufferedStackTrace *stack);
|
||||
|
||||
void NORETURN
|
||||
ReportODRViolation(const __asan_global *g1, u32 stack_id1,
|
||||
const __asan_global *g2, u32 stack_id2);
|
||||
|
||||
// Mac-specific errors and warnings.
|
||||
void WarnMacFreeUnallocated(
|
||||
uptr addr, uptr zone_ptr, const char *zone_name, StackTrace *stack);
|
||||
void NORETURN ReportMacMzReallocUnknown(
|
||||
uptr addr, uptr zone_ptr, const char *zone_name, StackTrace *stack);
|
||||
void NORETURN ReportMacCfReallocUnknown(
|
||||
uptr addr, uptr zone_ptr, const char *zone_name, StackTrace *stack);
|
||||
void WarnMacFreeUnallocated(uptr addr, uptr zone_ptr, const char *zone_name,
|
||||
BufferedStackTrace *stack);
|
||||
void NORETURN ReportMacMzReallocUnknown(uptr addr, uptr zone_ptr,
|
||||
const char *zone_name,
|
||||
BufferedStackTrace *stack);
|
||||
void NORETURN ReportMacCfReallocUnknown(uptr addr, uptr zone_ptr,
|
||||
const char *zone_name,
|
||||
BufferedStackTrace *stack);
|
||||
|
||||
} // namespace __asan
|
||||
|
@ -11,6 +11,7 @@
|
||||
//
|
||||
// Main file of the ASan run-time library.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "asan_activation.h"
|
||||
#include "asan_allocator.h"
|
||||
#include "asan_interceptors.h"
|
||||
#include "asan_interface_internal.h"
|
||||
@ -20,6 +21,7 @@
|
||||
#include "asan_report.h"
|
||||
#include "asan_stack.h"
|
||||
#include "asan_stats.h"
|
||||
#include "asan_suppressions.h"
|
||||
#include "asan_thread.h"
|
||||
#include "sanitizer_common/sanitizer_atomic.h"
|
||||
#include "sanitizer_common/sanitizer_flags.h"
|
||||
@ -28,6 +30,7 @@
|
||||
#include "lsan/lsan_common.h"
|
||||
|
||||
int __asan_option_detect_stack_use_after_return; // Global interface symbol.
|
||||
uptr *__asan_test_only_reported_buggy_pointer; // Used only for testing asan.
|
||||
|
||||
namespace __asan {
|
||||
|
||||
@ -51,6 +54,8 @@ static void AsanDie() {
|
||||
UnmapOrDie((void*)kLowShadowBeg, kHighShadowEnd - kLowShadowBeg);
|
||||
}
|
||||
}
|
||||
if (common_flags()->coverage)
|
||||
__sanitizer_cov_dump();
|
||||
if (death_callback)
|
||||
death_callback();
|
||||
if (flags()->abort_on_error)
|
||||
@ -60,10 +65,10 @@ static void AsanDie() {
|
||||
|
||||
static void AsanCheckFailed(const char *file, int line, const char *cond,
|
||||
u64 v1, u64 v2) {
|
||||
Report("AddressSanitizer CHECK failed: %s:%d \"%s\" (0x%zx, 0x%zx)\n",
|
||||
file, line, cond, (uptr)v1, (uptr)v2);
|
||||
Report("AddressSanitizer CHECK failed: %s:%d \"%s\" (0x%zx, 0x%zx)\n", file,
|
||||
line, cond, (uptr)v1, (uptr)v2);
|
||||
// FIXME: check for infinite recursion without a thread-local counter here.
|
||||
PRINT_CURRENT_STACK();
|
||||
PRINT_CURRENT_STACK_CHECK();
|
||||
Die();
|
||||
}
|
||||
|
||||
@ -76,7 +81,7 @@ static const char *MaybeCallAsanDefaultOptions() {
|
||||
return (&__asan_default_options) ? __asan_default_options() : "";
|
||||
}
|
||||
|
||||
static const char *MaybeUseAsanDefaultOptionsCompileDefiniton() {
|
||||
static const char *MaybeUseAsanDefaultOptionsCompileDefinition() {
|
||||
#ifdef ASAN_DEFAULT_OPTIONS
|
||||
// Stringize the macro value.
|
||||
# define ASAN_STRINGIZE(x) #x
|
||||
@ -88,58 +93,162 @@ static const char *MaybeUseAsanDefaultOptionsCompileDefiniton() {
|
||||
}
|
||||
|
||||
static void ParseFlagsFromString(Flags *f, const char *str) {
|
||||
ParseCommonFlagsFromString(str);
|
||||
CHECK((uptr)common_flags()->malloc_context_size <= kStackTraceMax);
|
||||
|
||||
ParseFlag(str, &f->quarantine_size, "quarantine_size");
|
||||
ParseFlag(str, &f->redzone, "redzone");
|
||||
CommonFlags *cf = common_flags();
|
||||
ParseCommonFlagsFromString(cf, str);
|
||||
CHECK((uptr)cf->malloc_context_size <= kStackTraceMax);
|
||||
// Please write meaningful flag descriptions when adding new flags.
|
||||
ParseFlag(str, &f->quarantine_size, "quarantine_size",
|
||||
"Size (in bytes) of quarantine used to detect use-after-free "
|
||||
"errors. Lower value may reduce memory usage but increase the "
|
||||
"chance of false negatives.");
|
||||
ParseFlag(str, &f->redzone, "redzone",
|
||||
"Minimal size (in bytes) of redzones around heap objects. "
|
||||
"Requirement: redzone >= 16, is a power of two.");
|
||||
ParseFlag(str, &f->max_redzone, "max_redzone",
|
||||
"Maximal size (in bytes) of redzones around heap objects.");
|
||||
CHECK_GE(f->redzone, 16);
|
||||
CHECK_GE(f->max_redzone, f->redzone);
|
||||
CHECK_LE(f->max_redzone, 2048);
|
||||
CHECK(IsPowerOfTwo(f->redzone));
|
||||
CHECK(IsPowerOfTwo(f->max_redzone));
|
||||
|
||||
ParseFlag(str, &f->debug, "debug");
|
||||
ParseFlag(str, &f->report_globals, "report_globals");
|
||||
ParseFlag(str, &f->check_initialization_order, "check_initialization_order");
|
||||
ParseFlag(str, &f->debug, "debug",
|
||||
"If set, prints some debugging information and does additional checks.");
|
||||
ParseFlag(str, &f->report_globals, "report_globals",
|
||||
"Controls the way to handle globals (0 - don't detect buffer overflow on "
|
||||
"globals, 1 - detect buffer overflow, 2 - print data about registered "
|
||||
"globals).");
|
||||
|
||||
ParseFlag(str, &f->replace_str, "replace_str");
|
||||
ParseFlag(str, &f->replace_intrin, "replace_intrin");
|
||||
ParseFlag(str, &f->mac_ignore_invalid_free, "mac_ignore_invalid_free");
|
||||
ParseFlag(str, &f->check_initialization_order,
|
||||
"check_initialization_order",
|
||||
"If set, attempts to catch initialization order issues.");
|
||||
|
||||
ParseFlag(str, &f->replace_str, "replace_str",
|
||||
"If set, uses custom wrappers and replacements for libc string functions "
|
||||
"to find more errors.");
|
||||
|
||||
ParseFlag(str, &f->replace_intrin, "replace_intrin",
|
||||
"If set, uses custom wrappers for memset/memcpy/memmove intinsics.");
|
||||
ParseFlag(str, &f->mac_ignore_invalid_free, "mac_ignore_invalid_free",
|
||||
"Ignore invalid free() calls to work around some bugs. Used on OS X "
|
||||
"only.");
|
||||
ParseFlag(str, &f->detect_stack_use_after_return,
|
||||
"detect_stack_use_after_return");
|
||||
ParseFlag(str, &f->uar_stack_size_log, "uar_stack_size_log");
|
||||
ParseFlag(str, &f->max_malloc_fill_size, "max_malloc_fill_size");
|
||||
ParseFlag(str, &f->malloc_fill_byte, "malloc_fill_byte");
|
||||
ParseFlag(str, &f->exitcode, "exitcode");
|
||||
ParseFlag(str, &f->allow_user_poisoning, "allow_user_poisoning");
|
||||
ParseFlag(str, &f->sleep_before_dying, "sleep_before_dying");
|
||||
ParseFlag(str, &f->handle_segv, "handle_segv");
|
||||
ParseFlag(str, &f->allow_user_segv_handler, "allow_user_segv_handler");
|
||||
ParseFlag(str, &f->use_sigaltstack, "use_sigaltstack");
|
||||
ParseFlag(str, &f->check_malloc_usable_size, "check_malloc_usable_size");
|
||||
ParseFlag(str, &f->unmap_shadow_on_exit, "unmap_shadow_on_exit");
|
||||
ParseFlag(str, &f->abort_on_error, "abort_on_error");
|
||||
ParseFlag(str, &f->print_stats, "print_stats");
|
||||
ParseFlag(str, &f->print_legend, "print_legend");
|
||||
ParseFlag(str, &f->atexit, "atexit");
|
||||
ParseFlag(str, &f->coverage, "coverage");
|
||||
ParseFlag(str, &f->disable_core, "disable_core");
|
||||
ParseFlag(str, &f->allow_reexec, "allow_reexec");
|
||||
ParseFlag(str, &f->print_full_thread_history, "print_full_thread_history");
|
||||
ParseFlag(str, &f->poison_heap, "poison_heap");
|
||||
ParseFlag(str, &f->poison_partial, "poison_partial");
|
||||
ParseFlag(str, &f->alloc_dealloc_mismatch, "alloc_dealloc_mismatch");
|
||||
ParseFlag(str, &f->strict_memcmp, "strict_memcmp");
|
||||
ParseFlag(str, &f->strict_init_order, "strict_init_order");
|
||||
"detect_stack_use_after_return",
|
||||
"Enables stack-use-after-return checking at run-time.");
|
||||
ParseFlag(str, &f->min_uar_stack_size_log, "min_uar_stack_size_log",
|
||||
"Minimum fake stack size log.");
|
||||
ParseFlag(str, &f->max_uar_stack_size_log, "max_uar_stack_size_log",
|
||||
"Maximum fake stack size log.");
|
||||
ParseFlag(str, &f->uar_noreserve, "uar_noreserve",
|
||||
"Use mmap with 'norserve' flag to allocate fake stack.");
|
||||
ParseFlag(str, &f->max_malloc_fill_size, "max_malloc_fill_size",
|
||||
"ASan allocator flag. max_malloc_fill_size is the maximal amount of "
|
||||
"bytes that will be filled with malloc_fill_byte on malloc.");
|
||||
ParseFlag(str, &f->malloc_fill_byte, "malloc_fill_byte",
|
||||
"Value used to fill the newly allocated memory.");
|
||||
ParseFlag(str, &f->exitcode, "exitcode",
|
||||
"Override the program exit status if the tool found an error.");
|
||||
ParseFlag(str, &f->allow_user_poisoning, "allow_user_poisoning",
|
||||
"If set, user may manually mark memory regions as poisoned or "
|
||||
"unpoisoned.");
|
||||
ParseFlag(str, &f->sleep_before_dying, "sleep_before_dying",
|
||||
"Number of seconds to sleep between printing an error report and "
|
||||
"terminating the program. Useful for debugging purposes (e.g. when one "
|
||||
"needs to attach gdb).");
|
||||
|
||||
ParseFlag(str, &f->check_malloc_usable_size, "check_malloc_usable_size",
|
||||
"Allows the users to work around the bug in Nvidia drivers prior to "
|
||||
"295.*.");
|
||||
|
||||
ParseFlag(str, &f->unmap_shadow_on_exit, "unmap_shadow_on_exit",
|
||||
"If set, explicitly unmaps the (huge) shadow at exit.");
|
||||
ParseFlag(str, &f->abort_on_error, "abort_on_error",
|
||||
"If set, the tool calls abort() instead of _exit() after printing the "
|
||||
"error report.");
|
||||
ParseFlag(str, &f->print_stats, "print_stats",
|
||||
"Print various statistics after printing an error message or if "
|
||||
"atexit=1.");
|
||||
ParseFlag(str, &f->print_legend, "print_legend",
|
||||
"Print the legend for the shadow bytes.");
|
||||
ParseFlag(str, &f->atexit, "atexit",
|
||||
"If set, prints ASan exit stats even after program terminates "
|
||||
"successfully.");
|
||||
|
||||
ParseFlag(str, &f->allow_reexec, "allow_reexec",
|
||||
"Allow the tool to re-exec the program. This may interfere badly with "
|
||||
"the debugger.");
|
||||
|
||||
ParseFlag(str, &f->print_full_thread_history,
|
||||
"print_full_thread_history",
|
||||
"If set, prints thread creation stacks for the threads involved in the "
|
||||
"report and their ancestors up to the main thread.");
|
||||
|
||||
ParseFlag(str, &f->poison_heap, "poison_heap",
|
||||
"Poison (or not) the heap memory on [de]allocation. Zero value is useful "
|
||||
"for benchmarking the allocator or instrumentator.");
|
||||
|
||||
ParseFlag(str, &f->poison_array_cookie, "poison_array_cookie",
|
||||
"Poison (or not) the array cookie after operator new[].");
|
||||
|
||||
ParseFlag(str, &f->poison_partial, "poison_partial",
|
||||
"If true, poison partially addressable 8-byte aligned words "
|
||||
"(default=true). This flag affects heap and global buffers, but not "
|
||||
"stack buffers.");
|
||||
|
||||
ParseFlag(str, &f->alloc_dealloc_mismatch, "alloc_dealloc_mismatch",
|
||||
"Report errors on malloc/delete, new/free, new/delete[], etc.");
|
||||
|
||||
ParseFlag(str, &f->new_delete_type_mismatch, "new_delete_type_mismatch",
|
||||
"Report errors on mismatch betwen size of new and delete.");
|
||||
|
||||
ParseFlag(str, &f->strict_memcmp, "strict_memcmp",
|
||||
"If true, assume that memcmp(p1, p2, n) always reads n bytes before "
|
||||
"comparing p1 and p2.");
|
||||
|
||||
ParseFlag(str, &f->strict_init_order, "strict_init_order",
|
||||
"If true, assume that dynamic initializers can never access globals from "
|
||||
"other modules, even if the latter are already initialized.");
|
||||
|
||||
ParseFlag(str, &f->start_deactivated, "start_deactivated",
|
||||
"If true, ASan tweaks a bunch of other flags (quarantine, redzone, heap "
|
||||
"poisoning) to reduce memory consumption as much as possible, and "
|
||||
"restores them to original values when the first instrumented module is "
|
||||
"loaded into the process. This is mainly intended to be used on "
|
||||
"Android. ");
|
||||
|
||||
ParseFlag(str, &f->detect_invalid_pointer_pairs,
|
||||
"detect_invalid_pointer_pairs",
|
||||
"If non-zero, try to detect operations like <, <=, >, >= and - on "
|
||||
"invalid pointer pairs (e.g. when pointers belong to different objects). "
|
||||
"The bigger the value the harder we try.");
|
||||
|
||||
ParseFlag(str, &f->detect_container_overflow,
|
||||
"detect_container_overflow",
|
||||
"If true, honor the container overflow annotations. "
|
||||
"See https://code.google.com/p/address-sanitizer/wiki/ContainerOverflow");
|
||||
|
||||
ParseFlag(str, &f->detect_odr_violation, "detect_odr_violation",
|
||||
"If >=2, detect violation of One-Definition-Rule (ODR); "
|
||||
"If ==1, detect ODR-violation only if the two variables "
|
||||
"have different sizes");
|
||||
|
||||
ParseFlag(str, &f->dump_instruction_bytes, "dump_instruction_bytes",
|
||||
"If true, dump 16 bytes starting at the instruction that caused SEGV");
|
||||
}
|
||||
|
||||
void InitializeFlags(Flags *f, const char *env) {
|
||||
CommonFlags *cf = common_flags();
|
||||
SetCommonFlagDefaults();
|
||||
SetCommonFlagsDefaults(cf);
|
||||
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;
|
||||
cf->coverage = false;
|
||||
|
||||
internal_memset(f, 0, sizeof(*f));
|
||||
f->quarantine_size = (ASAN_LOW_MEMORY) ? 1UL << 26 : 1UL << 28;
|
||||
f->redzone = 16;
|
||||
f->max_redzone = 2048;
|
||||
f->debug = false;
|
||||
f->report_globals = 1;
|
||||
f->check_initialization_order = false;
|
||||
@ -147,53 +256,58 @@ void InitializeFlags(Flags *f, const char *env) {
|
||||
f->replace_intrin = true;
|
||||
f->mac_ignore_invalid_free = false;
|
||||
f->detect_stack_use_after_return = false; // Also needs the compiler flag.
|
||||
f->uar_stack_size_log = 0;
|
||||
f->min_uar_stack_size_log = 16; // We can't do smaller anyway.
|
||||
f->max_uar_stack_size_log = 20; // 1Mb per size class, i.e. ~11Mb per thread.
|
||||
f->uar_noreserve = false;
|
||||
f->max_malloc_fill_size = 0x1000; // By default, fill only the first 4K.
|
||||
f->malloc_fill_byte = 0xbe;
|
||||
f->exitcode = ASAN_DEFAULT_FAILURE_EXITCODE;
|
||||
f->allow_user_poisoning = true;
|
||||
f->sleep_before_dying = 0;
|
||||
f->handle_segv = ASAN_NEEDS_SEGV;
|
||||
f->allow_user_segv_handler = false;
|
||||
f->use_sigaltstack = false;
|
||||
f->check_malloc_usable_size = true;
|
||||
f->unmap_shadow_on_exit = false;
|
||||
f->abort_on_error = false;
|
||||
f->print_stats = false;
|
||||
f->print_legend = true;
|
||||
f->atexit = false;
|
||||
f->coverage = false;
|
||||
f->disable_core = (SANITIZER_WORDSIZE == 64);
|
||||
f->allow_reexec = true;
|
||||
f->print_full_thread_history = true;
|
||||
f->poison_heap = true;
|
||||
f->poison_array_cookie = true;
|
||||
f->poison_partial = true;
|
||||
// Turn off alloc/dealloc mismatch checker on Mac and Windows for now.
|
||||
// https://code.google.com/p/address-sanitizer/issues/detail?id=131
|
||||
// https://code.google.com/p/address-sanitizer/issues/detail?id=309
|
||||
// TODO(glider,timurrrr): Fix known issues and enable this back.
|
||||
f->alloc_dealloc_mismatch = (SANITIZER_MAC == 0) && (SANITIZER_WINDOWS == 0);
|
||||
f->new_delete_type_mismatch = true;
|
||||
f->strict_memcmp = true;
|
||||
f->strict_init_order = false;
|
||||
f->start_deactivated = false;
|
||||
f->detect_invalid_pointer_pairs = 0;
|
||||
f->detect_container_overflow = true;
|
||||
f->detect_odr_violation = 2;
|
||||
f->dump_instruction_bytes = false;
|
||||
|
||||
// Override from compile definition.
|
||||
ParseFlagsFromString(f, MaybeUseAsanDefaultOptionsCompileDefiniton());
|
||||
ParseFlagsFromString(f, MaybeUseAsanDefaultOptionsCompileDefinition());
|
||||
|
||||
// Override from user-specified string.
|
||||
ParseFlagsFromString(f, MaybeCallAsanDefaultOptions());
|
||||
if (common_flags()->verbosity) {
|
||||
Report("Using the defaults from __asan_default_options: %s\n",
|
||||
VReport(1, "Using the defaults from __asan_default_options: %s\n",
|
||||
MaybeCallAsanDefaultOptions());
|
||||
}
|
||||
|
||||
// Override from command line.
|
||||
ParseFlagsFromString(f, env);
|
||||
if (common_flags()->help) {
|
||||
PrintFlagDescriptions();
|
||||
}
|
||||
|
||||
#if !CAN_SANITIZE_LEAKS
|
||||
if (cf->detect_leaks) {
|
||||
if (!CAN_SANITIZE_LEAKS && cf->detect_leaks) {
|
||||
Report("%s: detect_leaks is not supported on this platform.\n",
|
||||
SanitizerToolName);
|
||||
cf->detect_leaks = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Make "strict_init_order" imply "check_initialization_order".
|
||||
// TODO(samsonov): Use a single runtime flag for an init-order checker.
|
||||
@ -202,6 +316,17 @@ void InitializeFlags(Flags *f, const char *env) {
|
||||
}
|
||||
}
|
||||
|
||||
// Parse flags that may change between startup and activation.
|
||||
// On Android they come from a system property.
|
||||
// On other platforms this is no-op.
|
||||
void ParseExtraActivationFlags() {
|
||||
char buf[100];
|
||||
GetExtraActivationFlags(buf, sizeof(buf));
|
||||
ParseFlagsFromString(flags(), buf);
|
||||
if (buf[0] != '\0')
|
||||
VReport(1, "Extra activation flags: %s\n", buf);
|
||||
}
|
||||
|
||||
// -------------------------- Globals --------------------- {{{1
|
||||
int asan_inited;
|
||||
bool asan_init_is_running;
|
||||
@ -223,6 +348,7 @@ static void ReserveShadowMemoryRange(uptr beg, uptr end) {
|
||||
CHECK_EQ((beg % GetPageSizeCached()), 0);
|
||||
CHECK_EQ(((end + 1) % GetPageSizeCached()), 0);
|
||||
uptr size = end - beg + 1;
|
||||
DecreaseTotalMmap(size); // Don't count the shadow against mmap_limit_mb.
|
||||
void *res = MmapFixedNoReserve(beg, size);
|
||||
if (res != (void*)beg) {
|
||||
Report("ReserveShadowMemoryRange failed while trying to map 0x%zx bytes. "
|
||||
@ -268,6 +394,53 @@ void __asan_report_ ## type ## _n(uptr addr, uptr size) { \
|
||||
ASAN_REPORT_ERROR_N(load, false)
|
||||
ASAN_REPORT_ERROR_N(store, true)
|
||||
|
||||
#define ASAN_MEMORY_ACCESS_CALLBACK(type, is_write, size) \
|
||||
extern "C" NOINLINE INTERFACE_ATTRIBUTE void __asan_##type##size(uptr addr); \
|
||||
void __asan_##type##size(uptr addr) { \
|
||||
uptr sp = MEM_TO_SHADOW(addr); \
|
||||
uptr s = size <= SHADOW_GRANULARITY ? *reinterpret_cast<u8 *>(sp) \
|
||||
: *reinterpret_cast<u16 *>(sp); \
|
||||
if (UNLIKELY(s)) { \
|
||||
if (UNLIKELY(size >= SHADOW_GRANULARITY || \
|
||||
((s8)((addr & (SHADOW_GRANULARITY - 1)) + size - 1)) >= \
|
||||
(s8)s)) { \
|
||||
if (__asan_test_only_reported_buggy_pointer) { \
|
||||
*__asan_test_only_reported_buggy_pointer = addr; \
|
||||
} else { \
|
||||
GET_CALLER_PC_BP_SP; \
|
||||
__asan_report_error(pc, bp, sp, addr, is_write, size); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
ASAN_MEMORY_ACCESS_CALLBACK(load, false, 1)
|
||||
ASAN_MEMORY_ACCESS_CALLBACK(load, false, 2)
|
||||
ASAN_MEMORY_ACCESS_CALLBACK(load, false, 4)
|
||||
ASAN_MEMORY_ACCESS_CALLBACK(load, false, 8)
|
||||
ASAN_MEMORY_ACCESS_CALLBACK(load, false, 16)
|
||||
ASAN_MEMORY_ACCESS_CALLBACK(store, true, 1)
|
||||
ASAN_MEMORY_ACCESS_CALLBACK(store, true, 2)
|
||||
ASAN_MEMORY_ACCESS_CALLBACK(store, true, 4)
|
||||
ASAN_MEMORY_ACCESS_CALLBACK(store, true, 8)
|
||||
ASAN_MEMORY_ACCESS_CALLBACK(store, true, 16)
|
||||
|
||||
extern "C"
|
||||
NOINLINE INTERFACE_ATTRIBUTE void __asan_loadN(uptr addr, uptr size) {
|
||||
if (__asan_region_is_poisoned(addr, size)) {
|
||||
GET_CALLER_PC_BP_SP;
|
||||
__asan_report_error(pc, bp, sp, addr, false, size);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C"
|
||||
NOINLINE INTERFACE_ATTRIBUTE void __asan_storeN(uptr addr, uptr size) {
|
||||
if (__asan_region_is_poisoned(addr, size)) {
|
||||
GET_CALLER_PC_BP_SP;
|
||||
__asan_report_error(pc, bp, sp, addr, true, size);
|
||||
}
|
||||
}
|
||||
|
||||
// Force the linker to keep the symbols for various ASan interface functions.
|
||||
// We want to keep those in the executable in order to let the instrumented
|
||||
// dynamic libraries access the symbol even if it is not used by the executable
|
||||
@ -294,13 +467,6 @@ static NOINLINE void force_interface_symbols() {
|
||||
case 15: __asan_set_error_report_callback(0); break;
|
||||
case 16: __asan_handle_no_return(); break;
|
||||
case 17: __asan_address_is_poisoned(0); break;
|
||||
case 18: __asan_get_allocated_size(0); break;
|
||||
case 19: __asan_get_current_allocated_bytes(); break;
|
||||
case 20: __asan_get_estimated_allocated_size(0); break;
|
||||
case 21: __asan_get_free_bytes(); break;
|
||||
case 22: __asan_get_heap_size(); break;
|
||||
case 23: __asan_get_ownership(0); break;
|
||||
case 24: __asan_get_unmapped_bytes(); break;
|
||||
case 25: __asan_poison_memory_region(0, 0); break;
|
||||
case 26: __asan_unpoison_memory_region(0, 0); break;
|
||||
case 27: __asan_set_error_exit_code(0); break;
|
||||
@ -371,7 +537,8 @@ static void PrintAddressSpaceLayout() {
|
||||
(void*)MEM_TO_SHADOW(kMidShadowEnd));
|
||||
}
|
||||
Printf("\n");
|
||||
Printf("red_zone=%zu\n", (uptr)flags()->redzone);
|
||||
Printf("redzone=%zu\n", (uptr)flags()->redzone);
|
||||
Printf("max_redzone=%zu\n", (uptr)flags()->max_redzone);
|
||||
Printf("quarantine_size=%zuM\n", (uptr)flags()->quarantine_size >> 20);
|
||||
Printf("malloc_context_size=%zu\n",
|
||||
(uptr)common_flags()->malloc_context_size);
|
||||
@ -386,6 +553,172 @@ static void PrintAddressSpaceLayout() {
|
||||
kHighShadowBeg > kMidMemEnd);
|
||||
}
|
||||
|
||||
static void AsanInitInternal() {
|
||||
if (LIKELY(asan_inited)) return;
|
||||
SanitizerToolName = "AddressSanitizer";
|
||||
CHECK(!asan_init_is_running && "ASan init calls itself!");
|
||||
asan_init_is_running = true;
|
||||
|
||||
// Initialize flags. This must be done early, because most of the
|
||||
// initialization steps look at flags().
|
||||
const char *options = GetEnv("ASAN_OPTIONS");
|
||||
InitializeFlags(flags(), options);
|
||||
|
||||
InitializeHighMemEnd();
|
||||
|
||||
// Make sure we are not statically linked.
|
||||
AsanDoesNotSupportStaticLinkage();
|
||||
|
||||
// Install tool-specific callbacks in sanitizer_common.
|
||||
SetDieCallback(AsanDie);
|
||||
SetCheckFailedCallback(AsanCheckFailed);
|
||||
SetPrintfAndReportCallback(AppendToErrorMessageBuffer);
|
||||
|
||||
if (!flags()->start_deactivated)
|
||||
ParseExtraActivationFlags();
|
||||
|
||||
__sanitizer_set_report_path(common_flags()->log_path);
|
||||
__asan_option_detect_stack_use_after_return =
|
||||
flags()->detect_stack_use_after_return;
|
||||
CHECK_LE(flags()->min_uar_stack_size_log, flags()->max_uar_stack_size_log);
|
||||
|
||||
if (options) {
|
||||
VReport(1, "Parsed ASAN_OPTIONS: %s\n", options);
|
||||
}
|
||||
|
||||
if (flags()->start_deactivated)
|
||||
AsanStartDeactivated();
|
||||
|
||||
// Re-exec ourselves if we need to set additional env or command line args.
|
||||
MaybeReexec();
|
||||
|
||||
// Setup internal allocator callback.
|
||||
SetLowLevelAllocateCallback(OnLowLevelAllocate);
|
||||
|
||||
InitializeAsanInterceptors();
|
||||
|
||||
// Enable system log ("adb logcat") on Android.
|
||||
// Doing this before interceptors are initialized crashes in:
|
||||
// AsanInitInternal -> android_log_write -> __interceptor_strcmp
|
||||
AndroidLogInit();
|
||||
|
||||
ReplaceSystemMalloc();
|
||||
|
||||
uptr shadow_start = kLowShadowBeg;
|
||||
if (kLowShadowBeg)
|
||||
shadow_start -= GetMmapGranularity();
|
||||
bool full_shadow_is_available =
|
||||
MemoryRangeIsAvailable(shadow_start, kHighShadowEnd);
|
||||
|
||||
#if SANITIZER_LINUX && defined(__x86_64__) && defined(_LP64) && \
|
||||
!ASAN_FIXED_MAPPING
|
||||
if (!full_shadow_is_available) {
|
||||
kMidMemBeg = kLowMemEnd < 0x3000000000ULL ? 0x3000000000ULL : 0;
|
||||
kMidMemEnd = kLowMemEnd < 0x3000000000ULL ? 0x4fffffffffULL : 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (common_flags()->verbosity)
|
||||
PrintAddressSpaceLayout();
|
||||
|
||||
DisableCoreDumperIfNecessary();
|
||||
|
||||
if (full_shadow_is_available) {
|
||||
// mmap the low shadow plus at least one page at the left.
|
||||
if (kLowShadowBeg)
|
||||
ReserveShadowMemoryRange(shadow_start, kLowShadowEnd);
|
||||
// mmap the high shadow.
|
||||
ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd);
|
||||
// protect the gap.
|
||||
ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
|
||||
CHECK_EQ(kShadowGapEnd, kHighShadowBeg - 1);
|
||||
} else if (kMidMemBeg &&
|
||||
MemoryRangeIsAvailable(shadow_start, kMidMemBeg - 1) &&
|
||||
MemoryRangeIsAvailable(kMidMemEnd + 1, kHighShadowEnd)) {
|
||||
CHECK(kLowShadowBeg != kLowShadowEnd);
|
||||
// mmap the low shadow plus at least one page at the left.
|
||||
ReserveShadowMemoryRange(shadow_start, kLowShadowEnd);
|
||||
// mmap the mid shadow.
|
||||
ReserveShadowMemoryRange(kMidShadowBeg, kMidShadowEnd);
|
||||
// mmap the high shadow.
|
||||
ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd);
|
||||
// protect the gaps.
|
||||
ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
|
||||
ProtectGap(kShadowGap2Beg, kShadowGap2End - kShadowGap2Beg + 1);
|
||||
ProtectGap(kShadowGap3Beg, kShadowGap3End - kShadowGap3Beg + 1);
|
||||
} else {
|
||||
Report("Shadow memory range interleaves with an existing memory mapping. "
|
||||
"ASan cannot proceed correctly. ABORTING.\n");
|
||||
DumpProcessMap();
|
||||
Die();
|
||||
}
|
||||
|
||||
AsanTSDInit(PlatformTSDDtor);
|
||||
InstallDeadlySignalHandlers(AsanOnSIGSEGV);
|
||||
|
||||
InitializeAllocator();
|
||||
|
||||
// On Linux AsanThread::ThreadStart() calls malloc() that's why asan_inited
|
||||
// should be set to 1 prior to initializing the threads.
|
||||
asan_inited = 1;
|
||||
asan_init_is_running = false;
|
||||
|
||||
if (flags()->atexit)
|
||||
Atexit(asan_atexit);
|
||||
|
||||
if (common_flags()->coverage) {
|
||||
__sanitizer_cov_init();
|
||||
Atexit(__sanitizer_cov_dump);
|
||||
}
|
||||
|
||||
// interceptors
|
||||
InitTlsSize();
|
||||
|
||||
// Create main thread.
|
||||
AsanThread *main_thread = AsanThread::Create(
|
||||
/* start_routine */ nullptr, /* arg */ nullptr, /* parent_tid */ 0,
|
||||
/* stack */ nullptr, /* detached */ true);
|
||||
CHECK_EQ(0, main_thread->tid());
|
||||
SetCurrentThread(main_thread);
|
||||
main_thread->ThreadStart(internal_getpid(),
|
||||
/* signal_thread_is_registered */ nullptr);
|
||||
force_interface_symbols(); // no-op.
|
||||
SanitizerInitializeUnwinder();
|
||||
|
||||
#if CAN_SANITIZE_LEAKS
|
||||
__lsan::InitCommonLsan(false);
|
||||
if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) {
|
||||
Atexit(__lsan::DoLeakCheck);
|
||||
}
|
||||
#endif // CAN_SANITIZE_LEAKS
|
||||
|
||||
InitializeSuppressions();
|
||||
|
||||
VReport(1, "AddressSanitizer Init done\n");
|
||||
}
|
||||
|
||||
// Initialize as requested from some part of ASan runtime library (interceptors,
|
||||
// allocator, etc).
|
||||
void AsanInitFromRtl() {
|
||||
AsanInitInternal();
|
||||
}
|
||||
|
||||
#if ASAN_DYNAMIC
|
||||
// Initialize runtime in case it's LD_PRELOAD-ed into unsanitized executable
|
||||
// (and thus normal initializer from .preinit_array haven't run).
|
||||
|
||||
class AsanInitializer {
|
||||
public: // NOLINT
|
||||
AsanInitializer() {
|
||||
AsanCheckIncompatibleRT();
|
||||
AsanCheckDynamicRTPrereqs();
|
||||
AsanInitFromRtl();
|
||||
}
|
||||
};
|
||||
|
||||
static AsanInitializer asan_initializer;
|
||||
#endif // ASAN_DYNAMIC
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
// ---------------------- Interface ---------------- {{{1
|
||||
@ -434,139 +767,10 @@ void NOINLINE __asan_set_death_callback(void (*callback)(void)) {
|
||||
death_callback = callback;
|
||||
}
|
||||
|
||||
// Initialize as requested from instrumented application code.
|
||||
// We use this call as a trigger to wake up ASan from deactivated state.
|
||||
void __asan_init() {
|
||||
if (asan_inited) return;
|
||||
SanitizerToolName = "AddressSanitizer";
|
||||
CHECK(!asan_init_is_running && "ASan init calls itself!");
|
||||
asan_init_is_running = true;
|
||||
InitializeHighMemEnd();
|
||||
|
||||
// Make sure we are not statically linked.
|
||||
AsanDoesNotSupportStaticLinkage();
|
||||
|
||||
// Install tool-specific callbacks in sanitizer_common.
|
||||
SetDieCallback(AsanDie);
|
||||
SetCheckFailedCallback(AsanCheckFailed);
|
||||
SetPrintfAndReportCallback(AppendToErrorMessageBuffer);
|
||||
|
||||
// Initialize flags. This must be done early, because most of the
|
||||
// initialization steps look at flags().
|
||||
const char *options = GetEnv("ASAN_OPTIONS");
|
||||
InitializeFlags(flags(), options);
|
||||
__sanitizer_set_report_path(common_flags()->log_path);
|
||||
__asan_option_detect_stack_use_after_return =
|
||||
flags()->detect_stack_use_after_return;
|
||||
|
||||
if (common_flags()->verbosity && options) {
|
||||
Report("Parsed ASAN_OPTIONS: %s\n", options);
|
||||
}
|
||||
|
||||
// Re-exec ourselves if we need to set additional env or command line args.
|
||||
MaybeReexec();
|
||||
|
||||
// Setup internal allocator callback.
|
||||
SetLowLevelAllocateCallback(OnLowLevelAllocate);
|
||||
|
||||
InitializeAsanInterceptors();
|
||||
|
||||
ReplaceSystemMalloc();
|
||||
ReplaceOperatorsNewAndDelete();
|
||||
|
||||
uptr shadow_start = kLowShadowBeg;
|
||||
if (kLowShadowBeg)
|
||||
shadow_start -= GetMmapGranularity();
|
||||
bool full_shadow_is_available =
|
||||
MemoryRangeIsAvailable(shadow_start, kHighShadowEnd);
|
||||
|
||||
#if SANITIZER_LINUX && defined(__x86_64__) && !ASAN_FIXED_MAPPING
|
||||
if (!full_shadow_is_available) {
|
||||
kMidMemBeg = kLowMemEnd < 0x3000000000ULL ? 0x3000000000ULL : 0;
|
||||
kMidMemEnd = kLowMemEnd < 0x3000000000ULL ? 0x4fffffffffULL : 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (common_flags()->verbosity)
|
||||
PrintAddressSpaceLayout();
|
||||
|
||||
if (flags()->disable_core) {
|
||||
DisableCoreDumper();
|
||||
}
|
||||
|
||||
if (full_shadow_is_available) {
|
||||
// mmap the low shadow plus at least one page at the left.
|
||||
if (kLowShadowBeg)
|
||||
ReserveShadowMemoryRange(shadow_start, kLowShadowEnd);
|
||||
// mmap the high shadow.
|
||||
ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd);
|
||||
// protect the gap.
|
||||
ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
|
||||
} else if (kMidMemBeg &&
|
||||
MemoryRangeIsAvailable(shadow_start, kMidMemBeg - 1) &&
|
||||
MemoryRangeIsAvailable(kMidMemEnd + 1, kHighShadowEnd)) {
|
||||
CHECK(kLowShadowBeg != kLowShadowEnd);
|
||||
// mmap the low shadow plus at least one page at the left.
|
||||
ReserveShadowMemoryRange(shadow_start, kLowShadowEnd);
|
||||
// mmap the mid shadow.
|
||||
ReserveShadowMemoryRange(kMidShadowBeg, kMidShadowEnd);
|
||||
// mmap the high shadow.
|
||||
ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd);
|
||||
// protect the gaps.
|
||||
ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
|
||||
ProtectGap(kShadowGap2Beg, kShadowGap2End - kShadowGap2Beg + 1);
|
||||
ProtectGap(kShadowGap3Beg, kShadowGap3End - kShadowGap3Beg + 1);
|
||||
} else {
|
||||
Report("Shadow memory range interleaves with an existing memory mapping. "
|
||||
"ASan cannot proceed correctly. ABORTING.\n");
|
||||
DumpProcessMap();
|
||||
Die();
|
||||
}
|
||||
|
||||
AsanTSDInit(PlatformTSDDtor);
|
||||
InstallSignalHandlers();
|
||||
|
||||
// Allocator should be initialized before starting external symbolizer, as
|
||||
// fork() on Mac locks the allocator.
|
||||
InitializeAllocator();
|
||||
|
||||
// Start symbolizer process if necessary.
|
||||
if (common_flags()->symbolize) {
|
||||
Symbolizer::Init(common_flags()->external_symbolizer_path);
|
||||
} else {
|
||||
Symbolizer::Disable();
|
||||
}
|
||||
|
||||
// On Linux AsanThread::ThreadStart() calls malloc() that's why asan_inited
|
||||
// should be set to 1 prior to initializing the threads.
|
||||
asan_inited = 1;
|
||||
asan_init_is_running = false;
|
||||
|
||||
if (flags()->atexit)
|
||||
Atexit(asan_atexit);
|
||||
|
||||
if (flags()->coverage)
|
||||
Atexit(__sanitizer_cov_dump);
|
||||
|
||||
// interceptors
|
||||
InitTlsSize();
|
||||
|
||||
// Create main thread.
|
||||
AsanThread *main_thread = AsanThread::Create(0, 0);
|
||||
CreateThreadContextArgs create_main_args = { main_thread, 0 };
|
||||
u32 main_tid = asanThreadRegistry().CreateThread(
|
||||
0, true, 0, &create_main_args);
|
||||
CHECK_EQ(0, main_tid);
|
||||
SetCurrentThread(main_thread);
|
||||
main_thread->ThreadStart(internal_getpid());
|
||||
force_interface_symbols(); // no-op.
|
||||
|
||||
#if CAN_SANITIZE_LEAKS
|
||||
__lsan::InitCommonLsan();
|
||||
if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) {
|
||||
Atexit(__lsan::DoLeakCheck);
|
||||
}
|
||||
#endif // CAN_SANITIZE_LEAKS
|
||||
|
||||
if (common_flags()->verbosity) {
|
||||
Report("AddressSanitizer Init done\n");
|
||||
}
|
||||
AsanCheckIncompatibleRT();
|
||||
AsanActivate();
|
||||
AsanInitInternal();
|
||||
}
|
||||
|
@ -12,36 +12,14 @@
|
||||
// Code for ASan stack trace.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "asan_internal.h"
|
||||
#include "asan_flags.h"
|
||||
#include "asan_stack.h"
|
||||
#include "sanitizer_common/sanitizer_flags.h"
|
||||
|
||||
namespace __asan {
|
||||
|
||||
static bool MaybeCallAsanSymbolize(const void *pc, char *out_buffer,
|
||||
int out_size) {
|
||||
return (&__asan_symbolize) ? __asan_symbolize(pc, out_buffer, out_size)
|
||||
: false;
|
||||
}
|
||||
|
||||
void PrintStack(const uptr *trace, uptr size) {
|
||||
StackTrace::PrintStack(trace, size, MaybeCallAsanSymbolize);
|
||||
}
|
||||
|
||||
void PrintStack(StackTrace *stack) {
|
||||
PrintStack(stack->trace, stack->size);
|
||||
}
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
// ------------------ Interface -------------- {{{1
|
||||
|
||||
// Provide default implementation of __asan_symbolize that does nothing
|
||||
// and may be overriden by user if he wants to use his own symbolization.
|
||||
// ASan on Windows has its own implementation of this.
|
||||
#if !SANITIZER_WINDOWS && !SANITIZER_SUPPORTS_WEAK_HOOKS
|
||||
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE NOINLINE
|
||||
bool __asan_symbolize(const void *pc, char *out_buffer, int out_size) {
|
||||
return false;
|
||||
extern "C" {
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void __sanitizer_print_stack_trace() {
|
||||
using namespace __asan;
|
||||
PRINT_CURRENT_STACK();
|
||||
}
|
||||
#endif
|
||||
} // extern "C"
|
||||
|
@ -21,48 +21,75 @@
|
||||
|
||||
namespace __asan {
|
||||
|
||||
void PrintStack(StackTrace *stack);
|
||||
void PrintStack(const uptr *trace, uptr size);
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
// Get the stack trace with the given pc and bp.
|
||||
// The pc will be in the position 0 of the resulting stack trace.
|
||||
// The bp may refer to the current frame or to the caller's frame.
|
||||
ALWAYS_INLINE
|
||||
void GetStackTraceWithPcBpAndContext(BufferedStackTrace *stack, uptr max_depth,
|
||||
uptr pc, uptr bp, void *context,
|
||||
bool fast) {
|
||||
#if SANITIZER_WINDOWS
|
||||
#define GET_STACK_TRACE_WITH_PC_AND_BP(max_s, pc, bp, fast) \
|
||||
StackTrace stack; \
|
||||
stack.Unwind(max_s, pc, bp, 0, 0, fast)
|
||||
stack->Unwind(max_depth, pc, bp, context, 0, 0, fast);
|
||||
#else
|
||||
#define GET_STACK_TRACE_WITH_PC_AND_BP(max_s, pc, bp, fast) \
|
||||
StackTrace stack; \
|
||||
{ \
|
||||
AsanThread *t; \
|
||||
stack.size = 0; \
|
||||
if (asan_inited && (t = GetCurrentThread()) && !t->isUnwinding()) { \
|
||||
uptr stack_top = t->stack_top(); \
|
||||
uptr stack_bottom = t->stack_bottom(); \
|
||||
ScopedUnwinding unwind_scope(t); \
|
||||
stack.Unwind(max_s, pc, bp, stack_top, stack_bottom, fast); \
|
||||
} \
|
||||
AsanThread *t;
|
||||
stack->size = 0;
|
||||
if (LIKELY(asan_inited)) {
|
||||
if ((t = GetCurrentThread()) && !t->isUnwinding()) {
|
||||
// On FreeBSD the slow unwinding that leverages _Unwind_Backtrace()
|
||||
// yields the call stack of the signal's handler and not of the code
|
||||
// that raised the signal (as it does on Linux).
|
||||
if (SANITIZER_FREEBSD && t->isInDeadlySignal()) fast = true;
|
||||
uptr stack_top = t->stack_top();
|
||||
uptr stack_bottom = t->stack_bottom();
|
||||
ScopedUnwinding unwind_scope(t);
|
||||
stack->Unwind(max_depth, pc, bp, context, stack_top, stack_bottom, fast);
|
||||
} else if (t == 0 && !fast) {
|
||||
/* If GetCurrentThread() has failed, try to do slow unwind anyways. */
|
||||
stack->Unwind(max_depth, pc, bp, context, 0, 0, false);
|
||||
}
|
||||
}
|
||||
#endif // SANITIZER_WINDOWS
|
||||
}
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
// NOTE: A Rule of thumb is to retrieve stack trace in the interceptors
|
||||
// as early as possible (in functions exposed to the user), as we generally
|
||||
// don't want stack trace to contain functions from ASan internals.
|
||||
|
||||
#define GET_STACK_TRACE(max_size, fast) \
|
||||
GET_STACK_TRACE_WITH_PC_AND_BP(max_size, \
|
||||
StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(), fast)
|
||||
BufferedStackTrace stack; \
|
||||
if (max_size <= 2) { \
|
||||
stack.size = max_size; \
|
||||
if (max_size > 0) { \
|
||||
stack.top_frame_bp = GET_CURRENT_FRAME(); \
|
||||
stack.trace_buffer[0] = StackTrace::GetCurrentPc(); \
|
||||
if (max_size > 1) \
|
||||
stack.trace_buffer[1] = GET_CALLER_PC(); \
|
||||
} \
|
||||
} else { \
|
||||
GetStackTraceWithPcBpAndContext(&stack, max_size, \
|
||||
StackTrace::GetCurrentPc(), \
|
||||
GET_CURRENT_FRAME(), 0, fast); \
|
||||
}
|
||||
|
||||
#define GET_STACK_TRACE_FATAL(pc, bp) \
|
||||
GET_STACK_TRACE_WITH_PC_AND_BP(kStackTraceMax, pc, bp, \
|
||||
BufferedStackTrace stack; \
|
||||
GetStackTraceWithPcBpAndContext(&stack, kStackTraceMax, pc, bp, 0, \
|
||||
common_flags()->fast_unwind_on_fatal)
|
||||
|
||||
#define GET_STACK_TRACE_SIGNAL(sig) \
|
||||
BufferedStackTrace stack; \
|
||||
GetStackTraceWithPcBpAndContext(&stack, kStackTraceMax, \
|
||||
(sig).pc, (sig).bp, (sig).context, \
|
||||
common_flags()->fast_unwind_on_fatal)
|
||||
|
||||
#define GET_STACK_TRACE_FATAL_HERE \
|
||||
GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_fatal)
|
||||
|
||||
#define GET_STACK_TRACE_CHECK_HERE \
|
||||
GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_check)
|
||||
|
||||
#define GET_STACK_TRACE_THREAD \
|
||||
GET_STACK_TRACE(kStackTraceMax, true)
|
||||
|
||||
@ -74,9 +101,14 @@ void PrintStack(const uptr *trace, uptr size);
|
||||
|
||||
#define PRINT_CURRENT_STACK() \
|
||||
{ \
|
||||
GET_STACK_TRACE(kStackTraceMax, \
|
||||
common_flags()->fast_unwind_on_fatal); \
|
||||
PrintStack(&stack); \
|
||||
GET_STACK_TRACE_FATAL_HERE; \
|
||||
stack.Print(); \
|
||||
}
|
||||
|
||||
#define PRINT_CURRENT_STACK_CHECK() \
|
||||
{ \
|
||||
GET_STACK_TRACE_CHECK_HERE; \
|
||||
stack.Print(); \
|
||||
}
|
||||
|
||||
#endif // ASAN_STACK_H
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "asan_internal.h"
|
||||
#include "asan_stats.h"
|
||||
#include "asan_thread.h"
|
||||
#include "sanitizer_common/sanitizer_allocator_interface.h"
|
||||
#include "sanitizer_common/sanitizer_mutex.h"
|
||||
#include "sanitizer_common/sanitizer_stackdepot.h"
|
||||
|
||||
@ -129,8 +130,8 @@ static void PrintAccumulatedStats() {
|
||||
BlockingMutexLock lock(&print_lock);
|
||||
stats.Print();
|
||||
StackDepotStats *stack_depot_stats = StackDepotGetStats();
|
||||
Printf("Stats: StackDepot: %zd ids; %zdM mapped\n",
|
||||
stack_depot_stats->n_uniq_ids, stack_depot_stats->mapped >> 20);
|
||||
Printf("Stats: StackDepot: %zd ids; %zdM allocated\n",
|
||||
stack_depot_stats->n_uniq_ids, stack_depot_stats->allocated >> 20);
|
||||
PrintInternalAllocatorStats();
|
||||
}
|
||||
|
||||
@ -139,7 +140,7 @@ static void PrintAccumulatedStats() {
|
||||
// ---------------------- Interface ---------------- {{{1
|
||||
using namespace __asan; // NOLINT
|
||||
|
||||
uptr __asan_get_current_allocated_bytes() {
|
||||
uptr __sanitizer_get_current_allocated_bytes() {
|
||||
AsanStats stats;
|
||||
GetAccumulatedStats(&stats);
|
||||
uptr malloced = stats.malloced;
|
||||
@ -149,13 +150,13 @@ uptr __asan_get_current_allocated_bytes() {
|
||||
return (malloced > freed) ? malloced - freed : 1;
|
||||
}
|
||||
|
||||
uptr __asan_get_heap_size() {
|
||||
uptr __sanitizer_get_heap_size() {
|
||||
AsanStats stats;
|
||||
GetAccumulatedStats(&stats);
|
||||
return stats.mmaped - stats.munmaped;
|
||||
}
|
||||
|
||||
uptr __asan_get_free_bytes() {
|
||||
uptr __sanitizer_get_free_bytes() {
|
||||
AsanStats stats;
|
||||
GetAccumulatedStats(&stats);
|
||||
uptr total_free = stats.mmaped
|
||||
@ -169,7 +170,7 @@ uptr __asan_get_free_bytes() {
|
||||
return (total_free > total_used) ? total_free - total_used : 1;
|
||||
}
|
||||
|
||||
uptr __asan_get_unmapped_bytes() {
|
||||
uptr __sanitizer_get_unmapped_bytes() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -47,9 +47,9 @@ struct AsanStats {
|
||||
uptr malloc_large;
|
||||
uptr malloc_small_slow;
|
||||
|
||||
// Ctor for global AsanStats (accumulated stats and main thread stats).
|
||||
// Ctor for global AsanStats (accumulated stats for dead threads).
|
||||
explicit AsanStats(LinkerInitialized) { }
|
||||
// Default ctor for thread-local stats.
|
||||
// Creates empty stats.
|
||||
AsanStats();
|
||||
|
||||
void Print(); // Prints formatted stats to stderr.
|
||||
|
87
lib/asan/asan_suppressions.cc
Normal file
87
lib/asan/asan_suppressions.cc
Normal file
@ -0,0 +1,87 @@
|
||||
//===-- asan_suppressions.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 AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// Issue suppression and suppression-related functions.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "asan_suppressions.h"
|
||||
|
||||
#include "asan_stack.h"
|
||||
#include "sanitizer_common/sanitizer_suppressions.h"
|
||||
#include "sanitizer_common/sanitizer_symbolizer.h"
|
||||
|
||||
namespace __asan {
|
||||
|
||||
static bool suppressions_inited = false;
|
||||
|
||||
void InitializeSuppressions() {
|
||||
CHECK(!suppressions_inited);
|
||||
SuppressionContext::InitIfNecessary();
|
||||
suppressions_inited = true;
|
||||
}
|
||||
|
||||
bool IsInterceptorSuppressed(const char *interceptor_name) {
|
||||
CHECK(suppressions_inited);
|
||||
SuppressionContext *ctx = SuppressionContext::Get();
|
||||
Suppression *s;
|
||||
// Match "interceptor_name" suppressions.
|
||||
return ctx->Match(interceptor_name, SuppressionInterceptorName, &s);
|
||||
}
|
||||
|
||||
bool HaveStackTraceBasedSuppressions() {
|
||||
CHECK(suppressions_inited);
|
||||
SuppressionContext *ctx = SuppressionContext::Get();
|
||||
return ctx->HasSuppressionType(SuppressionInterceptorViaFunction) ||
|
||||
ctx->HasSuppressionType(SuppressionInterceptorViaLibrary);
|
||||
}
|
||||
|
||||
bool IsStackTraceSuppressed(const StackTrace *stack) {
|
||||
CHECK(suppressions_inited);
|
||||
if (!HaveStackTraceBasedSuppressions())
|
||||
return false;
|
||||
|
||||
SuppressionContext *ctx = SuppressionContext::Get();
|
||||
Symbolizer *symbolizer = Symbolizer::GetOrInit();
|
||||
Suppression *s;
|
||||
for (uptr i = 0; i < stack->size && stack->trace[i]; i++) {
|
||||
uptr addr = stack->trace[i];
|
||||
|
||||
if (ctx->HasSuppressionType(SuppressionInterceptorViaLibrary)) {
|
||||
const char *module_name;
|
||||
uptr module_offset;
|
||||
// Match "interceptor_via_lib" suppressions.
|
||||
if (symbolizer->GetModuleNameAndOffsetForPC(addr, &module_name,
|
||||
&module_offset) &&
|
||||
ctx->Match(module_name, SuppressionInterceptorViaLibrary, &s)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx->HasSuppressionType(SuppressionInterceptorViaFunction)) {
|
||||
SymbolizedStack *frames = symbolizer->SymbolizePC(addr);
|
||||
for (SymbolizedStack *cur = frames; cur; cur = cur->next) {
|
||||
const char *function_name = cur->info.function;
|
||||
if (!function_name) {
|
||||
continue;
|
||||
}
|
||||
// Match "interceptor_via_fun" suppressions.
|
||||
if (ctx->Match(function_name, SuppressionInterceptorViaFunction, &s)) {
|
||||
frames->ClearAll();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
frames->ClearAll();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace __asan
|
29
lib/asan/asan_suppressions.h
Normal file
29
lib/asan/asan_suppressions.h
Normal file
@ -0,0 +1,29 @@
|
||||
//===-- asan_suppressions.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 AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// ASan-private header for asan_suppressions.cc.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef ASAN_SUPPRESSIONS_H
|
||||
#define ASAN_SUPPRESSIONS_H
|
||||
|
||||
#include "asan_internal.h"
|
||||
#include "sanitizer_common/sanitizer_stacktrace.h"
|
||||
|
||||
namespace __asan {
|
||||
|
||||
void InitializeSuppressions();
|
||||
bool IsInterceptorSuppressed(const char *interceptor_name);
|
||||
bool HaveStackTraceBasedSuppressions();
|
||||
bool IsStackTraceSuppressed(const StackTrace *stack);
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
#endif // ASAN_SUPPRESSIONS_H
|
@ -20,16 +20,22 @@
|
||||
#include "sanitizer_common/sanitizer_common.h"
|
||||
#include "sanitizer_common/sanitizer_placement_new.h"
|
||||
#include "sanitizer_common/sanitizer_stackdepot.h"
|
||||
#include "sanitizer_common/sanitizer_tls_get_addr.h"
|
||||
#include "lsan/lsan_common.h"
|
||||
|
||||
namespace __asan {
|
||||
|
||||
// AsanThreadContext implementation.
|
||||
|
||||
struct CreateThreadContextArgs {
|
||||
AsanThread *thread;
|
||||
StackTrace *stack;
|
||||
};
|
||||
|
||||
void AsanThreadContext::OnCreated(void *arg) {
|
||||
CreateThreadContextArgs *args = static_cast<CreateThreadContextArgs*>(arg);
|
||||
if (args->stack)
|
||||
stack_id = StackDepotPut(args->stack->trace, args->stack->size);
|
||||
stack_id = StackDepotPut(*args->stack);
|
||||
thread = args->thread;
|
||||
thread->set_context(this);
|
||||
}
|
||||
@ -74,42 +80,44 @@ AsanThreadContext *GetThreadContextByTidLocked(u32 tid) {
|
||||
|
||||
// AsanThread implementation.
|
||||
|
||||
AsanThread *AsanThread::Create(thread_callback_t start_routine,
|
||||
void *arg) {
|
||||
AsanThread *AsanThread::Create(thread_callback_t start_routine, void *arg,
|
||||
u32 parent_tid, StackTrace *stack,
|
||||
bool detached) {
|
||||
uptr PageSize = GetPageSizeCached();
|
||||
uptr size = RoundUpTo(sizeof(AsanThread), PageSize);
|
||||
AsanThread *thread = (AsanThread*)MmapOrDie(size, __FUNCTION__);
|
||||
AsanThread *thread = (AsanThread*)MmapOrDie(size, __func__);
|
||||
thread->start_routine_ = start_routine;
|
||||
thread->arg_ = arg;
|
||||
thread->context_ = 0;
|
||||
CreateThreadContextArgs args = { thread, stack };
|
||||
asanThreadRegistry().CreateThread(*reinterpret_cast<uptr *>(thread), detached,
|
||||
parent_tid, &args);
|
||||
|
||||
return thread;
|
||||
}
|
||||
|
||||
void AsanThread::TSDDtor(void *tsd) {
|
||||
AsanThreadContext *context = (AsanThreadContext*)tsd;
|
||||
if (common_flags()->verbosity >= 1)
|
||||
Report("T%d TSDDtor\n", context->tid);
|
||||
VReport(1, "T%d TSDDtor\n", context->tid);
|
||||
if (context->thread)
|
||||
context->thread->Destroy();
|
||||
}
|
||||
|
||||
void AsanThread::Destroy() {
|
||||
if (common_flags()->verbosity >= 1) {
|
||||
Report("T%d exited\n", tid());
|
||||
}
|
||||
int tid = this->tid();
|
||||
VReport(1, "T%d exited\n", tid);
|
||||
|
||||
malloc_storage().CommitBack();
|
||||
if (flags()->use_sigaltstack) UnsetAlternateSignalStack();
|
||||
asanThreadRegistry().FinishThread(tid());
|
||||
if (common_flags()->use_sigaltstack) UnsetAlternateSignalStack();
|
||||
asanThreadRegistry().FinishThread(tid);
|
||||
FlushToDeadThreadStats(&stats_);
|
||||
// We also clear the shadow on thread destruction because
|
||||
// some code may still be executing in later TSD destructors
|
||||
// and we don't want it to have any poisoned stack.
|
||||
ClearShadowForThreadStackAndTLS();
|
||||
DeleteFakeStack();
|
||||
DeleteFakeStack(tid);
|
||||
uptr size = RoundUpTo(sizeof(AsanThread), GetPageSizeCached());
|
||||
UnmapOrDie(this, size);
|
||||
DTLS_Destroy();
|
||||
}
|
||||
|
||||
// We want to create the FakeStack lazyly on the first use, but not eralier
|
||||
@ -124,13 +132,16 @@ FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() {
|
||||
// 1 -- being initialized
|
||||
// ptr -- initialized
|
||||
// This CAS checks if the state was 0 and if so changes it to state 1,
|
||||
// if that was successfull, it initilizes the pointer.
|
||||
// if that was successful, it initializes the pointer.
|
||||
if (atomic_compare_exchange_strong(
|
||||
reinterpret_cast<atomic_uintptr_t *>(&fake_stack_), &old_val, 1UL,
|
||||
memory_order_relaxed)) {
|
||||
uptr stack_size_log = Log2(RoundUpToPowerOfTwo(stack_size));
|
||||
if (flags()->uar_stack_size_log)
|
||||
stack_size_log = static_cast<uptr>(flags()->uar_stack_size_log);
|
||||
CHECK_LE(flags()->min_uar_stack_size_log, flags()->max_uar_stack_size_log);
|
||||
stack_size_log =
|
||||
Min(stack_size_log, static_cast<uptr>(flags()->max_uar_stack_size_log));
|
||||
stack_size_log =
|
||||
Max(stack_size_log, static_cast<uptr>(flags()->min_uar_stack_size_log));
|
||||
fake_stack_ = FakeStack::Create(stack_size_log);
|
||||
SetTLSFakeStack(fake_stack_);
|
||||
return fake_stack_;
|
||||
@ -139,24 +150,28 @@ FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() {
|
||||
}
|
||||
|
||||
void AsanThread::Init() {
|
||||
fake_stack_ = 0; // Will be initialized lazily if needed.
|
||||
CHECK_EQ(this->stack_size(), 0U);
|
||||
SetThreadStackAndTls();
|
||||
CHECK_GT(this->stack_size(), 0U);
|
||||
CHECK(AddrIsInMem(stack_bottom_));
|
||||
CHECK(AddrIsInMem(stack_top_ - 1));
|
||||
ClearShadowForThreadStackAndTLS();
|
||||
if (common_flags()->verbosity >= 1) {
|
||||
int local = 0;
|
||||
Report("T%d: stack [%p,%p) size 0x%zx; local=%p\n",
|
||||
tid(), (void*)stack_bottom_, (void*)stack_top_,
|
||||
stack_top_ - stack_bottom_, &local);
|
||||
}
|
||||
fake_stack_ = 0; // Will be initialized lazily if needed.
|
||||
VReport(1, "T%d: stack [%p,%p) size 0x%zx; local=%p\n", tid(),
|
||||
(void *)stack_bottom_, (void *)stack_top_, stack_top_ - stack_bottom_,
|
||||
&local);
|
||||
AsanPlatformThreadInit();
|
||||
}
|
||||
|
||||
thread_return_t AsanThread::ThreadStart(uptr os_id) {
|
||||
thread_return_t AsanThread::ThreadStart(
|
||||
uptr os_id, atomic_uintptr_t *signal_thread_is_registered) {
|
||||
Init();
|
||||
asanThreadRegistry().StartThread(tid(), os_id, 0);
|
||||
if (flags()->use_sigaltstack) SetAlternateSignalStack();
|
||||
if (signal_thread_is_registered)
|
||||
atomic_store(signal_thread_is_registered, 1, memory_order_release);
|
||||
|
||||
if (common_flags()->use_sigaltstack) SetAlternateSignalStack();
|
||||
|
||||
if (!start_routine_) {
|
||||
// start_routine_ == 0 if we're on the main thread or on one of the
|
||||
@ -196,17 +211,18 @@ void AsanThread::ClearShadowForThreadStackAndTLS() {
|
||||
PoisonShadow(tls_begin_, tls_end_ - tls_begin_, 0);
|
||||
}
|
||||
|
||||
const char *AsanThread::GetFrameNameByAddr(uptr addr, uptr *offset,
|
||||
uptr *frame_pc) {
|
||||
bool AsanThread::GetStackFrameAccessByAddr(uptr addr,
|
||||
StackFrameAccess *access) {
|
||||
uptr bottom = 0;
|
||||
if (AddrIsInStack(addr)) {
|
||||
bottom = stack_bottom();
|
||||
} else if (has_fake_stack()) {
|
||||
bottom = fake_stack()->AddrIsInFakeStack(addr);
|
||||
CHECK(bottom);
|
||||
*offset = addr - bottom;
|
||||
*frame_pc = ((uptr*)bottom)[2];
|
||||
return (const char *)((uptr*)bottom)[1];
|
||||
access->offset = addr - bottom;
|
||||
access->frame_pc = ((uptr*)bottom)[2];
|
||||
access->frame_descr = (const char *)((uptr*)bottom)[1];
|
||||
return true;
|
||||
}
|
||||
uptr aligned_addr = addr & ~(SANITIZER_WORDSIZE/8 - 1); // align addr.
|
||||
u8 *shadow_ptr = (u8*)MemToShadow(aligned_addr);
|
||||
@ -223,15 +239,15 @@ const char *AsanThread::GetFrameNameByAddr(uptr addr, uptr *offset,
|
||||
}
|
||||
|
||||
if (shadow_ptr < shadow_bottom) {
|
||||
*offset = 0;
|
||||
return "UNKNOWN";
|
||||
return false;
|
||||
}
|
||||
|
||||
uptr* ptr = (uptr*)SHADOW_TO_MEM((uptr)(shadow_ptr + 1));
|
||||
CHECK(ptr[0] == kCurrentStackFrameMagic);
|
||||
*offset = addr - (uptr)ptr;
|
||||
*frame_pc = ptr[2];
|
||||
return (const char*)ptr[1];
|
||||
access->offset = addr - (uptr)ptr;
|
||||
access->frame_pc = ptr[2];
|
||||
access->frame_descr = (const char*)ptr[1];
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ThreadStackContainsAddress(ThreadContextBase *tctx_base,
|
||||
@ -268,10 +284,8 @@ AsanThread *GetCurrentThread() {
|
||||
|
||||
void SetCurrentThread(AsanThread *t) {
|
||||
CHECK(t->context());
|
||||
if (common_flags()->verbosity >= 2) {
|
||||
Report("SetCurrentThread: %p for thread %p\n",
|
||||
t->context(), (void*)GetThreadSelf());
|
||||
}
|
||||
VReport(2, "SetCurrentThread: %p for thread %p\n", t->context(),
|
||||
(void *)GetThreadSelf());
|
||||
// Make sure we do not reset the current AsanThread.
|
||||
CHECK_EQ(0, AsanTSDGet());
|
||||
AsanTSDSet(t->context());
|
||||
|
@ -17,7 +17,6 @@
|
||||
#include "asan_allocator.h"
|
||||
#include "asan_internal.h"
|
||||
#include "asan_fake_stack.h"
|
||||
#include "asan_stack.h"
|
||||
#include "asan_stats.h"
|
||||
#include "sanitizer_common/sanitizer_common.h"
|
||||
#include "sanitizer_common/sanitizer_libc.h"
|
||||
@ -56,12 +55,14 @@ COMPILER_CHECK(sizeof(AsanThreadContext) <= 256);
|
||||
// AsanThread are stored in TSD and destroyed when the thread dies.
|
||||
class AsanThread {
|
||||
public:
|
||||
static AsanThread *Create(thread_callback_t start_routine, void *arg);
|
||||
static AsanThread *Create(thread_callback_t start_routine, void *arg,
|
||||
u32 parent_tid, StackTrace *stack, bool detached);
|
||||
static void TSDDtor(void *tsd);
|
||||
void Destroy();
|
||||
|
||||
void Init(); // Should be called from the thread itself.
|
||||
thread_return_t ThreadStart(uptr os_id);
|
||||
thread_return_t ThreadStart(uptr os_id,
|
||||
atomic_uintptr_t *signal_thread_is_registered);
|
||||
|
||||
uptr stack_top() { return stack_top_; }
|
||||
uptr stack_bottom() { return stack_bottom_; }
|
||||
@ -72,18 +73,23 @@ class AsanThread {
|
||||
AsanThreadContext *context() { return context_; }
|
||||
void set_context(AsanThreadContext *context) { context_ = context; }
|
||||
|
||||
const char *GetFrameNameByAddr(uptr addr, uptr *offset, uptr *frame_pc);
|
||||
struct StackFrameAccess {
|
||||
uptr offset;
|
||||
uptr frame_pc;
|
||||
const char *frame_descr;
|
||||
};
|
||||
bool GetStackFrameAccessByAddr(uptr addr, StackFrameAccess *access);
|
||||
|
||||
bool AddrIsInStack(uptr addr) {
|
||||
return addr >= stack_bottom_ && addr < stack_top_;
|
||||
}
|
||||
|
||||
void DeleteFakeStack() {
|
||||
void DeleteFakeStack(int tid) {
|
||||
if (!fake_stack_) return;
|
||||
FakeStack *t = fake_stack_;
|
||||
fake_stack_ = 0;
|
||||
SetTLSFakeStack(0);
|
||||
t->Destroy();
|
||||
t->Destroy(tid);
|
||||
}
|
||||
|
||||
bool has_fake_stack() {
|
||||
@ -101,14 +107,19 @@ class AsanThread {
|
||||
// True is this thread is currently unwinding stack (i.e. collecting a stack
|
||||
// trace). Used to prevent deadlocks on platforms where libc unwinder calls
|
||||
// malloc internally. See PR17116 for more details.
|
||||
bool isUnwinding() const { return unwinding; }
|
||||
void setUnwinding(bool b) { unwinding = b; }
|
||||
bool isUnwinding() const { return unwinding_; }
|
||||
void setUnwinding(bool b) { unwinding_ = b; }
|
||||
|
||||
// True if we are in a deadly signal handler.
|
||||
bool isInDeadlySignal() const { return in_deadly_signal_; }
|
||||
void setInDeadlySignal(bool b) { in_deadly_signal_ = b; }
|
||||
|
||||
AsanThreadLocalMallocStorage &malloc_storage() { return malloc_storage_; }
|
||||
AsanStats &stats() { return stats_; }
|
||||
|
||||
private:
|
||||
AsanThread() : unwinding(false) {}
|
||||
// NOTE: There is no AsanThread constructor. It is allocated
|
||||
// via mmap() and *must* be valid in zero-initialized state.
|
||||
void SetThreadStackAndTls();
|
||||
void ClearShadowForThreadStackAndTLS();
|
||||
FakeStack *AsyncSignalSafeLazyInitFakeStack();
|
||||
@ -127,7 +138,8 @@ class AsanThread {
|
||||
FakeStack *fake_stack_;
|
||||
AsanThreadLocalMallocStorage malloc_storage_;
|
||||
AsanStats stats_;
|
||||
bool unwinding;
|
||||
bool unwinding_;
|
||||
bool in_deadly_signal_;
|
||||
};
|
||||
|
||||
// ScopedUnwinding is a scope for stacktracing member of a context
|
||||
@ -142,9 +154,18 @@ class ScopedUnwinding {
|
||||
AsanThread *thread;
|
||||
};
|
||||
|
||||
struct CreateThreadContextArgs {
|
||||
// ScopedDeadlySignal is a scope for handling deadly signals.
|
||||
class ScopedDeadlySignal {
|
||||
public:
|
||||
explicit ScopedDeadlySignal(AsanThread *t) : thread(t) {
|
||||
if (thread) thread->setInDeadlySignal(true);
|
||||
}
|
||||
~ScopedDeadlySignal() {
|
||||
if (thread) thread->setInDeadlySignal(false);
|
||||
}
|
||||
|
||||
private:
|
||||
AsanThread *thread;
|
||||
StackTrace *stack;
|
||||
};
|
||||
|
||||
// Returns a single instance of registry.
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
#include "asan_interceptors.h"
|
||||
#include "asan_internal.h"
|
||||
#include "asan_report.h"
|
||||
#include "asan_thread.h"
|
||||
#include "sanitizer_common/sanitizer_libc.h"
|
||||
#include "sanitizer_common/sanitizer_mutex.h"
|
||||
@ -35,11 +36,6 @@ extern "C" {
|
||||
|
||||
namespace __asan {
|
||||
|
||||
// ---------------------- Stacktraces, symbols, etc. ---------------- {{{1
|
||||
static BlockingMutex dbghelp_lock(LINKER_INITIALIZED);
|
||||
static bool dbghelp_initialized = false;
|
||||
#pragma comment(lib, "dbghelp.lib")
|
||||
|
||||
// ---------------------- TSD ---------------- {{{1
|
||||
static bool tsd_key_inited = false;
|
||||
|
||||
@ -75,17 +71,9 @@ void *AsanDoesNotSupportStaticLinkage() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SetAlternateSignalStack() {
|
||||
// FIXME: Decide what to do on Windows.
|
||||
}
|
||||
void AsanCheckDynamicRTPrereqs() {}
|
||||
|
||||
void UnsetAlternateSignalStack() {
|
||||
// FIXME: Decide what to do on Windows.
|
||||
}
|
||||
|
||||
void InstallSignalHandlers() {
|
||||
// FIXME: Decide what to do on Windows.
|
||||
}
|
||||
void AsanCheckIncompatibleRT() {}
|
||||
|
||||
void AsanPlatformThreadInit() {
|
||||
// Nothing here for now.
|
||||
@ -95,54 +83,82 @@ void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
void AsanOnSIGSEGV(int, void *siginfo, void *context) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
static LPTOP_LEVEL_EXCEPTION_FILTER default_seh_handler;
|
||||
|
||||
SignalContext SignalContext::Create(void *siginfo, void *context) {
|
||||
EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD*)siginfo;
|
||||
CONTEXT *context_record = (CONTEXT*)context;
|
||||
|
||||
uptr pc = (uptr)exception_record->ExceptionAddress;
|
||||
#ifdef _WIN64
|
||||
uptr bp = (uptr)context_record->Rbp;
|
||||
uptr sp = (uptr)context_record->Rsp;
|
||||
#else
|
||||
uptr bp = (uptr)context_record->Ebp;
|
||||
uptr sp = (uptr)context_record->Esp;
|
||||
#endif
|
||||
uptr access_addr = exception_record->ExceptionInformation[1];
|
||||
|
||||
return SignalContext(context, access_addr, pc, sp, bp);
|
||||
}
|
||||
|
||||
static long WINAPI SEHHandler(EXCEPTION_POINTERS *info) {
|
||||
EXCEPTION_RECORD *exception_record = info->ExceptionRecord;
|
||||
CONTEXT *context = info->ContextRecord;
|
||||
|
||||
if (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION ||
|
||||
exception_record->ExceptionCode == EXCEPTION_IN_PAGE_ERROR) {
|
||||
const char *description =
|
||||
(exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
|
||||
? "access-violation"
|
||||
: "in-page-error";
|
||||
SignalContext sig = SignalContext::Create(exception_record, context);
|
||||
ReportSIGSEGV(description, sig);
|
||||
}
|
||||
|
||||
// FIXME: Handle EXCEPTION_STACK_OVERFLOW here.
|
||||
|
||||
return default_seh_handler(info);
|
||||
}
|
||||
|
||||
// We want to install our own exception handler (EH) to print helpful reports
|
||||
// on access violations and whatnot. Unfortunately, the CRT initializers assume
|
||||
// they are run before any user code and drop any previously-installed EHs on
|
||||
// the floor, so we can't install our handler inside __asan_init.
|
||||
// (See crt0dat.c in the CRT sources for the details)
|
||||
//
|
||||
// Things get even more complicated with the dynamic runtime, as it finishes its
|
||||
// initialization before the .exe module CRT begins to initialize.
|
||||
//
|
||||
// For the static runtime (-MT), it's enough to put a callback to
|
||||
// __asan_set_seh_filter in the last section for C initializers.
|
||||
//
|
||||
// For the dynamic runtime (-MD), we want link the same
|
||||
// asan_dynamic_runtime_thunk.lib to all the modules, thus __asan_set_seh_filter
|
||||
// will be called for each instrumented module. This ensures that at least one
|
||||
// __asan_set_seh_filter call happens after the .exe module CRT is initialized.
|
||||
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
|
||||
int __asan_set_seh_filter() {
|
||||
// We should only store the previous handler if it's not our own handler in
|
||||
// order to avoid loops in the EH chain.
|
||||
auto prev_seh_handler = SetUnhandledExceptionFilter(SEHHandler);
|
||||
if (prev_seh_handler != &SEHHandler)
|
||||
default_seh_handler = prev_seh_handler;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if !ASAN_DYNAMIC
|
||||
// Put a pointer to __asan_set_seh_filter at the end of the global list
|
||||
// of C initializers, after the default EH is set by the CRT.
|
||||
#pragma section(".CRT$XIZ", long, read) // NOLINT
|
||||
static __declspec(allocate(".CRT$XIZ"))
|
||||
int (*__intercept_seh)() = __asan_set_seh_filter;
|
||||
#endif
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
// ---------------------- Interface ---------------- {{{1
|
||||
using namespace __asan; // NOLINT
|
||||
|
||||
extern "C" {
|
||||
SANITIZER_INTERFACE_ATTRIBUTE NOINLINE
|
||||
bool __asan_symbolize(const void *addr, char *out_buffer, int buffer_size) {
|
||||
BlockingMutexLock lock(&dbghelp_lock);
|
||||
if (!dbghelp_initialized) {
|
||||
SymSetOptions(SYMOPT_DEFERRED_LOADS |
|
||||
SYMOPT_UNDNAME |
|
||||
SYMOPT_LOAD_LINES);
|
||||
CHECK(SymInitialize(GetCurrentProcess(), 0, TRUE));
|
||||
// FIXME: We don't call SymCleanup() on exit yet - should we?
|
||||
dbghelp_initialized = true;
|
||||
}
|
||||
|
||||
// See http://msdn.microsoft.com/en-us/library/ms680578(VS.85).aspx
|
||||
char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(CHAR)];
|
||||
PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer;
|
||||
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
||||
symbol->MaxNameLen = MAX_SYM_NAME;
|
||||
DWORD64 offset = 0;
|
||||
BOOL got_objname = SymFromAddr(GetCurrentProcess(),
|
||||
(DWORD64)addr, &offset, symbol);
|
||||
if (!got_objname)
|
||||
return false;
|
||||
|
||||
DWORD unused;
|
||||
IMAGEHLP_LINE64 info;
|
||||
info.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
|
||||
BOOL got_fileline = SymGetLineFromAddr64(GetCurrentProcess(),
|
||||
(DWORD64)addr, &unused, &info);
|
||||
int written = 0;
|
||||
out_buffer[0] = '\0';
|
||||
// FIXME: it might be useful to print out 'obj' or 'obj+offset' info too.
|
||||
if (got_fileline) {
|
||||
written += internal_snprintf(out_buffer + written, buffer_size - written,
|
||||
" %s %s:%d", symbol->Name,
|
||||
info.FileName, info.LineNumber);
|
||||
} else {
|
||||
written += internal_snprintf(out_buffer + written, buffer_size - written,
|
||||
" %s+0x%p", symbol->Name, offset);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} // extern "C"
|
||||
|
||||
|
||||
#endif // _WIN32
|
||||
|
376
lib/asan/asan_win_dll_thunk.cc
Normal file
376
lib/asan/asan_win_dll_thunk.cc
Normal file
@ -0,0 +1,376 @@
|
||||
//===-- asan_win_dll_thunk.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 AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// This file defines a family of thunks that should be statically linked into
|
||||
// the DLLs that have ASan instrumentation in order to delegate the calls to the
|
||||
// shared runtime that lives in the main binary.
|
||||
// See https://code.google.com/p/address-sanitizer/issues/detail?id=209 for the
|
||||
// details.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Only compile this code when buidling asan_dll_thunk.lib
|
||||
// Using #ifdef rather than relying on Makefiles etc.
|
||||
// simplifies the build procedure.
|
||||
#ifdef ASAN_DLL_THUNK
|
||||
#include "asan_init_version.h"
|
||||
#include "interception/interception.h"
|
||||
|
||||
// ---------- Function interception helper functions and macros ----------- {{{1
|
||||
extern "C" {
|
||||
void *__stdcall GetModuleHandleA(const char *module_name);
|
||||
void *__stdcall GetProcAddress(void *module, const char *proc_name);
|
||||
void abort();
|
||||
}
|
||||
|
||||
static void *getRealProcAddressOrDie(const char *name) {
|
||||
void *ret = GetProcAddress(GetModuleHandleA(0), name);
|
||||
if (!ret)
|
||||
abort();
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 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().
|
||||
|
||||
// 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() { \
|
||||
void *wrapper = getRealProcAddressOrDie(main_function); \
|
||||
if (!__interception::OverrideFunction((uptr)dll_function, \
|
||||
(uptr)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 void (*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 void (*fntype)(void *arg); \
|
||||
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 void (*fntype)(void *, void *); \
|
||||
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 void *(*fntype)(void *, void *, void *); \
|
||||
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 void *(*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 void *(*fntype)(void *arg); \
|
||||
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 void *(*fntype)(void *, void *); \
|
||||
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 void *(*fntype)(void *, void *, void *); \
|
||||
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 void *(*fntype)(void *, void *, void *, void *); \
|
||||
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 void *(*fntype)(void *, void *, void *, void *, void *); \
|
||||
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 void *(*fntype)(void *, void *, void *, void *, void *, void *); \
|
||||
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)
|
||||
|
||||
extern "C" {
|
||||
int __asan_option_detect_stack_use_after_return;
|
||||
|
||||
// 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_name);
|
||||
fn();
|
||||
__asan_option_detect_stack_use_after_return =
|
||||
(__asan_should_detect_stack_use_after_return() != 0);
|
||||
|
||||
InterceptHooks();
|
||||
}
|
||||
}
|
||||
|
||||
INTERFACE_FUNCTION(__asan_handle_no_return)
|
||||
|
||||
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_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)
|
||||
|
||||
INTERFACE_FUNCTION(__sanitizer_cov_module_init)
|
||||
|
||||
// TODO(timurrrr): Add more interface functions on the as-needed basis.
|
||||
|
||||
// ----------------- Memory allocation functions ---------------------
|
||||
WRAP_V_W(free)
|
||||
WRAP_V_WW(_free_dbg)
|
||||
|
||||
WRAP_W_W(malloc)
|
||||
WRAP_W_WWWW(_malloc_dbg)
|
||||
|
||||
WRAP_W_WW(calloc)
|
||||
WRAP_W_WWWWW(_calloc_dbg)
|
||||
WRAP_W_WWW(_calloc_impl)
|
||||
|
||||
WRAP_W_WW(realloc)
|
||||
WRAP_W_WWW(_realloc_dbg)
|
||||
WRAP_W_WWW(_recalloc)
|
||||
|
||||
WRAP_W_W(_msize)
|
||||
WRAP_W_W(_expand)
|
||||
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().
|
||||
|
||||
// TODO(timurrrr): Do we need to add _Crt* stuff here? (see asan_malloc_win.cc).
|
||||
|
||||
INTERCEPT_LIBRARY_FUNCTION(atoi);
|
||||
INTERCEPT_LIBRARY_FUNCTION(atol);
|
||||
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);
|
||||
}
|
||||
|
||||
INTERCEPT_LIBRARY_FUNCTION(frexp);
|
||||
INTERCEPT_LIBRARY_FUNCTION(longjmp);
|
||||
INTERCEPT_LIBRARY_FUNCTION(memchr);
|
||||
INTERCEPT_LIBRARY_FUNCTION(memcmp);
|
||||
INTERCEPT_LIBRARY_FUNCTION(memcpy);
|
||||
INTERCEPT_LIBRARY_FUNCTION(memmove);
|
||||
INTERCEPT_LIBRARY_FUNCTION(memset);
|
||||
INTERCEPT_LIBRARY_FUNCTION(strcat); // NOLINT
|
||||
INTERCEPT_LIBRARY_FUNCTION(strchr);
|
||||
INTERCEPT_LIBRARY_FUNCTION(strcmp);
|
||||
INTERCEPT_LIBRARY_FUNCTION(strcpy); // NOLINT
|
||||
INTERCEPT_LIBRARY_FUNCTION(strlen);
|
||||
INTERCEPT_LIBRARY_FUNCTION(strncat);
|
||||
INTERCEPT_LIBRARY_FUNCTION(strncmp);
|
||||
INTERCEPT_LIBRARY_FUNCTION(strncpy);
|
||||
INTERCEPT_LIBRARY_FUNCTION(strnlen);
|
||||
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();
|
||||
INTERCEPT_FUNCTION(_except_handler4);
|
||||
}
|
||||
|
||||
// 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();
|
||||
return 0;
|
||||
}
|
||||
#pragma section(".CRT$XIB", long, read) // NOLINT
|
||||
__declspec(allocate(".CRT$XIB")) int (*__asan_preinit)() = call_asan_init;
|
||||
|
||||
#endif // ASAN_DLL_THUNK
|
52
lib/asan/asan_win_dynamic_runtime_thunk.cc
Normal file
52
lib/asan/asan_win_dynamic_runtime_thunk.cc
Normal file
@ -0,0 +1,52 @@
|
||||
//===-- asan_win_uar_thunk.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 AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// This file defines things that need to be present in the application modules
|
||||
// to interact with the ASan DLL runtime correctly and can't be implemented
|
||||
// using the default "import library" generated when linking the DLL RTL.
|
||||
//
|
||||
// This includes:
|
||||
// - forwarding the detect_stack_use_after_return runtime option
|
||||
// - installing a custom SEH handler
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Only compile this code when buidling asan_dynamic_runtime_thunk.lib
|
||||
// Using #ifdef rather than relying on Makefiles etc.
|
||||
// simplifies the build procedure.
|
||||
#ifdef ASAN_DYNAMIC_RUNTIME_THUNK
|
||||
extern "C" {
|
||||
__declspec(dllimport) int __asan_set_seh_filter();
|
||||
__declspec(dllimport) int __asan_should_detect_stack_use_after_return();
|
||||
|
||||
// Define a copy of __asan_option_detect_stack_use_after_return that should be
|
||||
// used when linking an MD runtime with a set of object files on Windows.
|
||||
//
|
||||
// The ASan MD runtime dllexports '__asan_option_detect_stack_use_after_return',
|
||||
// so normally we would just dllimport it. Unfortunately, the dllimport
|
||||
// attribute adds __imp_ prefix to the symbol name of a variable.
|
||||
// Since in general we don't know if a given TU is going to be used
|
||||
// with a MT or MD runtime and we don't want to use ugly __imp_ names on Windows
|
||||
// just to work around this issue, let's clone the a variable that is
|
||||
// constant after initialization anyways.
|
||||
int __asan_option_detect_stack_use_after_return =
|
||||
__asan_should_detect_stack_use_after_return();
|
||||
|
||||
// Set the ASan-specific SEH handler at the end of CRT initialization of each
|
||||
// module (see asan_win.cc for the details).
|
||||
//
|
||||
// Unfortunately, putting a pointer to __asan_set_seh_filter into
|
||||
// __asan_intercept_seh gets optimized out, so we have to use an extra function.
|
||||
static int SetSEHFilter() { return __asan_set_seh_filter(); }
|
||||
#pragma section(".CRT$XIZ", long, read) // NOLINT
|
||||
__declspec(allocate(".CRT$XIZ")) int (*__asan_seh_interceptor)() = SetSEHFilter;
|
||||
}
|
||||
#endif // ASAN_DYNAMIC_RUNTIME_THUNK
|
@ -1,13 +0,0 @@
|
||||
## Autogenerated by LLVM/Clang configuration.
|
||||
# Do not edit!
|
||||
|
||||
# Load common config for all compiler-rt lit tests.
|
||||
lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.configured")
|
||||
|
||||
# Tool-specific config options.
|
||||
config.asan_source_dir = "@ASAN_SOURCE_DIR@"
|
||||
config.bits = "32"
|
||||
|
||||
# Load tool-specific config that would do the real work.
|
||||
lit_config.load_config(config, "@ASAN_SOURCE_DIR@/lit_tests/lit.cfg")
|
||||
|
@ -1,12 +0,0 @@
|
||||
## Autogenerated by LLVM/Clang configuration.
|
||||
# Do not edit!
|
||||
|
||||
# Load common config for all compiler-rt lit tests.
|
||||
lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.configured")
|
||||
|
||||
# Tool-specific config options.
|
||||
config.asan_source_dir = "@ASAN_SOURCE_DIR@"
|
||||
config.bits = "64"
|
||||
|
||||
# Load tool-specific config that would do the real work.
|
||||
lit_config.load_config(config, "@ASAN_SOURCE_DIR@/lit_tests/lit.cfg")
|
@ -1,42 +0,0 @@
|
||||
set(ASAN_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/..)
|
||||
set(ASAN_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/..)
|
||||
|
||||
configure_lit_site_cfg(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/64bitConfig/lit.site.cfg.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/64bitConfig/lit.site.cfg
|
||||
)
|
||||
|
||||
configure_lit_site_cfg(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/32bitConfig/lit.site.cfg.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/32bitConfig/lit.site.cfg
|
||||
)
|
||||
|
||||
configure_lit_site_cfg(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg
|
||||
)
|
||||
|
||||
if(COMPILER_RT_CAN_EXECUTE_TESTS)
|
||||
set(ASAN_TESTSUITES)
|
||||
if(CAN_TARGET_i386)
|
||||
list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/32bitConfig)
|
||||
endif()
|
||||
if(CAN_TARGET_x86_64 OR CAN_TARGET_powerpc64)
|
||||
list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/64bitConfig)
|
||||
endif()
|
||||
# Run ASan tests only if we're sure we may produce working binaries.
|
||||
set(ASAN_TEST_DEPS
|
||||
${SANITIZER_COMMON_LIT_TEST_DEPS}
|
||||
asan_runtime_libraries)
|
||||
set(ASAN_TEST_PARAMS
|
||||
asan_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg)
|
||||
if(LLVM_INCLUDE_TESTS)
|
||||
list(APPEND ASAN_TEST_DEPS AsanUnitTests)
|
||||
list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/Unit)
|
||||
endif()
|
||||
add_lit_testsuite(check-asan "Running the AddressSanitizer tests"
|
||||
${ASAN_TESTSUITES}
|
||||
PARAMS ${ASAN_TEST_PARAMS}
|
||||
DEPENDS ${ASAN_TEST_DEPS})
|
||||
set_target_properties(check-asan PROPERTIES FOLDER "ASan tests")
|
||||
endif()
|
@ -1,45 +0,0 @@
|
||||
// RUN: %clangxx_asan -mllvm -asan-coverage=1 -DSHARED %s -shared -o %t.so -fPIC
|
||||
// RUN: %clangxx_asan -mllvm -asan-coverage=1 %s -o %t -Wl,-R. %t.so
|
||||
// RUN: export ASAN_OPTIONS=coverage=1:verbosity=1
|
||||
// RUN: %t 2>&1 | FileCheck %s --check-prefix=CHECK-main
|
||||
// RUN: %t foo 2>&1 | FileCheck %s --check-prefix=CHECK-foo
|
||||
// RUN: %t bar 2>&1 | FileCheck %s --check-prefix=CHECK-bar
|
||||
// RUN: %t foo bar 2>&1 | FileCheck %s --check-prefix=CHECK-foo-bar
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef SHARED
|
||||
void bar() { printf("bar\n"); }
|
||||
#else
|
||||
__attribute__((noinline))
|
||||
void foo() { printf("foo\n"); }
|
||||
extern void bar();
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
fprintf(stderr, "PID: %d\n", getpid());
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (!strcmp(argv[i], "foo"))
|
||||
foo();
|
||||
if (!strcmp(argv[i], "bar"))
|
||||
bar();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// CHECK-main: PID: [[PID:[0-9]+]]
|
||||
// CHECK-main: [[PID]].sancov: 1 PCs written
|
||||
// CHECK-main-NOT: .so.[[PID]]
|
||||
//
|
||||
// CHECK-foo: PID: [[PID:[0-9]+]]
|
||||
// CHECK-foo: [[PID]].sancov: 2 PCs written
|
||||
// CHECK-foo-NOT: .so.[[PID]]
|
||||
//
|
||||
// CHECK-bar: PID: [[PID:[0-9]+]]
|
||||
// CHECK-bar: [[PID]].sancov: 1 PCs written
|
||||
// CHECK-bar: .so.[[PID]].sancov: 1 PCs written
|
||||
//
|
||||
// CHECK-foo-bar: PID: [[PID:[0-9]+]]
|
||||
// CHECK-foo-bar: [[PID]].sancov: 2 PCs written
|
||||
// CHECK-foo-bar: so.[[PID]].sancov: 1 PCs written
|
@ -1,23 +0,0 @@
|
||||
// Regression test for
|
||||
// https://code.google.com/p/address-sanitizer/issues/detail?id=183
|
||||
|
||||
// RUN: %clangxx_asan -O2 %s -o %t
|
||||
// RUN: not %t 12 2>&1 | FileCheck %s
|
||||
// RUN: not %t 100 2>&1 | FileCheck %s
|
||||
// RUN: not %t 10000 2>&1 | FileCheck %s
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int *x = new int[5];
|
||||
memset(x, 0, sizeof(x[0]) * 5);
|
||||
int index = atoi(argv[1]);
|
||||
int res = x[index];
|
||||
// CHECK: AddressSanitizer: {{(heap-buffer-overflow|SEGV)}}
|
||||
// CHECK: #0 0x{{.*}} in main {{.*}}heap-overflow-large.cc:[[@LINE-2]]
|
||||
// CHECK: AddressSanitizer can not {{(provide additional info|describe address in more detail \(wild memory access suspected\))}}
|
||||
// CHECK: SUMMARY: AddressSanitizer: {{(heap-buffer-overflow|SEGV)}}
|
||||
delete[] x;
|
||||
return res;
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
// RUN: export ASAN_OPTIONS=detect_stack_use_after_return=1
|
||||
// RUN: %clangxx_asan -O0 %s -o %t && \
|
||||
// RUN: not %t 2>&1 | FileCheck %s
|
||||
// RUN: %clangxx_asan -O2 %s -o %t && \
|
||||
// RUN: not %t 2>&1 | FileCheck %s
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
__attribute__((noinline))
|
||||
char *pretend_to_do_something(char *x) {
|
||||
__asm__ __volatile__("" : : "r" (x) : "memory");
|
||||
return x;
|
||||
}
|
||||
|
||||
__attribute__((noinline))
|
||||
char *LeakStack() {
|
||||
char x[1024];
|
||||
memset(x, 0, sizeof(x));
|
||||
return pretend_to_do_something(x);
|
||||
}
|
||||
|
||||
template<size_t kFrameSize>
|
||||
__attribute__((noinline))
|
||||
void RecuriveFunctionWithStackFrame(int depth) {
|
||||
if (depth <= 0) return;
|
||||
char x[kFrameSize];
|
||||
x[0] = depth;
|
||||
pretend_to_do_something(x);
|
||||
RecuriveFunctionWithStackFrame<kFrameSize>(depth - 1);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int n_iter = argc >= 2 ? atoi(argv[1]) : 1000;
|
||||
int depth = argc >= 3 ? atoi(argv[2]) : 500;
|
||||
for (int i = 0; i < n_iter; i++) {
|
||||
RecuriveFunctionWithStackFrame<10>(depth);
|
||||
RecuriveFunctionWithStackFrame<100>(depth);
|
||||
RecuriveFunctionWithStackFrame<500>(depth);
|
||||
RecuriveFunctionWithStackFrame<1024>(depth);
|
||||
RecuriveFunctionWithStackFrame<2000>(depth);
|
||||
RecuriveFunctionWithStackFrame<5000>(depth);
|
||||
RecuriveFunctionWithStackFrame<10000>(depth);
|
||||
}
|
||||
char *stale_stack = LeakStack();
|
||||
RecuriveFunctionWithStackFrame<1024>(10);
|
||||
stale_stack[100]++;
|
||||
// CHECK: ERROR: AddressSanitizer: stack-use-after-return on address
|
||||
// CHECK: is located in stack of thread T0 at offset 132 in frame
|
||||
// CHECK: in LeakStack(){{.*}}heavy_uar_test.cc:
|
||||
// CHECK: [32, 1056) 'x'
|
||||
return 0;
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
// RUN: %clangxx_asan -O0 %s -fsanitize-address-zero-base-shadow -pie -o %t && %t 2>&1 | FileCheck %s
|
||||
|
||||
// Zero-base shadow only works on x86_64 and i386.
|
||||
// REQUIRES: x86_64-supported-target
|
||||
|
||||
// A regression test for time(NULL), which caused ASan to crash in the
|
||||
// zero-based shadow mode on Linux.
|
||||
// FIXME: this test does not work on Darwin, because the code pages of the
|
||||
// executable interleave with the zero-based shadow.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
int main() {
|
||||
time_t t = time(NULL);
|
||||
fprintf(stderr, "Time: %s\n", ctime(&t)); // NOLINT
|
||||
// CHECK: {{Time: .* .* .*}}
|
||||
return 0;
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
// RUN: %clangxx_asan -O0 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t
|
||||
// RUN: not %t 2>&1 | FileCheck %s
|
||||
// RUN: %clangxx_asan -O1 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t
|
||||
// RUN: not %t 2>&1 | FileCheck %s
|
||||
// RUN: %clangxx_asan -O2 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t
|
||||
// RUN: not %t 2>&1 | FileCheck %s
|
||||
|
||||
// Zero-base shadow only works on x86_64 and i386.
|
||||
// REQUIRES: i386-supported-target, asan-32-bits
|
||||
|
||||
#include <string.h>
|
||||
int main(int argc, char **argv) {
|
||||
char x[10];
|
||||
memset(x, 0, 10);
|
||||
int res = x[argc * 10]; // BOOOM
|
||||
// CHECK: {{READ of size 1 at 0x.* thread T0}}
|
||||
// CHECK: {{ #0 0x.* in main .*zero-base-shadow32.cc:}}[[@LINE-2]]
|
||||
// CHECK: {{Address 0x.* is .* frame}}
|
||||
// CHECK: main
|
||||
|
||||
// Check that shadow for stack memory occupies lower part of address space.
|
||||
// CHECK: =>0x1
|
||||
return res;
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
// RUN: %clangxx_asan -O0 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t
|
||||
// RUN: not %t 2>&1 | FileCheck %s
|
||||
// RUN: %clangxx_asan -O1 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t
|
||||
// RUN: not %t 2>&1 | FileCheck %s
|
||||
// RUN: %clangxx_asan -O2 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t
|
||||
// RUN: not %t 2>&1 | FileCheck %s
|
||||
|
||||
// Zero-base shadow only works on x86_64 and i386.
|
||||
// REQUIRES: x86_64-supported-target, asan-64-bits
|
||||
|
||||
#include <string.h>
|
||||
int main(int argc, char **argv) {
|
||||
char x[10];
|
||||
memset(x, 0, 10);
|
||||
int res = x[argc * 10]; // BOOOM
|
||||
// CHECK: {{READ of size 1 at 0x.* thread T0}}
|
||||
// CHECK: {{ #0 0x.* in main .*zero-base-shadow64.cc:}}[[@LINE-2]]
|
||||
// CHECK: {{Address 0x.* is .* frame}}
|
||||
// CHECK: main
|
||||
|
||||
// Check that shadow for stack memory occupies lower part of address space.
|
||||
// CHECK: =>0x0f
|
||||
return res;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user