Vendor import of compiler-rt release_39 branch r276489:
https://llvm.org/svn/llvm-project/compiler-rt/branches/release_39@276489
This commit is contained in:
parent
c003a57e2e
commit
6f08730ec5
@ -1,4 +1,4 @@
|
||||
{
|
||||
"project_id" : "compiler-rt",
|
||||
"conduit_uri" : "http://reviews.llvm.org/"
|
||||
"conduit_uri" : "https://reviews.llvm.org/"
|
||||
}
|
||||
|
134
CMakeLists.txt
134
CMakeLists.txt
@ -11,80 +11,34 @@
|
||||
if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
|
||||
project(CompilerRT C CXX ASM)
|
||||
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.
|
||||
if (NOT MSVC)
|
||||
cmake_minimum_required(VERSION 2.8.8)
|
||||
else()
|
||||
# Version 2.8.12.1 is required to build with Visual Studio 2013.
|
||||
cmake_minimum_required(VERSION 2.8.12.1)
|
||||
endif()
|
||||
cmake_minimum_required(VERSION 3.4.3)
|
||||
# FIXME:
|
||||
# The OLD behavior (pre 3.2) for this policy is to not set the value of the
|
||||
# CMAKE_EXE_LINKER_FLAGS variable in the generated test project. The NEW behavior
|
||||
# for this policy is to set the value of the CMAKE_EXE_LINKER_FLAGS variable
|
||||
# in the test project to the same as it is in the calling project. The new
|
||||
# behavior cause the compiler_rt test to fail during try_compile: see
|
||||
# projects/compiler-rt/cmake/Modules/CompilerRTUtils.cmake:121 such that
|
||||
# CAN_TARGET_${arch} is not set properly. This results in COMPILER_RT_SUPPORTED_ARCH
|
||||
# not being updated properly leading to poblems.
|
||||
cmake_policy(SET CMP0056 OLD)
|
||||
|
||||
# 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()
|
||||
# Add path for custom compiler-rt modules.
|
||||
list(INSERT CMAKE_MODULE_PATH 0
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules"
|
||||
)
|
||||
|
||||
# Top level target used to build all compiler-rt libraries.
|
||||
add_custom_target(compiler-rt ALL)
|
||||
include(base-config-ix)
|
||||
|
||||
option(COMPILER_RT_BUILD_BUILTINS "Build builtins" ON)
|
||||
mark_as_advanced(COMPILER_RT_BUILD_BUILTINS)
|
||||
option(COMPILER_RT_BUILD_SANITIZERS "Build sanitizers" ON)
|
||||
mark_as_advanced(COMPILER_RT_BUILD_SANITIZERS)
|
||||
|
||||
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)
|
||||
set(COMPILER_RT_TEST_CXX_COMPILER ${LLVM_RUNTIME_OUTPUT_INTDIR}/clang++)
|
||||
else()
|
||||
set(COMPILER_RT_TEST_COMPILER ${LLVM_RUNTIME_OUTPUT_INTDIR}/clang.exe)
|
||||
set(COMPILER_RT_TEST_CXX_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")
|
||||
set(COMPILER_RT_TEST_CXX_COMPILER ${CMAKE_CXX_COMPILER} CACHE PATH "C++ Compiler to use for testing")
|
||||
|
||||
if (COMPILER_RT_STANDALONE_BUILD)
|
||||
if (NOT LLVM_CONFIG_PATH)
|
||||
find_program(LLVM_CONFIG_PATH "llvm-config"
|
||||
DOC "Path to llvm-config binary")
|
||||
@ -107,7 +61,7 @@ else()
|
||||
|
||||
# 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")
|
||||
set(LLVM_CMAKE_PATH "${LLVM_BINARY_DIR_CMAKE_STYLE}/lib${LLVM_LIBDIR_SUFFIX}/cmake/llvm")
|
||||
list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_PATH}")
|
||||
# Get some LLVM variables from LLVMConfig.
|
||||
include("${LLVM_CMAKE_PATH}/LLVMConfig.cmake")
|
||||
@ -132,14 +86,6 @@ else()
|
||||
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()
|
||||
|
||||
set(COMPILER_RT_DEFAULT_TARGET_TRIPLE ${TARGET_TRIPLE} CACHE STRING
|
||||
"Default triple for which compiler-rt runtimes will be built.")
|
||||
if(DEFINED COMPILER_RT_TEST_TARGET_TRIPLE)
|
||||
@ -159,23 +105,9 @@ if(NOT COMPILER_RT_DEFAULT_TARGET_TRIPLE STREQUAL TARGET_TRIPLE)
|
||||
else()
|
||||
set(COMPILER_RT_HAS_EXPLICIT_DEFAULT_TARGET_TRIPLE FALSE)
|
||||
endif()
|
||||
|
||||
if ("${COMPILER_RT_DEFAULT_TARGET_ABI}" STREQUAL "androideabi")
|
||||
set(ANDROID 1)
|
||||
endif()
|
||||
|
||||
string(TOLOWER ${CMAKE_SYSTEM_NAME} COMPILER_RT_OS_DIR)
|
||||
set(COMPILER_RT_LIBRARY_OUTPUT_DIR
|
||||
${COMPILER_RT_OUTPUT_DIR}/lib/${COMPILER_RT_OS_DIR})
|
||||
set(COMPILER_RT_LIBRARY_INSTALL_DIR
|
||||
${COMPILER_RT_INSTALL_PATH}/lib/${COMPILER_RT_OS_DIR})
|
||||
|
||||
# Add path for custom compiler-rt modules.
|
||||
set(CMAKE_MODULE_PATH
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules"
|
||||
${CMAKE_MODULE_PATH}
|
||||
)
|
||||
include(CompilerRTUtils)
|
||||
|
||||
set(COMPILER_RT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
@ -200,13 +132,18 @@ pythonize_bool(COMPILER_RT_DEBUG)
|
||||
#================================
|
||||
# Setup Compiler Flags
|
||||
#================================
|
||||
include(CheckIncludeFile)
|
||||
check_include_file(unwind.h HAVE_UNWIND_H)
|
||||
|
||||
include(config-ix)
|
||||
|
||||
if(MSVC)
|
||||
append_string_if(COMPILER_RT_HAS_W3_FLAG /W3 CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
|
||||
# Override any existing /W flags with /W4. This is what LLVM does. Failing to
|
||||
# remove other /W[0-4] flags will result in a warning about overriding a
|
||||
# previous flag.
|
||||
if (COMPILER_RT_HAS_W4_FLAG)
|
||||
string(REGEX REPLACE " /W[0-4]" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
|
||||
string(REGEX REPLACE " /W[0-4]" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
append_string_if(COMPILER_RT_HAS_W4_FLAG /W4 CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
|
||||
endif()
|
||||
else()
|
||||
append_string_if(COMPILER_RT_HAS_WALL_FLAG -Wall CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
|
||||
endif()
|
||||
@ -226,7 +163,9 @@ endif()
|
||||
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)
|
||||
if(NOT COMPILER_RT_DEBUG)
|
||||
append_list_if(COMPILER_RT_HAS_FOMIT_FRAME_POINTER_FLAG -fomit-frame-pointer SANITIZER_COMMON_CFLAGS)
|
||||
endif()
|
||||
append_list_if(COMPILER_RT_HAS_FUNWIND_TABLES_FLAG -funwind-tables SANITIZER_COMMON_CFLAGS)
|
||||
append_list_if(COMPILER_RT_HAS_FNO_STACK_PROTECTOR_FLAG -fno-stack-protector SANITIZER_COMMON_CFLAGS)
|
||||
append_list_if(COMPILER_RT_HAS_FNO_SANITIZE_SAFE_STACK_FLAG -fno-sanitize=safe-stack SANITIZER_COMMON_CFLAGS)
|
||||
@ -241,6 +180,8 @@ if(MSVC)
|
||||
# FIXME: In fact, sanitizers should support both /MT and /MD, see PR20214.
|
||||
if(COMPILER_RT_HAS_MT_FLAG)
|
||||
foreach(flag_var
|
||||
CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
|
||||
CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO
|
||||
CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
|
||||
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
|
||||
string(REGEX REPLACE "/M[DT]d" "/MT" ${flag_var} "${${flag_var}}")
|
||||
@ -250,6 +191,12 @@ if(MSVC)
|
||||
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)
|
||||
# VS 2015 (version 1900) added support for thread safe static initialization.
|
||||
# However, ASan interceptors run before CRT initialization, which causes the
|
||||
# new thread safe code to crash. Disable this feature for now.
|
||||
if (MSVC_VERSION GREATER 1899)
|
||||
list(APPEND SANITIZER_COMMON_CFLAGS /Zc:threadSafeInit-)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
append_list_if(COMPILER_RT_DEBUG -DSANITIZER_DEBUG=1 SANITIZER_COMMON_CFLAGS)
|
||||
@ -292,10 +239,15 @@ 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)
|
||||
|
||||
# Warnings to turn off for all libraries, not just sanitizers.
|
||||
append_string_if(COMPILER_RT_HAS_WUNUSED_PARAMETER_FLAG -Wno-unused-parameter CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
|
||||
|
||||
if(APPLE AND SANITIZER_MIN_OSX_VERSION VERSION_LESS "10.9")
|
||||
# Mac OS X prior to 10.9 had problems with exporting symbols from
|
||||
# libc++/libc++abi.
|
||||
set(SANITIZER_CAN_USE_CXXABI FALSE)
|
||||
elseif(MSVC)
|
||||
set(SANITIZER_CAN_USE_CXXABI FALSE)
|
||||
else()
|
||||
set(SANITIZER_CAN_USE_CXXABI TRUE)
|
||||
endif()
|
||||
|
@ -24,10 +24,6 @@ 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
|
||||
@ -38,7 +34,7 @@ D: CMake build, test suite
|
||||
|
||||
N: Kostya Serebryany
|
||||
E: kcc@google.com
|
||||
D: AddressSanitizer, sanitizer_common, porting sanitizers to another platforms
|
||||
D: AddressSanitizer, sanitizer_common, porting sanitizers to another platforms, LeakSanitizer
|
||||
|
||||
N: Richard Smith
|
||||
E: richard-llvm@metafoo.co.uk
|
||||
|
@ -14,7 +14,7 @@ Full text of the relevant licenses is included below.
|
||||
University of Illinois/NCSA
|
||||
Open Source License
|
||||
|
||||
Copyright (c) 2009-2015 by the contributors listed in CREDITS.TXT
|
||||
Copyright (c) 2009-2016 by the contributors listed in CREDITS.TXT
|
||||
|
||||
All rights reserved.
|
||||
|
||||
|
@ -1,7 +1,28 @@
|
||||
include(AddLLVM)
|
||||
include(ExternalProject)
|
||||
include(CompilerRTUtils)
|
||||
|
||||
function(set_target_output_directories target output_dir)
|
||||
# For RUNTIME_OUTPUT_DIRECTORY variable, Multi-configuration generators
|
||||
# append a per-configuration subdirectory to the specified directory.
|
||||
# To avoid the appended folder, the configuration specific variable must be
|
||||
# set 'RUNTIME_OUTPUT_DIRECTORY_${CONF}':
|
||||
# RUNTIME_OUTPUT_DIRECTORY_DEBUG, RUNTIME_OUTPUT_DIRECTORY_RELEASE, ...
|
||||
if(CMAKE_CONFIGURATION_TYPES)
|
||||
foreach(build_mode ${CMAKE_CONFIGURATION_TYPES})
|
||||
string(TOUPPER "${build_mode}" CONFIG_SUFFIX)
|
||||
set_target_properties("${target}" PROPERTIES
|
||||
"ARCHIVE_OUTPUT_DIRECTORY_${CONFIG_SUFFIX}" ${output_dir}
|
||||
"LIBRARY_OUTPUT_DIRECTORY_${CONFIG_SUFFIX}" ${output_dir}
|
||||
"RUNTIME_OUTPUT_DIRECTORY_${CONFIG_SUFFIX}" ${output_dir})
|
||||
endforeach()
|
||||
else()
|
||||
set_target_properties("${target}" PROPERTIES
|
||||
ARCHIVE_OUTPUT_DIRECTORY ${output_dir}
|
||||
LIBRARY_OUTPUT_DIRECTORY ${output_dir}
|
||||
RUNTIME_OUTPUT_DIRECTORY ${output_dir})
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Tries to add an "object library" target for a given list of OSs and/or
|
||||
# architectures with name "<name>.<arch>" for non-Darwin platforms if
|
||||
# architecture can be targeted, and "<name>.<os>" for Darwin platforms.
|
||||
@ -32,13 +53,14 @@ function(add_compiler_rt_object_libraries name)
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
|
||||
foreach(libname ${libnames})
|
||||
add_library(${libname} OBJECT ${LIB_SOURCES})
|
||||
set_target_compile_flags(${libname}
|
||||
${CMAKE_CXX_FLAGS} ${extra_cflags_${libname}} ${LIB_CFLAGS})
|
||||
set_property(TARGET ${libname} APPEND PROPERTY
|
||||
COMPILE_DEFINITIONS ${LIB_DEFS})
|
||||
set_target_properties(${libname} PROPERTIES FOLDER "Compiler-RT Libraries")
|
||||
if(APPLE)
|
||||
set_target_properties(${libname} PROPERTIES
|
||||
OSX_ARCHITECTURES "${LIB_ARCHS_${libname}}")
|
||||
@ -107,7 +129,8 @@ function(add_compiler_rt_runtime name type)
|
||||
set(output_name_${libname} ${libname}${COMPILER_RT_OS_SUFFIX})
|
||||
else()
|
||||
set(libname "${name}-dynamic-${arch}")
|
||||
set(extra_linkflags_${libname} ${TARGET_${arch}_CFLAGS} ${LIB_CFLAGS} ${LIB_LINKFLAGS})
|
||||
set(extra_cflags_${libname} ${TARGET_${arch}_CFLAGS} ${LIB_CFLAGS})
|
||||
set(extra_linkflags_${libname} ${TARGET_${arch}_LINKFLAGS} ${LIB_LINKFLAGS})
|
||||
if(WIN32)
|
||||
set(output_name_${libname} ${name}_dynamic-${arch}${COMPILER_RT_OS_SUFFIX})
|
||||
else()
|
||||
@ -126,21 +149,42 @@ function(add_compiler_rt_runtime name type)
|
||||
endif()
|
||||
|
||||
if(LIB_PARENT_TARGET)
|
||||
set(COMPONENT_OPTION COMPONENT ${LIB_PARENT_TARGET})
|
||||
# If the parent targets aren't created we should create them
|
||||
if(NOT TARGET ${LIB_PARENT_TARGET})
|
||||
add_custom_target(${LIB_PARENT_TARGET})
|
||||
endif()
|
||||
if(NOT TARGET install-${LIB_PARENT_TARGET})
|
||||
# The parent install target specifies the parent component to scrape up
|
||||
# anything not installed by the individual install targets, and to handle
|
||||
# installation when running the multi-configuration generators.
|
||||
add_custom_target(install-${LIB_PARENT_TARGET}
|
||||
DEPENDS ${LIB_PARENT_TARGET}
|
||||
COMMAND "${CMAKE_COMMAND}"
|
||||
-DCMAKE_INSTALL_COMPONENT=${LIB_PARENT_TARGET}
|
||||
-P "${CMAKE_BINARY_DIR}/cmake_install.cmake")
|
||||
set_target_properties(install-${LIB_PARENT_TARGET} PROPERTIES
|
||||
FOLDER "Compiler-RT Misc")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
foreach(libname ${libnames})
|
||||
# If you are using a multi-configuration generator we don't generate
|
||||
# per-library install rules, so we fall back to the parent target COMPONENT
|
||||
if(CMAKE_CONFIGURATION_TYPES AND LIB_PARENT_TARGET)
|
||||
set(COMPONENT_OPTION COMPONENT ${LIB_PARENT_TARGET})
|
||||
else()
|
||||
set(COMPONENT_OPTION COMPONENT ${libname})
|
||||
endif()
|
||||
|
||||
add_library(${libname} ${type} ${sources_${libname}})
|
||||
set_target_compile_flags(${libname} ${extra_cflags_${libname}})
|
||||
set_target_link_flags(${libname} ${extra_linkflags_${libname}})
|
||||
set_property(TARGET ${libname} APPEND PROPERTY
|
||||
set_property(TARGET ${libname} APPEND PROPERTY
|
||||
COMPILE_DEFINITIONS ${LIB_DEFS})
|
||||
set_target_properties(${libname} PROPERTIES
|
||||
ARCHIVE_OUTPUT_DIRECTORY ${COMPILER_RT_LIBRARY_OUTPUT_DIR}
|
||||
LIBRARY_OUTPUT_DIRECTORY ${COMPILER_RT_LIBRARY_OUTPUT_DIR}
|
||||
RUNTIME_OUTPUT_DIRECTORY ${COMPILER_RT_LIBRARY_OUTPUT_DIR})
|
||||
set_target_output_directories(${libname} ${COMPILER_RT_LIBRARY_OUTPUT_DIR})
|
||||
set_target_properties(${libname} PROPERTIES
|
||||
OUTPUT_NAME ${output_name_${libname}})
|
||||
set_target_properties(${libname} PROPERTIES FOLDER "Compiler-RT Runtime")
|
||||
if(LIB_LINK_LIBS AND ${type} STREQUAL "SHARED")
|
||||
target_link_libraries(${libname} ${LIB_LINK_LIBS})
|
||||
endif()
|
||||
@ -151,6 +195,21 @@ function(add_compiler_rt_runtime name type)
|
||||
${COMPONENT_OPTION}
|
||||
RUNTIME DESTINATION ${COMPILER_RT_LIBRARY_INSTALL_DIR}
|
||||
${COMPONENT_OPTION})
|
||||
|
||||
# We only want to generate per-library install targets if you aren't using
|
||||
# an IDE because the extra targets get cluttered in IDEs.
|
||||
if(NOT CMAKE_CONFIGURATION_TYPES)
|
||||
add_custom_target(install-${libname}
|
||||
DEPENDS ${libname}
|
||||
COMMAND "${CMAKE_COMMAND}"
|
||||
-DCMAKE_INSTALL_COMPONENT=${libname}
|
||||
-P "${CMAKE_BINARY_DIR}/cmake_install.cmake")
|
||||
# If you have a parent target specified, we bind the new install target
|
||||
# to the parent install target.
|
||||
if(LIB_PARENT_TARGET)
|
||||
add_dependencies(install-${LIB_PARENT_TARGET} install-${libname})
|
||||
endif()
|
||||
endif()
|
||||
if(APPLE)
|
||||
set_target_properties(${libname} PROPERTIES
|
||||
OSX_ARCHITECTURES "${LIB_ARCHS_${libname}}")
|
||||
@ -165,7 +224,10 @@ function(add_compiler_rt_runtime name type)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
set(COMPILER_RT_TEST_CFLAGS)
|
||||
# when cross compiling, COMPILER_RT_TEST_COMPILER_CFLAGS help
|
||||
# in compilation and linking of unittests.
|
||||
string(REPLACE " " ";" COMPILER_RT_UNITTEST_CFLAGS "${COMPILER_RT_TEST_COMPILER_CFLAGS}")
|
||||
set(COMPILER_RT_UNITTEST_LINKFLAGS ${COMPILER_RT_UNITTEST_CFLAGS})
|
||||
|
||||
# Unittests support.
|
||||
set(COMPILER_RT_GTEST_PATH ${LLVM_MAIN_SRC_DIR}/utils/unittest/googletest)
|
||||
@ -177,14 +239,14 @@ set(COMPILER_RT_GTEST_CFLAGS
|
||||
-I${COMPILER_RT_GTEST_PATH}
|
||||
)
|
||||
|
||||
append_list_if(COMPILER_RT_DEBUG -DSANITIZER_DEBUG=1 COMPILER_RT_TEST_CFLAGS)
|
||||
append_list_if(COMPILER_RT_DEBUG -DSANITIZER_DEBUG=1 COMPILER_RT_UNITTEST_CFLAGS)
|
||||
|
||||
if(MSVC)
|
||||
# clang doesn't support exceptions on Windows yet.
|
||||
list(APPEND COMPILER_RT_TEST_CFLAGS -D_HAS_EXCEPTIONS=0)
|
||||
list(APPEND COMPILER_RT_UNITTEST_CFLAGS -D_HAS_EXCEPTIONS=0)
|
||||
|
||||
# We should teach clang to understand "#pragma intrinsic", see PR19898.
|
||||
list(APPEND COMPILER_RT_TEST_CFLAGS -Wno-undefined-inline)
|
||||
list(APPEND COMPILER_RT_UNITTEST_CFLAGS -Wno-undefined-inline)
|
||||
|
||||
# Clang doesn't support SEH on Windows yet.
|
||||
list(APPEND COMPILER_RT_GTEST_CFLAGS -DGTEST_HAS_SEH=0)
|
||||
@ -209,14 +271,18 @@ endif()
|
||||
# LINK_FLAGS <link flags>)
|
||||
macro(add_compiler_rt_test test_suite test_name)
|
||||
cmake_parse_arguments(TEST "" "SUBDIR" "OBJECTS;DEPS;LINK_FLAGS" "" ${ARGN})
|
||||
set(output_bin ${CMAKE_CURRENT_BINARY_DIR})
|
||||
if(TEST_SUBDIR)
|
||||
set(output_bin "${CMAKE_CURRENT_BINARY_DIR}/${TEST_SUBDIR}/${test_name}")
|
||||
else()
|
||||
set(output_bin "${CMAKE_CURRENT_BINARY_DIR}/${test_name}")
|
||||
set(output_bin "${output_bin}/${TEST_SUBDIR}")
|
||||
endif()
|
||||
if(CMAKE_CONFIGURATION_TYPES)
|
||||
set(output_bin "${output_bin}/${CMAKE_CFG_INTDIR}")
|
||||
endif()
|
||||
set(output_bin "${output_bin}/${test_name}")
|
||||
if(MSVC)
|
||||
set(output_bin "${output_bin}.exe")
|
||||
endif()
|
||||
|
||||
# Use host compiler in a standalone build, and just-built Clang otherwise.
|
||||
if(NOT COMPILER_RT_STANDALONE_BUILD)
|
||||
list(APPEND TEST_DEPS clang)
|
||||
@ -236,11 +302,13 @@ macro(add_compiler_rt_test test_suite test_name)
|
||||
-o "${output_bin}"
|
||||
${TEST_LINK_FLAGS}
|
||||
DEPENDS ${TEST_DEPS})
|
||||
set_target_properties(${test_name} PROPERTIES FOLDER "Compiler-RT Tests")
|
||||
|
||||
# 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)
|
||||
macro(add_compiler_rt_resource_file target_name file_name component)
|
||||
set(src_file "${CMAKE_CURRENT_SOURCE_DIR}/${file_name}")
|
||||
set(dst_file "${COMPILER_RT_OUTPUT_DIR}/${file_name}")
|
||||
add_custom_command(OUTPUT ${dst_file}
|
||||
@ -249,7 +317,12 @@ macro(add_compiler_rt_resource_file target_name file_name)
|
||||
COMMENT "Copying ${file_name}...")
|
||||
add_custom_target(${target_name} DEPENDS ${dst_file})
|
||||
# Install in Clang resource directory.
|
||||
install(FILES ${file_name} DESTINATION ${COMPILER_RT_INSTALL_PATH})
|
||||
install(FILES ${file_name}
|
||||
DESTINATION ${COMPILER_RT_INSTALL_PATH}
|
||||
COMPONENT ${component})
|
||||
add_dependencies(${component} ${target_name})
|
||||
|
||||
set_target_properties(${target_name} PROPERTIES FOLDER "Compiler-RT Misc")
|
||||
endmacro()
|
||||
|
||||
macro(add_compiler_rt_script name)
|
||||
@ -321,6 +394,10 @@ function(rt_externalize_debuginfo name)
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(NOT COMPILER_RT_EXTERNALIZE_DEBUGINFO_SKIP_STRIP)
|
||||
set(strip_command COMMAND xcrun strip -Sl $<TARGET_FILE:${name}>)
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
if(CMAKE_CXX_FLAGS MATCHES "-flto"
|
||||
OR CMAKE_CXX_FLAGS_${uppercase_CMAKE_BUILD_TYPE} MATCHES "-flto")
|
||||
@ -331,7 +408,7 @@ function(rt_externalize_debuginfo name)
|
||||
endif()
|
||||
add_custom_command(TARGET ${name} POST_BUILD
|
||||
COMMAND xcrun dsymutil $<TARGET_FILE:${name}>
|
||||
COMMAND xcrun strip -Sl $<TARGET_FILE:${name}>)
|
||||
${strip_command})
|
||||
else()
|
||||
message(FATAL_ERROR "COMPILER_RT_EXTERNALIZE_DEBUGINFO isn't implemented for non-darwin platforms!")
|
||||
endif()
|
||||
|
62
cmake/Modules/BuiltinTests.cmake
Normal file
62
cmake/Modules/BuiltinTests.cmake
Normal file
@ -0,0 +1,62 @@
|
||||
|
||||
# This function takes an OS and a list of architectures and identifies the
|
||||
# subset of the architectures list that the installed toolchain can target.
|
||||
function(try_compile_only output)
|
||||
set(SIMPLE_C ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/src.c)
|
||||
file(WRITE ${SIMPLE_C} "int foo(int x, int y) { return x + y; }\n")
|
||||
string(REGEX MATCHALL "<[A-Za-z0-9_]*>" substitutions
|
||||
${CMAKE_C_COMPILE_OBJECT})
|
||||
string(REPLACE ";" " " extra_flags "${ARGN}")
|
||||
|
||||
set(test_compile_command "${CMAKE_C_COMPILE_OBJECT}")
|
||||
foreach(substitution ${substitutions})
|
||||
if(substitution STREQUAL "<CMAKE_C_COMPILER>")
|
||||
string(REPLACE "<CMAKE_C_COMPILER>"
|
||||
"${CMAKE_C_COMPILER}" test_compile_command ${test_compile_command})
|
||||
elseif(substitution STREQUAL "<OBJECT>")
|
||||
string(REPLACE "<OBJECT>"
|
||||
"${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/test.o"
|
||||
test_compile_command ${test_compile_command})
|
||||
elseif(substitution STREQUAL "<SOURCE>")
|
||||
string(REPLACE "<SOURCE>" "${SIMPLE_C}" test_compile_command
|
||||
${test_compile_command})
|
||||
elseif(substitution STREQUAL "<FLAGS>")
|
||||
string(REPLACE "<FLAGS>" "${CMAKE_C_FLAGS} ${extra_flags}"
|
||||
test_compile_command ${test_compile_command})
|
||||
else()
|
||||
string(REPLACE "${substitution}" "" test_compile_command
|
||||
${test_compile_command})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
string(REPLACE " " ";" test_compile_command "${test_compile_command}")
|
||||
|
||||
execute_process(
|
||||
COMMAND ${test_compile_command}
|
||||
RESULT_VARIABLE result
|
||||
OUTPUT_VARIABLE TEST_OUTPUT
|
||||
ERROR_VARIABLE TEST_ERROR
|
||||
)
|
||||
if(result EQUAL 0)
|
||||
set(${output} True PARENT_SCOPE)
|
||||
else()
|
||||
file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
|
||||
"Testing compiler for supporting " ${ARGN} ":\n"
|
||||
"Command: ${test_compile_command}\n"
|
||||
"${TEST_OUTPUT}\n${TEST_ERROR}\n${result}\n")
|
||||
set(${output} False PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(builtin_check_c_compiler_flag flag output)
|
||||
if(NOT DEFINED ${output})
|
||||
message(STATUS "Performing Test ${output}")
|
||||
try_compile_only(result ${flag})
|
||||
set(${output} ${result} CACHE INTERNAL "Compiler supports ${flag}")
|
||||
if(${result})
|
||||
message(STATUS "Performing Test ${output} - Success")
|
||||
else()
|
||||
message(STATUS "Performing Test ${output} - Failed")
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
@ -90,8 +90,8 @@ macro(clang_compiler_add_cxx_check)
|
||||
" 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 ' cd ${LLVM_MAIN_SRC_DIR}/projects && svn co http://llvm.org/svn/llvm-project/libcxx/trunk libcxx'"
|
||||
" echo ' cd ${LLVM_BINARY_DIR} && make -C ${LLVM_MAIN_SRC_DIR}/projects/libcxx installheaders HEADER_DIR=${LLVM_BINARY_DIR}/include'"
|
||||
" echo"
|
||||
" false"
|
||||
"fi"
|
||||
|
@ -1,3 +1,5 @@
|
||||
include(CMakeParseArguments)
|
||||
|
||||
# On OS X SDKs can be installed anywhere on the base system and xcode-select can
|
||||
# set the default Xcode to use. This function finds the SDKs that are present in
|
||||
# the current Xcode.
|
||||
@ -16,6 +18,8 @@ function(find_darwin_sdk_dir var sdk_name)
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_FILE /dev/null
|
||||
)
|
||||
else()
|
||||
set(${var}_INTERNAL ${var_internal} PARENT_SCOPE)
|
||||
endif()
|
||||
set(${var} ${var_internal} PARENT_SCOPE)
|
||||
endfunction()
|
||||
@ -52,30 +56,36 @@ function(darwin_test_archs os valid_archs)
|
||||
endif()
|
||||
|
||||
set(archs ${ARGN})
|
||||
message(STATUS "Finding valid architectures for ${os}...")
|
||||
set(SIMPLE_CPP ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/src.cpp)
|
||||
file(WRITE ${SIMPLE_CPP} "#include <iostream>\nint main() { std::cout << std::endl; return 0; }\n")
|
||||
|
||||
set(os_linker_flags)
|
||||
foreach(flag ${DARWIN_${os}_LINKFLAGS})
|
||||
set(os_linker_flags "${os_linker_flags} ${flag}")
|
||||
endforeach()
|
||||
if(NOT TEST_COMPILE_ONLY)
|
||||
message(STATUS "Finding valid architectures for ${os}...")
|
||||
set(SIMPLE_C ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/src.c)
|
||||
file(WRITE ${SIMPLE_C} "#include <stdio.h>\nint main() { printf(__FILE__); return 0; }\n")
|
||||
|
||||
set(os_linker_flags)
|
||||
foreach(flag ${DARWIN_${os}_LINKFLAGS})
|
||||
set(os_linker_flags "${os_linker_flags} ${flag}")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
# The simple program will build for x86_64h on the simulator because it is
|
||||
# compatible with x86_64 libraries (mostly), but since x86_64h isn't actually
|
||||
# a valid or useful architecture for the iOS simulator we should drop it.
|
||||
if(${os} STREQUAL "iossim")
|
||||
if(${os} MATCHES "^(iossim|tvossim|watchossim)$")
|
||||
list(REMOVE_ITEM archs "x86_64h")
|
||||
endif()
|
||||
|
||||
set(working_archs)
|
||||
foreach(arch ${archs})
|
||||
|
||||
|
||||
set(arch_linker_flags "-arch ${arch} ${os_linker_flags}")
|
||||
try_compile(CAN_TARGET_${os}_${arch} ${CMAKE_BINARY_DIR} ${SIMPLE_CPP}
|
||||
COMPILE_DEFINITIONS "-v -arch ${arch}" ${DARWIN_${os}_CFLAGS}
|
||||
CMAKE_FLAGS "-DCMAKE_EXE_LINKER_FLAGS=${arch_linker_flags}"
|
||||
OUTPUT_VARIABLE TEST_OUTPUT)
|
||||
if(TEST_COMPILE_ONLY)
|
||||
try_compile_only(CAN_TARGET_${os}_${arch} -v -arch ${arch} ${DARWIN_${os}_CFLAGS})
|
||||
else()
|
||||
try_compile(CAN_TARGET_${os}_${arch} ${CMAKE_BINARY_DIR} ${SIMPLE_C}
|
||||
COMPILE_DEFINITIONS "-v -arch ${arch}" ${DARWIN_${os}_CFLAGS}
|
||||
CMAKE_FLAGS "-DCMAKE_EXE_LINKER_FLAGS=${arch_linker_flags}"
|
||||
OUTPUT_VARIABLE TEST_OUTPUT)
|
||||
endif()
|
||||
if(${CAN_TARGET_${os}_${arch}})
|
||||
list(APPEND working_archs ${arch})
|
||||
else()
|
||||
|
@ -1,3 +1,6 @@
|
||||
include(CMakePushCheckState)
|
||||
include(CheckSymbolExists)
|
||||
|
||||
# Because compiler-rt spends a lot of time setting up custom compile flags,
|
||||
# define a handy helper function for it. The compile flags setting in CMake
|
||||
# has serious issues that make its syntax challenging at best.
|
||||
@ -45,9 +48,14 @@ macro(append_string_if condition value)
|
||||
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})
|
||||
macro(append_rtti_flag polarity list)
|
||||
if(polarity)
|
||||
append_list_if(COMPILER_RT_HAS_FRTTI_FLAG -frtti ${list})
|
||||
append_list_if(COMPILER_RT_HAS_GR_FLAG /GR ${list})
|
||||
else()
|
||||
append_list_if(COMPILER_RT_HAS_FNO_RTTI_FLAG -fno-rtti ${list})
|
||||
append_list_if(COMPILER_RT_HAS_GR_FLAG /GR- ${list})
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro(append_have_file_definition filename varname list)
|
||||
@ -67,3 +75,94 @@ macro(list_intersect output input1 input2)
|
||||
endif()
|
||||
endforeach()
|
||||
endmacro()
|
||||
|
||||
# Takes ${ARGN} and puts only supported architectures in @out_var list.
|
||||
function(filter_available_targets out_var)
|
||||
set(archs ${${out_var}})
|
||||
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()
|
||||
|
||||
function(check_compile_definition def argstring out_var)
|
||||
if("${def}" STREQUAL "")
|
||||
set(${out_var} TRUE PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
cmake_push_check_state()
|
||||
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${argstring}")
|
||||
check_symbol_exists(${def} "" ${out_var})
|
||||
cmake_pop_check_state()
|
||||
endfunction()
|
||||
|
||||
# test_target_arch(<arch> <def> <target flags...>)
|
||||
# Checks if architecture is supported: runs host compiler with provided
|
||||
# flags to verify that:
|
||||
# 1) <def> is defined (if non-empty)
|
||||
# 2) simple file can be successfully built.
|
||||
# If successful, saves target flags for this architecture.
|
||||
macro(test_target_arch arch def)
|
||||
set(TARGET_${arch}_CFLAGS ${ARGN})
|
||||
set(TARGET_${arch}_LINKFLAGS ${ARGN})
|
||||
set(argstring "")
|
||||
foreach(arg ${ARGN})
|
||||
set(argstring "${argstring} ${arg}")
|
||||
endforeach()
|
||||
check_compile_definition("${def}" "${argstring}" HAS_${arch}_DEF)
|
||||
if(NOT HAS_${arch}_DEF)
|
||||
set(CAN_TARGET_${arch} FALSE)
|
||||
elseif(TEST_COMPILE_ONLY)
|
||||
try_compile_only(CAN_TARGET_${arch} ${TARGET_${arch}_CFLAGS})
|
||||
else()
|
||||
set(argstring "${CMAKE_EXE_LINKER_FLAGS} ${argstring}")
|
||||
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}")
|
||||
endif()
|
||||
if(${CAN_TARGET_${arch}})
|
||||
list(APPEND COMPILER_RT_SUPPORTED_ARCH ${arch})
|
||||
elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "${arch}" AND
|
||||
COMPILER_RT_HAS_EXPLICIT_DEFAULT_TARGET_TRIPLE)
|
||||
# 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()
|
||||
|
||||
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)
|
||||
check_symbol_exists(__s390x__ "" __S390X)
|
||||
check_symbol_exists(__wasm32__ "" __WEBASSEMBLY32)
|
||||
check_symbol_exists(__wasm64__ "" __WEBASSEMBLY64)
|
||||
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)
|
||||
elseif(__S390X)
|
||||
add_default_target_arch(s390x)
|
||||
elseif(__WEBASSEMBLY32)
|
||||
add_default_target_arch(wasm32)
|
||||
elseif(__WEBASSEMBLY64)
|
||||
add_default_target_arch(wasm64)
|
||||
endif()
|
||||
endmacro()
|
||||
|
@ -38,22 +38,8 @@ macro(add_sanitizer_rt_symbols name)
|
||||
DEPENDS ${stamp}
|
||||
SOURCES ${SANITIZER_GEN_DYNAMIC_LIST} ${ARG_EXTRA})
|
||||
|
||||
if(NOT CMAKE_VERSION VERSION_LESS 3.0)
|
||||
install(FILES $<TARGET_FILE:${target_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 ${target_name} LOCATION_${c})
|
||||
install(FILES ${libfile}.syms CONFIGURATIONS ${c}
|
||||
install(FILES $<TARGET_FILE:${target_name}>.syms
|
||||
DESTINATION ${COMPILER_RT_LIBRARY_INSTALL_DIR})
|
||||
endforeach()
|
||||
else()
|
||||
get_target_property(libfile ${target_name} LOCATION_${CMAKE_BUILD_TYPE})
|
||||
install(FILES ${libfile}.syms DESTINATION ${COMPILER_RT_LIBRARY_INSTALL_DIR})
|
||||
endif()
|
||||
endif()
|
||||
if(ARG_PARENT_TARGET)
|
||||
add_dependencies(${ARG_PARENT_TARGET} ${target_name}-symbols)
|
||||
endif()
|
||||
@ -84,9 +70,9 @@ macro(add_sanitizer_rt_version_list name)
|
||||
endmacro()
|
||||
|
||||
# Add target to check code style for sanitizer runtimes.
|
||||
if(UNIX)
|
||||
if(CMAKE_HOST_UNIX)
|
||||
add_custom_target(SanitizerLintCheck
|
||||
COMMAND LLVM_CHECKOUT=${LLVM_MAIN_SRC_DIR} SILENT=1 TMPDIR=
|
||||
COMMAND env LLVM_CHECKOUT=${LLVM_MAIN_SRC_DIR} SILENT=1 TMPDIR=
|
||||
PYTHON_EXECUTABLE=${PYTHON_EXECUTABLE}
|
||||
COMPILER_RT=${COMPILER_RT_SOURCE_DIR}
|
||||
${SANITIZER_LINT_SCRIPT}
|
||||
|
169
cmake/base-config-ix.cmake
Normal file
169
cmake/base-config-ix.cmake
Normal file
@ -0,0 +1,169 @@
|
||||
# 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.
|
||||
|
||||
include(CheckIncludeFile)
|
||||
check_include_file(unwind.h HAVE_UNWIND_H)
|
||||
|
||||
# Top level target used to build all compiler-rt libraries.
|
||||
add_custom_target(compiler-rt ALL)
|
||||
set_target_properties(compiler-rt PROPERTIES FOLDER "Compiler-RT Misc")
|
||||
|
||||
# Setting these variables from an LLVM build is sufficient that compiler-rt can
|
||||
# construct the output paths, so it can behave as if it were in-tree here.
|
||||
if (LLVM_LIBRARY_OUTPUT_INTDIR AND LLVM_RUNTIME_OUTPUT_INTDIR AND PACKAGE_VERSION)
|
||||
set(LLVM_TREE_AVAILABLE On)
|
||||
endif()
|
||||
|
||||
if (LLVM_TREE_AVAILABLE)
|
||||
# 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)
|
||||
set(COMPILER_RT_TEST_CXX_COMPILER ${LLVM_RUNTIME_OUTPUT_INTDIR}/clang++)
|
||||
else()
|
||||
set(COMPILER_RT_TEST_COMPILER ${LLVM_RUNTIME_OUTPUT_INTDIR}/clang.exe)
|
||||
set(COMPILER_RT_TEST_CXX_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")
|
||||
set(COMPILER_RT_TEST_CXX_COMPILER ${CMAKE_CXX_COMPILER} CACHE PATH "C++ Compiler to use for testing")
|
||||
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()
|
||||
|
||||
string(TOLOWER ${CMAKE_SYSTEM_NAME} COMPILER_RT_OS_DIR)
|
||||
set(COMPILER_RT_LIBRARY_OUTPUT_DIR
|
||||
${COMPILER_RT_OUTPUT_DIR}/lib/${COMPILER_RT_OS_DIR})
|
||||
set(COMPILER_RT_LIBRARY_INSTALL_DIR
|
||||
${COMPILER_RT_INSTALL_PATH}/lib/${COMPILER_RT_OS_DIR})
|
||||
|
||||
if(APPLE)
|
||||
# On Darwin if /usr/include doesn't exist, the user probably has Xcode but not
|
||||
# the command line tools. If this is the case, we need to find the OS X
|
||||
# sysroot to pass to clang.
|
||||
if(NOT EXISTS /usr/include)
|
||||
execute_process(COMMAND xcodebuild -version -sdk macosx Path
|
||||
OUTPUT_VARIABLE OSX_SYSROOT
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
set(OSX_SYSROOT_FLAG "-isysroot${OSX_SYSROOT}")
|
||||
endif()
|
||||
|
||||
option(COMPILER_RT_ENABLE_IOS "Enable building for iOS" Off)
|
||||
option(COMPILER_RT_ENABLE_WATCHOS "Enable building for watchOS - Experimental" Off)
|
||||
option(COMPILER_RT_ENABLE_TVOS "Enable building for tvOS - Experimental" Off)
|
||||
endif()
|
||||
|
||||
macro(test_targets)
|
||||
# Find and run MSVC (not clang-cl) and get its version. This will tell clang-cl
|
||||
# what version of MSVC to pretend to be so that the STL works.
|
||||
set(MSVC_VERSION_FLAG "")
|
||||
if (MSVC)
|
||||
# Find and run MSVC (not clang-cl) and get its version. This will tell
|
||||
# clang-cl what version of MSVC to pretend to be so that the STL works.
|
||||
execute_process(COMMAND "$ENV{VSINSTALLDIR}/VC/bin/cl.exe"
|
||||
OUTPUT_QUIET
|
||||
ERROR_VARIABLE MSVC_COMPAT_VERSION
|
||||
)
|
||||
string(REGEX REPLACE "^.*Compiler Version ([0-9.]+) for .*$" "\\1"
|
||||
MSVC_COMPAT_VERSION "${MSVC_COMPAT_VERSION}")
|
||||
if (MSVC_COMPAT_VERSION MATCHES "^[0-9].+$")
|
||||
set(MSVC_VERSION_FLAG "-fms-compatibility-version=${MSVC_COMPAT_VERSION}")
|
||||
# Add this flag into the host build if this is clang-cl.
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
append("${MSVC_VERSION_FLAG}" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
|
||||
elseif (COMPILER_RT_TEST_COMPILER_ID MATCHES "Clang")
|
||||
# Add this flag to test compiles to suppress clang's auto-detection
|
||||
# logic.
|
||||
append("${MSVC_VERSION_FLAG}" COMPILER_RT_TEST_COMPILER_CFLAGS)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Generate the COMPILER_RT_SUPPORTED_ARCH list.
|
||||
if(ANDROID)
|
||||
# Examine compiler output to determine target architecture.
|
||||
detect_target_arch()
|
||||
set(COMPILER_RT_OS_SUFFIX "-android")
|
||||
elseif(NOT APPLE) # Supported archs for Apple platforms are generated later
|
||||
if("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "i[2-6]86|x86|amd64")
|
||||
if(NOT MSVC)
|
||||
test_target_arch(x86_64 "" "-m64")
|
||||
# FIXME: We build runtimes for both i686 and i386, as "clang -m32" may
|
||||
# target different variant than "$CMAKE_C_COMPILER -m32". This part should
|
||||
# be gone after we resolve PR14109.
|
||||
test_target_arch(i686 __i686__ "-m32")
|
||||
test_target_arch(i386 __i386__ "-m32")
|
||||
else()
|
||||
if (CMAKE_SIZEOF_VOID_P EQUAL 4)
|
||||
test_target_arch(i386 "" "")
|
||||
else()
|
||||
test_target_arch(x86_64 "" "")
|
||||
endif()
|
||||
endif()
|
||||
elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "powerpc")
|
||||
TEST_BIG_ENDIAN(HOST_IS_BIG_ENDIAN)
|
||||
if(HOST_IS_BIG_ENDIAN)
|
||||
test_target_arch(powerpc64 "" "-m64")
|
||||
else()
|
||||
test_target_arch(powerpc64le "" "-m64")
|
||||
endif()
|
||||
elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "s390x")
|
||||
test_target_arch(s390x "" "")
|
||||
elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "mipsel|mips64el")
|
||||
# Gcc doesn't accept -m32/-m64 so we do the next best thing and use
|
||||
# -mips32r2/-mips64r2. We don't use -mips1/-mips3 because we want to match
|
||||
# clang's default CPU's. In the 64-bit case, we must also specify the ABI
|
||||
# since the default ABI differs between gcc and clang.
|
||||
# FIXME: Ideally, we would build the N32 library too.
|
||||
test_target_arch(mipsel "" "-mips32r2" "--target=mipsel-linux-gnu")
|
||||
test_target_arch(mips64el "" "-mips64r2" "--target=mips64el-linux-gnu" "-mabi=64")
|
||||
elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "mips")
|
||||
test_target_arch(mips "" "-mips32r2" "--target=mips-linux-gnu")
|
||||
test_target_arch(mips64 "" "-mips64r2" "--target=mips64-linux-gnu" "-mabi=64")
|
||||
elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "arm")
|
||||
test_target_arch(arm "" "-march=armv7-a" "-mfloat-abi=soft")
|
||||
test_target_arch(armhf "" "-march=armv7-a" "-mfloat-abi=hard")
|
||||
elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "aarch32")
|
||||
test_target_arch(aarch32 "" "-march=armv8-a")
|
||||
elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "aarch64")
|
||||
test_target_arch(aarch64 "" "-march=armv8-a")
|
||||
elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "wasm32")
|
||||
test_target_arch(wasm32 "" "--target=wasm32-unknown-unknown")
|
||||
elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "wasm64")
|
||||
test_target_arch(wasm64 "" "--target=wasm64-unknown-unknown")
|
||||
endif()
|
||||
set(COMPILER_RT_OS_SUFFIX "")
|
||||
endif()
|
||||
endmacro()
|
169
cmake/builtin-config-ix.cmake
Normal file
169
cmake/builtin-config-ix.cmake
Normal file
@ -0,0 +1,169 @@
|
||||
include(BuiltinTests)
|
||||
|
||||
# Make all the tests only check the compiler
|
||||
set(TEST_COMPILE_ONLY On)
|
||||
|
||||
builtin_check_c_compiler_flag(-fPIC COMPILER_RT_HAS_FPIC_FLAG)
|
||||
builtin_check_c_compiler_flag(-fPIE COMPILER_RT_HAS_FPIE_FLAG)
|
||||
builtin_check_c_compiler_flag(-fno-builtin COMPILER_RT_HAS_FNO_BUILTIN_FLAG)
|
||||
builtin_check_c_compiler_flag(-std=c99 COMPILER_RT_HAS_STD_C99_FLAG)
|
||||
builtin_check_c_compiler_flag(-fvisibility=hidden COMPILER_RT_HAS_VISIBILITY_HIDDEN_FLAG)
|
||||
builtin_check_c_compiler_flag(-fomit-frame-pointer COMPILER_RT_HAS_OMIT_FRAME_POINTER_FLAG)
|
||||
builtin_check_c_compiler_flag(-ffreestanding COMPILER_RT_HAS_FREESTANDING_FLAG)
|
||||
builtin_check_c_compiler_flag(-mfloat-abi=soft COMPILER_RT_HAS_FLOAT_ABI_SOFT_FLAG)
|
||||
builtin_check_c_compiler_flag(-mfloat-abi=hard COMPILER_RT_HAS_FLOAT_ABI_HARD_FLAG)
|
||||
builtin_check_c_compiler_flag(-static COMPILER_RT_HAS_STATIC_FLAG)
|
||||
|
||||
set(ARM64 aarch64)
|
||||
set(ARM32 arm armhf)
|
||||
set(X86 i386 i686)
|
||||
set(X86_64 x86_64)
|
||||
set(MIPS32 mips mipsel)
|
||||
set(MIPS64 mips64 mips64el)
|
||||
set(PPC64 powerpc64 powerpc64le)
|
||||
set(WASM32 wasm32)
|
||||
set(WASM64 wasm64)
|
||||
|
||||
if(APPLE)
|
||||
set(ARM64 arm64)
|
||||
set(ARM32 armv7 armv7k armv7s)
|
||||
set(X86_64 x86_64 x86_64h)
|
||||
endif()
|
||||
|
||||
set(ALL_BUILTIN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64}
|
||||
${MIPS32} ${MIPS64} ${WASM32} ${WASM64})
|
||||
|
||||
include(CompilerRTUtils)
|
||||
include(CompilerRTDarwinUtils)
|
||||
|
||||
if(APPLE)
|
||||
|
||||
find_darwin_sdk_dir(DARWIN_osx_SYSROOT macosx)
|
||||
find_darwin_sdk_dir(DARWIN_iossim_SYSROOT iphonesimulator)
|
||||
find_darwin_sdk_dir(DARWIN_ios_SYSROOT iphoneos)
|
||||
find_darwin_sdk_dir(DARWIN_watchossim_SYSROOT watchsimulator)
|
||||
find_darwin_sdk_dir(DARWIN_watchos_SYSROOT watchos)
|
||||
find_darwin_sdk_dir(DARWIN_tvossim_SYSROOT appletvsimulator)
|
||||
find_darwin_sdk_dir(DARWIN_tvos_SYSROOT appletvos)
|
||||
|
||||
set(DARWIN_EMBEDDED_PLATFORMS)
|
||||
set(DARWIN_osx_BUILTIN_MIN_VER 10.5)
|
||||
set(DARWIN_osx_BUILTIN_MIN_VER_FLAG
|
||||
-mmacosx-version-min=${DARWIN_osx_BUILTIN_MIN_VER})
|
||||
|
||||
if(COMPILER_RT_ENABLE_IOS)
|
||||
list(APPEND DARWIN_EMBEDDED_PLATFORMS ios)
|
||||
set(DARWIN_ios_MIN_VER_FLAG -miphoneos-version-min)
|
||||
set(DARWIN_ios_BUILTIN_MIN_VER 6.0)
|
||||
set(DARWIN_ios_BUILTIN_MIN_VER_FLAG
|
||||
${DARWIN_ios_MIN_VER_FLAG}=${DARWIN_ios_BUILTIN_MIN_VER})
|
||||
endif()
|
||||
if(COMPILER_RT_ENABLE_WATCHOS)
|
||||
list(APPEND DARWIN_EMBEDDED_PLATFORMS watchos)
|
||||
set(DARWIN_watchos_MIN_VER_FLAG -mwatchos-version-min)
|
||||
set(DARWIN_watchos_BUILTIN_MIN_VER 2.0)
|
||||
set(DARWIN_watchos_BUILTIN_MIN_VER_FLAG
|
||||
${DARWIN_watchos_MIN_VER_FLAG}=${DARWIN_watchos_BUILTIN_MIN_VER})
|
||||
endif()
|
||||
if(COMPILER_RT_ENABLE_TVOS)
|
||||
list(APPEND DARWIN_EMBEDDED_PLATFORMS tvos)
|
||||
set(DARWIN_tvos_MIN_VER_FLAG -mtvos-version-min)
|
||||
set(DARWIN_tvos_BUILTIN_MIN_VER 9.0)
|
||||
set(DARWIN_tvos_BUILTIN_MIN_VER_FLAG
|
||||
${DARWIN_tvos_MIN_VER_FLAG}=${DARWIN_tvos_BUILTIN_MIN_VER})
|
||||
endif()
|
||||
|
||||
set(BUILTIN_SUPPORTED_OS osx)
|
||||
|
||||
# We're setting the flag manually for each target OS
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "")
|
||||
|
||||
if(NOT DARWIN_osx_ARCHS)
|
||||
set(DARWIN_osx_ARCHS i386 x86_64 x86_64h)
|
||||
endif()
|
||||
|
||||
set(DARWIN_sim_ARCHS i386 x86_64)
|
||||
set(DARWIN_device_ARCHS armv7 armv7s armv7k arm64)
|
||||
|
||||
message(STATUS "OSX supported arches: ${DARWIN_osx_ARCHS}")
|
||||
foreach(arch ${DARWIN_osx_ARCHS})
|
||||
list(APPEND COMPILER_RT_SUPPORTED_ARCH ${arch})
|
||||
set(CAN_TARGET_${arch} 1)
|
||||
endforeach()
|
||||
|
||||
# Need to build a 10.4 compatible libclang_rt
|
||||
set(DARWIN_10.4_SYSROOT ${DARWIN_osx_SYSROOT})
|
||||
set(DARWIN_10.4_BUILTIN_MIN_VER 10.4)
|
||||
set(DARWIN_10.4_BUILTIN_MIN_VER_FLAG
|
||||
-mmacosx-version-min=${DARWIN_10.4_BUILTIN_MIN_VER})
|
||||
set(DARWIN_10.4_SKIP_CC_KEXT On)
|
||||
darwin_test_archs(10.4 DARWIN_10.4_ARCHS i386 x86_64)
|
||||
message(STATUS "OSX 10.4 supported builtin arches: ${DARWIN_10.4_ARCHS}")
|
||||
if(DARWIN_10.4_ARCHS)
|
||||
# don't include the Haswell slice in the 10.4 compatibility library
|
||||
list(REMOVE_ITEM DARWIN_10.4_ARCHS x86_64h)
|
||||
list(APPEND BUILTIN_SUPPORTED_OS 10.4)
|
||||
endif()
|
||||
|
||||
foreach(platform ${DARWIN_EMBEDDED_PLATFORMS})
|
||||
if(DARWIN_${platform}sim_SYSROOT)
|
||||
set(DARWIN_${platform}sim_BUILTIN_MIN_VER
|
||||
${DARWIN_${platform}_BUILTIN_MIN_VER})
|
||||
set(DARWIN_${platform}sim_BUILTIN_MIN_VER_FLAG
|
||||
${DARWIN_${platform}_BUILTIN_MIN_VER_FLAG})
|
||||
|
||||
set(DARWIN_${platform}sim_SKIP_CC_KEXT On)
|
||||
|
||||
set(test_arches ${DARWIN_sim_ARCHS})
|
||||
if(DARWIN_${platform}sim_ARCHS)
|
||||
set(test_arches DARWIN_${platform}sim_ARCHS)
|
||||
endif()
|
||||
|
||||
darwin_test_archs(${platform}sim
|
||||
DARWIN_${platform}sim_ARCHS
|
||||
${test_arches})
|
||||
message(STATUS "${platform} Simulator supported builtin arches: ${DARWIN_${platform}sim_ARCHS}")
|
||||
if(DARWIN_${platform}sim_ARCHS)
|
||||
list(APPEND BUILTIN_SUPPORTED_OS ${platform}sim)
|
||||
endif()
|
||||
foreach(arch ${DARWIN_${platform}sim_ARCHS})
|
||||
list(APPEND COMPILER_RT_SUPPORTED_ARCH ${arch})
|
||||
set(CAN_TARGET_${arch} 1)
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if(DARWIN_${platform}_SYSROOT)
|
||||
set(test_arches ${DARWIN_device_ARCHS})
|
||||
if(DARWIN_${platform}_ARCHS)
|
||||
set(test_arches DARWIN_${platform}_ARCHS)
|
||||
endif()
|
||||
|
||||
darwin_test_archs(${platform}
|
||||
DARWIN_${platform}_ARCHS
|
||||
${test_arches})
|
||||
message(STATUS "${platform} supported builtin arches: ${DARWIN_${platform}_ARCHS}")
|
||||
if(DARWIN_${platform}_ARCHS)
|
||||
list(APPEND BUILTIN_SUPPORTED_OS ${platform})
|
||||
endif()
|
||||
foreach(arch ${DARWIN_${platform}_ARCHS})
|
||||
list(APPEND COMPILER_RT_SUPPORTED_ARCH ${arch})
|
||||
set(CAN_TARGET_${arch} 1)
|
||||
endforeach()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
list_intersect(BUILTIN_SUPPORTED_ARCH ALL_BUILTIN_SUPPORTED_ARCH COMPILER_RT_SUPPORTED_ARCH)
|
||||
|
||||
else()
|
||||
# If we're not building the builtins standalone, just rely on the tests in
|
||||
# config-ix.cmake to tell us what to build. Otherwise we need to do some leg
|
||||
# work here...
|
||||
if(COMPILER_RT_BUILTINS_STANDALONE_BUILD)
|
||||
test_targets()
|
||||
endif()
|
||||
# Architectures supported by compiler-rt libraries.
|
||||
filter_available_targets(BUILTIN_SUPPORTED_ARCH
|
||||
${ALL_BUILTIN_SUPPORTED_ARCH})
|
||||
endif()
|
||||
|
||||
message(STATUS "Builtin supported architectures: ${BUILTIN_SUPPORTED_ARCH}")
|
15
cmake/caches/Apple.cmake
Normal file
15
cmake/caches/Apple.cmake
Normal file
@ -0,0 +1,15 @@
|
||||
# This file sets up a CMakeCache for Apple-style builds of compiler-rt.
|
||||
# This configuration matches Apple uses when shipping Xcode releases.
|
||||
|
||||
set(COMPILER_RT_INCLUDE_TESTS OFF CACHE BOOL "")
|
||||
set(COMPILER_RT_HAS_SAFESTACK OFF CACHE BOOL "")
|
||||
set(COMPILER_RT_EXTERNALIZE_DEBUGINFO ON CACHE BOOL "")
|
||||
set(CMAKE_MACOSX_RPATH ON CACHE BOOL "")
|
||||
|
||||
set(CMAKE_C_FLAGS_RELEASE "-O3" CACHE STRING "")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-O3" CACHE STRING "")
|
||||
set(CMAKE_ASM_FLAGS_RELEASE "-O3" CACHE STRING "")
|
||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O3 -gline-tables-only -DNDEBUG" CACHE STRING "")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O3 -gline-tables-only -DNDEBUG" CACHE STRING "")
|
||||
set(CMAKE_ASM_FLAGS_RELWITHDEBINFO "-O3 -gline-tables-only -DNDEBUG" CACHE STRING "")
|
||||
set(CMAKE_BUILD_TYPE RELEASE CACHE STRING "")
|
@ -21,6 +21,7 @@ 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(-fno-sanitize=safe-stack COMPILER_RT_HAS_FNO_SANITIZE_SAFE_STACK_FLAG)
|
||||
check_cxx_compiler_flag(-fvisibility=hidden COMPILER_RT_HAS_FVISIBILITY_HIDDEN_FLAG)
|
||||
check_cxx_compiler_flag(-frtti COMPILER_RT_HAS_FRTTI_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)
|
||||
@ -28,7 +29,6 @@ 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(-fno-lto COMPILER_RT_HAS_FNO_LTO_FLAG)
|
||||
check_cxx_compiler_flag("-Werror -msse3" COMPILER_RT_HAS_MSSE3_FLAG)
|
||||
check_cxx_compiler_flag(-std=c99 COMPILER_RT_HAS_STD_C99_FLAG)
|
||||
check_cxx_compiler_flag(--sysroot=. COMPILER_RT_HAS_SYSROOT_FLAG)
|
||||
|
||||
if(NOT WIN32 AND NOT CYGWIN)
|
||||
@ -55,11 +55,13 @@ check_cxx_compiler_flag("-Werror -Wc99-extensions" COMPILER_RT_HAS_WC99_EXTE
|
||||
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("-Werror -Wunused-parameter" COMPILER_RT_HAS_WUNUSED_PARAMETER_FLAG)
|
||||
|
||||
check_cxx_compiler_flag(/W3 COMPILER_RT_HAS_W3_FLAG)
|
||||
check_cxx_compiler_flag(/W4 COMPILER_RT_HAS_W4_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(/wd4221 COMPILER_RT_HAS_WD4221_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)
|
||||
@ -93,48 +95,6 @@ set(COMPILER_RT_SUPPORTED_ARCH)
|
||||
set(SIMPLE_SOURCE ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/simple.cc)
|
||||
file(WRITE ${SIMPLE_SOURCE} "#include <stdlib.h>\n#include <limits>\nint main() {}\n")
|
||||
|
||||
function(check_compile_definition def argstring out_var)
|
||||
if("${def}" STREQUAL "")
|
||||
set(${out_var} TRUE PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
cmake_push_check_state()
|
||||
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${argstring}")
|
||||
check_symbol_exists(${def} "" ${out_var})
|
||||
cmake_pop_check_state()
|
||||
endfunction()
|
||||
|
||||
# test_target_arch(<arch> <def> <target flags...>)
|
||||
# Checks if architecture is supported: runs host compiler with provided
|
||||
# flags to verify that:
|
||||
# 1) <def> is defined (if non-empty)
|
||||
# 2) simple file can be successfully built.
|
||||
# If successful, saves target flags for this architecture.
|
||||
macro(test_target_arch arch def)
|
||||
set(TARGET_${arch}_CFLAGS ${ARGN})
|
||||
set(argstring "")
|
||||
foreach(arg ${ARGN})
|
||||
set(argstring "${argstring} ${arg}")
|
||||
endforeach()
|
||||
check_compile_definition("${def}" "${argstring}" HAS_${arch}_DEF)
|
||||
if(NOT HAS_${arch}_DEF)
|
||||
set(CAN_TARGET_${arch} FALSE)
|
||||
else()
|
||||
set(argstring "${CMAKE_EXE_LINKER_FLAGS} ${argstring}")
|
||||
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}")
|
||||
endif()
|
||||
if(${CAN_TARGET_${arch}})
|
||||
list(APPEND COMPILER_RT_SUPPORTED_ARCH ${arch})
|
||||
elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "${arch}" AND
|
||||
COMPILER_RT_HAS_EXPLICIT_DEFAULT_TARGET_TRIPLE)
|
||||
# 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 "")
|
||||
@ -142,37 +102,6 @@ macro(add_default_target_arch arch)
|
||||
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)
|
||||
check_symbol_exists(__wasm32__ "" __WEBASSEMBLY32)
|
||||
check_symbol_exists(__wasm64__ "" __WEBASSEMBLY64)
|
||||
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)
|
||||
elseif(__WEBASSEMBLY32)
|
||||
add_default_target_arch(wasm32)
|
||||
elseif(__WEBASSEMBLY64)
|
||||
add_default_target_arch(wasm64)
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
# 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.
|
||||
if (NOT CMAKE_SIZEOF_VOID_P EQUAL 4 AND
|
||||
@ -180,71 +109,7 @@ if (NOT CMAKE_SIZEOF_VOID_P EQUAL 4 AND
|
||||
message(FATAL_ERROR "Please use architecture with 4 or 8 byte pointers.")
|
||||
endif()
|
||||
|
||||
# Generate the COMPILER_RT_SUPPORTED_ARCH list.
|
||||
if(ANDROID)
|
||||
# Examine compiler output to determine target architecture.
|
||||
detect_target_arch()
|
||||
set(COMPILER_RT_OS_SUFFIX "-android")
|
||||
elseif(NOT APPLE) # Supported archs for Apple platforms are generated later
|
||||
if("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "i[2-6]86|x86|amd64")
|
||||
if(NOT MSVC)
|
||||
test_target_arch(x86_64 "" "-m64")
|
||||
# FIXME: We build runtimes for both i686 and i386, as "clang -m32" may
|
||||
# target different variant than "$CMAKE_C_COMPILER -m32". This part should
|
||||
# be gone after we resolve PR14109.
|
||||
test_target_arch(i686 __i686__ "-m32")
|
||||
test_target_arch(i386 __i386__ "-m32")
|
||||
else()
|
||||
if (CMAKE_SIZEOF_VOID_P EQUAL 4)
|
||||
test_target_arch(i386 "" "")
|
||||
else()
|
||||
test_target_arch(x86_64 "" "")
|
||||
endif()
|
||||
endif()
|
||||
elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "powerpc")
|
||||
TEST_BIG_ENDIAN(HOST_IS_BIG_ENDIAN)
|
||||
if(HOST_IS_BIG_ENDIAN)
|
||||
test_target_arch(powerpc64 "" "-m64")
|
||||
else()
|
||||
test_target_arch(powerpc64le "" "-m64")
|
||||
endif()
|
||||
elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "mipsel|mips64el")
|
||||
# Gcc doesn't accept -m32/-m64 so we do the next best thing and use
|
||||
# -mips32r2/-mips64r2. We don't use -mips1/-mips3 because we want to match
|
||||
# clang's default CPU's. In the 64-bit case, we must also specify the ABI
|
||||
# since the default ABI differs between gcc and clang.
|
||||
# FIXME: Ideally, we would build the N32 library too.
|
||||
test_target_arch(mipsel "" "-mips32r2" "--target=mipsel-linux-gnu")
|
||||
test_target_arch(mips64el "" "-mips64r2" "--target=mips64el-linux-gnu" "-mabi=n64")
|
||||
elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "mips")
|
||||
test_target_arch(mips "" "-mips32r2" "--target=mips-linux-gnu")
|
||||
test_target_arch(mips64 "" "-mips64r2" "--target=mips64-linux-gnu" "-mabi=n64")
|
||||
elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "arm")
|
||||
test_target_arch(arm "" "-march=armv7-a" "-mfloat-abi=soft")
|
||||
test_target_arch(armhf "" "-march=armv7-a" "-mfloat-abi=hard")
|
||||
elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "aarch32")
|
||||
test_target_arch(aarch32 "" "-march=armv8-a")
|
||||
elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "aarch64")
|
||||
test_target_arch(aarch64 "" "-march=armv8-a")
|
||||
elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "wasm32")
|
||||
test_target_arch(wasm32 "" "--target=wasm32-unknown-unknown")
|
||||
elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "wasm64")
|
||||
test_target_arch(wasm64 "" "--target=wasm64-unknown-unknown")
|
||||
endif()
|
||||
set(COMPILER_RT_OS_SUFFIX "")
|
||||
endif()
|
||||
|
||||
# Takes ${ARGN} and puts only supported architectures in @out_var list.
|
||||
function(filter_available_targets out_var)
|
||||
set(archs ${${out_var}})
|
||||
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()
|
||||
test_targets()
|
||||
|
||||
# Returns a list of architecture specific target cflags in @out_var list.
|
||||
function(get_target_flags_for_arch arch out_var)
|
||||
@ -270,50 +135,36 @@ set(X86_64 x86_64)
|
||||
set(MIPS32 mips mipsel)
|
||||
set(MIPS64 mips64 mips64el)
|
||||
set(PPC64 powerpc64 powerpc64le)
|
||||
set(S390X s390x)
|
||||
set(WASM32 wasm32)
|
||||
set(WASM64 wasm64)
|
||||
|
||||
if(APPLE)
|
||||
set(ARM64 arm64)
|
||||
set(ARM32 armv7 armv7s)
|
||||
set(ARM32 armv7 armv7s armv7k)
|
||||
set(X86_64 x86_64 x86_64h)
|
||||
endif()
|
||||
|
||||
set(ALL_BUILTIN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64}
|
||||
${MIPS32} ${MIPS64} ${WASM32} ${WASM64})
|
||||
set(ALL_SANITIZER_COMMON_SUPPORTED_ARCH ${X86} ${X86_64} ${PPC64}
|
||||
${ARM32} ${ARM64} ${MIPS32} ${MIPS64})
|
||||
${ARM32} ${ARM64} ${MIPS32} ${MIPS64} ${S390X})
|
||||
set(ALL_ASAN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64}
|
||||
${MIPS32} ${MIPS64} ${PPC64})
|
||||
set(ALL_DFSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64})
|
||||
set(ALL_LSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64})
|
||||
set(ALL_MSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64})
|
||||
set(ALL_MSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64} ${PPC64})
|
||||
set(ALL_PROFILE_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${PPC64}
|
||||
${MIPS32} ${MIPS64})
|
||||
set(ALL_TSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64} ${PPC64})
|
||||
set(ALL_UBSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64}
|
||||
${MIPS32} ${MIPS64} ${PPC64})
|
||||
set(ALL_SAFESTACK_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM64})
|
||||
set(ALL_CFI_SUPPORTED_ARCH ${X86} ${X86_64})
|
||||
${MIPS32} ${MIPS64} ${PPC64} ${S390X})
|
||||
set(ALL_SAFESTACK_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM64} ${MIPS32} ${MIPS64})
|
||||
set(ALL_CFI_SUPPORTED_ARCH ${X86} ${X86_64} ${MIPS64})
|
||||
set(ALL_ESAN_SUPPORTED_ARCH ${X86_64})
|
||||
set(ALL_SCUDO_SUPPORTED_ARCH ${X86_64})
|
||||
|
||||
if(APPLE)
|
||||
include(CompilerRTDarwinUtils)
|
||||
|
||||
# On Darwin if /usr/include doesn't exist, the user probably has Xcode but not
|
||||
# the command line tools. If this is the case, we need to find the OS X
|
||||
# sysroot to pass to clang.
|
||||
if(NOT EXISTS /usr/include)
|
||||
execute_process(COMMAND xcodebuild -version -sdk macosx Path
|
||||
OUTPUT_VARIABLE OSX_SYSROOT
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
set(OSX_SYSROOT_FLAG "-isysroot${OSX_SYSROOT}")
|
||||
endif()
|
||||
|
||||
option(COMPILER_RT_ENABLE_IOS "Enable building for iOS - Experimental" Off)
|
||||
option(COMPILER_RT_ENABLE_WATCHOS "Enable building for watchOS - Experimental" Off)
|
||||
option(COMPILER_RT_ENABLE_TVOS "Enable building for tvOS - Experimental" Off)
|
||||
|
||||
find_darwin_sdk_dir(DARWIN_osx_SYSROOT macosx)
|
||||
find_darwin_sdk_dir(DARWIN_iossim_SYSROOT iphonesimulator)
|
||||
find_darwin_sdk_dir(DARWIN_ios_SYSROOT iphoneos)
|
||||
@ -327,33 +178,23 @@ if(APPLE)
|
||||
set(DARWIN_ios_MIN_VER_FLAG -miphoneos-version-min)
|
||||
set(DARWIN_ios_SANITIZER_MIN_VER_FLAG
|
||||
${DARWIN_ios_MIN_VER_FLAG}=7.0)
|
||||
set(DARWIN_ios_BUILTIN_MIN_VER 6.0)
|
||||
set(DARWIN_ios_BUILTIN_MIN_VER_FLAG
|
||||
${DARWIN_ios_MIN_VER_FLAG}=${DARWIN_ios_BUILTIN_MIN_VER})
|
||||
endif()
|
||||
if(COMPILER_RT_ENABLE_WATCHOS)
|
||||
list(APPEND DARWIN_EMBEDDED_PLATFORMS watchos)
|
||||
set(DARWIN_watchos_MIN_VER_FLAG -mwatchos-version-min)
|
||||
set(DARWIN_watchos_SANITIZER_MIN_VER_FLAG
|
||||
${DARWIN_watchos_MIN_VER_FLAG}=2.0)
|
||||
set(DARWIN_watchos_BUILTIN_MIN_VER 2.0)
|
||||
set(DARWIN_watchos_BUILTIN_MIN_VER_FLAG
|
||||
${DARWIN_watchos_MIN_VER_FLAG}=${DARWIN_watchos_BUILTIN_MIN_VER})
|
||||
endif()
|
||||
if(COMPILER_RT_ENABLE_TVOS)
|
||||
list(APPEND DARWIN_EMBEDDED_PLATFORMS tvos)
|
||||
set(DARWIN_tvos_MIN_VER_FLAG -mtvos-version-min)
|
||||
set(DARWIN_tvos_SANITIZER_MIN_VER_FLAG
|
||||
${DARWIN_tvos_MIN_VER_FLAG}=9.0)
|
||||
set(DARWIN_tvos_BUILTIN_MIN_VER 9.0)
|
||||
set(DARWIN_tvos_BUILTIN_MIN_VER_FLAG
|
||||
${DARWIN_tvos_MIN_VER_FLAG}=${DARWIN_tvos_BUILTIN_MIN_VER})
|
||||
endif()
|
||||
|
||||
# Note: In order to target x86_64h on OS X the minimum deployment target must
|
||||
# be 10.8 or higher.
|
||||
set(SANITIZER_COMMON_SUPPORTED_OS osx)
|
||||
set(BUILTIN_SUPPORTED_OS osx)
|
||||
set(PROFILE_SUPPORTED_OS osx)
|
||||
set(TSAN_SUPPORTED_OS osx)
|
||||
if(NOT SANITIZER_MIN_OSX_VERSION)
|
||||
@ -391,9 +232,6 @@ if(APPLE)
|
||||
set(DARWIN_osx_LINKFLAGS
|
||||
${DARWIN_COMMON_LINKFLAGS}
|
||||
-mmacosx-version-min=${SANITIZER_MIN_OSX_VERSION})
|
||||
set(DARWIN_osx_BUILTIN_MIN_VER 10.5)
|
||||
set(DARWIN_osx_BUILTIN_MIN_VER_FLAG
|
||||
-mmacosx-version-min=${DARWIN_osx_BUILTIN_MIN_VER})
|
||||
|
||||
if(DARWIN_osx_SYSROOT)
|
||||
list(APPEND DARWIN_osx_CFLAGS -isysroot ${DARWIN_osx_SYSROOT})
|
||||
@ -414,46 +252,28 @@ if(APPLE)
|
||||
set(CAN_TARGET_${arch} 1)
|
||||
endforeach()
|
||||
|
||||
# Need to build a 10.4 compatible libclang_rt
|
||||
set(DARWIN_10.4_SYSROOT ${DARWIN_osx_SYSROOT})
|
||||
set(DARWIN_10.4_BUILTIN_MIN_VER 10.4)
|
||||
set(DARWIN_10.4_BUILTIN_MIN_VER_FLAG
|
||||
-mmacosx-version-min=${DARWIN_10.4_BUILTIN_MIN_VER})
|
||||
set(DARWIN_10.4_SKIP_CC_KEXT On)
|
||||
darwin_test_archs(10.4
|
||||
DARWIN_10.4_ARCHS
|
||||
${toolchain_arches})
|
||||
message(STATUS "OSX 10.4 supported arches: ${DARWIN_10.4_ARCHS}")
|
||||
if(DARWIN_10.4_ARCHS)
|
||||
# don't include the Haswell slice in the 10.4 compatibility library
|
||||
list(REMOVE_ITEM DARWIN_10.4_ARCHS x86_64h)
|
||||
list(APPEND BUILTIN_SUPPORTED_OS 10.4)
|
||||
endif()
|
||||
|
||||
foreach(platform ${DARWIN_EMBEDDED_PLATFORMS})
|
||||
if(DARWIN_${platform}sim_SYSROOT)
|
||||
set(DARWIN_${platform}sim_CFLAGS
|
||||
${DARWIN_COMMON_CFLAGS}
|
||||
${DARWIN_${platform}_SANITIZER_MIN_VER_FLAG}
|
||||
-isysroot ${DARWIN_iossim_SYSROOT})
|
||||
-isysroot ${DARWIN_${platform}sim_SYSROOT})
|
||||
set(DARWIN_${platform}sim_LINKFLAGS
|
||||
${DARWIN_COMMON_LINKFLAGS}
|
||||
${DARWIN_${platform}_SANITIZER_MIN_VER_FLAG}
|
||||
-isysroot ${DARWIN_${platform}sim_SYSROOT})
|
||||
set(DARWIN_${platform}sim_BUILTIN_MIN_VER
|
||||
${DARWIN_${platform}_BUILTIN_MIN_VER})
|
||||
set(DARWIN_${platform}sim_BUILTIN_MIN_VER_FLAG
|
||||
${DARWIN_${platform}_BUILTIN_MIN_VER_FLAG})
|
||||
|
||||
set(DARWIN_${platform}sim_SKIP_CC_KEXT On)
|
||||
darwin_test_archs(${platform}sim
|
||||
DARWIN_${platform}sim_ARCHS
|
||||
${toolchain_arches})
|
||||
message(STATUS "${platform} Simulator supported arches: ${DARWIN_${platform}sim_ARCHS}")
|
||||
if(DARWIN_iossim_ARCHS)
|
||||
if(DARWIN_${platform}_ARCHS)
|
||||
list(APPEND SANITIZER_COMMON_SUPPORTED_OS ${platform}sim)
|
||||
list(APPEND BUILTIN_SUPPORTED_OS ${platform}sim)
|
||||
list(APPEND PROFILE_SUPPORTED_OS ${platform}sim)
|
||||
if(DARWIN_${platform}_SYSROOT_INTERNAL)
|
||||
list(APPEND TSAN_SUPPORTED_OS ${platform}sim)
|
||||
endif()
|
||||
endif()
|
||||
foreach(arch ${DARWIN_${platform}sim_ARCHS})
|
||||
list(APPEND COMPILER_RT_SUPPORTED_ARCH ${arch})
|
||||
@ -477,7 +297,6 @@ if(APPLE)
|
||||
message(STATUS "${platform} supported arches: ${DARWIN_${platform}_ARCHS}")
|
||||
if(DARWIN_${platform}_ARCHS)
|
||||
list(APPEND SANITIZER_COMMON_SUPPORTED_OS ${platform})
|
||||
list(APPEND BUILTIN_SUPPORTED_OS ${platform})
|
||||
list(APPEND PROFILE_SUPPORTED_OS ${platform})
|
||||
endif()
|
||||
foreach(arch ${DARWIN_${platform}_ARCHS})
|
||||
@ -491,7 +310,6 @@ if(APPLE)
|
||||
# for list_intersect
|
||||
include(CompilerRTUtils)
|
||||
|
||||
list_intersect(BUILTIN_SUPPORTED_ARCH ALL_BUILTIN_SUPPORTED_ARCH toolchain_arches)
|
||||
|
||||
list_intersect(SANITIZER_COMMON_SUPPORTED_ARCH
|
||||
ALL_SANITIZER_COMMON_SUPPORTED_ARCH
|
||||
@ -526,10 +344,14 @@ if(APPLE)
|
||||
list_intersect(CFI_SUPPORTED_ARCH
|
||||
ALL_CFI_SUPPORTED_ARCH
|
||||
SANITIZER_COMMON_SUPPORTED_ARCH)
|
||||
list_intersect(ESAN_SUPPORTED_ARCH
|
||||
ALL_ESAN_SUPPORTED_ARCH
|
||||
SANITIZER_COMMON_SUPPORTED_ARCH)
|
||||
list_intersect(SCUDO_SUPPORTED_ARCH
|
||||
ALL_SCUDO_SUPPORTED_ARCH
|
||||
SANITIZER_COMMON_SUPPORTED_ARCH)
|
||||
else()
|
||||
# Architectures supported by compiler-rt libraries.
|
||||
filter_available_targets(BUILTIN_SUPPORTED_ARCH
|
||||
${ALL_BUILTIN_SUPPORTED_ARCH})
|
||||
filter_available_targets(SANITIZER_COMMON_SUPPORTED_ARCH
|
||||
${ALL_SANITIZER_COMMON_SUPPORTED_ARCH})
|
||||
# LSan and UBSan common files should be available on all architectures
|
||||
@ -548,6 +370,21 @@ else()
|
||||
filter_available_targets(SAFESTACK_SUPPORTED_ARCH
|
||||
${ALL_SAFESTACK_SUPPORTED_ARCH})
|
||||
filter_available_targets(CFI_SUPPORTED_ARCH ${ALL_CFI_SUPPORTED_ARCH})
|
||||
filter_available_targets(ESAN_SUPPORTED_ARCH ${ALL_ESAN_SUPPORTED_ARCH})
|
||||
filter_available_targets(SCUDO_SUPPORTED_ARCH
|
||||
${ALL_SCUDO_SUPPORTED_ARCH})
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
# See if the DIA SDK is available and usable.
|
||||
set(MSVC_DIA_SDK_DIR "$ENV{VSINSTALLDIR}DIA SDK")
|
||||
if (IS_DIRECTORY ${MSVC_DIA_SDK_DIR})
|
||||
set(CAN_SYMBOLIZE 1)
|
||||
else()
|
||||
set(CAN_SYMBOLIZE 0)
|
||||
endif()
|
||||
else()
|
||||
set(CAN_SYMBOLIZE 1)
|
||||
endif()
|
||||
|
||||
message(STATUS "Compiler-RT supported architectures: ${COMPILER_RT_SUPPORTED_ARCH}")
|
||||
@ -566,15 +403,13 @@ else()
|
||||
set(COMPILER_RT_HAS_SANITIZER_COMMON FALSE)
|
||||
endif()
|
||||
|
||||
if (COMPILER_RT_HAS_SANITIZER_COMMON AND
|
||||
(NOT OS_NAME MATCHES "Windows" OR CMAKE_SIZEOF_VOID_P EQUAL 4))
|
||||
if (COMPILER_RT_HAS_SANITIZER_COMMON)
|
||||
set(COMPILER_RT_HAS_INTERCEPTION TRUE)
|
||||
else()
|
||||
set(COMPILER_RT_HAS_INTERCEPTION FALSE)
|
||||
endif()
|
||||
|
||||
if (COMPILER_RT_HAS_SANITIZER_COMMON AND ASAN_SUPPORTED_ARCH AND
|
||||
(NOT OS_NAME MATCHES "Windows" OR CMAKE_SIZEOF_VOID_P EQUAL 4))
|
||||
if (COMPILER_RT_HAS_SANITIZER_COMMON AND ASAN_SUPPORTED_ARCH)
|
||||
set(COMPILER_RT_HAS_ASAN TRUE)
|
||||
else()
|
||||
set(COMPILER_RT_HAS_ASAN FALSE)
|
||||
@ -643,3 +478,18 @@ if (COMPILER_RT_HAS_SANITIZER_COMMON AND CFI_SUPPORTED_ARCH AND
|
||||
else()
|
||||
set(COMPILER_RT_HAS_CFI FALSE)
|
||||
endif()
|
||||
|
||||
if (COMPILER_RT_HAS_SANITIZER_COMMON AND ESAN_SUPPORTED_ARCH AND
|
||||
OS_NAME MATCHES "Linux")
|
||||
set(COMPILER_RT_HAS_ESAN TRUE)
|
||||
else()
|
||||
set(COMPILER_RT_HAS_ESAN FALSE)
|
||||
endif()
|
||||
|
||||
if (COMPILER_RT_HAS_SANITIZER_COMMON AND SCUDO_SUPPORTED_ARCH AND
|
||||
OS_NAME MATCHES "Linux")
|
||||
set(COMPILER_RT_HAS_SCUDO TRUE)
|
||||
else()
|
||||
set(COMPILER_RT_HAS_SCUDO FALSE)
|
||||
endif()
|
||||
|
||||
|
@ -4,6 +4,7 @@ set(SANITIZER_HEADERS
|
||||
sanitizer/common_interface_defs.h
|
||||
sanitizer/coverage_interface.h
|
||||
sanitizer/dfsan_interface.h
|
||||
sanitizer/esan_interface.h
|
||||
sanitizer/linux_syscall_hooks.h
|
||||
sanitizer/lsan_interface.h
|
||||
sanitizer/msan_interface.h
|
||||
@ -25,6 +26,7 @@ endforeach( f )
|
||||
|
||||
add_custom_target(compiler-rt-headers ALL DEPENDS ${out_files})
|
||||
add_dependencies(compiler-rt compiler-rt-headers)
|
||||
set_target_properties(compiler-rt-headers PROPERTIES FOLDER "Compiler-RT Misc")
|
||||
|
||||
# Install sanitizer headers.
|
||||
install(FILES ${SANITIZER_HEADERS}
|
||||
|
@ -59,6 +59,23 @@ extern "C" {
|
||||
deallocation of "ptr". */
|
||||
void __sanitizer_malloc_hook(const volatile void *ptr, size_t size);
|
||||
void __sanitizer_free_hook(const volatile void *ptr);
|
||||
|
||||
/* Installs a pair of hooks for malloc/free.
|
||||
Several (currently, 5) hook pairs may be installed, they are executed
|
||||
in the order they were installed and after calling
|
||||
__sanitizer_malloc_hook/__sanitizer_free_hook.
|
||||
Unlike __sanitizer_malloc_hook/__sanitizer_free_hook these hooks can be
|
||||
chained and do not rely on weak symbols working on the platform, but
|
||||
require __sanitizer_install_malloc_and_free_hooks to be called at startup
|
||||
and thus will not be called on malloc/free very early in the process.
|
||||
Returns the number of hooks currently installed or 0 on failure.
|
||||
Not thread-safe, should be called in the main thread before starting
|
||||
other threads.
|
||||
*/
|
||||
int __sanitizer_install_malloc_and_free_hooks(
|
||||
void (*malloc_hook)(const volatile void *, size_t),
|
||||
void (*free_hook)(const volatile void *));
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
@ -41,6 +41,9 @@ extern "C" {
|
||||
|
||||
// Tell the tools to write their reports to "path.<pid>" instead of stderr.
|
||||
void __sanitizer_set_report_path(const char *path);
|
||||
// Tell the tools to write their reports to the provided file descriptor
|
||||
// (casted to void *).
|
||||
void __sanitizer_set_report_fd(void *fd);
|
||||
|
||||
// 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
|
||||
@ -128,8 +131,45 @@ extern "C" {
|
||||
const void *s2, size_t n, int result);
|
||||
void __sanitizer_weak_hook_strncmp(void *called_pc, const char *s1,
|
||||
const char *s2, size_t n, int result);
|
||||
void __sanitizer_weak_hook_strncasecmp(void *called_pc, const char *s1,
|
||||
const char *s2, size_t n, int result);
|
||||
void __sanitizer_weak_hook_strcmp(void *called_pc, const char *s1,
|
||||
const char *s2, int result);
|
||||
void __sanitizer_weak_hook_strcasecmp(void *called_pc, const char *s1,
|
||||
const char *s2, int result);
|
||||
void __sanitizer_weak_hook_strstr(void *called_pc, const char *s1,
|
||||
const char *s2, char *result);
|
||||
void __sanitizer_weak_hook_strcasestr(void *called_pc, const char *s1,
|
||||
const char *s2, char *result);
|
||||
void __sanitizer_weak_hook_memmem(void *called_pc,
|
||||
const void *s1, size_t len1,
|
||||
const void *s2, size_t len2, void *result);
|
||||
|
||||
// Prints stack traces for all live heap allocations ordered by total
|
||||
// allocation size until `top_percent` of total live heap is shown.
|
||||
// `top_percent` should be between 1 and 100.
|
||||
// Experimental feature currently available only with asan on Linux/x86_64.
|
||||
void __sanitizer_print_memory_profile(size_t top_percent);
|
||||
|
||||
// Fiber annotation interface.
|
||||
// Before switching to a different stack, one must call
|
||||
// __sanitizer_start_switch_fiber with a pointer to the bottom of the
|
||||
// destination stack and its size. When code starts running on the new stack,
|
||||
// it must call __sanitizer_finish_switch_fiber to finalize the switch.
|
||||
// The start_switch function takes a void** to store the current fake stack if
|
||||
// there is one (it is needed when detect_stack_use_after_return is enabled).
|
||||
// When restoring a stack, this pointer must be given to the finish_switch
|
||||
// function. In most cases, this void* can be stored on the stack just before
|
||||
// switching. When leaving a fiber definitely, null must be passed as first
|
||||
// argument to the start_switch function so that the fake stack is destroyed.
|
||||
// If you do not want support for stack use-after-return detection, you can
|
||||
// always pass null to these two functions.
|
||||
// Note that the fake stack mechanism is disabled during fiber switch, so if a
|
||||
// signal callback runs during the switch, it will not benefit from the stack
|
||||
// use-after-return detection.
|
||||
void __sanitizer_start_switch_fiber(void **fake_stack_save,
|
||||
const void *bottom, size_t size);
|
||||
void __sanitizer_finish_switch_fiber(void *fake_stack_save);
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
50
include/sanitizer/esan_interface.h
Normal file
50
include/sanitizer/esan_interface.h
Normal file
@ -0,0 +1,50 @@
|
||||
//===-- sanitizer/esan_interface.h ------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of EfficiencySanitizer, a family of performance tuners.
|
||||
//
|
||||
// Public interface header.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef SANITIZER_ESAN_INTERFACE_H
|
||||
#define SANITIZER_ESAN_INTERFACE_H
|
||||
|
||||
#include <sanitizer/common_interface_defs.h>
|
||||
|
||||
// We declare our interface routines as weak to allow the user to avoid
|
||||
// ifdefs and instead use this pattern to allow building the same sources
|
||||
// with and without our runtime library:
|
||||
// if (__esan_report)
|
||||
// __esan_report();
|
||||
#ifdef _MSC_VER
|
||||
/* selectany is as close to weak as we'll get. */
|
||||
#define COMPILER_RT_WEAK __declspec(selectany)
|
||||
#elif __GNUC__
|
||||
#define COMPILER_RT_WEAK __attribute__((weak))
|
||||
#else
|
||||
#define COMPILER_RT_WEAK
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// This function can be called mid-run (or at the end of a run for
|
||||
// a server process that doesn't shut down normally) to request that
|
||||
// data for that point in the run be reported from the tool.
|
||||
void COMPILER_RT_WEAK __esan_report();
|
||||
|
||||
// This function returns the number of samples that the esan tool has collected
|
||||
// to this point. This is useful for testing.
|
||||
unsigned int COMPILER_RT_WEAK __esan_get_sample_count();
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // SANITIZER_ESAN_INTERFACE_H
|
@ -1835,6 +1835,17 @@
|
||||
__sanitizer_syscall_pre_impl_vfork()
|
||||
#define __sanitizer_syscall_post_vfork(res) \
|
||||
__sanitizer_syscall_post_impl_vfork(res)
|
||||
#define __sanitizer_syscall_pre_sigaction(signum, act, oldact) \
|
||||
__sanitizer_syscall_pre_impl_sigaction((long)signum, (long)act, (long)oldact)
|
||||
#define __sanitizer_syscall_post_sigaction(res, signum, act, oldact) \
|
||||
__sanitizer_syscall_post_impl_sigaction(res, (long)signum, (long)act, \
|
||||
(long)oldact)
|
||||
#define __sanitizer_syscall_pre_rt_sigaction(signum, act, oldact, sz) \
|
||||
__sanitizer_syscall_pre_impl_rt_sigaction((long)signum, (long)act, \
|
||||
(long)oldact, (long)sz)
|
||||
#define __sanitizer_syscall_post_rt_sigaction(res, signum, act, oldact, sz) \
|
||||
__sanitizer_syscall_post_impl_rt_sigaction(res, (long)signum, (long)act, \
|
||||
(long)oldact, (long)sz)
|
||||
|
||||
// And now a few syscalls we don't handle yet.
|
||||
#define __sanitizer_syscall_pre_afs_syscall(...)
|
||||
@ -1889,7 +1900,6 @@
|
||||
#define __sanitizer_syscall_pre_query_module(...)
|
||||
#define __sanitizer_syscall_pre_readahead(...)
|
||||
#define __sanitizer_syscall_pre_readdir(...)
|
||||
#define __sanitizer_syscall_pre_rt_sigaction(...)
|
||||
#define __sanitizer_syscall_pre_rt_sigreturn(...)
|
||||
#define __sanitizer_syscall_pre_rt_sigsuspend(...)
|
||||
#define __sanitizer_syscall_pre_security(...)
|
||||
@ -1903,7 +1913,6 @@
|
||||
#define __sanitizer_syscall_pre_setreuid32(...)
|
||||
#define __sanitizer_syscall_pre_set_thread_area(...)
|
||||
#define __sanitizer_syscall_pre_setuid32(...)
|
||||
#define __sanitizer_syscall_pre_sigaction(...)
|
||||
#define __sanitizer_syscall_pre_sigaltstack(...)
|
||||
#define __sanitizer_syscall_pre_sigreturn(...)
|
||||
#define __sanitizer_syscall_pre_sigsuspend(...)
|
||||
@ -1971,7 +1980,6 @@
|
||||
#define __sanitizer_syscall_post_query_module(res, ...)
|
||||
#define __sanitizer_syscall_post_readahead(res, ...)
|
||||
#define __sanitizer_syscall_post_readdir(res, ...)
|
||||
#define __sanitizer_syscall_post_rt_sigaction(res, ...)
|
||||
#define __sanitizer_syscall_post_rt_sigreturn(res, ...)
|
||||
#define __sanitizer_syscall_post_rt_sigsuspend(res, ...)
|
||||
#define __sanitizer_syscall_post_security(res, ...)
|
||||
@ -1985,7 +1993,6 @@
|
||||
#define __sanitizer_syscall_post_setreuid32(res, ...)
|
||||
#define __sanitizer_syscall_post_set_thread_area(res, ...)
|
||||
#define __sanitizer_syscall_post_setuid32(res, ...)
|
||||
#define __sanitizer_syscall_post_sigaction(res, ...)
|
||||
#define __sanitizer_syscall_post_sigaltstack(res, ...)
|
||||
#define __sanitizer_syscall_post_sigreturn(res, ...)
|
||||
#define __sanitizer_syscall_post_sigsuspend(res, ...)
|
||||
@ -3062,7 +3069,13 @@ void __sanitizer_syscall_pre_impl_fork();
|
||||
void __sanitizer_syscall_post_impl_fork(long res);
|
||||
void __sanitizer_syscall_pre_impl_vfork();
|
||||
void __sanitizer_syscall_post_impl_vfork(long res);
|
||||
|
||||
void __sanitizer_syscall_pre_impl_sigaction(long signum, long act, long oldact);
|
||||
void __sanitizer_syscall_post_impl_sigaction(long res, long signum, long act,
|
||||
long oldact);
|
||||
void __sanitizer_syscall_pre_impl_rt_sigaction(long signum, long act,
|
||||
long oldact, long sz);
|
||||
void __sanitizer_syscall_post_impl_rt_sigaction(long res, long signum, long act,
|
||||
long oldact, long sz);
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
@ -15,6 +15,7 @@ if(COMPILER_RT_BUILD_SANITIZERS)
|
||||
|
||||
if(COMPILER_RT_HAS_SANITIZER_COMMON)
|
||||
add_subdirectory(sanitizer_common)
|
||||
add_subdirectory(stats)
|
||||
add_subdirectory(lsan)
|
||||
add_subdirectory(ubsan)
|
||||
endif()
|
||||
@ -47,4 +48,12 @@ if(COMPILER_RT_BUILD_SANITIZERS)
|
||||
if(COMPILER_RT_HAS_CFI)
|
||||
add_subdirectory(cfi)
|
||||
endif()
|
||||
|
||||
if(COMPILER_RT_HAS_ESAN)
|
||||
add_subdirectory(esan)
|
||||
endif()
|
||||
|
||||
if(COMPILER_RT_HAS_SCUDO)
|
||||
add_subdirectory(scudo)
|
||||
endif()
|
||||
endif()
|
||||
|
@ -10,10 +10,4 @@
|
||||
SubDirs :=
|
||||
|
||||
# Add submodules.
|
||||
SubDirs += asan
|
||||
SubDirs += builtins
|
||||
SubDirs += interception
|
||||
SubDirs += lsan
|
||||
SubDirs += profile
|
||||
SubDirs += sanitizer_common
|
||||
SubDirs += ubsan
|
||||
|
@ -13,6 +13,7 @@ set(ASAN_SOURCES
|
||||
asan_malloc_linux.cc
|
||||
asan_malloc_mac.cc
|
||||
asan_malloc_win.cc
|
||||
asan_memory_profile.cc
|
||||
asan_poisoning.cc
|
||||
asan_posix.cc
|
||||
asan_report.cc
|
||||
@ -32,7 +33,7 @@ set(ASAN_PREINIT_SOURCES
|
||||
include_directories(..)
|
||||
|
||||
set(ASAN_CFLAGS ${SANITIZER_COMMON_CFLAGS})
|
||||
append_no_rtti_flag(ASAN_CFLAGS)
|
||||
append_rtti_flag(OFF ASAN_CFLAGS)
|
||||
|
||||
set(ASAN_COMMON_DEFINITIONS
|
||||
ASAN_HAS_EXCEPTIONS=1)
|
||||
@ -62,7 +63,7 @@ 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(MSVC /DEBUG ASAN_DYNAMIC_LINK_FLAGS)
|
||||
|
||||
append_list_if(COMPILER_RT_HAS_LIBC c ASAN_DYNAMIC_LIBS)
|
||||
append_list_if(COMPILER_RT_HAS_LIBDL dl ASAN_DYNAMIC_LIBS)
|
||||
@ -74,7 +75,7 @@ append_list_if(COMPILER_RT_HAS_LIBLOG log ASAN_DYNAMIC_LIBS)
|
||||
|
||||
# Compile ASan sources into an object library.
|
||||
|
||||
add_compiler_rt_object_libraries(RTAsan_dynamic
|
||||
add_compiler_rt_object_libraries(RTAsan_dynamic
|
||||
OS ${SANITIZER_COMMON_SUPPORTED_OS}
|
||||
ARCHS ${ASAN_SUPPORTED_ARCH}
|
||||
SOURCES ${ASAN_SOURCES} ${ASAN_CXX_SOURCES}
|
||||
@ -82,15 +83,15 @@ add_compiler_rt_object_libraries(RTAsan_dynamic
|
||||
DEFS ${ASAN_DYNAMIC_DEFINITIONS})
|
||||
|
||||
if(NOT APPLE)
|
||||
add_compiler_rt_object_libraries(RTAsan
|
||||
add_compiler_rt_object_libraries(RTAsan
|
||||
ARCHS ${ASAN_SUPPORTED_ARCH}
|
||||
SOURCES ${ASAN_SOURCES} CFLAGS ${ASAN_CFLAGS}
|
||||
DEFS ${ASAN_COMMON_DEFINITIONS})
|
||||
add_compiler_rt_object_libraries(RTAsan_cxx
|
||||
add_compiler_rt_object_libraries(RTAsan_cxx
|
||||
ARCHS ${ASAN_SUPPORTED_ARCH}
|
||||
SOURCES ${ASAN_CXX_SOURCES} CFLAGS ${ASAN_CFLAGS}
|
||||
DEFS ${ASAN_COMMON_DEFINITIONS})
|
||||
add_compiler_rt_object_libraries(RTAsan_preinit
|
||||
add_compiler_rt_object_libraries(RTAsan_preinit
|
||||
ARCHS ${ASAN_SUPPORTED_ARCH}
|
||||
SOURCES ${ASAN_PREINIT_SOURCES} CFLAGS ${ASAN_CFLAGS}
|
||||
DEFS ${ASAN_COMMON_DEFINITIONS})
|
||||
@ -105,6 +106,8 @@ endif()
|
||||
|
||||
# Build ASan runtimes shipped with Clang.
|
||||
add_custom_target(asan)
|
||||
set_target_properties(asan PROPERTIES FOLDER "Compiler-RT Misc")
|
||||
|
||||
if(APPLE)
|
||||
add_compiler_rt_runtime(clang_rt.asan
|
||||
SHARED
|
||||
@ -121,40 +124,40 @@ if(APPLE)
|
||||
PARENT_TARGET asan)
|
||||
else()
|
||||
# Build separate libraries for each target.
|
||||
|
||||
set(ASAN_COMMON_RUNTIME_OBJECT_LIBS
|
||||
RTInterception
|
||||
RTSanitizerCommon
|
||||
RTSanitizerCommonLibc
|
||||
RTLSanCommon
|
||||
RTUbsan)
|
||||
|
||||
add_compiler_rt_runtime(clang_rt.asan
|
||||
STATIC
|
||||
ARCHS ${ASAN_SUPPORTED_ARCH}
|
||||
OBJECT_LIBS RTAsan_preinit
|
||||
RTAsan
|
||||
${ASAN_COMMON_RUNTIME_OBJECT_LIBS}
|
||||
CFLAGS ${ASAN_CFLAGS}
|
||||
DEFS ${ASAN_COMMON_DEFINITIONS}
|
||||
PARENT_TARGET asan)
|
||||
set(ASAN_COMMON_RUNTIME_OBJECT_LIBS
|
||||
RTInterception
|
||||
RTSanitizerCommon
|
||||
RTSanitizerCommonLibc
|
||||
RTLSanCommon
|
||||
RTUbsan)
|
||||
|
||||
add_compiler_rt_runtime(clang_rt.asan_cxx
|
||||
STATIC
|
||||
ARCHS ${ASAN_SUPPORTED_ARCH}
|
||||
OBJECT_LIBS RTAsan_cxx
|
||||
RTUbsan_cxx
|
||||
CFLAGS ${ASAN_CFLAGS}
|
||||
DEFS ${ASAN_COMMON_DEFINITIONS}
|
||||
PARENT_TARGET asan)
|
||||
add_compiler_rt_runtime(clang_rt.asan
|
||||
STATIC
|
||||
ARCHS ${ASAN_SUPPORTED_ARCH}
|
||||
OBJECT_LIBS RTAsan_preinit
|
||||
RTAsan
|
||||
${ASAN_COMMON_RUNTIME_OBJECT_LIBS}
|
||||
CFLAGS ${ASAN_CFLAGS}
|
||||
DEFS ${ASAN_COMMON_DEFINITIONS}
|
||||
PARENT_TARGET asan)
|
||||
|
||||
add_compiler_rt_runtime(clang_rt.asan-preinit
|
||||
STATIC
|
||||
ARCHS ${ASAN_SUPPORTED_ARCH}
|
||||
OBJECT_LIBS RTAsan_preinit
|
||||
CFLAGS ${ASAN_CFLAGS}
|
||||
DEFS ${ASAN_COMMON_DEFINITIONS}
|
||||
PARENT_TARGET asan)
|
||||
add_compiler_rt_runtime(clang_rt.asan_cxx
|
||||
STATIC
|
||||
ARCHS ${ASAN_SUPPORTED_ARCH}
|
||||
OBJECT_LIBS RTAsan_cxx
|
||||
RTUbsan_cxx
|
||||
CFLAGS ${ASAN_CFLAGS}
|
||||
DEFS ${ASAN_COMMON_DEFINITIONS}
|
||||
PARENT_TARGET asan)
|
||||
|
||||
add_compiler_rt_runtime(clang_rt.asan-preinit
|
||||
STATIC
|
||||
ARCHS ${ASAN_SUPPORTED_ARCH}
|
||||
OBJECT_LIBS RTAsan_preinit
|
||||
CFLAGS ${ASAN_CFLAGS}
|
||||
DEFS ${ASAN_COMMON_DEFINITIONS}
|
||||
PARENT_TARGET asan)
|
||||
|
||||
foreach(arch ${ASAN_SUPPORTED_ARCH})
|
||||
if (UNIX AND NOT ${arch} MATCHES "i386|i686")
|
||||
@ -165,8 +168,8 @@ else()
|
||||
-Wl,--version-script,${CMAKE_CURRENT_BINARY_DIR}/clang_rt.asan-dynamic-${arch}.vers)
|
||||
set_source_files_properties(
|
||||
${CMAKE_CURRENT_BINARY_DIR}/dummy.cc
|
||||
PROPERTIES
|
||||
OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/clang_rt.asan-dynamic-${arch}.vers)
|
||||
PROPERTIES
|
||||
OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/clang_rt.asan-dynamic-${arch}.vers)
|
||||
else()
|
||||
set(VERSION_SCRIPT_FLAG)
|
||||
endif()
|
||||
@ -194,7 +197,7 @@ else()
|
||||
ARCHS ${arch})
|
||||
add_dependencies(asan clang_rt.asan_cxx-${arch}-symbols)
|
||||
add_sanitizer_rt_symbols(clang_rt.asan
|
||||
ARCHS ${arch}
|
||||
ARCHS ${arch}
|
||||
EXTRA asan.syms.extra)
|
||||
add_dependencies(asan clang_rt.asan-${arch}-symbols)
|
||||
endif()
|
||||
@ -219,8 +222,7 @@ else()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
add_compiler_rt_resource_file(asan_blacklist asan_blacklist.txt)
|
||||
add_dependencies(asan asan_blacklist)
|
||||
add_compiler_rt_resource_file(asan_blacklist asan_blacklist.txt asan)
|
||||
add_dependencies(compiler-rt asan)
|
||||
|
||||
add_subdirectory(scripts)
|
||||
|
@ -1,29 +0,0 @@
|
||||
#===- lib/asan/Makefile.mk ---------------------------------*- Makefile -*--===#
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
#===------------------------------------------------------------------------===#
|
||||
|
||||
ModuleName := asan
|
||||
SubDirs :=
|
||||
|
||||
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
|
||||
|
||||
# FIXME: use automatic dependencies?
|
||||
Dependencies := $(wildcard $(Dir)/*.h)
|
||||
Dependencies += $(wildcard $(Dir)/../interception/*.h)
|
||||
Dependencies += $(wildcard $(Dir)/../sanitizer_common/*.h)
|
||||
|
||||
# Define a convenience variable for all the asan functions.
|
||||
AsanFunctions := $(COnlySources:%.cc=%) $(SSources:%.S=%)
|
||||
AsanCXXFunctions := $(CXXOnlySources:%.cc=%)
|
@ -47,6 +47,7 @@ static struct AsanDeactivatedFlags {
|
||||
FlagParser parser;
|
||||
RegisterActivationFlags(&parser, &f, &cf);
|
||||
|
||||
cf.SetDefaults();
|
||||
// Copy the current activation flags.
|
||||
allocator_options.CopyTo(&f, &cf);
|
||||
cf.malloc_context_size = malloc_context_size;
|
||||
@ -61,7 +62,7 @@ static struct AsanDeactivatedFlags {
|
||||
parser.ParseString(env);
|
||||
}
|
||||
|
||||
SetVerbosity(cf.verbosity);
|
||||
InitializeCommonFlags(&cf);
|
||||
|
||||
if (Verbosity()) ReportUnrecognizedFlags();
|
||||
|
||||
|
@ -223,7 +223,7 @@ void AllocatorOptions::CopyTo(Flags *f, CommonFlags *cf) {
|
||||
|
||||
struct Allocator {
|
||||
static const uptr kMaxAllowedMallocSize =
|
||||
FIRST_32_SECOND_64(3UL << 30, 1UL << 40);
|
||||
FIRST_32_SECOND_64(3UL << 30, 1ULL << 40);
|
||||
static const uptr kMaxThreadLocalQuarantine =
|
||||
FIRST_32_SECOND_64(1 << 18, 1 << 20);
|
||||
|
||||
@ -457,29 +457,28 @@ struct Allocator {
|
||||
return res;
|
||||
}
|
||||
|
||||
void AtomicallySetQuarantineFlag(AsanChunk *m, void *ptr,
|
||||
// Set quarantine flag if chunk is allocated, issue ASan error report on
|
||||
// available and quarantined chunks. Return true on success, false otherwise.
|
||||
bool AtomicallySetQuarantineFlagIfAllocated(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,
|
||||
CHUNK_QUARANTINE, memory_order_acquire))
|
||||
if (!atomic_compare_exchange_strong((atomic_uint8_t *)m, &old_chunk_state,
|
||||
CHUNK_QUARANTINE,
|
||||
memory_order_acquire)) {
|
||||
ReportInvalidFree(ptr, old_chunk_state, stack);
|
||||
// It's not safe to push a chunk in quarantine on invalid free.
|
||||
return false;
|
||||
}
|
||||
CHECK_EQ(CHUNK_ALLOCATED, old_chunk_state);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Expects the chunk to already be marked as quarantined by using
|
||||
// AtomicallySetQuarantineFlag.
|
||||
// AtomicallySetQuarantineFlagIfAllocated.
|
||||
void QuarantineChunk(AsanChunk *m, void *ptr, BufferedStackTrace *stack,
|
||||
AllocType alloc_type) {
|
||||
CHECK_EQ(m->chunk_state, CHUNK_QUARANTINE);
|
||||
|
||||
if (m->alloc_type != alloc_type) {
|
||||
if (atomic_load(&alloc_dealloc_mismatch, memory_order_acquire)) {
|
||||
ReportAllocTypeMismatch((uptr)ptr, stack, (AllocType)m->alloc_type,
|
||||
(AllocType)alloc_type);
|
||||
}
|
||||
}
|
||||
|
||||
CHECK_GE(m->alloc_tid, 0);
|
||||
if (SANITIZER_WORDSIZE == 64) // On 32-bits this resides in user area.
|
||||
CHECK_EQ(m->free_tid, kInvalidTid);
|
||||
@ -516,13 +515,24 @@ struct Allocator {
|
||||
|
||||
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);
|
||||
// Do not quarantine given chunk if we failed to set CHUNK_QUARANTINE flag.
|
||||
if (!AtomicallySetQuarantineFlagIfAllocated(m, ptr, stack)) return;
|
||||
|
||||
if (m->alloc_type != alloc_type) {
|
||||
if (atomic_load(&alloc_dealloc_mismatch, memory_order_acquire)) {
|
||||
ReportAllocTypeMismatch((uptr)ptr, stack, (AllocType)m->alloc_type,
|
||||
(AllocType)alloc_type);
|
||||
}
|
||||
}
|
||||
|
||||
if (delete_size && flags()->new_delete_type_mismatch &&
|
||||
delete_size != m->UsedSize()) {
|
||||
ReportNewDeleteSizeMismatch(p, m->UsedSize(), delete_size, stack);
|
||||
}
|
||||
|
||||
QuarantineChunk(m, ptr, stack, alloc_type);
|
||||
}
|
||||
|
||||
@ -655,6 +665,9 @@ static AsanAllocator &get_allocator() {
|
||||
bool AsanChunkView::IsValid() {
|
||||
return chunk_ && chunk_->chunk_state != CHUNK_AVAILABLE;
|
||||
}
|
||||
bool AsanChunkView::IsAllocated() {
|
||||
return chunk_ && chunk_->chunk_state == CHUNK_ALLOCATED;
|
||||
}
|
||||
uptr AsanChunkView::Beg() { return chunk_->Beg(); }
|
||||
uptr AsanChunkView::End() { return Beg() + UsedSize(); }
|
||||
uptr AsanChunkView::UsedSize() { return chunk_->UsedSize(); }
|
||||
@ -668,12 +681,15 @@ static StackTrace GetStackTraceFromId(u32 id) {
|
||||
return res;
|
||||
}
|
||||
|
||||
u32 AsanChunkView::GetAllocStackId() { return chunk_->alloc_context_id; }
|
||||
u32 AsanChunkView::GetFreeStackId() { return chunk_->free_context_id; }
|
||||
|
||||
StackTrace AsanChunkView::GetAllocStack() {
|
||||
return GetStackTraceFromId(chunk_->alloc_context_id);
|
||||
return GetStackTraceFromId(GetAllocStackId());
|
||||
}
|
||||
|
||||
StackTrace AsanChunkView::GetFreeStack() {
|
||||
return GetStackTraceFromId(chunk_->free_context_id);
|
||||
return GetStackTraceFromId(GetFreeStackId());
|
||||
}
|
||||
|
||||
void InitializeAllocator(const AllocatorOptions &options) {
|
||||
@ -754,7 +770,7 @@ int asan_posix_memalign(void **memptr, uptr alignment, uptr size,
|
||||
return 0;
|
||||
}
|
||||
|
||||
uptr asan_malloc_usable_size(void *ptr, uptr pc, uptr bp) {
|
||||
uptr asan_malloc_usable_size(const void *ptr, uptr pc, uptr bp) {
|
||||
if (!ptr) return 0;
|
||||
uptr usable_size = instance.AllocationSize(reinterpret_cast<uptr>(ptr));
|
||||
if (flags()->check_malloc_usable_size && (usable_size == 0)) {
|
||||
|
@ -49,14 +49,17 @@ void GetAllocatorOptions(AllocatorOptions *options);
|
||||
class AsanChunkView {
|
||||
public:
|
||||
explicit AsanChunkView(AsanChunk *chunk) : chunk_(chunk) {}
|
||||
bool IsValid(); // Checks if AsanChunkView points to a valid allocated
|
||||
// or quarantined chunk.
|
||||
uptr Beg(); // First byte of user memory.
|
||||
uptr End(); // Last byte of user memory.
|
||||
uptr UsedSize(); // Size requested by the user.
|
||||
bool IsValid(); // Checks if AsanChunkView points to a valid allocated
|
||||
// or quarantined chunk.
|
||||
bool IsAllocated(); // Checks if the memory is currently allocated.
|
||||
uptr Beg(); // First byte of user memory.
|
||||
uptr End(); // Last byte of user memory.
|
||||
uptr UsedSize(); // Size requested by the user.
|
||||
uptr AllocTid();
|
||||
uptr FreeTid();
|
||||
bool Eq(const AsanChunkView &c) const { return chunk_ == c.chunk_; }
|
||||
u32 GetAllocStackId();
|
||||
u32 GetFreeStackId();
|
||||
StackTrace GetAllocStack();
|
||||
StackTrace GetFreeStack();
|
||||
bool AddrIsInside(uptr addr, uptr access_size, sptr *offset) {
|
||||
@ -171,7 +174,7 @@ void *asan_pvalloc(uptr size, BufferedStackTrace *stack);
|
||||
|
||||
int asan_posix_memalign(void **memptr, uptr alignment, uptr size,
|
||||
BufferedStackTrace *stack);
|
||||
uptr asan_malloc_usable_size(void *ptr, uptr pc, uptr bp);
|
||||
uptr asan_malloc_usable_size(const void *ptr, uptr pc, uptr bp);
|
||||
|
||||
uptr asan_mz_size(const void *ptr);
|
||||
void asan_mz_force_lock();
|
||||
|
@ -31,7 +31,7 @@ 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 < (((uptr)1) << class_id); i++) {
|
||||
shadow[i] = magic;
|
||||
// Make sure this does not become memset.
|
||||
SanitizerBreakOptimization(nullptr);
|
||||
@ -121,7 +121,7 @@ uptr FakeStack::AddrIsInFakeStack(uptr ptr, uptr *frame_beg, uptr *frame_end) {
|
||||
uptr class_id = (ptr - beg) >> stack_size_log;
|
||||
uptr base = beg + (class_id << stack_size_log);
|
||||
CHECK_LE(base, ptr);
|
||||
CHECK_LT(ptr, base + (1UL << stack_size_log));
|
||||
CHECK_LT(ptr, base + (((uptr)1) << stack_size_log));
|
||||
uptr pos = (ptr - base) >> (kMinStackFrameSizeLog + class_id);
|
||||
uptr res = base + pos * BytesInSizeClass(class_id);
|
||||
*frame_end = res + BytesInSizeClass(class_id);
|
||||
|
@ -69,12 +69,12 @@ class FakeStack {
|
||||
|
||||
// stack_size_log is at least 15 (stack_size >= 32K).
|
||||
static uptr SizeRequiredForFlags(uptr stack_size_log) {
|
||||
return 1UL << (stack_size_log + 1 - kMinStackFrameSizeLog);
|
||||
return ((uptr)1) << (stack_size_log + 1 - kMinStackFrameSizeLog);
|
||||
}
|
||||
|
||||
// Each size class occupies stack_size bytes.
|
||||
static uptr SizeRequiredForFrames(uptr stack_size_log) {
|
||||
return (1ULL << stack_size_log) * kNumberOfSizeClasses;
|
||||
return (((uptr)1) << stack_size_log) * kNumberOfSizeClasses;
|
||||
}
|
||||
|
||||
// Number of bytes requires for the whole object.
|
||||
@ -91,12 +91,12 @@ class FakeStack {
|
||||
// and so on.
|
||||
static uptr FlagsOffset(uptr stack_size_log, uptr class_id) {
|
||||
uptr t = kNumberOfSizeClasses - 1 - class_id;
|
||||
const uptr all_ones = (1 << (kNumberOfSizeClasses - 1)) - 1;
|
||||
const uptr all_ones = (((uptr)1) << (kNumberOfSizeClasses - 1)) - 1;
|
||||
return ((all_ones >> t) << t) << (stack_size_log - 15);
|
||||
}
|
||||
|
||||
static uptr NumberOfFrames(uptr stack_size_log, uptr class_id) {
|
||||
return 1UL << (stack_size_log - kMinStackFrameSizeLog - class_id);
|
||||
return ((uptr)1) << (stack_size_log - kMinStackFrameSizeLog - class_id);
|
||||
}
|
||||
|
||||
// Divide n by the numbe of frames in size class.
|
||||
@ -114,7 +114,8 @@ class FakeStack {
|
||||
u8 *GetFrame(uptr stack_size_log, uptr class_id, uptr pos) {
|
||||
return reinterpret_cast<u8 *>(this) + kFlagsOffset +
|
||||
SizeRequiredForFlags(stack_size_log) +
|
||||
(1 << stack_size_log) * class_id + BytesInSizeClass(class_id) * pos;
|
||||
(((uptr)1) << stack_size_log) * class_id +
|
||||
BytesInSizeClass(class_id) * pos;
|
||||
}
|
||||
|
||||
// Allocate the fake frame.
|
||||
@ -137,7 +138,7 @@ class FakeStack {
|
||||
|
||||
// Number of bytes in a fake frame of this size class.
|
||||
static uptr BytesInSizeClass(uptr class_id) {
|
||||
return 1UL << (class_id + kMinStackFrameSizeLog);
|
||||
return ((uptr)1) << (class_id + kMinStackFrameSizeLog);
|
||||
}
|
||||
|
||||
// The fake frame is guaranteed to have a right redzone.
|
||||
@ -159,7 +160,7 @@ class FakeStack {
|
||||
static const uptr kFlagsOffset = 4096; // This is were the flags begin.
|
||||
// Must match the number of uses of DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID
|
||||
COMPILER_CHECK(kNumberOfSizeClasses == 11);
|
||||
static const uptr kMaxStackMallocSize = 1 << kMaxStackFrameSizeLog;
|
||||
static const uptr kMaxStackMallocSize = ((uptr)1) << kMaxStackFrameSizeLog;
|
||||
|
||||
uptr hint_position_[kNumberOfSizeClasses];
|
||||
uptr stack_size_log_;
|
||||
|
@ -116,7 +116,7 @@ void InitializeFlags() {
|
||||
ubsan_parser.ParseString(GetEnv("UBSAN_OPTIONS"));
|
||||
#endif
|
||||
|
||||
SetVerbosity(common_flags()->verbosity);
|
||||
InitializeCommonFlags();
|
||||
|
||||
// TODO(eugenis): dump all flags at verbosity>=2?
|
||||
if (Verbosity()) ReportUnrecognizedFlags();
|
||||
@ -159,6 +159,14 @@ void InitializeFlags() {
|
||||
(ASAN_LOW_MEMORY) ? 1UL << 6 : 1UL << 8;
|
||||
f->quarantine_size_mb = kDefaultQuarantineSizeMb;
|
||||
}
|
||||
if (!f->replace_str && common_flags()->intercept_strlen) {
|
||||
Report("WARNING: strlen interceptor is enabled even though replace_str=0. "
|
||||
"Use intercept_strlen=0 to disable it.");
|
||||
}
|
||||
if (!f->replace_str && common_flags()->intercept_strchr) {
|
||||
Report("WARNING: strchr* interceptors are enabled even though "
|
||||
"replace_str=0. Use intercept_strchr=0 to disable them.");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace __asan
|
||||
|
@ -43,7 +43,7 @@ ASAN_FLAG(
|
||||
"If set, uses custom wrappers and replacements for libc string functions "
|
||||
"to find more errors.")
|
||||
ASAN_FLAG(bool, replace_intrin, true,
|
||||
"If set, uses custom wrappers for memset/memcpy/memmove intinsics.")
|
||||
"If set, uses custom wrappers for memset/memcpy/memmove intrinsics.")
|
||||
ASAN_FLAG(bool, detect_stack_use_after_return, false,
|
||||
"Enables stack-use-after-return checking at run-time.")
|
||||
ASAN_FLAG(int, min_uar_stack_size_log, 16, // We can't do smaller anyway.
|
||||
@ -77,6 +77,8 @@ ASAN_FLAG(bool, print_stats, false,
|
||||
"Print various statistics after printing an error message or if "
|
||||
"atexit=1.")
|
||||
ASAN_FLAG(bool, print_legend, true, "Print the legend for the shadow bytes.")
|
||||
ASAN_FLAG(bool, print_scariness, false,
|
||||
"Print the scariness score. Experimental.")
|
||||
ASAN_FLAG(bool, atexit, false,
|
||||
"If set, prints ASan exit stats even after program terminates "
|
||||
"successfully.")
|
||||
@ -104,7 +106,7 @@ ASAN_FLAG(bool, alloc_dealloc_mismatch,
|
||||
"Report errors on malloc/delete, new/free, new/delete[], etc.")
|
||||
|
||||
ASAN_FLAG(bool, new_delete_type_mismatch, true,
|
||||
"Report errors on mismatch betwen size of new and delete.")
|
||||
"Report errors on mismatch between size of new and delete.")
|
||||
ASAN_FLAG(
|
||||
bool, strict_init_order, false,
|
||||
"If true, assume that dynamic initializers can never access globals from "
|
||||
@ -135,3 +137,5 @@ ASAN_FLAG(const char *, suppressions, "", "Suppressions file name.")
|
||||
ASAN_FLAG(bool, halt_on_error, true,
|
||||
"Crash the program after printing the first error report "
|
||||
"(WARNING: USE AT YOUR OWN RISK!)")
|
||||
ASAN_FLAG(bool, use_odr_indicator, false,
|
||||
"Use special ODR indicator symbol for ODR violation detection")
|
||||
|
@ -135,6 +135,70 @@ bool GetInfoForAddressIfGlobal(uptr addr, AddressDescription *descr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
enum GlobalSymbolState {
|
||||
UNREGISTERED = 0,
|
||||
REGISTERED = 1
|
||||
};
|
||||
|
||||
// Check ODR violation for given global G via special ODR indicator. We use
|
||||
// this method in case compiler instruments global variables through their
|
||||
// local aliases.
|
||||
static void CheckODRViolationViaIndicator(const Global *g) {
|
||||
u8 *odr_indicator = reinterpret_cast<u8 *>(g->odr_indicator);
|
||||
if (*odr_indicator == UNREGISTERED) {
|
||||
*odr_indicator = REGISTERED;
|
||||
return;
|
||||
}
|
||||
// If *odr_indicator is DEFINED, some module have already registered
|
||||
// externally visible symbol with the same name. This is an ODR violation.
|
||||
for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
|
||||
if (g->odr_indicator == l->g->odr_indicator &&
|
||||
(flags()->detect_odr_violation >= 2 || g->size != l->g->size) &&
|
||||
!IsODRViolationSuppressed(g->name))
|
||||
ReportODRViolation(g, FindRegistrationSite(g),
|
||||
l->g, FindRegistrationSite(l->g));
|
||||
}
|
||||
}
|
||||
|
||||
// Check ODR violation for given global G by checking if it's already poisoned.
|
||||
// We use this method in case compiler doesn't use private aliases for global
|
||||
// variables.
|
||||
static void CheckODRViolationViaPoisoning(const Global *g) {
|
||||
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) &&
|
||||
!IsODRViolationSuppressed(g->name))
|
||||
ReportODRViolation(g, FindRegistrationSite(g),
|
||||
l->g, FindRegistrationSite(l->g));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clang provides two different ways for global variables protection:
|
||||
// it can poison the global itself or its private alias. In former
|
||||
// case we may poison same symbol multiple times, that can help us to
|
||||
// cheaply detect ODR violation: if we try to poison an already poisoned
|
||||
// global, we have ODR violation error.
|
||||
// In latter case, we poison each symbol exactly once, so we use special
|
||||
// indicator symbol to perform similar check.
|
||||
// In either case, compiler provides a special odr_indicator field to Global
|
||||
// structure, that can contain two kinds of values:
|
||||
// 1) Non-zero value. In this case, odr_indicator is an address of
|
||||
// corresponding indicator variable for given global.
|
||||
// 2) Zero. This means that we don't use private aliases for global variables
|
||||
// and can freely check ODR violation with the first method.
|
||||
//
|
||||
// This routine chooses between two different methods of ODR violation
|
||||
// detection.
|
||||
static inline bool UseODRIndicator(const Global *g) {
|
||||
// Use ODR indicator method iff use_odr_indicator flag is set and
|
||||
// indicator symbol address is not 0.
|
||||
return flags()->use_odr_indicator && g->odr_indicator > 0;
|
||||
}
|
||||
|
||||
// Register a global variable.
|
||||
// This function may be called more than once for every global
|
||||
// so we store the globals in a map.
|
||||
@ -144,22 +208,24 @@ static void RegisterGlobal(const Global *g) {
|
||||
ReportGlobal(*g, "Added");
|
||||
CHECK(flags()->report_globals);
|
||||
CHECK(AddrIsInMem(g->beg));
|
||||
CHECK(AddrIsAlignedByGranularity(g->beg));
|
||||
if (!AddrIsAlignedByGranularity(g->beg)) {
|
||||
Report("The following global variable is not properly aligned.\n");
|
||||
Report("This may happen if another global with the same name\n");
|
||||
Report("resides in another non-instrumented module.\n");
|
||||
Report("Or the global comes from a C file built w/o -fno-common.\n");
|
||||
Report("In either case this is likely an ODR violation bug,\n");
|
||||
Report("but AddressSanitizer can not provide more details.\n");
|
||||
ReportODRViolation(g, FindRegistrationSite(g), g, FindRegistrationSite(g));
|
||||
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) &&
|
||||
!IsODRViolationSuppressed(g->name))
|
||||
ReportODRViolation(g, FindRegistrationSite(g),
|
||||
l->g, FindRegistrationSite(l->g));
|
||||
}
|
||||
}
|
||||
if (UseODRIndicator(g))
|
||||
CheckODRViolationViaIndicator(g);
|
||||
else
|
||||
CheckODRViolationViaPoisoning(g);
|
||||
}
|
||||
if (CanPoisonMemory())
|
||||
PoisonRedZones(*g);
|
||||
@ -190,6 +256,12 @@ static void UnregisterGlobal(const Global *g) {
|
||||
// We unpoison the shadow memory for the global but we do not remove it from
|
||||
// the list because that would require O(n^2) time with the current list
|
||||
// implementation. It might not be worth doing anyway.
|
||||
|
||||
// Release ODR indicator.
|
||||
if (UseODRIndicator(g)) {
|
||||
u8 *odr_indicator = reinterpret_cast<u8 *>(g->odr_indicator);
|
||||
*odr_indicator = UNREGISTERED;
|
||||
}
|
||||
}
|
||||
|
||||
void StopInitOrderChecking() {
|
||||
@ -212,6 +284,25 @@ void StopInitOrderChecking() {
|
||||
// ---------------------- Interface ---------------- {{{1
|
||||
using namespace __asan; // NOLINT
|
||||
|
||||
|
||||
// Apply __asan_register_globals to all globals found in the same loaded
|
||||
// executable or shared library as `flag'. The flag tracks whether globals have
|
||||
// already been registered or not for this image.
|
||||
void __asan_register_image_globals(uptr *flag) {
|
||||
if (*flag)
|
||||
return;
|
||||
AsanApplyToGlobals(__asan_register_globals, flag);
|
||||
*flag = 1;
|
||||
}
|
||||
|
||||
// This mirrors __asan_register_image_globals.
|
||||
void __asan_unregister_image_globals(uptr *flag) {
|
||||
if (!*flag)
|
||||
return;
|
||||
AsanApplyToGlobals(__asan_unregister_globals, flag);
|
||||
*flag = 0;
|
||||
}
|
||||
|
||||
// Register an array of globals.
|
||||
void __asan_register_globals(__asan_global *globals, uptr n) {
|
||||
if (!flags()->report_globals) return;
|
||||
|
@ -19,16 +19,20 @@ 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.
|
||||
// contains the function PC as the 3rd field (see
|
||||
// DescribeAddressIfStack)
|
||||
// v3=>v4: added '__asan_global_source_location' to __asan_global
|
||||
// v4=>v5: changed the semantics and format of __asan_stack_malloc_ and
|
||||
// __asan_stack_free_ functions.
|
||||
// __asan_stack_free_ functions
|
||||
// v5=>v6: changed the name of the version check symbol
|
||||
#define __asan_version_mismatch_check __asan_version_mismatch_check_v6
|
||||
// v6=>v7: added 'odr_indicator' to __asan_global
|
||||
// v7=>v8: added '__asan_(un)register_image_globals' functions for dead
|
||||
// stripping support on Mach-O platforms
|
||||
#define __asan_version_mismatch_check __asan_version_mismatch_check_v8
|
||||
}
|
||||
|
||||
#endif // ASAN_INIT_VERSION_H
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "asan_stack.h"
|
||||
#include "asan_stats.h"
|
||||
#include "asan_suppressions.h"
|
||||
#include "lsan/lsan_common.h"
|
||||
#include "sanitizer_common/sanitizer_libc.h"
|
||||
|
||||
#if SANITIZER_POSIX
|
||||
@ -110,7 +111,7 @@ static inline bool RangesOverlap(const char *offset1, uptr length1,
|
||||
} while (0)
|
||||
|
||||
static inline uptr MaybeRealStrnlen(const char *s, uptr maxlen) {
|
||||
#if ASAN_INTERCEPT_STRNLEN
|
||||
#if SANITIZER_INTERCEPT_STRNLEN
|
||||
if (REAL(strnlen)) {
|
||||
return REAL(strnlen)(s, maxlen);
|
||||
}
|
||||
@ -143,6 +144,8 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)
|
||||
(void) ctx; \
|
||||
|
||||
#define COMMON_INTERCEPT_FUNCTION(name) ASAN_INTERCEPT_FUNC(name)
|
||||
#define COMMON_INTERCEPT_FUNCTION_VER(name, ver) \
|
||||
ASAN_INTERCEPT_FUNC_VER(name, ver)
|
||||
#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \
|
||||
ASAN_WRITE_RANGE(ctx, ptr, size)
|
||||
#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \
|
||||
@ -195,6 +198,10 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)
|
||||
} else { \
|
||||
*begin = *end = 0; \
|
||||
}
|
||||
// Asan needs custom handling of these:
|
||||
#undef SANITIZER_INTERCEPT_MEMSET
|
||||
#undef SANITIZER_INTERCEPT_MEMMOVE
|
||||
#undef SANITIZER_INTERCEPT_MEMCPY
|
||||
#include "sanitizer_common/sanitizer_common_interceptors.inc"
|
||||
|
||||
// Syscall interceptors don't have contexts, we don't support suppressions
|
||||
@ -218,6 +225,7 @@ struct ThreadStartParam {
|
||||
atomic_uintptr_t is_registered;
|
||||
};
|
||||
|
||||
#if ASAN_INTERCEPT_PTHREAD_CREATE
|
||||
static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {
|
||||
ThreadStartParam *param = reinterpret_cast<ThreadStartParam *>(arg);
|
||||
AsanThread *t = nullptr;
|
||||
@ -228,7 +236,6 @@ static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {
|
||||
return t->ThreadStart(GetTid(), ¶m->is_registered);
|
||||
}
|
||||
|
||||
#if ASAN_INTERCEPT_PTHREAD_CREATE
|
||||
INTERCEPTOR(int, pthread_create, void *thread,
|
||||
void *attr, void *(*start_routine)(void*), void *arg) {
|
||||
EnsureMainThreadIDIsCorrect();
|
||||
@ -242,7 +249,17 @@ INTERCEPTOR(int, pthread_create, void *thread,
|
||||
ThreadStartParam param;
|
||||
atomic_store(¶m.t, 0, memory_order_relaxed);
|
||||
atomic_store(¶m.is_registered, 0, memory_order_relaxed);
|
||||
int result = REAL(pthread_create)(thread, attr, asan_thread_start, ¶m);
|
||||
int result;
|
||||
{
|
||||
// Ignore all allocations made by pthread_create: thread stack/TLS may be
|
||||
// stored by pthread for future reuse even after thread destruction, and
|
||||
// the linked list it's stored in doesn't even hold valid pointers to the
|
||||
// objects, the latter are calculated by obscure pointer arithmetic.
|
||||
#if CAN_SANITIZE_LEAKS
|
||||
__lsan::ScopedInterceptorDisabler disabler;
|
||||
#endif
|
||||
result = REAL(pthread_create)(thread, attr, asan_thread_start, ¶m);
|
||||
}
|
||||
if (result == 0) {
|
||||
u32 current_tid = GetCurrentTidOrInvalid();
|
||||
AsanThread *t =
|
||||
@ -271,7 +288,8 @@ DEFINE_REAL_PTHREAD_FUNCTIONS
|
||||
|
||||
#if SANITIZER_ANDROID
|
||||
INTERCEPTOR(void*, bsd_signal, int signum, void *handler) {
|
||||
if (!IsDeadlySignal(signum) || common_flags()->allow_user_segv_handler) {
|
||||
if (!IsHandledDeadlySignal(signum) ||
|
||||
common_flags()->allow_user_segv_handler) {
|
||||
return REAL(bsd_signal)(signum, handler);
|
||||
}
|
||||
return 0;
|
||||
@ -279,7 +297,8 @@ INTERCEPTOR(void*, bsd_signal, int signum, void *handler) {
|
||||
#endif
|
||||
|
||||
INTERCEPTOR(void*, signal, int signum, void *handler) {
|
||||
if (!IsDeadlySignal(signum) || common_flags()->allow_user_segv_handler) {
|
||||
if (!IsHandledDeadlySignal(signum) ||
|
||||
common_flags()->allow_user_segv_handler) {
|
||||
return REAL(signal)(signum, handler);
|
||||
}
|
||||
return nullptr;
|
||||
@ -287,7 +306,8 @@ INTERCEPTOR(void*, signal, int signum, void *handler) {
|
||||
|
||||
INTERCEPTOR(int, sigaction, int signum, const struct sigaction *act,
|
||||
struct sigaction *oldact) {
|
||||
if (!IsDeadlySignal(signum) || common_flags()->allow_user_segv_handler) {
|
||||
if (!IsHandledDeadlySignal(signum) ||
|
||||
common_flags()->allow_user_segv_handler) {
|
||||
return REAL(sigaction)(signum, act, oldact);
|
||||
}
|
||||
return 0;
|
||||
@ -453,25 +473,6 @@ INTERCEPTOR(void*, memset, void *block, int c, uptr size) {
|
||||
ASAN_MEMSET_IMPL(ctx, block, c, size);
|
||||
}
|
||||
|
||||
INTERCEPTOR(char*, strchr, const char *str, int 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) {
|
||||
return REAL(strchr)(str, c);
|
||||
}
|
||||
ENSURE_ASAN_INITED();
|
||||
char *result = REAL(strchr)(str, c);
|
||||
if (flags()->replace_str) {
|
||||
uptr len = REAL(strlen)(str);
|
||||
uptr bytes_read = (result ? result - str : len) + 1;
|
||||
ASAN_READ_STRING_OF_LEN(ctx, str, len, bytes_read);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#if ASAN_INTERCEPT_INDEX
|
||||
# if ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX
|
||||
INTERCEPTOR(char*, index, const char *string, int c)
|
||||
@ -549,7 +550,6 @@ INTERCEPTOR(char*, strcpy, char *to, const char *from) { // NOLINT
|
||||
return REAL(strcpy)(to, from); // NOLINT
|
||||
}
|
||||
|
||||
#if ASAN_INTERCEPT_STRDUP
|
||||
INTERCEPTOR(char*, strdup, const char *s) {
|
||||
void *ctx;
|
||||
ASAN_INTERCEPTOR_ENTER(ctx, strdup);
|
||||
@ -564,29 +564,28 @@ INTERCEPTOR(char*, strdup, const char *s) {
|
||||
REAL(memcpy)(new_mem, s, length + 1);
|
||||
return reinterpret_cast<char*>(new_mem);
|
||||
}
|
||||
#endif
|
||||
|
||||
INTERCEPTOR(SIZE_T, strlen, const char *s) {
|
||||
#if ASAN_INTERCEPT___STRDUP
|
||||
INTERCEPTOR(char*, __strdup, 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);
|
||||
}
|
||||
ASAN_INTERCEPTOR_ENTER(ctx, strdup);
|
||||
if (UNLIKELY(!asan_inited)) return internal_strdup(s);
|
||||
ENSURE_ASAN_INITED();
|
||||
SIZE_T length = REAL(strlen)(s);
|
||||
uptr length = REAL(strlen)(s);
|
||||
if (flags()->replace_str) {
|
||||
ASAN_READ_RANGE(ctx, s, length + 1);
|
||||
}
|
||||
return length;
|
||||
GET_STACK_TRACE_MALLOC;
|
||||
void *new_mem = asan_malloc(length + 1, &stack);
|
||||
REAL(memcpy)(new_mem, s, length + 1);
|
||||
return reinterpret_cast<char*>(new_mem);
|
||||
}
|
||||
#endif // ASAN_INTERCEPT___STRDUP
|
||||
|
||||
INTERCEPTOR(SIZE_T, wcslen, const wchar_t *s) {
|
||||
void *ctx;
|
||||
ASAN_INTERCEPTOR_ENTER(ctx, wcslen);
|
||||
SIZE_T length = REAL(wcslen)(s);
|
||||
SIZE_T length = internal_wcslen(s);
|
||||
if (!asan_init_is_running) {
|
||||
ENSURE_ASAN_INITED();
|
||||
ASAN_READ_RANGE(ctx, s, (length + 1) * sizeof(wchar_t));
|
||||
@ -607,19 +606,6 @@ INTERCEPTOR(char*, strncpy, char *to, const char *from, uptr 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(ctx, s, Min(length + 1, maxlen));
|
||||
}
|
||||
return length;
|
||||
}
|
||||
#endif // ASAN_INTERCEPT_STRNLEN
|
||||
|
||||
INTERCEPTOR(long, strtol, const char *nptr, // NOLINT
|
||||
char **endptr, int base) {
|
||||
void *ctx;
|
||||
@ -702,12 +688,12 @@ INTERCEPTOR(long long, atoll, const char *nptr) { // NOLINT
|
||||
}
|
||||
#endif // ASAN_INTERCEPT_ATOLL_AND_STRTOLL
|
||||
|
||||
#if ASAN_INTERCEPT___CXA_ATEXIT
|
||||
static void AtCxaAtexit(void *unused) {
|
||||
(void)unused;
|
||||
StopInitOrderChecking();
|
||||
}
|
||||
|
||||
#if ASAN_INTERCEPT___CXA_ATEXIT
|
||||
INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
|
||||
void *dso_handle) {
|
||||
#if SANITIZER_MAC
|
||||
@ -739,25 +725,23 @@ void InitializeAsanInterceptors() {
|
||||
InitializeCommonInterceptors();
|
||||
|
||||
// Intercept mem* functions.
|
||||
ASAN_INTERCEPT_FUNC(memmove);
|
||||
ASAN_INTERCEPT_FUNC(memcpy);
|
||||
ASAN_INTERCEPT_FUNC(memset);
|
||||
if (PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE) {
|
||||
ASAN_INTERCEPT_FUNC(memcpy);
|
||||
// In asan, REAL(memmove) is not used, but it is used in msan.
|
||||
ASAN_INTERCEPT_FUNC(memmove);
|
||||
}
|
||||
CHECK(REAL(memcpy));
|
||||
|
||||
// Intercept str* functions.
|
||||
ASAN_INTERCEPT_FUNC(strcat); // NOLINT
|
||||
ASAN_INTERCEPT_FUNC(strchr);
|
||||
ASAN_INTERCEPT_FUNC(strcpy); // NOLINT
|
||||
ASAN_INTERCEPT_FUNC(strlen);
|
||||
ASAN_INTERCEPT_FUNC(wcslen);
|
||||
ASAN_INTERCEPT_FUNC(strncat);
|
||||
ASAN_INTERCEPT_FUNC(strncpy);
|
||||
#if ASAN_INTERCEPT_STRDUP
|
||||
ASAN_INTERCEPT_FUNC(strdup);
|
||||
#endif
|
||||
#if ASAN_INTERCEPT_STRNLEN
|
||||
ASAN_INTERCEPT_FUNC(strnlen);
|
||||
#if ASAN_INTERCEPT___STRDUP
|
||||
ASAN_INTERCEPT_FUNC(__strdup);
|
||||
#endif
|
||||
#if ASAN_INTERCEPT_INDEX && ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX
|
||||
ASAN_INTERCEPT_FUNC(index);
|
||||
|
@ -23,14 +23,12 @@
|
||||
#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
|
||||
@ -42,12 +40,6 @@
|
||||
# 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
|
||||
@ -80,6 +72,12 @@
|
||||
# define ASAN_INTERCEPT___CXA_ATEXIT 0
|
||||
#endif
|
||||
|
||||
#if SANITIZER_LINUX && !SANITIZER_ANDROID
|
||||
# define ASAN_INTERCEPT___STRDUP 1
|
||||
#else
|
||||
# define ASAN_INTERCEPT___STRDUP 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)
|
||||
|
@ -54,8 +54,17 @@ extern "C" {
|
||||
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.
|
||||
uptr odr_indicator; // The address of the ODR indicator symbol.
|
||||
};
|
||||
|
||||
// These functions can be called on some platforms to find globals in the same
|
||||
// loaded image as `flag' and apply __asan_(un)register_globals to them,
|
||||
// filtering out redundant calls.
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void __asan_register_image_globals(uptr *flag);
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void __asan_unregister_image_globals(uptr *flag);
|
||||
|
||||
// These two functions should be called by the instrumented code.
|
||||
// 'globals' is an array of structures describing 'n' globals.
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
|
@ -36,9 +36,9 @@
|
||||
// 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
|
||||
#if SANITIZER_WORDSIZE == 32
|
||||
# if SANITIZER_IOS || (SANITIZER_WORDSIZE == 32)
|
||||
# define ASAN_LOW_MEMORY 1
|
||||
#else
|
||||
# else
|
||||
# define ASAN_LOW_MEMORY 0
|
||||
# endif
|
||||
#endif
|
||||
@ -62,6 +62,9 @@ using __sanitizer::StackTrace;
|
||||
|
||||
void AsanInitFromRtl();
|
||||
|
||||
// asan_win.cc
|
||||
void InitializePlatformExceptionHandlers();
|
||||
|
||||
// asan_rtl.cc
|
||||
void NORETURN ShowStatsAndAbort();
|
||||
|
||||
@ -73,6 +76,13 @@ void *AsanDoesNotSupportStaticLinkage();
|
||||
void AsanCheckDynamicRTPrereqs();
|
||||
void AsanCheckIncompatibleRT();
|
||||
|
||||
// Support function for __asan_(un)register_image_globals. Searches for the
|
||||
// loaded image containing `needle' and then enumerates all global metadata
|
||||
// structures declared in that image, applying `op' (e.g.,
|
||||
// __asan_(un)register_globals) to them.
|
||||
typedef void (*globals_op_fptr)(__asan_global *, uptr);
|
||||
void AsanApplyToGlobals(globals_op_fptr op, const void *needle);
|
||||
|
||||
void AsanOnDeadlySignal(int, void *siginfo, void *context);
|
||||
|
||||
void ReadContextStack(void *context, uptr *stack, uptr *ssize);
|
||||
@ -95,16 +105,24 @@ void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name);
|
||||
bool PlatformHasDifferentMemcpyAndMemmove();
|
||||
# define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE \
|
||||
(PlatformHasDifferentMemcpyAndMemmove())
|
||||
#elif SANITIZER_WINDOWS64
|
||||
# define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE false
|
||||
#else
|
||||
# define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE true
|
||||
#endif // SANITIZER_MAC
|
||||
|
||||
// Add convenient macro for interface functions that may be represented as
|
||||
// weak hooks.
|
||||
#define ASAN_MALLOC_HOOK(ptr, size) \
|
||||
if (&__sanitizer_malloc_hook) __sanitizer_malloc_hook(ptr, size)
|
||||
#define ASAN_FREE_HOOK(ptr) \
|
||||
if (&__sanitizer_free_hook) __sanitizer_free_hook(ptr)
|
||||
#define ASAN_MALLOC_HOOK(ptr, size) \
|
||||
do { \
|
||||
if (&__sanitizer_malloc_hook) __sanitizer_malloc_hook(ptr, size); \
|
||||
RunMallocHooks(ptr, size); \
|
||||
} while (false)
|
||||
#define ASAN_FREE_HOOK(ptr) \
|
||||
do { \
|
||||
if (&__sanitizer_free_hook) __sanitizer_free_hook(ptr); \
|
||||
RunFreeHooks(ptr); \
|
||||
} while (false)
|
||||
#define ASAN_ON_ERROR() \
|
||||
if (&__asan_on_error) __asan_on_error()
|
||||
|
||||
@ -112,7 +130,6 @@ extern int asan_inited;
|
||||
// Used to avoid infinite recursion in __asan_init().
|
||||
extern bool asan_init_is_running;
|
||||
extern void (*death_callback)(void);
|
||||
|
||||
// These magic values are written to shadow for better error reporting.
|
||||
const int kAsanHeapLeftRedzoneMagic = 0xfa;
|
||||
const int kAsanHeapRightRedzoneMagic = 0xfb;
|
||||
|
@ -69,12 +69,17 @@ asan_rt_version_t __asan_rt_version;
|
||||
namespace __asan {
|
||||
|
||||
void InitializePlatformInterceptors() {}
|
||||
void InitializePlatformExceptionHandlers() {}
|
||||
|
||||
void *AsanDoesNotSupportStaticLinkage() {
|
||||
// This will fail to link with -static.
|
||||
return &_DYNAMIC; // defined in link.h
|
||||
}
|
||||
|
||||
void AsanApplyToGlobals(globals_op_fptr op, const void *needle) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
#if SANITIZER_ANDROID
|
||||
// FIXME: should we do anything for Android?
|
||||
void AsanCheckDynamicRTPrereqs() {}
|
||||
|
@ -24,9 +24,11 @@
|
||||
#include "sanitizer_common/sanitizer_libc.h"
|
||||
#include "sanitizer_common/sanitizer_mac.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <fcntl.h>
|
||||
#include <libkern/OSAtomic.h>
|
||||
#include <mach-o/dyld.h>
|
||||
#include <mach-o/getsect.h>
|
||||
#include <mach-o/loader.h>
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h> // for free()
|
||||
@ -36,9 +38,16 @@
|
||||
#include <sys/ucontext.h>
|
||||
#include <unistd.h>
|
||||
|
||||
// from <crt_externs.h>, but we don't have that file on iOS
|
||||
extern "C" {
|
||||
extern char ***_NSGetArgv(void);
|
||||
extern char ***_NSGetEnviron(void);
|
||||
}
|
||||
|
||||
namespace __asan {
|
||||
|
||||
void InitializePlatformInterceptors() {}
|
||||
void InitializePlatformExceptionHandlers() {}
|
||||
|
||||
bool PlatformHasDifferentMemcpyAndMemmove() {
|
||||
// On OS X 10.7 memcpy() and memmove() are both resolved
|
||||
@ -60,6 +69,30 @@ void AsanCheckDynamicRTPrereqs() {}
|
||||
// No-op. Mac does not support static linkage anyway.
|
||||
void AsanCheckIncompatibleRT() {}
|
||||
|
||||
void AsanApplyToGlobals(globals_op_fptr op, const void *needle) {
|
||||
// Find the Mach-O header for the image containing the needle
|
||||
Dl_info info;
|
||||
int err = dladdr(needle, &info);
|
||||
if (err == 0) return;
|
||||
|
||||
#if __LP64__
|
||||
const struct mach_header_64 *mh = (struct mach_header_64 *)info.dli_fbase;
|
||||
#else
|
||||
const struct mach_header *mh = (struct mach_header *)info.dli_fbase;
|
||||
#endif
|
||||
|
||||
// Look up the __asan_globals section in that image and register its globals
|
||||
unsigned long size = 0;
|
||||
__asan_global *globals = (__asan_global *)getsectiondata(
|
||||
mh,
|
||||
"__DATA", "__asan_globals",
|
||||
&size);
|
||||
|
||||
if (!globals) return;
|
||||
if (size % sizeof(__asan_global) != 0) return;
|
||||
op(globals, size / sizeof(__asan_global));
|
||||
}
|
||||
|
||||
void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
@ -26,52 +26,58 @@
|
||||
// ---------------------- Replacement functions ---------------- {{{1
|
||||
using namespace __asan; // NOLINT
|
||||
|
||||
static const uptr kCallocPoolSize = 1024;
|
||||
static uptr calloc_memory_for_dlsym[kCallocPoolSize];
|
||||
static uptr allocated_for_dlsym;
|
||||
static const uptr kDlsymAllocPoolSize = 1024;
|
||||
static uptr alloc_memory_for_dlsym[kDlsymAllocPoolSize];
|
||||
|
||||
static bool IsInCallocPool(const void *ptr) {
|
||||
sptr off = (sptr)ptr - (sptr)calloc_memory_for_dlsym;
|
||||
return 0 <= off && off < (sptr)kCallocPoolSize;
|
||||
static bool IsInDlsymAllocPool(const void *ptr) {
|
||||
uptr off = (uptr)ptr - (uptr)alloc_memory_for_dlsym;
|
||||
return off < sizeof(alloc_memory_for_dlsym);
|
||||
}
|
||||
|
||||
static void *AllocateFromLocalPool(uptr size_in_bytes) {
|
||||
uptr size_in_words = RoundUpTo(size_in_bytes, kWordSize) / kWordSize;
|
||||
void *mem = (void*)&alloc_memory_for_dlsym[allocated_for_dlsym];
|
||||
allocated_for_dlsym += size_in_words;
|
||||
CHECK_LT(allocated_for_dlsym, kDlsymAllocPoolSize);
|
||||
return mem;
|
||||
}
|
||||
|
||||
INTERCEPTOR(void, free, void *ptr) {
|
||||
GET_STACK_TRACE_FREE;
|
||||
if (UNLIKELY(IsInCallocPool(ptr)))
|
||||
if (UNLIKELY(IsInDlsymAllocPool(ptr)))
|
||||
return;
|
||||
asan_free(ptr, &stack, FROM_MALLOC);
|
||||
}
|
||||
|
||||
INTERCEPTOR(void, cfree, void *ptr) {
|
||||
GET_STACK_TRACE_FREE;
|
||||
if (UNLIKELY(IsInCallocPool(ptr)))
|
||||
if (UNLIKELY(IsInDlsymAllocPool(ptr)))
|
||||
return;
|
||||
asan_free(ptr, &stack, FROM_MALLOC);
|
||||
}
|
||||
|
||||
INTERCEPTOR(void*, malloc, uptr size) {
|
||||
if (UNLIKELY(!asan_inited))
|
||||
// Hack: dlsym calls malloc before REAL(malloc) is retrieved from dlsym.
|
||||
return AllocateFromLocalPool(size);
|
||||
GET_STACK_TRACE_MALLOC;
|
||||
return asan_malloc(size, &stack);
|
||||
}
|
||||
|
||||
INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
|
||||
if (UNLIKELY(!asan_inited)) {
|
||||
if (UNLIKELY(!asan_inited))
|
||||
// Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
|
||||
static uptr allocated;
|
||||
uptr size_in_words = ((nmemb * size) + kWordSize - 1) / kWordSize;
|
||||
void *mem = (void*)&calloc_memory_for_dlsym[allocated];
|
||||
allocated += size_in_words;
|
||||
CHECK(allocated < kCallocPoolSize);
|
||||
return mem;
|
||||
}
|
||||
return AllocateFromLocalPool(nmemb * size);
|
||||
GET_STACK_TRACE_MALLOC;
|
||||
return asan_calloc(nmemb, size, &stack);
|
||||
}
|
||||
|
||||
INTERCEPTOR(void*, realloc, void *ptr, uptr size) {
|
||||
GET_STACK_TRACE_MALLOC;
|
||||
if (UNLIKELY(IsInCallocPool(ptr))) {
|
||||
uptr offset = (uptr)ptr - (uptr)calloc_memory_for_dlsym;
|
||||
uptr copy_size = Min(size, kCallocPoolSize - offset);
|
||||
if (UNLIKELY(IsInDlsymAllocPool(ptr))) {
|
||||
uptr offset = (uptr)ptr - (uptr)alloc_memory_for_dlsym;
|
||||
uptr copy_size = Min(size, kDlsymAllocPoolSize - offset);
|
||||
void *new_ptr = asan_malloc(size, &stack);
|
||||
internal_memcpy(new_ptr, ptr, copy_size);
|
||||
return new_ptr;
|
||||
@ -92,7 +98,7 @@ INTERCEPTOR(void*, aligned_alloc, uptr boundary, uptr size) {
|
||||
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);
|
||||
DTLS_on_libc_memalign(res, size);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,8 @@
|
||||
|
||||
#include "sanitizer_common/sanitizer_platform.h"
|
||||
#if SANITIZER_WINDOWS
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
#include "asan_allocator.h"
|
||||
#include "asan_interceptors.h"
|
||||
@ -48,6 +50,11 @@ void _free_dbg(void *ptr, int) {
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
ALLOCATION_FUNCTION_ATTRIBUTE
|
||||
void _free_base(void *ptr) {
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
ALLOCATION_FUNCTION_ATTRIBUTE
|
||||
void cfree(void *ptr) {
|
||||
CHECK(!"cfree() should not be used on Windows");
|
||||
@ -59,6 +66,11 @@ void *malloc(size_t size) {
|
||||
return asan_malloc(size, &stack);
|
||||
}
|
||||
|
||||
ALLOCATION_FUNCTION_ATTRIBUTE
|
||||
void *_malloc_base(size_t size) {
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
ALLOCATION_FUNCTION_ATTRIBUTE
|
||||
void *_malloc_dbg(size_t size, int, const char *, int) {
|
||||
return malloc(size);
|
||||
@ -70,6 +82,11 @@ void *calloc(size_t nmemb, size_t size) {
|
||||
return asan_calloc(nmemb, size, &stack);
|
||||
}
|
||||
|
||||
ALLOCATION_FUNCTION_ATTRIBUTE
|
||||
void *_calloc_base(size_t nmemb, size_t size) {
|
||||
return calloc(nmemb, size);
|
||||
}
|
||||
|
||||
ALLOCATION_FUNCTION_ATTRIBUTE
|
||||
void *_calloc_dbg(size_t nmemb, size_t size, int, const char *, int) {
|
||||
return calloc(nmemb, size);
|
||||
@ -92,6 +109,11 @@ void *_realloc_dbg(void *ptr, size_t size, int) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ALLOCATION_FUNCTION_ATTRIBUTE
|
||||
void *_realloc_base(void *ptr, size_t size) {
|
||||
return realloc(ptr, size);
|
||||
}
|
||||
|
||||
ALLOCATION_FUNCTION_ATTRIBUTE
|
||||
void *_recalloc(void *p, size_t n, size_t elem_size) {
|
||||
if (!p)
|
||||
@ -103,7 +125,7 @@ void *_recalloc(void *p, size_t n, size_t elem_size) {
|
||||
}
|
||||
|
||||
ALLOCATION_FUNCTION_ATTRIBUTE
|
||||
size_t _msize(void *ptr) {
|
||||
size_t _msize(const void *ptr) {
|
||||
GET_CURRENT_PC_BP_SP;
|
||||
(void)sp;
|
||||
return asan_malloc_usable_size(ptr, pc, bp);
|
||||
@ -139,38 +161,89 @@ int _CrtSetReportMode(int, int) {
|
||||
}
|
||||
} // extern "C"
|
||||
|
||||
INTERCEPTOR_WINAPI(LPVOID, HeapAlloc, HANDLE hHeap, DWORD dwFlags,
|
||||
SIZE_T dwBytes) {
|
||||
GET_STACK_TRACE_MALLOC;
|
||||
void *p = asan_malloc(dwBytes, &stack);
|
||||
// Reading MSDN suggests that the *entire* usable allocation is zeroed out.
|
||||
// Otherwise it is difficult to HeapReAlloc with HEAP_ZERO_MEMORY.
|
||||
// https://blogs.msdn.microsoft.com/oldnewthing/20120316-00/?p=8083
|
||||
if (dwFlags == HEAP_ZERO_MEMORY)
|
||||
internal_memset(p, 0, asan_mz_size(p));
|
||||
else
|
||||
CHECK(dwFlags == 0 && "unsupported heap flags");
|
||||
return p;
|
||||
}
|
||||
|
||||
INTERCEPTOR_WINAPI(BOOL, HeapFree, HANDLE hHeap, DWORD dwFlags, LPVOID lpMem) {
|
||||
CHECK(dwFlags == 0 && "unsupported heap flags");
|
||||
GET_STACK_TRACE_FREE;
|
||||
asan_free(lpMem, &stack, FROM_MALLOC);
|
||||
return true;
|
||||
}
|
||||
|
||||
INTERCEPTOR_WINAPI(LPVOID, HeapReAlloc, HANDLE hHeap, DWORD dwFlags,
|
||||
LPVOID lpMem, SIZE_T dwBytes) {
|
||||
GET_STACK_TRACE_MALLOC;
|
||||
// Realloc should never reallocate in place.
|
||||
if (dwFlags & HEAP_REALLOC_IN_PLACE_ONLY)
|
||||
return nullptr;
|
||||
CHECK(dwFlags == 0 && "unsupported heap flags");
|
||||
return asan_realloc(lpMem, dwBytes, &stack);
|
||||
}
|
||||
|
||||
INTERCEPTOR_WINAPI(SIZE_T, HeapSize, HANDLE hHeap, DWORD dwFlags,
|
||||
LPCVOID lpMem) {
|
||||
CHECK(dwFlags == 0 && "unsupported heap flags");
|
||||
GET_CURRENT_PC_BP_SP;
|
||||
(void)sp;
|
||||
return asan_malloc_usable_size(lpMem, pc, bp);
|
||||
}
|
||||
|
||||
namespace __asan {
|
||||
|
||||
static void TryToOverrideFunction(const char *fname, uptr new_func) {
|
||||
// Failure here is not fatal. The CRT may not be present, and different CRT
|
||||
// versions use different symbols.
|
||||
if (!__interception::OverrideFunction(fname, new_func))
|
||||
VPrintf(2, "Failed to override function %s\n", fname);
|
||||
}
|
||||
|
||||
void ReplaceSystemMalloc() {
|
||||
#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);
|
||||
TryToOverrideFunction("free", (uptr)free);
|
||||
TryToOverrideFunction("_free_base", (uptr)free);
|
||||
TryToOverrideFunction("malloc", (uptr)malloc);
|
||||
TryToOverrideFunction("_malloc_base", (uptr)malloc);
|
||||
TryToOverrideFunction("_malloc_crt", (uptr)malloc);
|
||||
TryToOverrideFunction("calloc", (uptr)calloc);
|
||||
TryToOverrideFunction("_calloc_base", (uptr)calloc);
|
||||
TryToOverrideFunction("_calloc_crt", (uptr)calloc);
|
||||
TryToOverrideFunction("realloc", (uptr)realloc);
|
||||
TryToOverrideFunction("_realloc_base", (uptr)realloc);
|
||||
TryToOverrideFunction("_realloc_crt", (uptr)realloc);
|
||||
TryToOverrideFunction("_recalloc", (uptr)_recalloc);
|
||||
TryToOverrideFunction("_recalloc_crt", (uptr)_recalloc);
|
||||
TryToOverrideFunction("_msize", (uptr)_msize);
|
||||
TryToOverrideFunction("_expand", (uptr)_expand);
|
||||
TryToOverrideFunction("_expand_base", (uptr)_expand);
|
||||
|
||||
// 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);
|
||||
// Recent versions of ucrtbase.dll appear to be built with PGO and LTCG, which
|
||||
// enable cross-module inlining. This means our _malloc_base hook won't catch
|
||||
// all CRT allocations. This code here patches the import table of
|
||||
// ucrtbase.dll so that all attempts to use the lower-level win32 heap
|
||||
// allocation API will be directed to ASan's heap. We don't currently
|
||||
// intercept all calls to HeapAlloc. If we did, we would have to check on
|
||||
// HeapFree whether the pointer came from ASan of from the system.
|
||||
#define INTERCEPT_UCRT_FUNCTION(func) \
|
||||
if (!INTERCEPT_FUNCTION_DLLIMPORT("ucrtbase.dll", \
|
||||
"api-ms-win-core-heap-l1-1-0.dll", func)) \
|
||||
VPrintf(2, "Failed to intercept ucrtbase.dll import %s\n", #func);
|
||||
INTERCEPT_UCRT_FUNCTION(HeapAlloc);
|
||||
INTERCEPT_UCRT_FUNCTION(HeapFree);
|
||||
INTERCEPT_UCRT_FUNCTION(HeapReAlloc);
|
||||
INTERCEPT_UCRT_FUNCTION(HeapSize);
|
||||
#undef INTERCEPT_UCRT_FUNCTION
|
||||
#endif
|
||||
}
|
||||
} // namespace __asan
|
||||
|
@ -87,6 +87,20 @@
|
||||
// || `[0x08000000000, 0x08fffffffff]` || lowshadow ||
|
||||
// || `[0x00000000000, 0x07fffffffff]` || lowmem ||
|
||||
//
|
||||
// Default Linux/S390 mapping:
|
||||
// || `[0x30000000, 0x7fffffff]` || HighMem ||
|
||||
// || `[0x26000000, 0x2fffffff]` || HighShadow ||
|
||||
// || `[0x24000000, 0x25ffffff]` || ShadowGap ||
|
||||
// || `[0x20000000, 0x23ffffff]` || LowShadow ||
|
||||
// || `[0x00000000, 0x1fffffff]` || LowMem ||
|
||||
//
|
||||
// Default Linux/SystemZ mapping:
|
||||
// || `[0x14000000000000, 0x1fffffffffffff]` || HighMem ||
|
||||
// || `[0x12800000000000, 0x13ffffffffffff]` || HighShadow ||
|
||||
// || `[0x12000000000000, 0x127fffffffffff]` || ShadowGap ||
|
||||
// || `[0x10000000000000, 0x11ffffffffffff]` || LowShadow ||
|
||||
// || `[0x00000000000000, 0x0fffffffffffff]` || LowMem ||
|
||||
//
|
||||
// Shadow mapping on FreeBSD/x86-64 with SHADOW_OFFSET == 0x400000000000:
|
||||
// || `[0x500000000000, 0x7fffffffffff]` || HighMem ||
|
||||
// || `[0x4a0000000000, 0x4fffffffffff]` || HighShadow ||
|
||||
@ -115,16 +129,18 @@ static const u64 kDefaultShadowOffset32 = 1ULL << 29; // 0x20000000
|
||||
static const u64 kDefaultShadowOffset64 = 1ULL << 44;
|
||||
static const u64 kDefaultShort64bitShadowOffset = 0x7FFF8000; // < 2G.
|
||||
static const u64 kIosShadowOffset32 = 1ULL << 30; // 0x40000000
|
||||
static const u64 kIosShadowOffset64 = 0x130000000;
|
||||
static const u64 kIosShadowOffset64 = 0x120200000;
|
||||
static const u64 kIosSimShadowOffset32 = 1ULL << 30;
|
||||
static const u64 kIosSimShadowOffset64 = kDefaultShadowOffset64;
|
||||
static const u64 kAArch64_ShadowOffset64 = 1ULL << 36;
|
||||
static const u64 kMIPS32_ShadowOffset32 = 0x0aaa0000;
|
||||
static const u64 kMIPS64_ShadowOffset64 = 1ULL << 37;
|
||||
static const u64 kPPC64_ShadowOffset64 = 1ULL << 41;
|
||||
static const u64 kSystemZ_ShadowOffset64 = 1ULL << 52;
|
||||
static const u64 kFreeBSD_ShadowOffset32 = 1ULL << 30; // 0x40000000
|
||||
static const u64 kFreeBSD_ShadowOffset64 = 1ULL << 46; // 0x400000000000
|
||||
static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000
|
||||
static const u64 kWindowsShadowOffset64 = 1ULL << 45; // 32TB
|
||||
|
||||
#define SHADOW_SCALE kDefaultShadowScale
|
||||
|
||||
@ -138,28 +154,36 @@ static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000
|
||||
# define SHADOW_OFFSET kFreeBSD_ShadowOffset32
|
||||
# elif SANITIZER_WINDOWS
|
||||
# define SHADOW_OFFSET kWindowsShadowOffset32
|
||||
# elif SANITIZER_IOSSIM
|
||||
# define SHADOW_OFFSET kIosSimShadowOffset32
|
||||
# elif SANITIZER_IOS
|
||||
# define SHADOW_OFFSET kIosShadowOffset32
|
||||
# if SANITIZER_IOSSIM
|
||||
# define SHADOW_OFFSET kIosSimShadowOffset32
|
||||
# else
|
||||
# define SHADOW_OFFSET kIosShadowOffset32
|
||||
# endif
|
||||
# else
|
||||
# define SHADOW_OFFSET kDefaultShadowOffset32
|
||||
# endif
|
||||
#else
|
||||
# if defined(__aarch64__)
|
||||
# if SANITIZER_IOS
|
||||
# if SANITIZER_IOSSIM
|
||||
# define SHADOW_OFFSET kIosSimShadowOffset64
|
||||
# else
|
||||
# define SHADOW_OFFSET kIosShadowOffset64
|
||||
# endif
|
||||
# elif defined(__aarch64__)
|
||||
# define SHADOW_OFFSET kAArch64_ShadowOffset64
|
||||
# elif defined(__powerpc64__)
|
||||
# define SHADOW_OFFSET kPPC64_ShadowOffset64
|
||||
# elif defined(__s390x__)
|
||||
# define SHADOW_OFFSET kSystemZ_ShadowOffset64
|
||||
# elif SANITIZER_FREEBSD
|
||||
# define SHADOW_OFFSET kFreeBSD_ShadowOffset64
|
||||
# elif SANITIZER_MAC
|
||||
# define SHADOW_OFFSET kDefaultShadowOffset64
|
||||
# elif defined(__mips64)
|
||||
# define SHADOW_OFFSET kMIPS64_ShadowOffset64
|
||||
# elif SANITIZER_IOSSIM
|
||||
# define SHADOW_OFFSET kIosSimShadowOffset64
|
||||
# elif SANITIZER_IOS
|
||||
# define SHADOW_OFFSET kIosShadowOffset64
|
||||
# elif SANITIZER_WINDOWS64
|
||||
# define SHADOW_OFFSET kWindowsShadowOffset64
|
||||
# else
|
||||
# define SHADOW_OFFSET kDefaultShort64bitShadowOffset
|
||||
# endif
|
||||
|
100
lib/asan/asan_memory_profile.cc
Normal file
100
lib/asan/asan_memory_profile.cc
Normal file
@ -0,0 +1,100 @@
|
||||
//===-- asan_memory_profile.cc.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 implements __sanitizer_print_memory_profile.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "sanitizer_common/sanitizer_common.h"
|
||||
#include "sanitizer_common/sanitizer_stackdepot.h"
|
||||
#include "sanitizer_common/sanitizer_stacktrace.h"
|
||||
#include "sanitizer_common/sanitizer_stoptheworld.h"
|
||||
#include "lsan/lsan_common.h"
|
||||
#include "asan/asan_allocator.h"
|
||||
|
||||
#if CAN_SANITIZE_LEAKS
|
||||
|
||||
namespace __asan {
|
||||
|
||||
struct AllocationSite {
|
||||
u32 id;
|
||||
uptr total_size;
|
||||
uptr count;
|
||||
};
|
||||
|
||||
class HeapProfile {
|
||||
public:
|
||||
HeapProfile() : allocations_(1024) {}
|
||||
void Insert(u32 id, uptr size) {
|
||||
total_allocated_ += size;
|
||||
total_count_++;
|
||||
// Linear lookup will be good enough for most cases (although not all).
|
||||
for (uptr i = 0; i < allocations_.size(); i++) {
|
||||
if (allocations_[i].id == id) {
|
||||
allocations_[i].total_size += size;
|
||||
allocations_[i].count++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
allocations_.push_back({id, size, 1});
|
||||
}
|
||||
|
||||
void Print(uptr top_percent) {
|
||||
InternalSort(&allocations_, allocations_.size(),
|
||||
[](const AllocationSite &a, const AllocationSite &b) {
|
||||
return a.total_size > b.total_size;
|
||||
});
|
||||
CHECK(total_allocated_);
|
||||
uptr total_shown = 0;
|
||||
Printf("Live Heap Allocations: %zd bytes from %zd allocations; "
|
||||
"showing top %zd%%\n", total_allocated_, total_count_, top_percent);
|
||||
for (uptr i = 0; i < allocations_.size(); i++) {
|
||||
auto &a = allocations_[i];
|
||||
Printf("%zd byte(s) (%zd%%) in %zd allocation(s)\n", a.total_size,
|
||||
a.total_size * 100 / total_allocated_, a.count);
|
||||
StackDepotGet(a.id).Print();
|
||||
total_shown += a.total_size;
|
||||
if (total_shown * 100 / total_allocated_ > top_percent)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
uptr total_allocated_ = 0;
|
||||
uptr total_count_ = 0;
|
||||
InternalMmapVector<AllocationSite> allocations_;
|
||||
};
|
||||
|
||||
static void ChunkCallback(uptr chunk, void *arg) {
|
||||
HeapProfile *hp = reinterpret_cast<HeapProfile*>(arg);
|
||||
AsanChunkView cv = FindHeapChunkByAddress(chunk);
|
||||
if (!cv.IsAllocated()) return;
|
||||
u32 id = cv.GetAllocStackId();
|
||||
if (!id) return;
|
||||
hp->Insert(id, cv.UsedSize());
|
||||
}
|
||||
|
||||
static void MemoryProfileCB(const SuspendedThreadsList &suspended_threads_list,
|
||||
void *argument) {
|
||||
HeapProfile hp;
|
||||
__lsan::ForEachChunk(ChunkCallback, &hp);
|
||||
hp.Print(reinterpret_cast<uptr>(argument));
|
||||
}
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
extern "C" {
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void __sanitizer_print_memory_profile(uptr top_percent) {
|
||||
__sanitizer::StopTheWorld(__asan::MemoryProfileCB, (void*)top_percent);
|
||||
}
|
||||
} // extern "C"
|
||||
|
||||
#endif // CAN_SANITIZE_LEAKS
|
@ -20,9 +20,25 @@
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
// C++ operators can't have visibility attributes on Windows.
|
||||
// C++ operators can't have dllexport attributes on Windows. We export them
|
||||
// anyway by passing extra -export flags to the linker, which is exactly that
|
||||
// dllexport would normally do. We need to export them in order to make the
|
||||
// VS2015 dynamic CRT (MD) work.
|
||||
#if SANITIZER_WINDOWS
|
||||
# define CXX_OPERATOR_ATTRIBUTE
|
||||
# ifdef _WIN64
|
||||
# pragma comment(linker, "/export:??2@YAPEAX_K@Z") // operator new
|
||||
# pragma comment(linker, "/export:??3@YAXPEAX@Z") // operator delete
|
||||
# pragma comment(linker, "/export:??3@YAXPEAX_K@Z") // sized operator delete
|
||||
# pragma comment(linker, "/export:??_U@YAPEAX_K@Z") // operator new[]
|
||||
# pragma comment(linker, "/export:??_V@YAXPEAX@Z") // operator delete[]
|
||||
# else
|
||||
# pragma comment(linker, "/export:??2@YAPAXI@Z") // operator new
|
||||
# pragma comment(linker, "/export:??3@YAXPAX@Z") // operator delete
|
||||
# pragma comment(linker, "/export:??3@YAXPAXI@Z") // sized operator delete
|
||||
# pragma comment(linker, "/export:??_U@YAPAXI@Z") // operator new[]
|
||||
# pragma comment(linker, "/export:??_V@YAXPAX@Z") // operator delete[]
|
||||
# endif
|
||||
#else
|
||||
# define CXX_OPERATOR_ATTRIBUTE INTERCEPTOR_ATTRIBUTE
|
||||
#endif
|
||||
|
@ -343,7 +343,7 @@ void __sanitizer_annotate_contiguous_container(const void *beg_p,
|
||||
&stack);
|
||||
}
|
||||
CHECK_LE(end - beg,
|
||||
FIRST_32_SECOND_64(1UL << 30, 1UL << 34)); // Sanity check.
|
||||
FIRST_32_SECOND_64(1UL << 30, 1ULL << 34)); // Sanity check.
|
||||
|
||||
uptr a = RoundDownTo(Min(old_mid, new_mid), granularity);
|
||||
uptr c = RoundUpTo(Max(old_mid, new_mid), granularity);
|
||||
|
@ -36,14 +36,23 @@ namespace __asan {
|
||||
void AsanOnDeadlySignal(int signo, 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 (18 != internal_write(2, "ASAN:DEADLYSIGNAL\n", 18)) Die();
|
||||
// Write the first message using fd=2, just in case.
|
||||
// It may actually fail to write in case stderr is closed.
|
||||
internal_write(2, "ASAN:DEADLYSIGNAL\n", 18);
|
||||
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.
|
||||
#ifdef __s390__
|
||||
// On s390, the fault address in siginfo points to start of the page, not
|
||||
// to the precise word that was accessed. Mask off the low bits of sp to
|
||||
// take it into account.
|
||||
bool IsStackAccess = sig.addr >= (sig.sp & ~0xFFF) &&
|
||||
sig.addr < sig.sp + 0xFFFF;
|
||||
#else
|
||||
bool IsStackAccess = sig.addr + 512 > sig.sp && sig.addr < sig.sp + 0xFFFF;
|
||||
#endif
|
||||
|
||||
#if __powerpc__
|
||||
// Large stack frames can be allocated with e.g.
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "asan_internal.h"
|
||||
#include "asan_mapping.h"
|
||||
#include "asan_report.h"
|
||||
#include "asan_scariness_score.h"
|
||||
#include "asan_stack.h"
|
||||
#include "asan_thread.h"
|
||||
#include "sanitizer_common/sanitizer_common.h"
|
||||
@ -470,7 +471,7 @@ bool DescribeAddressIfStack(uptr addr, uptr access_size) {
|
||||
// previously. That's unfortunate, but I have no better solution,
|
||||
// especially given that the alloca may be from entirely different place
|
||||
// (e.g. use-after-scope, or different thread's stack).
|
||||
#if defined(__powerpc64__) && defined(__BIG_ENDIAN__)
|
||||
#if SANITIZER_PPC64V1
|
||||
// On PowerPC64 ELFv1, the address of a function actually points to a
|
||||
// three-doubleword data structure with the first field containing
|
||||
// the address of the function's code.
|
||||
@ -687,6 +688,9 @@ class ScopedInErrorReport {
|
||||
if (flags()->print_stats)
|
||||
__asan_print_accumulated_stats();
|
||||
|
||||
if (common_flags()->print_cmdline)
|
||||
PrintCmdline();
|
||||
|
||||
// Copy the message buffer so that we could start logging without holding a
|
||||
// lock that gets aquired during printing.
|
||||
InternalScopedBuffer<char> buffer_copy(kErrorMessageBufferSize);
|
||||
@ -732,10 +736,10 @@ class ScopedInErrorReport {
|
||||
};
|
||||
|
||||
StaticSpinMutex ScopedInErrorReport::lock_;
|
||||
u32 ScopedInErrorReport::reporting_thread_tid_;
|
||||
u32 ScopedInErrorReport::reporting_thread_tid_ = kInvalidTid;
|
||||
|
||||
void ReportStackOverflow(const SignalContext &sig) {
|
||||
ScopedInErrorReport in_report;
|
||||
ScopedInErrorReport in_report(/*report*/ nullptr, /*fatal*/ true);
|
||||
Decorator d;
|
||||
Printf("%s", d.Warning());
|
||||
Report(
|
||||
@ -744,13 +748,14 @@ void ReportStackOverflow(const SignalContext &sig) {
|
||||
(void *)sig.addr, (void *)sig.pc, (void *)sig.bp, (void *)sig.sp,
|
||||
GetCurrentTidOrInvalid());
|
||||
Printf("%s", d.EndWarning());
|
||||
ScarinessScore::PrintSimple(10, "stack-overflow");
|
||||
GET_STACK_TRACE_SIGNAL(sig);
|
||||
stack.Print();
|
||||
ReportErrorSummary("stack-overflow", &stack);
|
||||
}
|
||||
|
||||
void ReportDeadlySignal(const char *description, const SignalContext &sig) {
|
||||
ScopedInErrorReport in_report(/*report*/nullptr, /*fatal*/true);
|
||||
ScopedInErrorReport in_report(/*report*/ nullptr, /*fatal*/ true);
|
||||
Decorator d;
|
||||
Printf("%s", d.Warning());
|
||||
Report(
|
||||
@ -758,10 +763,32 @@ void ReportDeadlySignal(const char *description, const SignalContext &sig) {
|
||||
" (pc %p bp %p sp %p T%d)\n",
|
||||
description, (void *)sig.addr, (void *)sig.pc, (void *)sig.bp,
|
||||
(void *)sig.sp, GetCurrentTidOrInvalid());
|
||||
if (sig.pc < GetPageSizeCached()) {
|
||||
Report("Hint: pc points to the zero page.\n");
|
||||
}
|
||||
Printf("%s", d.EndWarning());
|
||||
ScarinessScore SS;
|
||||
if (sig.pc < GetPageSizeCached())
|
||||
Report("Hint: pc points to the zero page.\n");
|
||||
if (sig.is_memory_access) {
|
||||
const char *access_type =
|
||||
sig.write_flag == SignalContext::WRITE
|
||||
? "WRITE"
|
||||
: (sig.write_flag == SignalContext::READ ? "READ" : "UNKNOWN");
|
||||
Report("The signal is caused by a %s memory access.\n", access_type);
|
||||
if (sig.addr < GetPageSizeCached()) {
|
||||
Report("Hint: address points to the zero page.\n");
|
||||
SS.Scare(10, "null-deref");
|
||||
} else if (sig.addr == sig.pc) {
|
||||
SS.Scare(60, "wild-jump");
|
||||
} else if (sig.write_flag == SignalContext::WRITE) {
|
||||
SS.Scare(30, "wild-addr-write");
|
||||
} else if (sig.write_flag == SignalContext::READ) {
|
||||
SS.Scare(20, "wild-addr-read");
|
||||
} else {
|
||||
SS.Scare(25, "wild-addr");
|
||||
}
|
||||
} else {
|
||||
SS.Scare(10, "signal");
|
||||
}
|
||||
SS.Print();
|
||||
GET_STACK_TRACE_SIGNAL(sig);
|
||||
stack.Print();
|
||||
MaybeDumpInstructionBytes(sig.pc);
|
||||
@ -781,13 +808,14 @@ void ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack) {
|
||||
ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname)));
|
||||
Printf("%s", d.EndWarning());
|
||||
CHECK_GT(free_stack->size, 0);
|
||||
ScarinessScore::PrintSimple(42, "double-free");
|
||||
GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp);
|
||||
stack.Print();
|
||||
DescribeHeapAddress(addr, 1);
|
||||
ReportErrorSummary("double-free", &stack);
|
||||
}
|
||||
|
||||
void ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size,
|
||||
void ReportNewDeleteSizeMismatch(uptr addr, uptr alloc_size, uptr delete_size,
|
||||
BufferedStackTrace *free_stack) {
|
||||
ScopedInErrorReport in_report;
|
||||
Decorator d;
|
||||
@ -801,8 +829,9 @@ void ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size,
|
||||
Printf("%s object passed to delete has wrong type:\n", d.EndWarning());
|
||||
Printf(" size of the allocated type: %zd bytes;\n"
|
||||
" size of the deallocated type: %zd bytes.\n",
|
||||
asan_mz_size(reinterpret_cast<void*>(addr)), delete_size);
|
||||
alloc_size, delete_size);
|
||||
CHECK_GT(free_stack->size, 0);
|
||||
ScarinessScore::PrintSimple(10, "new-delete-type-mismatch");
|
||||
GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp);
|
||||
stack.Print();
|
||||
DescribeHeapAddress(addr, 1);
|
||||
@ -822,6 +851,7 @@ void ReportFreeNotMalloced(uptr addr, BufferedStackTrace *free_stack) {
|
||||
curr_tid, ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname)));
|
||||
Printf("%s", d.EndWarning());
|
||||
CHECK_GT(free_stack->size, 0);
|
||||
ScarinessScore::PrintSimple(40, "bad-free");
|
||||
GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp);
|
||||
stack.Print();
|
||||
DescribeHeapAddress(addr, 1);
|
||||
@ -843,6 +873,7 @@ void ReportAllocTypeMismatch(uptr addr, BufferedStackTrace *free_stack,
|
||||
alloc_names[alloc_type], dealloc_names[dealloc_type], addr);
|
||||
Printf("%s", d.EndWarning());
|
||||
CHECK_GT(free_stack->size, 0);
|
||||
ScarinessScore::PrintSimple(10, "alloc-dealloc-mismatch");
|
||||
GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp);
|
||||
stack.Print();
|
||||
DescribeHeapAddress(addr, 1);
|
||||
@ -891,6 +922,7 @@ void ReportStringFunctionMemoryRangesOverlap(const char *function,
|
||||
"memory ranges [%p,%p) and [%p, %p) overlap\n", \
|
||||
bug_type, offset1, offset1 + length1, offset2, offset2 + length2);
|
||||
Printf("%s", d.EndWarning());
|
||||
ScarinessScore::PrintSimple(10, bug_type);
|
||||
stack->Print();
|
||||
DescribeAddress((uptr)offset1, length1, bug_type);
|
||||
DescribeAddress((uptr)offset2, length2, bug_type);
|
||||
@ -905,6 +937,7 @@ void ReportStringFunctionSizeOverflow(uptr offset, uptr size,
|
||||
Printf("%s", d.Warning());
|
||||
Report("ERROR: AddressSanitizer: %s: (size=%zd)\n", bug_type, size);
|
||||
Printf("%s", d.EndWarning());
|
||||
ScarinessScore::PrintSimple(10, bug_type);
|
||||
stack->Print();
|
||||
DescribeAddress(offset, size, bug_type);
|
||||
ReportErrorSummary(bug_type, stack);
|
||||
@ -979,10 +1012,10 @@ static INLINE void CheckForInvalidPointerPair(void *p1, void *p2) {
|
||||
uptr a2 = reinterpret_cast<uptr>(p2);
|
||||
AsanChunkView chunk1 = FindHeapChunkByAddress(a1);
|
||||
AsanChunkView chunk2 = FindHeapChunkByAddress(a2);
|
||||
bool valid1 = chunk1.IsValid();
|
||||
bool valid2 = chunk2.IsValid();
|
||||
if ((valid1 != valid2) || (valid1 && valid2 && !chunk1.Eq(chunk2))) {
|
||||
GET_CALLER_PC_BP_SP; \
|
||||
bool valid1 = chunk1.IsAllocated();
|
||||
bool valid2 = chunk2.IsAllocated();
|
||||
if (!valid1 || !valid2 || !chunk1.Eq(chunk2)) {
|
||||
GET_CALLER_PC_BP_SP;
|
||||
return ReportInvalidPointerPair(pc, bp, sp, a1, a2);
|
||||
}
|
||||
}
|
||||
@ -1013,10 +1046,34 @@ static bool SuppressErrorReport(uptr pc) {
|
||||
Die();
|
||||
}
|
||||
|
||||
static void PrintContainerOverflowHint() {
|
||||
Printf("HINT: if you don't care about these errors you may set "
|
||||
"ASAN_OPTIONS=detect_container_overflow=0.\n"
|
||||
"If you suspect a false positive see also: "
|
||||
"https://github.com/google/sanitizers/wiki/"
|
||||
"AddressSanitizerContainerOverflow.\n");
|
||||
}
|
||||
|
||||
static bool AdjacentShadowValuesAreFullyPoisoned(u8 *s) {
|
||||
return s[-1] > 127 && s[1] > 127;
|
||||
}
|
||||
|
||||
void ReportGenericError(uptr pc, uptr bp, uptr sp, uptr addr, bool is_write,
|
||||
uptr access_size, u32 exp, bool fatal) {
|
||||
if (!fatal && SuppressErrorReport(pc)) return;
|
||||
ENABLE_FRAME_POINTER;
|
||||
ScarinessScore SS;
|
||||
|
||||
if (access_size) {
|
||||
if (access_size <= 9) {
|
||||
char desr[] = "?-byte";
|
||||
desr[0] = '0' + access_size;
|
||||
SS.Scare(access_size + access_size / 2, desr);
|
||||
} else if (access_size >= 10) {
|
||||
SS.Scare(15, "multi-byte");
|
||||
}
|
||||
is_write ? SS.Scare(20, "write") : SS.Scare(1, "read");
|
||||
}
|
||||
|
||||
// Optimization experiments.
|
||||
// The experiments can be used to evaluate potential optimizations that remove
|
||||
@ -1029,6 +1086,7 @@ void ReportGenericError(uptr pc, uptr bp, uptr sp, uptr addr, bool is_write,
|
||||
|
||||
// Determine the error type.
|
||||
const char *bug_descr = "unknown-crash";
|
||||
u8 shadow_val = 0;
|
||||
if (AddrIsInMem(addr)) {
|
||||
u8 *shadow_addr = (u8*)MemToShadow(addr);
|
||||
// If we are accessing 16 bytes, look at the second shadow byte.
|
||||
@ -1037,49 +1095,76 @@ void ReportGenericError(uptr pc, uptr bp, uptr sp, uptr addr, bool is_write,
|
||||
// If we are in the partial right redzone, look at the next shadow byte.
|
||||
if (*shadow_addr > 0 && *shadow_addr < 128)
|
||||
shadow_addr++;
|
||||
switch (*shadow_addr) {
|
||||
bool far_from_bounds = false;
|
||||
shadow_val = *shadow_addr;
|
||||
int bug_type_score = 0;
|
||||
// For use-after-frees reads are almost as bad as writes.
|
||||
int read_after_free_bonus = 0;
|
||||
switch (shadow_val) {
|
||||
case kAsanHeapLeftRedzoneMagic:
|
||||
case kAsanHeapRightRedzoneMagic:
|
||||
case kAsanArrayCookieMagic:
|
||||
bug_descr = "heap-buffer-overflow";
|
||||
bug_type_score = 10;
|
||||
far_from_bounds = AdjacentShadowValuesAreFullyPoisoned(shadow_addr);
|
||||
break;
|
||||
case kAsanHeapFreeMagic:
|
||||
bug_descr = "heap-use-after-free";
|
||||
bug_type_score = 20;
|
||||
if (!is_write) read_after_free_bonus = 18;
|
||||
break;
|
||||
case kAsanStackLeftRedzoneMagic:
|
||||
bug_descr = "stack-buffer-underflow";
|
||||
bug_type_score = 25;
|
||||
far_from_bounds = AdjacentShadowValuesAreFullyPoisoned(shadow_addr);
|
||||
break;
|
||||
case kAsanInitializationOrderMagic:
|
||||
bug_descr = "initialization-order-fiasco";
|
||||
bug_type_score = 1;
|
||||
break;
|
||||
case kAsanStackMidRedzoneMagic:
|
||||
case kAsanStackRightRedzoneMagic:
|
||||
case kAsanStackPartialRedzoneMagic:
|
||||
bug_descr = "stack-buffer-overflow";
|
||||
bug_type_score = 25;
|
||||
far_from_bounds = AdjacentShadowValuesAreFullyPoisoned(shadow_addr);
|
||||
break;
|
||||
case kAsanStackAfterReturnMagic:
|
||||
bug_descr = "stack-use-after-return";
|
||||
bug_type_score = 30;
|
||||
if (!is_write) read_after_free_bonus = 18;
|
||||
break;
|
||||
case kAsanUserPoisonedMemoryMagic:
|
||||
bug_descr = "use-after-poison";
|
||||
bug_type_score = 20;
|
||||
break;
|
||||
case kAsanContiguousContainerOOBMagic:
|
||||
bug_descr = "container-overflow";
|
||||
bug_type_score = 10;
|
||||
break;
|
||||
case kAsanStackUseAfterScopeMagic:
|
||||
bug_descr = "stack-use-after-scope";
|
||||
bug_type_score = 10;
|
||||
break;
|
||||
case kAsanGlobalRedzoneMagic:
|
||||
bug_descr = "global-buffer-overflow";
|
||||
bug_type_score = 10;
|
||||
far_from_bounds = AdjacentShadowValuesAreFullyPoisoned(shadow_addr);
|
||||
break;
|
||||
case kAsanIntraObjectRedzone:
|
||||
bug_descr = "intra-object-overflow";
|
||||
bug_type_score = 10;
|
||||
break;
|
||||
case kAsanAllocaLeftMagic:
|
||||
case kAsanAllocaRightMagic:
|
||||
bug_descr = "dynamic-stack-buffer-overflow";
|
||||
bug_type_score = 25;
|
||||
far_from_bounds = AdjacentShadowValuesAreFullyPoisoned(shadow_addr);
|
||||
break;
|
||||
}
|
||||
SS.Scare(bug_type_score + read_after_free_bonus, bug_descr);
|
||||
if (far_from_bounds)
|
||||
SS.Scare(10, "far-from-bounds");
|
||||
}
|
||||
|
||||
ReportData report = { pc, sp, bp, addr, (bool)is_write, access_size,
|
||||
@ -1102,10 +1187,13 @@ void ReportGenericError(uptr pc, uptr bp, uptr sp, uptr addr, bool is_write,
|
||||
ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname)),
|
||||
d.EndAccess());
|
||||
|
||||
SS.Print();
|
||||
GET_STACK_TRACE_FATAL(pc, bp);
|
||||
stack.Print();
|
||||
|
||||
DescribeAddress(addr, access_size, bug_descr);
|
||||
if (shadow_val == kAsanContiguousContainerOOBMagic)
|
||||
PrintContainerOverflowHint();
|
||||
ReportErrorSummary(bug_descr, &stack);
|
||||
PrintShadowMemoryForAddress(addr);
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ void ReportGenericError(uptr pc, uptr bp, uptr sp, uptr addr, bool is_write,
|
||||
uptr access_size, u32 exp, bool fatal);
|
||||
void ReportStackOverflow(const SignalContext &sig);
|
||||
void ReportDeadlySignal(const char *description, const SignalContext &sig);
|
||||
void ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size,
|
||||
void ReportNewDeleteSizeMismatch(uptr addr, uptr alloc_size, uptr delete_size,
|
||||
BufferedStackTrace *free_stack);
|
||||
void ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack);
|
||||
void ReportFreeNotMalloced(uptr addr, BufferedStackTrace *free_stack);
|
||||
|
@ -86,8 +86,8 @@ void ShowStatsAndAbort() {
|
||||
// Reserve memory range [beg, end].
|
||||
// We need to use inclusive range because end+1 may not be representable.
|
||||
void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name) {
|
||||
CHECK_EQ((beg % GetPageSizeCached()), 0);
|
||||
CHECK_EQ(((end + 1) % GetPageSizeCached()), 0);
|
||||
CHECK_EQ((beg % GetMmapGranularity()), 0);
|
||||
CHECK_EQ(((end + 1) % GetMmapGranularity()), 0);
|
||||
uptr size = end - beg + 1;
|
||||
DecreaseTotalMmap(size); // Don't count the shadow against mmap_limit_mb.
|
||||
void *res = MmapFixedNoReserve(beg, size, name);
|
||||
@ -320,26 +320,26 @@ static void InitializeHighMemEnd() {
|
||||
kHighMemEnd = GetMaxVirtualAddress();
|
||||
// Increase kHighMemEnd to make sure it's properly
|
||||
// aligned together with kHighMemBeg:
|
||||
kHighMemEnd |= SHADOW_GRANULARITY * GetPageSizeCached() - 1;
|
||||
kHighMemEnd |= SHADOW_GRANULARITY * GetMmapGranularity() - 1;
|
||||
#endif // !ASAN_FIXED_MAPPING
|
||||
CHECK_EQ((kHighMemBeg % GetPageSizeCached()), 0);
|
||||
CHECK_EQ((kHighMemBeg % GetMmapGranularity()), 0);
|
||||
}
|
||||
|
||||
static void ProtectGap(uptr addr, uptr size) {
|
||||
if (!flags()->protect_shadow_gap)
|
||||
return;
|
||||
void *res = MmapNoAccess(addr, size, "shadow gap");
|
||||
void *res = MmapFixedNoAccess(addr, size, "shadow gap");
|
||||
if (addr == (uptr)res)
|
||||
return;
|
||||
// A few pages at the start of the address space can not be protected.
|
||||
// But we really want to protect as much as possible, to prevent this memory
|
||||
// being returned as a result of a non-FIXED mmap().
|
||||
if (addr == kZeroBaseShadowStart) {
|
||||
uptr step = GetPageSizeCached();
|
||||
uptr step = GetMmapGranularity();
|
||||
while (size > step && addr < kZeroBaseMaxShadowStart) {
|
||||
addr += step;
|
||||
size -= step;
|
||||
void *res = MmapNoAccess(addr, size, "shadow gap");
|
||||
void *res = MmapFixedNoAccess(addr, size, "shadow gap");
|
||||
if (addr == (uptr)res)
|
||||
return;
|
||||
}
|
||||
@ -415,10 +415,13 @@ static void AsanInitInternal() {
|
||||
|
||||
AsanCheckIncompatibleRT();
|
||||
AsanCheckDynamicRTPrereqs();
|
||||
AvoidCVE_2016_2143();
|
||||
|
||||
SetCanPoisonMemory(flags()->poison_heap);
|
||||
SetMallocContextSize(common_flags()->malloc_context_size);
|
||||
|
||||
InitializePlatformExceptionHandlers();
|
||||
|
||||
InitializeHighMemEnd();
|
||||
|
||||
// Make sure we are not statically linked.
|
||||
@ -462,6 +465,12 @@ static void AsanInitInternal() {
|
||||
kMidMemBeg = kLowMemEnd < 0x3000000000ULL ? 0x3000000000ULL : 0;
|
||||
kMidMemEnd = kLowMemEnd < 0x3000000000ULL ? 0x4fffffffffULL : 0;
|
||||
}
|
||||
#elif SANITIZER_WINDOWS64
|
||||
// Disable the "mid mem" shadow layout.
|
||||
if (!full_shadow_is_available) {
|
||||
kMidMemBeg = 0;
|
||||
kMidMemEnd = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (Verbosity()) PrintAddressSpaceLayout();
|
||||
@ -539,12 +548,12 @@ static void AsanInitInternal() {
|
||||
force_interface_symbols(); // no-op.
|
||||
SanitizerInitializeUnwinder();
|
||||
|
||||
#if CAN_SANITIZE_LEAKS
|
||||
__lsan::InitCommonLsan();
|
||||
if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) {
|
||||
Atexit(__lsan::DoLeakCheck);
|
||||
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 CAN_SANITIZE_UB
|
||||
__ubsan::InitAsPlugin();
|
||||
@ -552,6 +561,15 @@ static void AsanInitInternal() {
|
||||
|
||||
InitializeSuppressions();
|
||||
|
||||
if (CAN_SANITIZE_LEAKS) {
|
||||
// LateInitialize() calls dlsym, which can allocate an error string buffer
|
||||
// in the TLS. Let's ignore the allocation to avoid reporting a leak.
|
||||
__lsan::ScopedInterceptorDisabler disabler;
|
||||
Symbolizer::LateInitialize();
|
||||
} else {
|
||||
Symbolizer::LateInitialize();
|
||||
}
|
||||
|
||||
VReport(1, "AddressSanitizer Init done\n");
|
||||
}
|
||||
|
||||
|
67
lib/asan/asan_scariness_score.h
Normal file
67
lib/asan/asan_scariness_score.h
Normal file
@ -0,0 +1,67 @@
|
||||
//===-- asan_scariness_score.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.
|
||||
//
|
||||
// Compute the level of scariness of the error message.
|
||||
// Don't expect any deep science here, just a set of heuristics that suggest
|
||||
// that e.g. 1-byte-read-global-buffer-overflow is less scary than
|
||||
// 8-byte-write-stack-use-after-return.
|
||||
//
|
||||
// Every error report has one or more features, such as memory access size,
|
||||
// type (read or write), type of accessed memory (e.g. free-d heap, or a global
|
||||
// redzone), etc. Every such feature has an int score and a string description.
|
||||
// The overall score is the sum of all feature scores and the description
|
||||
// is a concatenation of feature descriptions.
|
||||
// Examples:
|
||||
// 17 (4-byte-read-heap-buffer-overflow)
|
||||
// 65 (multi-byte-write-stack-use-after-return)
|
||||
// 10 (null-deref)
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef ASAN_SCARINESS_SCORE_H
|
||||
#define ASAN_SCARINESS_SCORE_H
|
||||
|
||||
#include "asan_flags.h"
|
||||
#include "sanitizer_common/sanitizer_common.h"
|
||||
#include "sanitizer_common/sanitizer_libc.h"
|
||||
|
||||
namespace __asan {
|
||||
class ScarinessScore {
|
||||
public:
|
||||
ScarinessScore() {
|
||||
descr[0] = 0;
|
||||
}
|
||||
void Scare(int add_to_score, const char *reason) {
|
||||
if (descr[0])
|
||||
internal_strlcat(descr, "-", sizeof(descr));
|
||||
internal_strlcat(descr, reason, sizeof(descr));
|
||||
score += add_to_score;
|
||||
};
|
||||
int GetScore() const { return score; }
|
||||
const char *GetDescription() const { return descr; }
|
||||
void Print() {
|
||||
if (score && flags()->print_scariness)
|
||||
Printf("SCARINESS: %d (%s)\n", score, descr);
|
||||
}
|
||||
static void PrintSimple(int score, const char *descr) {
|
||||
ScarinessScore SS;
|
||||
SS.Scare(score, descr);
|
||||
SS.Print();
|
||||
}
|
||||
|
||||
private:
|
||||
int score = 0;
|
||||
char descr[1024];
|
||||
};
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
#endif // ASAN_SCARINESS_SCORE_H
|
@ -48,7 +48,10 @@ void GetStackTraceWithPcBpAndContext(BufferedStackTrace *stack, uptr max_depth,
|
||||
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);
|
||||
if (!SANITIZER_MIPS || IsValidFrame(bp, stack_top, stack_bottom)) {
|
||||
stack->Unwind(max_depth, pc, bp, context, stack_top, stack_bottom,
|
||||
fast);
|
||||
}
|
||||
} else if (!t && !fast) {
|
||||
/* If GetCurrentThread() has failed, try to do slow unwind anyways. */
|
||||
stack->Unwind(max_depth, pc, bp, context, 0, 0, false);
|
||||
|
@ -89,6 +89,7 @@ bool IsStackTraceSuppressed(const StackTrace *stack) {
|
||||
|
||||
if (suppression_ctx->HasSuppressionType(kInterceptorViaFunction)) {
|
||||
SymbolizedStack *frames = symbolizer->SymbolizePC(addr);
|
||||
CHECK(frames);
|
||||
for (SymbolizedStack *cur = frames; cur; cur = cur->next) {
|
||||
const char *function_name = cur->info.function;
|
||||
if (!function_name) {
|
||||
|
@ -120,6 +120,71 @@ void AsanThread::Destroy() {
|
||||
DTLS_Destroy();
|
||||
}
|
||||
|
||||
void AsanThread::StartSwitchFiber(FakeStack **fake_stack_save, uptr bottom,
|
||||
uptr size) {
|
||||
if (atomic_load(&stack_switching_, memory_order_relaxed)) {
|
||||
Report("ERROR: starting fiber switch while in fiber switch\n");
|
||||
Die();
|
||||
}
|
||||
|
||||
next_stack_bottom_ = bottom;
|
||||
next_stack_top_ = bottom + size;
|
||||
atomic_store(&stack_switching_, 1, memory_order_release);
|
||||
|
||||
FakeStack *current_fake_stack = fake_stack_;
|
||||
if (fake_stack_save)
|
||||
*fake_stack_save = fake_stack_;
|
||||
fake_stack_ = nullptr;
|
||||
SetTLSFakeStack(nullptr);
|
||||
// if fake_stack_save is null, the fiber will die, delete the fakestack
|
||||
if (!fake_stack_save && current_fake_stack)
|
||||
current_fake_stack->Destroy(this->tid());
|
||||
}
|
||||
|
||||
void AsanThread::FinishSwitchFiber(FakeStack *fake_stack_save) {
|
||||
if (!atomic_load(&stack_switching_, memory_order_relaxed)) {
|
||||
Report("ERROR: finishing a fiber switch that has not started\n");
|
||||
Die();
|
||||
}
|
||||
|
||||
if (fake_stack_save) {
|
||||
SetTLSFakeStack(fake_stack_save);
|
||||
fake_stack_ = fake_stack_save;
|
||||
}
|
||||
|
||||
stack_bottom_ = next_stack_bottom_;
|
||||
stack_top_ = next_stack_top_;
|
||||
atomic_store(&stack_switching_, 0, memory_order_release);
|
||||
next_stack_top_ = 0;
|
||||
next_stack_bottom_ = 0;
|
||||
}
|
||||
|
||||
inline AsanThread::StackBounds AsanThread::GetStackBounds() const {
|
||||
if (!atomic_load(&stack_switching_, memory_order_acquire))
|
||||
return StackBounds{stack_bottom_, stack_top_}; // NOLINT
|
||||
char local;
|
||||
const uptr cur_stack = (uptr)&local;
|
||||
// Note: need to check next stack first, because FinishSwitchFiber
|
||||
// may be in process of overwriting stack_top_/bottom_. But in such case
|
||||
// we are already on the next stack.
|
||||
if (cur_stack >= next_stack_bottom_ && cur_stack < next_stack_top_)
|
||||
return StackBounds{next_stack_bottom_, next_stack_top_}; // NOLINT
|
||||
return StackBounds{stack_bottom_, stack_top_}; // NOLINT
|
||||
}
|
||||
|
||||
uptr AsanThread::stack_top() {
|
||||
return GetStackBounds().top;
|
||||
}
|
||||
|
||||
uptr AsanThread::stack_bottom() {
|
||||
return GetStackBounds().bottom;
|
||||
}
|
||||
|
||||
uptr AsanThread::stack_size() {
|
||||
const auto bounds = GetStackBounds();
|
||||
return bounds.top - bounds.bottom;
|
||||
}
|
||||
|
||||
// We want to create the FakeStack lazyly on the first use, but not eralier
|
||||
// than the stack size is known and the procedure has to be async-signal safe.
|
||||
FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() {
|
||||
@ -150,6 +215,8 @@ FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() {
|
||||
}
|
||||
|
||||
void AsanThread::Init() {
|
||||
next_stack_top_ = next_stack_bottom_ = 0;
|
||||
atomic_store(&stack_switching_, false, memory_order_release);
|
||||
fake_stack_ = nullptr; // Will be initialized lazily if needed.
|
||||
CHECK_EQ(this->stack_size(), 0U);
|
||||
SetThreadStackAndTls();
|
||||
@ -195,10 +262,12 @@ thread_return_t AsanThread::ThreadStart(
|
||||
|
||||
void AsanThread::SetThreadStackAndTls() {
|
||||
uptr tls_size = 0;
|
||||
GetThreadStackAndTls(tid() == 0, &stack_bottom_, &stack_size_, &tls_begin_,
|
||||
&tls_size);
|
||||
stack_top_ = stack_bottom_ + stack_size_;
|
||||
uptr stack_size = 0;
|
||||
GetThreadStackAndTls(tid() == 0, const_cast<uptr *>(&stack_bottom_),
|
||||
const_cast<uptr *>(&stack_size), &tls_begin_, &tls_size);
|
||||
stack_top_ = stack_bottom_ + stack_size;
|
||||
tls_end_ = tls_begin_ + tls_size;
|
||||
dtls_ = DTLS_Get();
|
||||
|
||||
int local;
|
||||
CHECK(AddrIsInStack((uptr)&local));
|
||||
@ -249,6 +318,11 @@ bool AsanThread::GetStackFrameAccessByAddr(uptr addr,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AsanThread::AddrIsInStack(uptr addr) {
|
||||
const auto bounds = GetStackBounds();
|
||||
return addr >= bounds.bottom && addr < bounds.top;
|
||||
}
|
||||
|
||||
static bool ThreadStackContainsAddress(ThreadContextBase *tctx_base,
|
||||
void *addr) {
|
||||
AsanThreadContext *tctx = static_cast<AsanThreadContext*>(tctx_base);
|
||||
@ -322,8 +396,8 @@ __asan::AsanThread *GetAsanThreadByOsIDLocked(uptr os_id) {
|
||||
// --- Implementation of LSan-specific functions --- {{{1
|
||||
namespace __lsan {
|
||||
bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end,
|
||||
uptr *tls_begin, uptr *tls_end,
|
||||
uptr *cache_begin, uptr *cache_end) {
|
||||
uptr *tls_begin, uptr *tls_end, uptr *cache_begin,
|
||||
uptr *cache_end, DTLS **dtls) {
|
||||
__asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id);
|
||||
if (!t) return false;
|
||||
*stack_begin = t->stack_bottom();
|
||||
@ -333,6 +407,7 @@ bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end,
|
||||
// ASan doesn't keep allocator caches in TLS, so these are unused.
|
||||
*cache_begin = 0;
|
||||
*cache_end = 0;
|
||||
*dtls = t->dtls();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -355,3 +430,29 @@ void EnsureMainThreadIDIsCorrect() {
|
||||
__asan::EnsureMainThreadIDIsCorrect();
|
||||
}
|
||||
} // namespace __lsan
|
||||
|
||||
// ---------------------- Interface ---------------- {{{1
|
||||
using namespace __asan; // NOLINT
|
||||
|
||||
extern "C" {
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void __sanitizer_start_switch_fiber(void **fakestacksave, const void *bottom,
|
||||
uptr size) {
|
||||
AsanThread *t = GetCurrentThread();
|
||||
if (!t) {
|
||||
VReport(1, "__asan_start_switch_fiber called from unknown thread\n");
|
||||
return;
|
||||
}
|
||||
t->StartSwitchFiber((FakeStack**)fakestacksave, (uptr)bottom, size);
|
||||
}
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void __sanitizer_finish_switch_fiber(void* fakestack) {
|
||||
AsanThread *t = GetCurrentThread();
|
||||
if (!t) {
|
||||
VReport(1, "__asan_finish_switch_fiber called from unknown thread\n");
|
||||
return;
|
||||
}
|
||||
t->FinishSwitchFiber((FakeStack*)fakestack);
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,10 @@
|
||||
#include "sanitizer_common/sanitizer_libc.h"
|
||||
#include "sanitizer_common/sanitizer_thread_registry.h"
|
||||
|
||||
namespace __sanitizer {
|
||||
struct DTLS;
|
||||
} // namespace __sanitizer
|
||||
|
||||
namespace __asan {
|
||||
|
||||
const u32 kInvalidTid = 0xffffff; // Must fit into 24 bits.
|
||||
@ -62,11 +66,12 @@ class AsanThread {
|
||||
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_; }
|
||||
uptr stack_size() { return stack_size_; }
|
||||
uptr stack_top();
|
||||
uptr stack_bottom();
|
||||
uptr stack_size();
|
||||
uptr tls_begin() { return tls_begin_; }
|
||||
uptr tls_end() { return tls_end_; }
|
||||
DTLS *dtls() { return dtls_; }
|
||||
u32 tid() { return context_->tid; }
|
||||
AsanThreadContext *context() { return context_; }
|
||||
void set_context(AsanThreadContext *context) { context_ = context; }
|
||||
@ -78,9 +83,7 @@ class AsanThread {
|
||||
};
|
||||
bool GetStackFrameAccessByAddr(uptr addr, StackFrameAccess *access);
|
||||
|
||||
bool AddrIsInStack(uptr addr) {
|
||||
return addr >= stack_bottom_ && addr < stack_top_;
|
||||
}
|
||||
bool AddrIsInStack(uptr addr);
|
||||
|
||||
void DeleteFakeStack(int tid) {
|
||||
if (!fake_stack_) return;
|
||||
@ -90,13 +93,19 @@ class AsanThread {
|
||||
t->Destroy(tid);
|
||||
}
|
||||
|
||||
void StartSwitchFiber(FakeStack **fake_stack_save, uptr bottom, uptr size);
|
||||
void FinishSwitchFiber(FakeStack *fake_stack_save);
|
||||
|
||||
bool has_fake_stack() {
|
||||
return (reinterpret_cast<uptr>(fake_stack_) > 1);
|
||||
return !atomic_load(&stack_switching_, memory_order_relaxed) &&
|
||||
(reinterpret_cast<uptr>(fake_stack_) > 1);
|
||||
}
|
||||
|
||||
FakeStack *fake_stack() {
|
||||
if (!__asan_option_detect_stack_use_after_return)
|
||||
return nullptr;
|
||||
if (atomic_load(&stack_switching_, memory_order_relaxed))
|
||||
return nullptr;
|
||||
if (!has_fake_stack())
|
||||
return AsyncSignalSafeLazyInitFakeStack();
|
||||
return fake_stack_;
|
||||
@ -122,16 +131,27 @@ class AsanThread {
|
||||
void ClearShadowForThreadStackAndTLS();
|
||||
FakeStack *AsyncSignalSafeLazyInitFakeStack();
|
||||
|
||||
struct StackBounds {
|
||||
uptr bottom;
|
||||
uptr top;
|
||||
};
|
||||
StackBounds GetStackBounds() const;
|
||||
|
||||
AsanThreadContext *context_;
|
||||
thread_callback_t start_routine_;
|
||||
void *arg_;
|
||||
|
||||
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_;
|
||||
// these variables are used when the thread is about to switch stack
|
||||
uptr next_stack_top_;
|
||||
uptr next_stack_bottom_;
|
||||
// true if switching is in progress
|
||||
atomic_uint8_t stack_switching_;
|
||||
|
||||
uptr tls_begin_;
|
||||
uptr tls_end_;
|
||||
DTLS *dtls_;
|
||||
|
||||
FakeStack *fake_stack_;
|
||||
AsanThreadLocalMallocStorage malloc_storage_;
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "asan_report.h"
|
||||
#include "asan_stack.h"
|
||||
#include "asan_thread.h"
|
||||
#include "asan_mapping.h"
|
||||
#include "sanitizer_common/sanitizer_libc.h"
|
||||
#include "sanitizer_common/sanitizer_mutex.h"
|
||||
|
||||
@ -46,11 +47,20 @@ void __sanitizer_default_free_hook(void *ptr) { }
|
||||
const char* __asan_default_default_options() { return ""; }
|
||||
const char* __asan_default_default_suppressions() { return ""; }
|
||||
void __asan_default_on_error() {}
|
||||
// 64-bit msvc will not prepend an underscore for symbols.
|
||||
#ifdef _WIN64
|
||||
#pragma comment(linker, "/alternatename:__sanitizer_malloc_hook=__sanitizer_default_malloc_hook") // NOLINT
|
||||
#pragma comment(linker, "/alternatename:__sanitizer_free_hook=__sanitizer_default_free_hook") // NOLINT
|
||||
#pragma comment(linker, "/alternatename:__asan_default_options=__asan_default_default_options") // NOLINT
|
||||
#pragma comment(linker, "/alternatename:__asan_default_suppressions=__asan_default_default_suppressions") // NOLINT
|
||||
#pragma comment(linker, "/alternatename:__asan_on_error=__asan_default_on_error") // NOLINT
|
||||
#else
|
||||
#pragma comment(linker, "/alternatename:___sanitizer_malloc_hook=___sanitizer_default_malloc_hook") // NOLINT
|
||||
#pragma comment(linker, "/alternatename:___sanitizer_free_hook=___sanitizer_default_free_hook") // NOLINT
|
||||
#pragma comment(linker, "/alternatename:___asan_default_options=___asan_default_default_options") // NOLINT
|
||||
#pragma comment(linker, "/alternatename:___asan_default_suppressions=___asan_default_default_suppressions") // NOLINT
|
||||
#pragma comment(linker, "/alternatename:___asan_on_error=___asan_default_on_error") // NOLINT
|
||||
#endif
|
||||
// }}}
|
||||
} // extern "C"
|
||||
|
||||
@ -61,6 +71,17 @@ INTERCEPTOR_WINAPI(void, RaiseException, void *a, void *b, void *c, void *d) {
|
||||
REAL(RaiseException)(a, b, c, d);
|
||||
}
|
||||
|
||||
|
||||
#ifdef _WIN64
|
||||
|
||||
INTERCEPTOR_WINAPI(int, __C_specific_handler, void *a, void *b, void *c, void *d) { // NOLINT
|
||||
CHECK(REAL(__C_specific_handler));
|
||||
__asan_handle_no_return();
|
||||
return REAL(__C_specific_handler)(a, b, c, d);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
INTERCEPTOR(int, _except_handler3, void *a, void *b, void *c, void *d) {
|
||||
CHECK(REAL(_except_handler3));
|
||||
__asan_handle_no_return();
|
||||
@ -76,6 +97,7 @@ INTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) {
|
||||
__asan_handle_no_return();
|
||||
return REAL(_except_handler4)(a, b, c, d);
|
||||
}
|
||||
#endif
|
||||
|
||||
static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {
|
||||
AsanThread *t = (AsanThread*)arg;
|
||||
@ -139,8 +161,13 @@ namespace __asan {
|
||||
void InitializePlatformInterceptors() {
|
||||
ASAN_INTERCEPT_FUNC(CreateThread);
|
||||
ASAN_INTERCEPT_FUNC(RaiseException);
|
||||
|
||||
#ifdef _WIN64
|
||||
ASAN_INTERCEPT_FUNC(__C_specific_handler);
|
||||
#else
|
||||
ASAN_INTERCEPT_FUNC(_except_handler3);
|
||||
ASAN_INTERCEPT_FUNC(_except_handler4);
|
||||
#endif
|
||||
|
||||
// NtWaitForWorkViaWorkerFactory is always linked dynamically.
|
||||
CHECK(::__interception::OverrideFunction(
|
||||
@ -149,6 +176,10 @@ void InitializePlatformInterceptors() {
|
||||
(uptr *)&REAL(NtWaitForWorkViaWorkerFactory)));
|
||||
}
|
||||
|
||||
void AsanApplyToGlobals(globals_op_fptr op, const void *needle) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
// ---------------------- TSD ---------------- {{{
|
||||
static bool tsd_key_inited = false;
|
||||
|
||||
@ -194,6 +225,55 @@ void AsanOnDeadlySignal(int, void *siginfo, void *context) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
#if SANITIZER_WINDOWS64
|
||||
// Exception handler for dealing with shadow memory.
|
||||
static LONG CALLBACK
|
||||
ShadowExceptionHandler(PEXCEPTION_POINTERS exception_pointers) {
|
||||
static uptr page_size = GetPageSizeCached();
|
||||
static uptr alloc_granularity = GetMmapGranularity();
|
||||
// Only handle access violations.
|
||||
if (exception_pointers->ExceptionRecord->ExceptionCode !=
|
||||
EXCEPTION_ACCESS_VIOLATION) {
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
// Only handle access violations that land within the shadow memory.
|
||||
uptr addr =
|
||||
(uptr)(exception_pointers->ExceptionRecord->ExceptionInformation[1]);
|
||||
|
||||
// Check valid shadow range.
|
||||
if (!AddrIsInShadow(addr)) return EXCEPTION_CONTINUE_SEARCH;
|
||||
|
||||
// This is an access violation while trying to read from the shadow. Commit
|
||||
// the relevant page and let execution continue.
|
||||
|
||||
// Determine the address of the page that is being accessed.
|
||||
uptr page = RoundDownTo(addr, page_size);
|
||||
|
||||
// Query the existing page.
|
||||
MEMORY_BASIC_INFORMATION mem_info = {};
|
||||
if (::VirtualQuery((LPVOID)page, &mem_info, sizeof(mem_info)) == 0)
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
|
||||
// Commit the page.
|
||||
uptr result =
|
||||
(uptr)::VirtualAlloc((LPVOID)page, page_size, MEM_COMMIT, PAGE_READWRITE);
|
||||
if (result != page) return EXCEPTION_CONTINUE_SEARCH;
|
||||
|
||||
// The page mapping succeeded, so continue execution as usual.
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void InitializePlatformExceptionHandlers() {
|
||||
#if SANITIZER_WINDOWS64
|
||||
// On Win64, we map memory on demand with access violation handler.
|
||||
// Install our exception handler.
|
||||
CHECK(AddVectoredExceptionHandler(TRUE, &ShadowExceptionHandler));
|
||||
#endif
|
||||
}
|
||||
|
||||
static LPTOP_LEVEL_EXCEPTION_FILTER default_seh_handler;
|
||||
|
||||
static long WINAPI SEHHandler(EXCEPTION_POINTERS *info) {
|
||||
@ -242,10 +322,16 @@ int __asan_set_seh_filter() {
|
||||
}
|
||||
|
||||
#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
|
||||
__declspec(allocate(".CRT$XIZ"))
|
||||
// The CRT runs initializers in this order:
|
||||
// - C initializers, from XIA to XIZ
|
||||
// - C++ initializers, from XCA to XCZ
|
||||
// Prior to 2015, the CRT set the unhandled exception filter at priority XIY,
|
||||
// near the end of C initialization. Starting in 2015, it was moved to the
|
||||
// beginning of C++ initialization. We set our priority to XCAB to run
|
||||
// immediately after the CRT runs. This way, our exception filter is called
|
||||
// first and we can delegate to their filter if appropriate.
|
||||
#pragma section(".CRT$XCAB", long, read) // NOLINT
|
||||
__declspec(allocate(".CRT$XCAB"))
|
||||
int (*__intercept_seh)() = __asan_set_seh_filter;
|
||||
#endif
|
||||
// }}}
|
||||
|
@ -21,6 +21,7 @@
|
||||
#ifdef ASAN_DLL_THUNK
|
||||
#include "asan_init_version.h"
|
||||
#include "interception/interception.h"
|
||||
#include "sanitizer_common/sanitizer_platform_interceptors.h"
|
||||
|
||||
// ---------- Function interception helper functions and macros ----------- {{{1
|
||||
extern "C" {
|
||||
@ -335,6 +336,7 @@ INTERFACE_FUNCTION(__sanitizer_update_counter_bitset_and_clear_counters)
|
||||
INTERFACE_FUNCTION(__sanitizer_sandbox_on_notify)
|
||||
INTERFACE_FUNCTION(__sanitizer_set_death_callback)
|
||||
INTERFACE_FUNCTION(__sanitizer_set_report_path)
|
||||
INTERFACE_FUNCTION(__sanitizer_set_report_fd)
|
||||
INTERFACE_FUNCTION(__sanitizer_unaligned_load16)
|
||||
INTERFACE_FUNCTION(__sanitizer_unaligned_load32)
|
||||
INTERFACE_FUNCTION(__sanitizer_unaligned_load64)
|
||||
@ -342,21 +344,28 @@ INTERFACE_FUNCTION(__sanitizer_unaligned_store16)
|
||||
INTERFACE_FUNCTION(__sanitizer_unaligned_store32)
|
||||
INTERFACE_FUNCTION(__sanitizer_unaligned_store64)
|
||||
INTERFACE_FUNCTION(__sanitizer_verify_contiguous_container)
|
||||
INTERFACE_FUNCTION(__sanitizer_install_malloc_and_free_hooks)
|
||||
INTERFACE_FUNCTION(__sanitizer_start_switch_fiber)
|
||||
INTERFACE_FUNCTION(__sanitizer_finish_switch_fiber)
|
||||
|
||||
// TODO(timurrrr): Add more interface functions on the as-needed basis.
|
||||
|
||||
// ----------------- Memory allocation functions ---------------------
|
||||
WRAP_V_W(free)
|
||||
WRAP_V_W(_free_base)
|
||||
WRAP_V_WW(_free_dbg)
|
||||
|
||||
WRAP_W_W(malloc)
|
||||
WRAP_W_W(_malloc_base)
|
||||
WRAP_W_WWWW(_malloc_dbg)
|
||||
|
||||
WRAP_W_WW(calloc)
|
||||
WRAP_W_WW(_calloc_base)
|
||||
WRAP_W_WWWWW(_calloc_dbg)
|
||||
WRAP_W_WWW(_calloc_impl)
|
||||
|
||||
WRAP_W_WW(realloc)
|
||||
WRAP_W_WW(_realloc_base)
|
||||
WRAP_W_WWW(_realloc_dbg)
|
||||
WRAP_W_WWW(_recalloc)
|
||||
|
||||
@ -371,6 +380,10 @@ WRAP_W_W(_expand_dbg)
|
||||
|
||||
INTERCEPT_LIBRARY_FUNCTION(atoi);
|
||||
INTERCEPT_LIBRARY_FUNCTION(atol);
|
||||
|
||||
#ifdef _WIN64
|
||||
INTERCEPT_LIBRARY_FUNCTION(__C_specific_handler);
|
||||
#else
|
||||
INTERCEPT_LIBRARY_FUNCTION(_except_handler3);
|
||||
|
||||
// _except_handler4 checks -GS cookie which is different for each module, so we
|
||||
@ -379,10 +392,13 @@ INTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) {
|
||||
__asan_handle_no_return();
|
||||
return REAL(_except_handler4)(a, b, c, d);
|
||||
}
|
||||
#endif
|
||||
|
||||
INTERCEPT_LIBRARY_FUNCTION(frexp);
|
||||
INTERCEPT_LIBRARY_FUNCTION(longjmp);
|
||||
#if SANITIZER_INTERCEPT_MEMCHR
|
||||
INTERCEPT_LIBRARY_FUNCTION(memchr);
|
||||
#endif
|
||||
INTERCEPT_LIBRARY_FUNCTION(memcmp);
|
||||
INTERCEPT_LIBRARY_FUNCTION(memcpy);
|
||||
INTERCEPT_LIBRARY_FUNCTION(memmove);
|
||||
@ -392,12 +408,14 @@ INTERCEPT_LIBRARY_FUNCTION(strchr);
|
||||
INTERCEPT_LIBRARY_FUNCTION(strcmp);
|
||||
INTERCEPT_LIBRARY_FUNCTION(strcpy); // NOLINT
|
||||
INTERCEPT_LIBRARY_FUNCTION(strcspn);
|
||||
INTERCEPT_LIBRARY_FUNCTION(strdup);
|
||||
INTERCEPT_LIBRARY_FUNCTION(strlen);
|
||||
INTERCEPT_LIBRARY_FUNCTION(strncat);
|
||||
INTERCEPT_LIBRARY_FUNCTION(strncmp);
|
||||
INTERCEPT_LIBRARY_FUNCTION(strncpy);
|
||||
INTERCEPT_LIBRARY_FUNCTION(strnlen);
|
||||
INTERCEPT_LIBRARY_FUNCTION(strpbrk);
|
||||
INTERCEPT_LIBRARY_FUNCTION(strrchr);
|
||||
INTERCEPT_LIBRARY_FUNCTION(strspn);
|
||||
INTERCEPT_LIBRARY_FUNCTION(strstr);
|
||||
INTERCEPT_LIBRARY_FUNCTION(strtol);
|
||||
@ -407,7 +425,9 @@ INTERCEPT_LIBRARY_FUNCTION(wcslen);
|
||||
// is defined.
|
||||
void InterceptHooks() {
|
||||
INTERCEPT_HOOKS();
|
||||
#ifndef _WIN64
|
||||
INTERCEPT_FUNCTION(_except_handler4);
|
||||
#endif
|
||||
}
|
||||
|
||||
// We want to call __asan_init before C/C++ initializers/constructors are
|
||||
|
@ -29,7 +29,7 @@
|
||||
|
||||
// First, declare CRT sections we'll be using in this file
|
||||
#pragma section(".CRT$XID", long, read) // NOLINT
|
||||
#pragma section(".CRT$XIZ", long, read) // NOLINT
|
||||
#pragma section(".CRT$XCAB", long, read) // NOLINT
|
||||
#pragma section(".CRT$XTW", long, read) // NOLINT
|
||||
#pragma section(".CRT$XTY", long, read) // NOLINT
|
||||
|
||||
@ -93,7 +93,8 @@ static int SetSEHFilter() { return __asan_set_seh_filter(); }
|
||||
|
||||
// Unfortunately, putting a pointer to __asan_set_seh_filter into
|
||||
// __asan_intercept_seh gets optimized out, so we have to use an extra function.
|
||||
__declspec(allocate(".CRT$XIZ")) int (*__asan_seh_interceptor)() = SetSEHFilter;
|
||||
__declspec(allocate(".CRT$XCAB")) int (*__asan_seh_interceptor)() =
|
||||
SetSEHFilter;
|
||||
}
|
||||
|
||||
#endif // ASAN_DYNAMIC_RUNTIME_THUNK
|
||||
|
@ -308,11 +308,18 @@ function generate_zygote_wrapper { # from, to, asan_rt
|
||||
local _from=$1
|
||||
local _to=$2
|
||||
local _asan_rt=$3
|
||||
if [[ PRE_L -eq 0 ]]; then
|
||||
# LD_PRELOAD parsing is broken in N if it starts with ":". Luckily, it is
|
||||
# unset in the system environment since L.
|
||||
local _ld_preload=$_asan_rt
|
||||
else
|
||||
local _ld_preload=\$LD_PRELOAD:$_asan_rt
|
||||
fi
|
||||
cat <<EOF >"$TMPDIR/$_from"
|
||||
#!/system/bin/sh-from-zygote
|
||||
ASAN_OPTIONS=$ASAN_OPTIONS \\
|
||||
ASAN_ACTIVATION_OPTIONS=include_if_exists=/data/local/tmp/asan.options.%b \\
|
||||
LD_PRELOAD=\$LD_PRELOAD:$_asan_rt \\
|
||||
LD_PRELOAD=$_ld_preload \\
|
||||
exec $_to \$@
|
||||
|
||||
EOF
|
||||
|
@ -21,7 +21,7 @@ set(ASAN_UNITTEST_HEADERS
|
||||
asan_test_utils.h)
|
||||
|
||||
set(ASAN_UNITTEST_COMMON_CFLAGS
|
||||
${COMPILER_RT_TEST_CFLAGS}
|
||||
${COMPILER_RT_UNITTEST_CFLAGS}
|
||||
${COMPILER_RT_GTEST_CFLAGS}
|
||||
-I${COMPILER_RT_SOURCE_DIR}/include
|
||||
-I${COMPILER_RT_SOURCE_DIR}/lib
|
||||
@ -34,12 +34,21 @@ set(ASAN_UNITTEST_COMMON_CFLAGS
|
||||
-Wno-non-virtual-dtor)
|
||||
append_list_if(COMPILER_RT_HAS_WVARIADIC_MACROS_FLAG -Wno-variadic-macros ASAN_UNITTEST_COMMON_CFLAGS)
|
||||
|
||||
# This will ensure the target linker is used
|
||||
# during cross compilation
|
||||
set(ASAN_UNITTEST_COMMON_LINKFLAGS
|
||||
${COMPILER_RT_UNITTEST_LINKFLAGS})
|
||||
|
||||
# -gline-tables-only must be enough for ASan, so use it if possible.
|
||||
if(COMPILER_RT_TEST_COMPILER_ID MATCHES "Clang")
|
||||
list(APPEND ASAN_UNITTEST_COMMON_CFLAGS -gline-tables-only)
|
||||
else()
|
||||
list(APPEND ASAN_UNITTEST_COMMON_CFLAGS -g)
|
||||
endif()
|
||||
if(MSVC)
|
||||
list(APPEND ASAN_UNITTEST_COMMON_CFLAGS -gcodeview)
|
||||
endif()
|
||||
list(APPEND ASAN_UNITTEST_COMMON_LINKFLAGS -g)
|
||||
|
||||
# Use -D instead of definitions to please custom compile command.
|
||||
list(APPEND ASAN_UNITTEST_COMMON_CFLAGS
|
||||
@ -114,7 +123,11 @@ append_list_if(ANDROID atomic ASAN_UNITTEST_NOINST_LIBS)
|
||||
# options in ${ARGN}, and add it to the object list.
|
||||
macro(asan_compile obj_list source arch kind)
|
||||
get_filename_component(basename ${source} NAME)
|
||||
set(output_obj "${obj_list}.${basename}.${arch}${kind}.o")
|
||||
if(CMAKE_CONFIGURATION_TYPES)
|
||||
set(output_obj "${CMAKE_CFG_INTDIR}/${obj_list}.${basename}.${arch}${kind}.o")
|
||||
else()
|
||||
set(output_obj "${obj_list}.${basename}.${arch}${kind}.o")
|
||||
endif()
|
||||
get_target_flags_for_arch(${arch} TARGET_CFLAGS)
|
||||
set(COMPILE_DEPS ${ASAN_UNITTEST_HEADERS} ${ASAN_BLACKLIST_FILE})
|
||||
if(NOT COMPILER_RT_STANDALONE_BUILD)
|
||||
@ -137,11 +150,17 @@ macro(add_asan_test test_suite test_name arch kind)
|
||||
endif()
|
||||
if(TEST_WITH_TEST_RUNTIME)
|
||||
list(APPEND TEST_DEPS ${ASAN_TEST_RUNTIME})
|
||||
if(NOT MSVC)
|
||||
list(APPEND TEST_OBJECTS lib${ASAN_TEST_RUNTIME}.a)
|
||||
if(CMAKE_CONFIGURATION_TYPES)
|
||||
set(configuration_path "${CMAKE_CFG_INTDIR}/")
|
||||
else()
|
||||
list(APPEND TEST_OBJECTS ${ASAN_TEST_RUNTIME}.lib)
|
||||
set(configuration_path "")
|
||||
endif()
|
||||
if(NOT MSVC)
|
||||
set(asan_test_runtime_path ${configuration_path}lib${ASAN_TEST_RUNTIME}.a)
|
||||
else()
|
||||
set(asan_test_runtime_path ${configuration_path}${ASAN_TEST_RUNTIME}.lib)
|
||||
endif()
|
||||
list(APPEND TEST_OBJECTS ${asan_test_runtime_path})
|
||||
endif()
|
||||
add_compiler_rt_test(${test_suite} ${test_name}
|
||||
SUBDIR ${TEST_SUBDIR}
|
||||
@ -153,15 +172,15 @@ endmacro()
|
||||
|
||||
# Main AddressSanitizer unit tests.
|
||||
add_custom_target(AsanUnitTests)
|
||||
set_target_properties(AsanUnitTests PROPERTIES FOLDER "ASan unit tests")
|
||||
set_target_properties(AsanUnitTests PROPERTIES FOLDER "Compiler-RT Tests")
|
||||
|
||||
# AddressSanitizer unit tests with dynamic runtime (on platforms where it's
|
||||
# not the default).
|
||||
add_custom_target(AsanDynamicUnitTests)
|
||||
set_target_properties(AsanDynamicUnitTests
|
||||
PROPERTIES FOLDER "ASan unit tests with dynamic runtime")
|
||||
set_target_properties(AsanDynamicUnitTests PROPERTIES FOLDER "Compiler-RT Tests")
|
||||
# ASan benchmarks (not actively used now).
|
||||
add_custom_target(AsanBenchmarks)
|
||||
set_target_properties(AsanBenchmarks PROPERTIES FOLDER "Asan benchmarks")
|
||||
set_target_properties(AsanBenchmarks PROPERTIES FOLDER "Compiler-RT Tests")
|
||||
|
||||
set(ASAN_NOINST_TEST_SOURCES
|
||||
${COMPILER_RT_GTEST_SOURCE}
|
||||
@ -200,13 +219,30 @@ macro(add_asan_tests_for_arch_and_kind arch kind)
|
||||
asan_compile(ASAN_INST_TEST_OBJECTS asan_mac_test_helpers.mm ${arch} ${kind}
|
||||
${ASAN_UNITTEST_INSTRUMENTED_CFLAGS} -ObjC ${ARGN})
|
||||
endif()
|
||||
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/default")
|
||||
|
||||
# Create the 'default' folder where ASAN tests are produced.
|
||||
if(CMAKE_CONFIGURATION_TYPES)
|
||||
foreach(build_mode ${CMAKE_CONFIGURATION_TYPES})
|
||||
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/default/${build_mode}")
|
||||
endforeach()
|
||||
else()
|
||||
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/default")
|
||||
endif()
|
||||
|
||||
add_asan_test(AsanUnitTests "Asan-${arch}${kind}-Test"
|
||||
${arch} ${kind} SUBDIR "default"
|
||||
OBJECTS ${ASAN_INST_TEST_OBJECTS}
|
||||
LINKFLAGS ${ASAN_UNITTEST_INSTRUMENTED_LINKFLAGS})
|
||||
if(COMPILER_RT_ASAN_HAS_STATIC_RUNTIME)
|
||||
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/dynamic")
|
||||
# Create the 'dynamic' folder where ASAN tests are produced.
|
||||
if(CMAKE_CONFIGURATION_TYPES)
|
||||
foreach(build_mode ${CMAKE_CONFIGURATION_TYPES})
|
||||
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/dynamic/${build_mode}")
|
||||
endforeach()
|
||||
else()
|
||||
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/dynamic")
|
||||
endif()
|
||||
|
||||
add_asan_test(AsanDynamicUnitTests "Asan-${arch}${kind}-Dynamic-Test"
|
||||
${arch} ${kind} SUBDIR "dynamic"
|
||||
OBJECTS ${ASAN_INST_TEST_OBJECTS}
|
||||
@ -236,7 +272,8 @@ macro(add_asan_tests_for_arch_and_kind arch kind)
|
||||
endif()
|
||||
add_library(${ASAN_TEST_RUNTIME} STATIC ${ASAN_TEST_RUNTIME_OBJECTS})
|
||||
set_target_properties(${ASAN_TEST_RUNTIME} PROPERTIES
|
||||
ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
FOLDER "Compiler-RT Runtime tests")
|
||||
# Uninstrumented tests.
|
||||
set(ASAN_NOINST_TEST_OBJECTS)
|
||||
foreach(src ${ASAN_NOINST_TEST_SOURCES})
|
||||
|
@ -34,7 +34,6 @@
|
||||
// Make sure __asan_init is called before any test case is run.
|
||||
struct AsanInitCaller {
|
||||
AsanInitCaller() {
|
||||
DisableReexec();
|
||||
__asan_init();
|
||||
}
|
||||
};
|
||||
|
@ -20,10 +20,41 @@
|
||||
static char global_string[] = "global";
|
||||
static size_t global_string_length = 6;
|
||||
|
||||
const char kStackReadUnderflow[] =
|
||||
#if !GTEST_USES_SIMPLE_RE
|
||||
ASAN_PCRE_DOTALL
|
||||
"READ.*"
|
||||
#endif
|
||||
"underflows this variable";
|
||||
const char kStackReadOverflow[] =
|
||||
#if !GTEST_USES_SIMPLE_RE
|
||||
ASAN_PCRE_DOTALL
|
||||
"READ.*"
|
||||
#endif
|
||||
"overflows this variable";
|
||||
|
||||
namespace {
|
||||
enum class OOBKind {
|
||||
Heap,
|
||||
Stack,
|
||||
Global,
|
||||
};
|
||||
|
||||
string LeftOOBReadMessage(OOBKind oob_kind, int oob_distance) {
|
||||
return oob_kind == OOBKind::Stack ? kStackReadUnderflow
|
||||
: ::LeftOOBReadMessage(oob_distance);
|
||||
}
|
||||
|
||||
string RightOOBReadMessage(OOBKind oob_kind, int oob_distance) {
|
||||
return oob_kind == OOBKind::Stack ? kStackReadOverflow
|
||||
: ::RightOOBReadMessage(oob_distance);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
// Input to a test is a zero-terminated string str with given length
|
||||
// Accesses to the bytes to the left and to the right of str
|
||||
// are presumed to produce OOB errors
|
||||
void StrLenOOBTestTemplate(char *str, size_t length, bool is_global) {
|
||||
void StrLenOOBTestTemplate(char *str, size_t length, OOBKind oob_kind) {
|
||||
// Normal strlen calls
|
||||
EXPECT_EQ(strlen(str), length);
|
||||
if (length > 0) {
|
||||
@ -31,17 +62,18 @@ void StrLenOOBTestTemplate(char *str, size_t length, bool is_global) {
|
||||
EXPECT_EQ(0U, strlen(str + length));
|
||||
}
|
||||
// Arg of strlen is not malloced, OOB access
|
||||
if (!is_global) {
|
||||
if (oob_kind != OOBKind::Global) {
|
||||
// We don't insert RedZones to the left of global variables
|
||||
EXPECT_DEATH(Ident(strlen(str - 1)), LeftOOBReadMessage(1));
|
||||
EXPECT_DEATH(Ident(strlen(str - 5)), LeftOOBReadMessage(5));
|
||||
EXPECT_DEATH(Ident(strlen(str - 1)), LeftOOBReadMessage(oob_kind, 1));
|
||||
EXPECT_DEATH(Ident(strlen(str - 5)), LeftOOBReadMessage(oob_kind, 5));
|
||||
}
|
||||
EXPECT_DEATH(Ident(strlen(str + length + 1)), RightOOBReadMessage(0));
|
||||
EXPECT_DEATH(Ident(strlen(str + length + 1)),
|
||||
RightOOBReadMessage(oob_kind, 0));
|
||||
// Overwrite terminator
|
||||
str[length] = 'a';
|
||||
// String is not zero-terminated, strlen will lead to OOB access
|
||||
EXPECT_DEATH(Ident(strlen(str)), RightOOBReadMessage(0));
|
||||
EXPECT_DEATH(Ident(strlen(str + length)), RightOOBReadMessage(0));
|
||||
EXPECT_DEATH(Ident(strlen(str)), RightOOBReadMessage(oob_kind, 0));
|
||||
EXPECT_DEATH(Ident(strlen(str + length)), RightOOBReadMessage(oob_kind, 0));
|
||||
// Restore terminator
|
||||
str[length] = 0;
|
||||
}
|
||||
@ -57,11 +89,9 @@ TEST(AddressSanitizer, StrLenOOBTest) {
|
||||
}
|
||||
heap_string[length] = 0;
|
||||
stack_string[length] = 0;
|
||||
StrLenOOBTestTemplate(heap_string, length, false);
|
||||
// TODO(samsonov): Fix expected messages in StrLenOOBTestTemplate to
|
||||
// make test for stack_string work. Or move it to output tests.
|
||||
// StrLenOOBTestTemplate(stack_string, length, false);
|
||||
StrLenOOBTestTemplate(global_string, global_string_length, true);
|
||||
StrLenOOBTestTemplate(heap_string, length, OOBKind::Heap);
|
||||
StrLenOOBTestTemplate(stack_string, length, OOBKind::Stack);
|
||||
StrLenOOBTestTemplate(global_string, global_string_length, OOBKind::Global);
|
||||
free(heap_string);
|
||||
}
|
||||
|
||||
@ -186,23 +216,8 @@ TEST(AddressSanitizer, StrNCpyOOBTest) {
|
||||
typedef char*(*PointerToStrChr1)(const char*, int);
|
||||
typedef char*(*PointerToStrChr2)(char*, int);
|
||||
|
||||
UNUSED static void RunStrChrTest(PointerToStrChr1 StrChr) {
|
||||
size_t size = Ident(100);
|
||||
char *str = MallocAndMemsetString(size);
|
||||
str[10] = 'q';
|
||||
str[11] = '\0';
|
||||
EXPECT_EQ(str, StrChr(str, 'z'));
|
||||
EXPECT_EQ(str + 10, StrChr(str, 'q'));
|
||||
EXPECT_EQ(NULL, StrChr(str, 'a'));
|
||||
// StrChr argument points to not allocated memory.
|
||||
EXPECT_DEATH(Ident(StrChr(str - 1, 'z')), LeftOOBReadMessage(1));
|
||||
EXPECT_DEATH(Ident(StrChr(str + size, 'z')), RightOOBReadMessage(0));
|
||||
// Overwrite the terminator and hit not allocated memory.
|
||||
str[11] = 'z';
|
||||
EXPECT_DEATH(Ident(StrChr(str, 'a')), RightOOBReadMessage(0));
|
||||
free(str);
|
||||
}
|
||||
UNUSED static void RunStrChrTest(PointerToStrChr2 StrChr) {
|
||||
template<typename StrChrFn>
|
||||
static void RunStrChrTestImpl(StrChrFn *StrChr) {
|
||||
size_t size = Ident(100);
|
||||
char *str = MallocAndMemsetString(size);
|
||||
str[10] = 'q';
|
||||
@ -219,11 +234,19 @@ UNUSED static void RunStrChrTest(PointerToStrChr2 StrChr) {
|
||||
free(str);
|
||||
}
|
||||
|
||||
// Prefer to use the standard signature if both are available.
|
||||
UNUSED static void RunStrChrTest(PointerToStrChr1 StrChr, ...) {
|
||||
RunStrChrTestImpl(StrChr);
|
||||
}
|
||||
UNUSED static void RunStrChrTest(PointerToStrChr2 StrChr, int) {
|
||||
RunStrChrTestImpl(StrChr);
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, StrChrAndIndexOOBTest) {
|
||||
RunStrChrTest(&strchr);
|
||||
RunStrChrTest(&strchr, 0);
|
||||
// No index() on Windows and on Android L.
|
||||
#if !defined(_WIN32) && !defined(__ANDROID__)
|
||||
RunStrChrTest(&index);
|
||||
RunStrChrTest(&index, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -300,6 +300,7 @@ TEST(AddressSanitizer, LargeMallocTest) {
|
||||
}
|
||||
}
|
||||
|
||||
#if !GTEST_USES_SIMPLE_RE
|
||||
TEST(AddressSanitizer, HugeMallocTest) {
|
||||
if (SANITIZER_WORDSIZE != 64 || ASAN_AVOID_EXPENSIVE_TESTS) return;
|
||||
size_t n_megs = 4100;
|
||||
@ -307,6 +308,7 @@ TEST(AddressSanitizer, HugeMallocTest) {
|
||||
"is located 1 bytes to the left|"
|
||||
"AddressSanitizer failed to allocate");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SANITIZER_TEST_HAS_MEMALIGN
|
||||
void MemalignRun(size_t align, size_t size, int idx) {
|
||||
@ -595,9 +597,8 @@ NOINLINE void SigLongJmpFunc1(sigjmp_buf buf) {
|
||||
}
|
||||
|
||||
#if !defined(__ANDROID__) && !defined(__arm__) && \
|
||||
!defined(__powerpc64__) && !defined(__powerpc__) && \
|
||||
!defined(__aarch64__) && !defined(__mips__) && \
|
||||
!defined(__mips64)
|
||||
!defined(__mips64) && !defined(__s390__)
|
||||
NOINLINE void BuiltinLongJmpFunc1(jmp_buf buf) {
|
||||
// create three red zones for these two stack objects.
|
||||
int a;
|
||||
@ -609,7 +610,7 @@ NOINLINE void BuiltinLongJmpFunc1(jmp_buf buf) {
|
||||
__builtin_longjmp((void**)buf, 1);
|
||||
}
|
||||
|
||||
// Does not work on Power and ARM:
|
||||
// Does not work on ARM:
|
||||
// https://github.com/google/sanitizers/issues/185
|
||||
TEST(AddressSanitizer, BuiltinLongJmpTest) {
|
||||
static jmp_buf buf;
|
||||
@ -619,9 +620,9 @@ TEST(AddressSanitizer, BuiltinLongJmpTest) {
|
||||
TouchStackFunc();
|
||||
}
|
||||
}
|
||||
#endif // !defined(__ANDROID__) && !defined(__powerpc64__) &&
|
||||
// !defined(__powerpc__) && !defined(__arm__) &&
|
||||
// !defined(__mips__) && !defined(__mips64)
|
||||
#endif // !defined(__ANDROID__) && !defined(__arm__) &&
|
||||
// !defined(__aarch64__) && !defined(__mips__)
|
||||
// !defined(__mips64) && !defined(__s390__)
|
||||
|
||||
TEST(AddressSanitizer, UnderscopeLongJmpTest) {
|
||||
static jmp_buf buf;
|
||||
@ -809,9 +810,6 @@ TEST(AddressSanitizer, DISABLED_MemIntrinsicUnalignedAccessTest) {
|
||||
free(s);
|
||||
}
|
||||
|
||||
// TODO(samsonov): Add a test with malloc(0)
|
||||
// TODO(samsonov): Add tests for str* and mem* functions.
|
||||
|
||||
NOINLINE static int LargeFunction(bool do_bad_access) {
|
||||
int *x = new int[100];
|
||||
x[0]++;
|
||||
@ -941,6 +939,8 @@ TEST(AddressSanitizer, ShadowGapTest) {
|
||||
#else
|
||||
# if defined(__powerpc64__)
|
||||
char *addr = (char*)0x024000800000;
|
||||
# elif defined(__s390x__)
|
||||
char *addr = (char*)0x11000000000000;
|
||||
# else
|
||||
char *addr = (char*)0x0000100000080000;
|
||||
# endif
|
||||
@ -1166,15 +1166,21 @@ static string MismatchStr(const string &str) {
|
||||
return string("AddressSanitizer: alloc-dealloc-mismatch \\(") + str;
|
||||
}
|
||||
|
||||
static string MismatchOrNewDeleteTypeStr(const string &mismatch_str) {
|
||||
return "(" + MismatchStr(mismatch_str) +
|
||||
")|(AddressSanitizer: new-delete-type-mismatch)";
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, AllocDeallocMismatch) {
|
||||
EXPECT_DEATH(free(Ident(new int)),
|
||||
MismatchStr("operator new vs free"));
|
||||
EXPECT_DEATH(free(Ident(new int[2])),
|
||||
MismatchStr("operator new \\[\\] vs free"));
|
||||
EXPECT_DEATH(delete (Ident(new int[2])),
|
||||
MismatchStr("operator new \\[\\] vs operator delete"));
|
||||
EXPECT_DEATH(delete (Ident((int*)malloc(2 * sizeof(int)))),
|
||||
MismatchStr("malloc vs operator delete"));
|
||||
EXPECT_DEATH(
|
||||
delete (Ident(new int[2])),
|
||||
MismatchOrNewDeleteTypeStr("operator new \\[\\] vs operator delete"));
|
||||
EXPECT_DEATH(delete (Ident((int *)malloc(2 * sizeof(int)))),
|
||||
MismatchOrNewDeleteTypeStr("malloc vs operator delete"));
|
||||
EXPECT_DEATH(delete [] (Ident(new int)),
|
||||
MismatchStr("operator new vs operator delete \\[\\]"));
|
||||
EXPECT_DEATH(delete [] (Ident((int*)malloc(2 * sizeof(int)))),
|
||||
|
@ -26,6 +26,12 @@ extern "C" const char* __asan_default_options() {
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace __sanitizer {
|
||||
bool ReexecDisabled() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
testing::GTEST_FLAG(death_test_style) = "threadsafe";
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
|
@ -2,9 +2,27 @@
|
||||
# generic implementations of the core runtime library along with optimized
|
||||
# architecture-specific code in various subdirectories.
|
||||
|
||||
if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
|
||||
cmake_minimum_required(VERSION 3.4.3)
|
||||
|
||||
project(CompilerRTBuiltins C ASM)
|
||||
set(COMPILER_RT_STANDALONE_BUILD TRUE)
|
||||
set(COMPILER_RT_BUILTINS_STANDALONE_BUILD TRUE)
|
||||
list(INSERT CMAKE_MODULE_PATH 0
|
||||
"${CMAKE_SOURCE_DIR}/../../cmake"
|
||||
"${CMAKE_SOURCE_DIR}/../../cmake/Modules")
|
||||
include(base-config-ix)
|
||||
include(CompilerRTUtils)
|
||||
if(APPLE)
|
||||
include(CompilerRTDarwinUtils)
|
||||
endif()
|
||||
include(AddCompilerRT)
|
||||
endif()
|
||||
|
||||
include(builtin-config-ix)
|
||||
|
||||
# TODO: Need to add a mechanism for logging errors when builtin source files are
|
||||
# added to a sub-directory and not this CMakeLists file.
|
||||
|
||||
set(GENERIC_SOURCES
|
||||
absvdi2.c
|
||||
absvsi2.c
|
||||
@ -30,6 +48,7 @@ set(GENERIC_SOURCES
|
||||
cmpti2.c
|
||||
comparedf2.c
|
||||
comparesf2.c
|
||||
cpu_model.c
|
||||
ctzdi2.c
|
||||
ctzsi2.c
|
||||
ctzti2.c
|
||||
@ -143,6 +162,15 @@ set(GENERIC_SOURCES
|
||||
umodsi3.c
|
||||
umodti3.c)
|
||||
|
||||
set(MSVC_SOURCES
|
||||
divsc3.c
|
||||
divdc3.c
|
||||
divxc3.c
|
||||
mulsc3.c
|
||||
muldc3.c
|
||||
mulxc3.c)
|
||||
|
||||
|
||||
if(APPLE)
|
||||
set(GENERIC_SOURCES
|
||||
${GENERIC_SOURCES}
|
||||
@ -216,14 +244,15 @@ if (NOT MSVC)
|
||||
${i386_SOURCES})
|
||||
else () # MSVC
|
||||
# Use C versions of functions when building on MSVC
|
||||
# MSVC's assembler takes Intel syntax, not AT&T syntax
|
||||
# MSVC's assembler takes Intel syntax, not AT&T syntax.
|
||||
# Also use only MSVC compilable builtin implementations.
|
||||
set(x86_64_SOURCES
|
||||
x86_64/floatdidf.c
|
||||
x86_64/floatdisf.c
|
||||
x86_64/floatdixf.c
|
||||
${GENERIC_SOURCES})
|
||||
${MSVC_SOURCES})
|
||||
set(x86_64h_SOURCES ${x86_64_SOURCES})
|
||||
set(i386_SOURCES ${GENERIC_SOURCES})
|
||||
set(i386_SOURCES ${MSVC_SOURCES})
|
||||
set(i686_SOURCES ${i386_SOURCES})
|
||||
endif () # if (NOT MSVC)
|
||||
|
||||
@ -341,6 +370,7 @@ set(aarch64_SOURCES
|
||||
set(armhf_SOURCES ${arm_SOURCES})
|
||||
set(armv7_SOURCES ${arm_SOURCES})
|
||||
set(armv7s_SOURCES ${arm_SOURCES})
|
||||
set(armv7k_SOURCES ${arm_SOURCES})
|
||||
set(arm64_SOURCES ${aarch64_SOURCES})
|
||||
|
||||
# macho_embedded archs
|
||||
@ -357,13 +387,14 @@ set(wasm32_SOURCES ${GENERIC_SOURCES})
|
||||
set(wasm64_SOURCES ${GENERIC_SOURCES})
|
||||
|
||||
add_custom_target(builtins)
|
||||
set_target_properties(builtins PROPERTIES FOLDER "Compiler-RT Misc")
|
||||
|
||||
if (APPLE)
|
||||
add_subdirectory(Darwin-excludes)
|
||||
add_subdirectory(macho_embedded)
|
||||
darwin_add_builtin_libraries(${BUILTIN_SUPPORTED_OS})
|
||||
elseif (NOT WIN32 OR MINGW)
|
||||
append_string_if(COMPILER_RT_HAS_STD_C99_FLAG -std=c99 maybe_stdc99)
|
||||
else ()
|
||||
append_string_if(COMPILER_RT_HAS_STD_C99_FLAG -std=gnu99 maybe_stdc99)
|
||||
|
||||
foreach (arch ${BUILTIN_SUPPORTED_ARCH})
|
||||
if (CAN_TARGET_${arch})
|
||||
|
@ -1,35 +0,0 @@
|
||||
absvti2
|
||||
addvti3
|
||||
ashlti3
|
||||
ashrti3
|
||||
clzti2
|
||||
cmpti2
|
||||
ctzti2
|
||||
divti3
|
||||
ffsti2
|
||||
fixdfti
|
||||
fixsfti
|
||||
fixunsdfti
|
||||
fixunssfti
|
||||
fixunsxfti
|
||||
fixxfti
|
||||
floattidf
|
||||
floattisf
|
||||
floattixf
|
||||
floatuntidf
|
||||
floatuntisf
|
||||
floatuntixf
|
||||
lshrti3
|
||||
modti3
|
||||
muloti4
|
||||
multi3
|
||||
mulvti3
|
||||
negti2
|
||||
negvti2
|
||||
parityti2
|
||||
popcountti2
|
||||
subvti3
|
||||
ucmpti2
|
||||
udivmodti4
|
||||
udivti3
|
||||
umodti3
|
@ -1,18 +1,34 @@
|
||||
apple_versioning
|
||||
absvdi2
|
||||
absvsi2
|
||||
absvti2
|
||||
adddf3
|
||||
addsf3
|
||||
addtf3
|
||||
addvdi3
|
||||
addvsi3
|
||||
addvti3
|
||||
apple_versioning
|
||||
ashldi3
|
||||
ashlti3
|
||||
ashrdi3
|
||||
ashrti3
|
||||
atomic_flag_clear
|
||||
atomic_flag_clear_explicit
|
||||
atomic_flag_test_and_set
|
||||
atomic_flag_test_and_set_explicit
|
||||
atomic_signal_fence
|
||||
atomic_thread_fence
|
||||
clear_cache
|
||||
clzdi2
|
||||
clzsi2
|
||||
clzti2
|
||||
cmpdi2
|
||||
cmpti2
|
||||
comparedf2
|
||||
comparesf2
|
||||
ctzdi2
|
||||
ctzsi2
|
||||
ctzti2
|
||||
divdc3
|
||||
divdf3
|
||||
divdi3
|
||||
@ -21,76 +37,101 @@ divmodsi4
|
||||
divsc3
|
||||
divsf3
|
||||
divsi3
|
||||
divtf3
|
||||
divti3
|
||||
divxc3
|
||||
enable_execute_stack
|
||||
comparedf2
|
||||
comparesf2
|
||||
extendhfsf2
|
||||
extendsfdf2
|
||||
ffsdi2
|
||||
ffsti2
|
||||
fixdfdi
|
||||
fixdfsi
|
||||
fixdfti
|
||||
fixsfdi
|
||||
fixsfsi
|
||||
fixsfti
|
||||
fixunsdfdi
|
||||
fixunsdfsi
|
||||
fixunsdfti
|
||||
fixunssfdi
|
||||
fixunssfsi
|
||||
fixunssfti
|
||||
fixunsxfdi
|
||||
fixunsxfsi
|
||||
fixunsxfti
|
||||
fixxfdi
|
||||
fixxfti
|
||||
floatdidf
|
||||
floatdisf
|
||||
floatdixf
|
||||
floatsidf
|
||||
floatsisf
|
||||
floattidf
|
||||
floattisf
|
||||
floattixf
|
||||
floatunsidf
|
||||
floatunsisf
|
||||
floatuntidf
|
||||
floatuntisf
|
||||
floatuntixf
|
||||
gcc_personality_v0
|
||||
gnu_f2h_ieee
|
||||
gnu_h2f_ieee
|
||||
lshrdi3
|
||||
lshrti3
|
||||
moddi3
|
||||
modsi3
|
||||
modti3
|
||||
muldc3
|
||||
muldf3
|
||||
muldi3
|
||||
mulodi4
|
||||
mulosi4
|
||||
muloti4
|
||||
mulsc3
|
||||
mulsf3
|
||||
multf3
|
||||
multi3
|
||||
mulvdi3
|
||||
mulvsi3
|
||||
mulvti3
|
||||
mulxc3
|
||||
negdf2
|
||||
negdi2
|
||||
negsf2
|
||||
negti2
|
||||
negvdi2
|
||||
negvsi2
|
||||
negvti2
|
||||
paritydi2
|
||||
paritysi2
|
||||
parityti2
|
||||
popcountdi2
|
||||
popcountsi2
|
||||
popcountti2
|
||||
powidf2
|
||||
powisf2
|
||||
powitf2
|
||||
powixf2
|
||||
subdf3
|
||||
subsf3
|
||||
subtf3
|
||||
subvdi3
|
||||
subvsi3
|
||||
subvti3
|
||||
trampoline_setup
|
||||
truncdfhf2
|
||||
truncdfsf2
|
||||
truncsfhf2
|
||||
ucmpdi2
|
||||
ucmpti2
|
||||
udivdi3
|
||||
udivmoddi4
|
||||
udivmodsi4
|
||||
udivmodti4
|
||||
udivsi3
|
||||
udivti3
|
||||
umoddi3
|
||||
umodsi3
|
||||
atomic_flag_clear
|
||||
atomic_flag_clear_explicit
|
||||
atomic_flag_test_and_set
|
||||
atomic_flag_test_and_set_explicit
|
||||
atomic_signal_fence
|
||||
atomic_thread_fence
|
||||
umodti3
|
||||
|
@ -1,5 +1,4 @@
|
||||
absvti2
|
||||
addtf3
|
||||
addvti3
|
||||
ashlti3
|
||||
ashrti3
|
||||
@ -7,7 +6,6 @@ clzti2
|
||||
cmpti2
|
||||
ctzti2
|
||||
divti3
|
||||
divtf3
|
||||
ffsti2
|
||||
fixdfti
|
||||
fixsfti
|
||||
@ -25,57 +23,12 @@ lshrti3
|
||||
modti3
|
||||
muloti4
|
||||
multi3
|
||||
multf3
|
||||
mulvti3
|
||||
negti2
|
||||
negvti2
|
||||
parityti2
|
||||
popcountti2
|
||||
powitf2
|
||||
subvti3
|
||||
subtf3
|
||||
trampoline_setup
|
||||
ucmpti2
|
||||
udivmodti4
|
||||
udivti3
|
||||
umodti3
|
||||
absvti2
|
||||
addtf3
|
||||
addvti3
|
||||
ashlti3
|
||||
ashrti3
|
||||
clzti2
|
||||
cmpti2
|
||||
ctzti2
|
||||
divti3
|
||||
divtf3
|
||||
ffsti2
|
||||
fixdfti
|
||||
fixsfti
|
||||
fixunsdfti
|
||||
fixunssfti
|
||||
fixunsxfti
|
||||
fixxfti
|
||||
floattidf
|
||||
floattisf
|
||||
floattixf
|
||||
floatuntidf
|
||||
floatuntisf
|
||||
floatuntixf
|
||||
lshrti3
|
||||
modti3
|
||||
muloti4
|
||||
multi3
|
||||
multf3
|
||||
mulvti3
|
||||
negti2
|
||||
negvti2
|
||||
parityti2
|
||||
popcountti2
|
||||
powitf2
|
||||
subvti3
|
||||
subtf3
|
||||
trampoline_setup
|
||||
ucmpti2
|
||||
udivmodti4
|
||||
udivti3
|
||||
|
@ -1,12 +0,0 @@
|
||||
addtf3
|
||||
divtf3
|
||||
multf3
|
||||
powitf2
|
||||
subtf3
|
||||
trampoline_setup
|
||||
addtf3
|
||||
divtf3
|
||||
multf3
|
||||
powitf2
|
||||
subtf3
|
||||
trampoline_setup
|
@ -1 +1,7 @@
|
||||
apple_versioning
|
||||
addtf3
|
||||
divtf3
|
||||
multf3
|
||||
powitf2
|
||||
subtf3
|
||||
trampoline_setup
|
||||
|
@ -24,3 +24,6 @@ DEFINE_COMPILERRT_FUNCTION(__adddf3vfp)
|
||||
vmov r0, r1, d6 // move result back to r0/r1 pair
|
||||
bx lr
|
||||
END_COMPILERRT_FUNCTION(__adddf3vfp)
|
||||
|
||||
NO_EXEC_STACK_DIRECTIVE
|
||||
|
||||
|
@ -24,3 +24,6 @@ DEFINE_COMPILERRT_FUNCTION(__addsf3vfp)
|
||||
vmov r0, s14 // move result back to r0
|
||||
bx lr
|
||||
END_COMPILERRT_FUNCTION(__addsf3vfp)
|
||||
|
||||
NO_EXEC_STACK_DIRECTIVE
|
||||
|
||||
|
@ -94,3 +94,5 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cdrcmple)
|
||||
b __aeabi_cdcmple
|
||||
END_COMPILERRT_FUNCTION(__aeabi_cdrcmple)
|
||||
|
||||
NO_EXEC_STACK_DIRECTIVE
|
||||
|
||||
|
@ -89,3 +89,5 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cfrcmple)
|
||||
b __aeabi_cfcmple
|
||||
END_COMPILERRT_FUNCTION(__aeabi_cfrcmple)
|
||||
|
||||
NO_EXEC_STACK_DIRECTIVE
|
||||
|
||||
|
@ -38,3 +38,6 @@ DEFINE_AEABI_DCMP(lt)
|
||||
DEFINE_AEABI_DCMP(le)
|
||||
DEFINE_AEABI_DCMP(ge)
|
||||
DEFINE_AEABI_DCMP(gt)
|
||||
|
||||
NO_EXEC_STACK_DIRECTIVE
|
||||
|
||||
|
@ -38,3 +38,6 @@ DEFINE_AEABI_FCMP(lt)
|
||||
DEFINE_AEABI_FCMP(le)
|
||||
DEFINE_AEABI_FCMP(ge)
|
||||
DEFINE_AEABI_FCMP(gt)
|
||||
|
||||
NO_EXEC_STACK_DIRECTIVE
|
||||
|
||||
|
@ -26,3 +26,6 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_idivmod)
|
||||
add sp, sp, #4
|
||||
pop { pc }
|
||||
END_COMPILERRT_FUNCTION(__aeabi_idivmod)
|
||||
|
||||
NO_EXEC_STACK_DIRECTIVE
|
||||
|
||||
|
@ -29,3 +29,6 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_ldivmod)
|
||||
add sp, sp, #16
|
||||
pop {r11, pc}
|
||||
END_COMPILERRT_FUNCTION(__aeabi_ldivmod)
|
||||
|
||||
NO_EXEC_STACK_DIRECTIVE
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
// void __aeabi_memcmp(void *dest, void *src, size_t n) { memcmp(dest, src, n); }
|
||||
|
||||
.syntax unified
|
||||
.p2align 2
|
||||
DEFINE_COMPILERRT_FUNCTION(__aeabi_memcmp)
|
||||
b memcmp
|
||||
@ -18,3 +19,6 @@ END_COMPILERRT_FUNCTION(__aeabi_memcmp)
|
||||
|
||||
DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memcmp4, __aeabi_memcmp)
|
||||
DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memcmp8, __aeabi_memcmp)
|
||||
|
||||
NO_EXEC_STACK_DIRECTIVE
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
// void __aeabi_memcpy(void *dest, void *src, size_t n) { memcpy(dest, src, n); }
|
||||
|
||||
.syntax unified
|
||||
.p2align 2
|
||||
DEFINE_COMPILERRT_FUNCTION(__aeabi_memcpy)
|
||||
b memcpy
|
||||
@ -18,3 +19,6 @@ END_COMPILERRT_FUNCTION(__aeabi_memcpy)
|
||||
|
||||
DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memcpy4, __aeabi_memcpy)
|
||||
DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memcpy8, __aeabi_memcpy)
|
||||
|
||||
NO_EXEC_STACK_DIRECTIVE
|
||||
|
||||
|
@ -18,3 +18,6 @@ END_COMPILERRT_FUNCTION(__aeabi_memmove)
|
||||
|
||||
DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memmove4, __aeabi_memmove)
|
||||
DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memmove8, __aeabi_memmove)
|
||||
|
||||
NO_EXEC_STACK_DIRECTIVE
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
// void __aeabi_memset(void *dest, size_t n, int c) { memset(dest, c, n); }
|
||||
// void __aeabi_memclr(void *dest, size_t n) { __aeabi_memset(dest, n, 0); }
|
||||
|
||||
.syntax unified
|
||||
.p2align 2
|
||||
DEFINE_COMPILERRT_FUNCTION(__aeabi_memset)
|
||||
mov r3, r1
|
||||
@ -32,3 +33,5 @@ END_COMPILERRT_FUNCTION(__aeabi_memclr)
|
||||
DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memclr4, __aeabi_memclr)
|
||||
DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memclr8, __aeabi_memclr)
|
||||
|
||||
NO_EXEC_STACK_DIRECTIVE
|
||||
|
||||
|
@ -27,3 +27,6 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_uidivmod)
|
||||
add sp, sp, #4
|
||||
pop { pc }
|
||||
END_COMPILERRT_FUNCTION(__aeabi_uidivmod)
|
||||
|
||||
NO_EXEC_STACK_DIRECTIVE
|
||||
|
||||
|
@ -29,3 +29,6 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_uldivmod)
|
||||
add sp, sp, #16
|
||||
pop {r11, pc}
|
||||
END_COMPILERRT_FUNCTION(__aeabi_uldivmod)
|
||||
|
||||
NO_EXEC_STACK_DIRECTIVE
|
||||
|
||||
|
@ -45,3 +45,6 @@ DEFINE_COMPILERRT_FUNCTION(__bswapdi2)
|
||||
mov r1, r2 // r1 = r2 = rev(r0)
|
||||
JMP(lr)
|
||||
END_COMPILERRT_FUNCTION(__bswapdi2)
|
||||
|
||||
NO_EXEC_STACK_DIRECTIVE
|
||||
|
||||
|
@ -37,3 +37,6 @@ DEFINE_COMPILERRT_FUNCTION(__bswapsi2)
|
||||
#endif
|
||||
JMP(lr)
|
||||
END_COMPILERRT_FUNCTION(__bswapsi2)
|
||||
|
||||
NO_EXEC_STACK_DIRECTIVE
|
||||
|
||||
|
@ -95,3 +95,6 @@ DEFINE_COMPILERRT_FUNCTION(__clzdi2)
|
||||
JMP(lr)
|
||||
#endif // __ARM_FEATURE_CLZ
|
||||
END_COMPILERRT_FUNCTION(__clzdi2)
|
||||
|
||||
NO_EXEC_STACK_DIRECTIVE
|
||||
|
||||
|
@ -74,3 +74,6 @@ DEFINE_COMPILERRT_FUNCTION(__clzsi2)
|
||||
JMP(lr)
|
||||
#endif // __ARM_FEATURE_CLZ
|
||||
END_COMPILERRT_FUNCTION(__clzsi2)
|
||||
|
||||
NO_EXEC_STACK_DIRECTIVE
|
||||
|
||||
|
@ -146,3 +146,6 @@ DEFINE_COMPILERRT_FUNCTION(__unordsf2)
|
||||
END_COMPILERRT_FUNCTION(__unordsf2)
|
||||
|
||||
DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_fcmpun, __unordsf2)
|
||||
|
||||
NO_EXEC_STACK_DIRECTIVE
|
||||
|
||||
|
@ -24,3 +24,6 @@ DEFINE_COMPILERRT_FUNCTION(__divdf3vfp)
|
||||
vmov r0, r1, d5 // move result back to r0/r1 pair
|
||||
bx lr
|
||||
END_COMPILERRT_FUNCTION(__divdf3vfp)
|
||||
|
||||
NO_EXEC_STACK_DIRECTIVE
|
||||
|
||||
|
@ -72,3 +72,6 @@ LOCAL_LABEL(divzero):
|
||||
CLEAR_FRAME_AND_RETURN
|
||||
#endif
|
||||
END_COMPILERRT_FUNCTION(__divmodsi4)
|
||||
|
||||
NO_EXEC_STACK_DIRECTIVE
|
||||
|
||||
|
@ -24,3 +24,6 @@ DEFINE_COMPILERRT_FUNCTION(__divsf3vfp)
|
||||
vmov r0, s13 // move result back to r0
|
||||
bx lr
|
||||
END_COMPILERRT_FUNCTION(__divsf3vfp)
|
||||
|
||||
NO_EXEC_STACK_DIRECTIVE
|
||||
|
||||
|
@ -63,3 +63,6 @@ ESTABLISH_FRAME
|
||||
CLEAR_FRAME_AND_RETURN
|
||||
#endif
|
||||
END_COMPILERRT_FUNCTION(__divsi3)
|
||||
|
||||
NO_EXEC_STACK_DIRECTIVE
|
||||
|
||||
|
@ -27,3 +27,6 @@ DEFINE_COMPILERRT_FUNCTION(__eqdf2vfp)
|
||||
movne r0, #0
|
||||
bx lr
|
||||
END_COMPILERRT_FUNCTION(__eqdf2vfp)
|
||||
|
||||
NO_EXEC_STACK_DIRECTIVE
|
||||
|
||||
|
@ -27,3 +27,6 @@ DEFINE_COMPILERRT_FUNCTION(__eqsf2vfp)
|
||||
movne r0, #0
|
||||
bx lr
|
||||
END_COMPILERRT_FUNCTION(__eqsf2vfp)
|
||||
|
||||
NO_EXEC_STACK_DIRECTIVE
|
||||
|
||||
|
@ -24,3 +24,6 @@ DEFINE_COMPILERRT_FUNCTION(__extendsfdf2vfp)
|
||||
vmov r0, r1, d7 // return result in r0/r1 pair
|
||||
bx lr
|
||||
END_COMPILERRT_FUNCTION(__extendsfdf2vfp)
|
||||
|
||||
NO_EXEC_STACK_DIRECTIVE
|
||||
|
||||
|
@ -24,3 +24,6 @@ DEFINE_COMPILERRT_FUNCTION(__fixdfsivfp)
|
||||
vmov r0, s15 // move s15 to result register
|
||||
bx lr
|
||||
END_COMPILERRT_FUNCTION(__fixdfsivfp)
|
||||
|
||||
NO_EXEC_STACK_DIRECTIVE
|
||||
|
||||
|
@ -24,3 +24,6 @@ DEFINE_COMPILERRT_FUNCTION(__fixsfsivfp)
|
||||
vmov r0, s15 // move s15 to result register
|
||||
bx lr
|
||||
END_COMPILERRT_FUNCTION(__fixsfsivfp)
|
||||
|
||||
NO_EXEC_STACK_DIRECTIVE
|
||||
|
||||
|
@ -25,3 +25,6 @@ DEFINE_COMPILERRT_FUNCTION(__fixunsdfsivfp)
|
||||
vmov r0, s15 // move s15 to result register
|
||||
bx lr
|
||||
END_COMPILERRT_FUNCTION(__fixunsdfsivfp)
|
||||
|
||||
NO_EXEC_STACK_DIRECTIVE
|
||||
|
||||
|
@ -25,3 +25,6 @@ DEFINE_COMPILERRT_FUNCTION(__fixunssfsivfp)
|
||||
vmov r0, s15 // move s15 to result register
|
||||
bx lr
|
||||
END_COMPILERRT_FUNCTION(__fixunssfsivfp)
|
||||
|
||||
NO_EXEC_STACK_DIRECTIVE
|
||||
|
||||
|
@ -24,3 +24,6 @@ DEFINE_COMPILERRT_FUNCTION(__floatsidfvfp)
|
||||
vmov r0, r1, d7 // move d7 to result register pair r0/r1
|
||||
bx lr
|
||||
END_COMPILERRT_FUNCTION(__floatsidfvfp)
|
||||
|
||||
NO_EXEC_STACK_DIRECTIVE
|
||||
|
||||
|
@ -24,3 +24,6 @@ DEFINE_COMPILERRT_FUNCTION(__floatsisfvfp)
|
||||
vmov r0, s15 // move s15 to result register
|
||||
bx lr
|
||||
END_COMPILERRT_FUNCTION(__floatsisfvfp)
|
||||
|
||||
NO_EXEC_STACK_DIRECTIVE
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user