Import compiler-rt trunk r224034.

https://llvm.org/svn/llvm-project/compiler-rt/trunk@224034
This commit is contained in:
Dimitry Andric 2015-01-07 19:55:37 +00:00
parent 8ef50bf3d1
commit ca9211ecde
1693 changed files with 52793 additions and 19105 deletions

View File

@ -1,4 +1,4 @@
{
"project_id" : "compiler-rt",
"conduit_uri" : "http://llvm-reviews.chandlerc.com/"
"conduit_uri" : "http://reviews.llvm.org/"
}

1
.gitignore vendored
View File

@ -2,3 +2,4 @@
darwin_fat
clang_darwin
multi_arch
*.sw?

View File

@ -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
${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})
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(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")
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
${LIBCLANG_INSTALL_PATH}/lib/${LIBCLANG_OS_DIR})
${COMPILER_RT_INSTALL_PATH}/lib/${COMPILER_RT_OS_DIR})
# Add path for custom modules
# 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,18 +289,17 @@ 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(SANITIZER_MIN_OSX_VERSION 10.7)
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
set(DARWIN_iossim_CFLAGS
-mios-simulator-version-min=7.0 -isysroot ${IOSSIM_SDK_DIR})
set(DARWIN_osx_LINKFLAGS)
set(DARWIN_iossim_LINKFLAGS
@ -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
View 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

View File

@ -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.

View File

@ -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

View File

@ -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 $$@ $$<

View File

@ -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.

View File

@ -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.

View File

@ -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>

View File

@ -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>

View File

@ -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__ */

View File

@ -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__ */

View File

@ -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__ */

View File

@ -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__ */

View File

@ -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

View File

@ -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_ */

View File

@ -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__ */

View File

@ -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__ */

View File

@ -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__ */

View File

@ -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 *);

View 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>
# SOURCES <source files>
# CFLAGS <compile flags>
# DEFS <compile definitions>)
macro(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>
# 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()

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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
View 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()

View File

@ -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)

View 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

View File

@ -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

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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

View File

@ -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)
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)
add_subdirectory(dfsan)
endif()
include(AddCompilerRT)
include(SanitizerUtils)
if(COMPILER_RT_HAS_SANITIZER_COMMON)
add_subdirectory(interception)
add_subdirectory(sanitizer_common)
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_ASAN)
add_subdirectory(asan)
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)
add_subdirectory(builtins)
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_DFSAN)
add_subdirectory(dfsan)
endif()
if(COMPILER_RT_HAS_LSAN OR COMPILER_RT_HAS_LSAN_COMMON)
add_subdirectory(lsan)
endif()
if(COMPILER_RT_HAS_MSAN)
add_subdirectory(msan)
endif()
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()

View File

@ -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)

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
CFLAGS ${ASAN_CFLAGS} -DASAN_DLL_THUNK
DEFS ${ASAN_COMMON_DEFINITIONS})
list(APPEND ASAN_RUNTIME_LIBRARIES clang_rt.asan_dll_thunk-${arch})
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})
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)

View File

@ -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=%)

View File

@ -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.

View 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

View File

@ -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

View File

@ -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);

View File

@ -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 {
PoisonShadow(p, size, kAsanHeapLeftRedzoneMagic);
// Statistics.
AsanStats &thread_stats = GetCurrentThreadStats();
thread_stats.mmaps++;
thread_stats.mmaped += size;
}
void 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);
// 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;
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 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.
FlushUnneededASanShadowMemory(p, size);
// Statistics.
AsanStats &thread_stats = GetCurrentThreadStats();
thread_stats.munmaps++;
thread_stats.munmaped += size;
}
// 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"

View File

@ -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
View 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;
}

View File

@ -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

View File

@ -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",
GetCurrentTidOrInvalid(), p,
p + FakeStack::RequiredSize(stack_size_log), stack_size_log);
}
u8 *p = reinterpret_cast<u8 *>(res);
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,
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"

View File

@ -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) {

View File

@ -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;

View File

@ -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 (flags()->report_globals >= 2)
ReportGlobal(g, "Search");
res |= DescribeAddressRelativeToGlobal(addr, size, 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]);
}

View 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

View File

@ -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

View File

@ -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))) { \
GET_CURRENT_PC_BP_SP; \
__asan_report_error(pc, bp, sp, __bad, isWrite, __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) {
@ -108,31 +121,34 @@ DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, uptr)
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"); \
#define ASAN_INTERCEPT_FUNC(name) \
do { \
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)
#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__); \
ENSURE_ASAN_INITED(); \
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__); \
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) \
do { \
@ -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(&param->t, memory_order_acquire))) == 0)
internal_sched_yield();
SetCurrentThread(t);
return t->ThreadStart(GetTid());
return t->ThreadStart(GetTid(), &param->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);
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);
ThreadStartParam param;
atomic_store(&param.t, 0, memory_order_relaxed);
atomic_store(&param.is_registered, 0, memory_order_relaxed);
int result = REAL(pthread_create)(thread, attr, asan_thread_start, &param);
if (result == 0) {
u32 current_tid = GetCurrentTidOrInvalid();
AsanThread *t =
AsanThread::Create(start_routine, arg, current_tid, &stack, detached);
atomic_store(&param.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(&param.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); \
if (asan_init_is_running) { \
return REAL(memmove)(to, from, size); \
} \
ENSURE_ASAN_INITED(); \
if (flags()->replace_intrin) { \
ASAN_READ_RANGE(from, size); \
ASAN_WRITE_RANGE(to, size); \
} \
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(memcpy)(to, from, size); \
} \
ENSURE_ASAN_INITED(); \
if (flags()->replace_intrin) { \
if (to != from) { \
CHECK_RANGES_OVERLAP("memcpy", to, size, 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(&param.t, 0, memory_order_relaxed);
atomic_store(&param.is_registered, 0, memory_order_relaxed);
DWORD result = REAL(CreateThread)(security, stack_size, asan_thread_start,
&param, thr_flags, tid);
if (result) {
u32 current_tid = GetCurrentTidOrInvalid();
AsanThread *t =
AsanThread::Create(start_routine, arg, current_tid, &stack, detached);
atomic_store(&param.t, reinterpret_cast<uptr>(t), memory_order_release);
// The pthread_create interceptor waits here, so we do the same for
// consistency.
while (atomic_load(&param.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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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(): "
"context: %p, pthread_self: %p\n",
block, pthread_self());
}
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;
@ -349,10 +315,10 @@ asan_block_context_t *alloc_asan_context(void *ctxt, dispatch_function_t func,
if (common_flags()->verbosity >= 2) { \
Report(#dispatch_x_f "(): context: %p, pthread_self: %p\n", \
asan_ctxt, pthread_self()); \
PRINT_CURRENT_STACK(); \
} \
return REAL(dispatch_x_f)(dq, (void*)asan_ctxt, \
asan_dispatch_call_block_and_release); \
PRINT_CURRENT_STACK(); \
} \
return REAL(dispatch_x_f)(dq, (void*)asan_ctxt, \
asan_dispatch_call_block_and_release); \
}
INTERCEPT_DISPATCH_X_F_3(dispatch_async_f)
@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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)
#define SHADOW_SCALE kDefaultShadowScale
#if SANITIZER_ANDROID
# define SHADOW_OFFSET (0)
#else
# define SHADOW_SCALE kDefaultShadowScale
# if SANITIZER_ANDROID
# define SHADOW_OFFSET (0)
# else
# if SANITIZER_WORDSIZE == 32
# if defined(__mips__)
# define SHADOW_OFFSET kMIPS32_ShadowOffset32
# else
# define SHADOW_OFFSET kDefaultShadowOffset32
# endif
# if SANITIZER_WORDSIZE == 32
# if defined(__mips__)
# define SHADOW_OFFSET kMIPS32_ShadowOffset32
# elif SANITIZER_FREEBSD
# define SHADOW_OFFSET kFreeBSD_ShadowOffset32
# else
# if defined(__powerpc64__)
# if SANITIZER_IOS
# define SHADOW_OFFSET kIosShadowOffset32
# else
# define SHADOW_OFFSET kDefaultShadowOffset32
# endif
# endif
# else
# if defined(__aarch64__)
# define SHADOW_OFFSET kAArch64_ShadowOffset64
# elif defined(__powerpc64__)
# define SHADOW_OFFSET kPPC64_ShadowOffset64
# elif SANITIZER_MAC
# define SHADOW_OFFSET kDefaultShadowOffset64
# else
# define SHADOW_OFFSET kDefaultShort64bitShadowOffset
# endif
# 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 // ASAN_FLEXIBLE_MAPPING_AND_OFFSET
#endif
#define SHADOW_GRANULARITY (1ULL << SHADOW_SCALE)
#define MEM_TO_SHADOW(mem) (((mem) >> SHADOW_SCALE) + (SHADOW_OFFSET))

View File

@ -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

View File

@ -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);
}
}

View File

@ -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;
REAL(memset)((void*)shadow_beg, value, shadow_end - shadow_beg);
// 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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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",
MaybeCallAsanDefaultOptions());
}
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();
}

View File

@ -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"

View File

@ -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)
#define GET_STACK_TRACE(max_size, 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, \
common_flags()->fast_unwind_on_fatal)
#define GET_STACK_TRACE_FATAL(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)
@ -72,11 +99,16 @@ void PrintStack(const uptr *trace, uptr size);
#define GET_STACK_TRACE_FREE GET_STACK_TRACE_MALLOC
#define PRINT_CURRENT_STACK() \
{ \
GET_STACK_TRACE(kStackTraceMax, \
common_flags()->fast_unwind_on_fatal); \
PrintStack(&stack); \
#define PRINT_CURRENT_STACK() \
{ \
GET_STACK_TRACE_FATAL_HERE; \
stack.Print(); \
}
#define PRINT_CURRENT_STACK_CHECK() \
{ \
GET_STACK_TRACE_CHECK_HERE; \
stack.Print(); \
}
#endif // ASAN_STACK_H

View File

@ -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;
}

View File

@ -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.

View 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

View 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

View File

@ -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.
int local = 0;
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());

View File

@ -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();
@ -116,18 +127,19 @@ class AsanThread {
AsanThreadContext *context_;
thread_callback_t start_routine_;
void *arg_;
uptr stack_top_;
uptr stack_bottom_;
uptr stack_top_;
uptr stack_bottom_;
// stack_size_ == stack_top_ - stack_bottom_;
// It needs to be set in a async-signal-safe manner.
uptr stack_size_;
uptr stack_size_;
uptr tls_begin_;
uptr tls_end_;
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.

View File

@ -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

View 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

View 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

View File

@ -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")

View File

@ -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")

View File

@ -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()

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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