Vendor import of compiler-rt trunk r321017:
https://llvm.org/svn/llvm-project/compiler-rt/trunk@321017
This commit is contained in:
parent
625108084a
commit
cdf4f3055e
@ -1,4 +1,4 @@
|
||||
{
|
||||
"project_id" : "compiler-rt",
|
||||
"repository.callsign" : "CRT",
|
||||
"conduit_uri" : "https://reviews.llvm.org/"
|
||||
}
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,3 +3,4 @@ darwin_fat
|
||||
clang_darwin
|
||||
multi_arch
|
||||
*.sw?
|
||||
*.pyc
|
||||
|
149
CMakeLists.txt
149
CMakeLists.txt
@ -1,9 +1,5 @@
|
||||
# CMake build for CompilerRT.
|
||||
#
|
||||
# This build assumes that CompilerRT is checked out into the
|
||||
# 'projects/compiler-rt' or 'runtimes/compiler-rt' inside of an LLVM tree.
|
||||
# Standalone build system for CompilerRT is not yet ready.
|
||||
#
|
||||
# An important constraint of the build is that it only produces libraries
|
||||
# based on the ability of the host toolchain to target various platforms.
|
||||
|
||||
@ -21,6 +17,12 @@ list(INSERT CMAKE_MODULE_PATH 0
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules"
|
||||
)
|
||||
|
||||
if(CMAKE_CONFIGURATION_TYPES)
|
||||
set(CMAKE_CFG_RESOLVED_INTDIR "${CMAKE_CFG_INTDIR}/")
|
||||
else()
|
||||
set(CMAKE_CFG_RESOLVED_INTDIR "")
|
||||
endif()
|
||||
|
||||
include(base-config-ix)
|
||||
include(CompilerRTUtils)
|
||||
|
||||
@ -30,6 +32,31 @@ option(COMPILER_RT_BUILD_SANITIZERS "Build sanitizers" ON)
|
||||
mark_as_advanced(COMPILER_RT_BUILD_SANITIZERS)
|
||||
option(COMPILER_RT_BUILD_XRAY "Build xray" ON)
|
||||
mark_as_advanced(COMPILER_RT_BUILD_XRAY)
|
||||
option(COMPILER_RT_BUILD_LIBFUZZER "Build libFuzzer" ON)
|
||||
mark_as_advanced(COMPILER_RT_BUILD_LIBFUZZER)
|
||||
option(COMPILER_RT_BUILD_PROFILE "Build profile runtime" ON)
|
||||
mark_as_advanced(COMPILER_RT_BUILD_PROFILE)
|
||||
option(COMPILER_RT_BUILD_XRAY_NO_PREINIT "Build xray with no preinit patching" OFF)
|
||||
mark_as_advanced(COMPILER_RT_BUILD_XRAY_NO_PREINIT)
|
||||
|
||||
set(COMPILER_RT_ASAN_SHADOW_SCALE ""
|
||||
CACHE STRING "Override the shadow scale to be used in ASan runtime")
|
||||
|
||||
if (NOT COMPILER_RT_ASAN_SHADOW_SCALE STREQUAL "")
|
||||
# Check that the shadow scale value is valid.
|
||||
if (NOT (COMPILER_RT_ASAN_SHADOW_SCALE GREATER -1 AND
|
||||
COMPILER_RT_ASAN_SHADOW_SCALE LESS 8))
|
||||
message(FATAL_ERROR "
|
||||
Invalid ASan Shadow Scale '${COMPILER_RT_ASAN_SHADOW_SCALE}'.")
|
||||
endif()
|
||||
|
||||
set(COMPILER_RT_ASAN_SHADOW_SCALE_LLVM_FLAG
|
||||
-mllvm -asan-mapping-scale=${COMPILER_RT_ASAN_SHADOW_SCALE})
|
||||
set(COMPILER_RT_ASAN_SHADOW_SCALE_DEFINITION
|
||||
ASAN_SHADOW_SCALE=${COMPILER_RT_ASAN_SHADOW_SCALE})
|
||||
set(COMPILER_RT_ASAN_SHADOW_SCALE_FLAG
|
||||
-D${COMPILER_RT_ASAN_SHADOW_SCALE_DEFINITION})
|
||||
endif()
|
||||
|
||||
set(COMPILER_RT_BAREMETAL_BUILD OFF CACHE BOOLEAN
|
||||
"Build for a bare-metal target.")
|
||||
@ -52,12 +79,19 @@ if (COMPILER_RT_STANDALONE_BUILD)
|
||||
set(LIT_ARGS_DEFAULT "${LIT_ARGS_DEFAULT} --no-progress-bar")
|
||||
endif()
|
||||
set(LLVM_LIT_ARGS "${LIT_ARGS_DEFAULT}" CACHE STRING "Default options for lit")
|
||||
set(LLVM_LIT_OUTPUT_DIR "${COMPILER_RT_EXEC_OUTPUT_DIR}")
|
||||
endif()
|
||||
|
||||
construct_compiler_rt_default_triple()
|
||||
if ("${COMPILER_RT_DEFAULT_TARGET_ABI}" STREQUAL "androideabi")
|
||||
if ("${COMPILER_RT_DEFAULT_TARGET_ABI}" MATCHES "hf$")
|
||||
if (${COMPILER_RT_DEFAULT_TARGET_ARCH} MATCHES "^arm")
|
||||
set(COMPILER_RT_DEFAULT_TARGET_ARCH "armhf")
|
||||
endif()
|
||||
endif()
|
||||
if ("${COMPILER_RT_DEFAULT_TARGET_ABI}" MATCHES "^android")
|
||||
set(ANDROID 1)
|
||||
endif()
|
||||
pythonize_bool(ANDROID)
|
||||
|
||||
set(COMPILER_RT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
set(COMPILER_RT_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
|
||||
@ -78,21 +112,63 @@ option(COMPILER_RT_EXTERNALIZE_DEBUGINFO
|
||||
# COMPILER_RT_DEBUG_PYBOOL is used by lit.common.configured.in.
|
||||
pythonize_bool(COMPILER_RT_DEBUG)
|
||||
|
||||
include(HandleCompilerRT)
|
||||
include(config-ix)
|
||||
|
||||
if(APPLE AND SANITIZER_MIN_OSX_VERSION 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(use_cxxabi_default OFF)
|
||||
elseif(MSVC)
|
||||
set(use_cxxabi_default OFF)
|
||||
set(cxxabi_supported OFF)
|
||||
else()
|
||||
set(use_cxxabi_default ON)
|
||||
set(cxxabi_supported ON)
|
||||
endif()
|
||||
|
||||
option(SANITIZER_CAN_USE_CXXABI "Sanitizers can use cxxabi" ${use_cxxabi_default})
|
||||
option(SANITIZER_ALLOW_CXXABI "Allow use of C++ ABI details in ubsan" ON)
|
||||
|
||||
set(SANITIZE_CAN_USE_CXXABI OFF)
|
||||
if (cxxabi_supported AND SANITIZER_ALLOW_CXXABI)
|
||||
set(SANITIZER_CAN_USE_CXXABI ON)
|
||||
endif()
|
||||
pythonize_bool(SANITIZER_CAN_USE_CXXABI)
|
||||
|
||||
set(SANITIZER_CXX_ABI "default" CACHE STRING
|
||||
"Specify C++ ABI library to use.")
|
||||
set(CXXABIS none default libcxxabi libstdc++ libc++)
|
||||
set_property(CACHE SANITIZER_CXX_ABI PROPERTY STRINGS ;${CXXABIS})
|
||||
|
||||
if (SANITIZER_CXX_ABI STREQUAL "default")
|
||||
if (HAVE_LIBCXXABI AND COMPILER_RT_DEFAULT_TARGET_ONLY)
|
||||
set(SANITIZER_CXX_ABI_LIBNAME "libcxxabi")
|
||||
set(SANITIZER_CXX_ABI_INTREE 1)
|
||||
elseif (APPLE)
|
||||
set(SANITIZER_CXX_ABI_LIBNAME "libcxxabi")
|
||||
set(SANITIZER_CXX_ABI_SYSTEM 1)
|
||||
else()
|
||||
set(SANITIZER_CXX_ABI_LIBNAME "libstdc++")
|
||||
endif()
|
||||
else()
|
||||
set(SANITIZER_CXX_ABI_LIBNAME "${SANITIZER_CXX_ABI}")
|
||||
endif()
|
||||
|
||||
if (SANITIZER_CXX_ABI_LIBNAME STREQUAL "libcxxabi")
|
||||
if (SANITIZER_CXX_ABI_INTREE)
|
||||
if (TARGET unwind_shared OR HAVE_LIBUNWIND)
|
||||
list(APPEND SANITIZER_CXX_ABI_LIBRARY unwind_shared)
|
||||
endif()
|
||||
if (TARGET cxxabi_shared OR HAVE_LIBCXXABI)
|
||||
list(APPEND SANITIZER_CXX_ABI_LIBRARY cxxabi_shared)
|
||||
endif()
|
||||
else()
|
||||
list(APPEND SANITIZER_CXX_ABI_LIBRARY "c++abi")
|
||||
endif()
|
||||
elseif (SANITIZER_CXX_ABI_LIBNAME STREQUAL "libc++")
|
||||
list(APPEND SANITIZER_CXX_ABI_LIBRARY "c++")
|
||||
elseif (SANITIZER_CXX_ABI_LIBNAME STREQUAL "libstdc++")
|
||||
append_list_if(COMPILER_RT_HAS_LIBSTDCXX stdc++ SANITIZER_CXX_ABI_LIBRARY)
|
||||
endif()
|
||||
|
||||
option(SANITIZER_USE_COMPILER_RT "Use compiler-rt builtins instead of libgcc" OFF)
|
||||
|
||||
#================================
|
||||
# Setup Compiler Flags
|
||||
#================================
|
||||
@ -134,7 +210,9 @@ append_list_if(COMPILER_RT_HAS_FUNWIND_TABLES_FLAG -funwind-tables SANITIZER_COM
|
||||
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)
|
||||
append_list_if(COMPILER_RT_HAS_FVISIBILITY_HIDDEN_FLAG -fvisibility=hidden SANITIZER_COMMON_CFLAGS)
|
||||
if(NOT COMPILER_RT_HAS_FVISIBILITY_HIDDEN_FLAG)
|
||||
append_list_if(COMPILER_RT_HAS_FVISIBILITY_INLINES_HIDDEN_FLAG -fvisibility-inlines-hidden SANITIZER_COMMON_CFLAGS)
|
||||
endif()
|
||||
append_list_if(COMPILER_RT_HAS_FNO_LTO_FLAG -fno-lto SANITIZER_COMMON_CFLAGS)
|
||||
|
||||
# The following is a workaround for powerpc64le. This is the only architecture
|
||||
@ -228,6 +306,28 @@ 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)
|
||||
|
||||
# Set common link flags.
|
||||
append_list_if(COMPILER_RT_HAS_NODEFAULTLIBS_FLAG -nodefaultlibs SANITIZER_COMMON_LINK_FLAGS)
|
||||
|
||||
if (SANITIZER_USE_COMPILER_RT)
|
||||
list(APPEND SANITIZER_COMMON_LINK_FLAGS -rtlib=compiler-rt)
|
||||
find_compiler_rt_library(builtins COMPILER_RT_BUILTINS_LIBRARY)
|
||||
list(APPEND SANITIZER_COMMON_LINK_LIBS ${COMPILER_RT_BUILTINS_LIBRARY})
|
||||
else()
|
||||
if (ANDROID)
|
||||
append_list_if(COMPILER_RT_HAS_GCC_LIB gcc SANITIZER_COMMON_LINK_LIBS)
|
||||
else()
|
||||
append_list_if(COMPILER_RT_HAS_GCC_S_LIB gcc_s SANITIZER_COMMON_LINK_LIBS)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
append_list_if(COMPILER_RT_HAS_LIBC c SANITIZER_COMMON_LINK_LIBS)
|
||||
|
||||
if("${CMAKE_SYSTEM_NAME}" STREQUAL "Fuchsia")
|
||||
list(APPEND SANITIZER_COMMON_LINK_FLAGS -Wl,-z,defs,-z,now,-z,relro)
|
||||
list(APPEND SANITIZER_COMMON_LINK_LIBS zircon)
|
||||
endif()
|
||||
|
||||
# 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)
|
||||
|
||||
@ -244,17 +344,15 @@ endif()
|
||||
|
||||
add_subdirectory(include)
|
||||
|
||||
set(COMPILER_RT_LIBCXX_PATH ${LLVM_MAIN_SRC_DIR}/projects/libcxx)
|
||||
if(EXISTS ${COMPILER_RT_LIBCXX_PATH}/)
|
||||
set(COMPILER_RT_HAS_LIBCXX_SOURCES TRUE)
|
||||
else()
|
||||
set(COMPILER_RT_LIBCXX_PATH ${LLVM_MAIN_SRC_DIR}/../libcxx)
|
||||
if(EXISTS ${COMPILER_RT_LIBCXX_PATH}/)
|
||||
set(COMPILER_RT_HAS_LIBCXX_SOURCES TRUE)
|
||||
else()
|
||||
set(COMPILER_RT_HAS_LIBCXX_SOURCES FALSE)
|
||||
endif()
|
||||
foreach(path IN ITEMS ${LLVM_MAIN_SRC_DIR}/projects/libcxx
|
||||
${LLVM_MAIN_SRC_DIR}/runtimes/libcxx
|
||||
${LLVM_MAIN_SRC_DIR}/../libcxx
|
||||
${LLVM_EXTERNAL_LIBCXX_SOURCE_DIR})
|
||||
if(IS_DIRECTORY ${path})
|
||||
set(COMPILER_RT_LIBCXX_PATH ${path})
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
set(COMPILER_RT_LLD_PATH ${LLVM_MAIN_SRC_DIR}/tools/lld)
|
||||
if(EXISTS ${COMPILER_RT_LLD_PATH}/ AND LLVM_TOOL_LLD_BUILD)
|
||||
@ -274,4 +372,15 @@ add_subdirectory(lib)
|
||||
if(COMPILER_RT_INCLUDE_TESTS)
|
||||
add_subdirectory(unittests)
|
||||
add_subdirectory(test)
|
||||
if (COMPILER_RT_STANDALONE_BUILD)
|
||||
# If we have a valid source tree, generate llvm-lit into the bin directory.
|
||||
# The user can still choose to have the check targets *use* a different lit
|
||||
# by specifying -DLLVM_EXTERNAL_LIT, but we generate it regardless.
|
||||
if (EXISTS ${LLVM_MAIN_SRC_DIR}/utils/llvm-lit)
|
||||
add_subdirectory(${LLVM_MAIN_SRC_DIR}/utils/llvm-lit ${CMAKE_CURRENT_BINARY_DIR}/llvm-lit)
|
||||
elseif(NOT EXISTS ${LLVM_EXTERNAL_LIT})
|
||||
message(WARNING "Could not find LLVM source directory and LLVM_EXTERNAL_LIT does not"
|
||||
"point to a valid file. You will not be able to run tests.")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
@ -56,8 +56,15 @@ function(add_compiler_rt_object_libraries name)
|
||||
|
||||
foreach(libname ${libnames})
|
||||
add_library(${libname} OBJECT ${LIB_SOURCES})
|
||||
|
||||
# Strip out -msse3 if this isn't macOS.
|
||||
set(target_flags ${LIB_CFLAGS})
|
||||
if(APPLE AND NOT "${libname}" MATCHES ".*\.osx.*")
|
||||
list(REMOVE_ITEM target_flags "-msse3")
|
||||
endif()
|
||||
|
||||
set_target_compile_flags(${libname}
|
||||
${CMAKE_CXX_FLAGS} ${extra_cflags_${libname}} ${LIB_CFLAGS})
|
||||
${CMAKE_CXX_FLAGS} ${extra_cflags_${libname}} ${target_flags})
|
||||
set_property(TARGET ${libname} APPEND PROPERTY
|
||||
COMPILE_DEFINITIONS ${LIB_DEFS})
|
||||
set_target_properties(${libname} PROPERTIES FOLDER "Compiler-RT Libraries")
|
||||
@ -86,6 +93,25 @@ function(add_compiler_rt_component name)
|
||||
add_dependencies(compiler-rt ${name})
|
||||
endfunction()
|
||||
|
||||
function(add_asm_sources output)
|
||||
set(${output} ${ARGN} PARENT_SCOPE)
|
||||
# Xcode will try to compile asm files as C ('clang -x c'), and that will fail.
|
||||
if (${CMAKE_GENERATOR} STREQUAL "Xcode")
|
||||
enable_language(ASM)
|
||||
else()
|
||||
# Pass ASM file directly to the C++ compiler.
|
||||
set_source_files_properties(${ARGN} PROPERTIES LANGUAGE C)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
macro(set_output_name output name arch)
|
||||
if(ANDROID AND ${arch} STREQUAL "i386")
|
||||
set(${output} "${name}-i686${COMPILER_RT_OS_SUFFIX}")
|
||||
else()
|
||||
set(${output} "${name}-${arch}${COMPILER_RT_OS_SUFFIX}")
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
# Adds static or shared runtime for a list of architectures and operating
|
||||
# systems and puts it in the proper directory in the build and install trees.
|
||||
# add_compiler_rt_runtime(<name>
|
||||
@ -117,8 +143,14 @@ function(add_compiler_rt_runtime name type)
|
||||
else()
|
||||
set(NO_LTO_FLAGS "")
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
foreach(os ${LIB_OS})
|
||||
# Strip out -msse3 if this isn't macOS.
|
||||
list(LENGTH LIB_CFLAGS HAS_EXTRA_CFLAGS)
|
||||
if(HAS_EXTRA_CFLAGS AND NOT "${os}" MATCHES "^(osx)$")
|
||||
list(REMOVE_ITEM LIB_CFLAGS "-msse3")
|
||||
endif()
|
||||
if(type STREQUAL "STATIC")
|
||||
set(libname "${name}_${os}")
|
||||
else()
|
||||
@ -142,15 +174,15 @@ function(add_compiler_rt_runtime name type)
|
||||
endif()
|
||||
if(type STREQUAL "STATIC")
|
||||
set(libname "${name}-${arch}")
|
||||
set(output_name_${libname} ${libname}${COMPILER_RT_OS_SUFFIX})
|
||||
set_output_name(output_name_${libname} ${name} ${arch})
|
||||
else()
|
||||
set(libname "${name}-dynamic-${arch}")
|
||||
set(extra_cflags_${libname} ${TARGET_${arch}_CFLAGS} ${LIB_CFLAGS})
|
||||
set(extra_link_flags_${libname} ${TARGET_${arch}_LINK_FLAGS} ${LIB_LINK_FLAGS})
|
||||
if(WIN32)
|
||||
set(output_name_${libname} ${name}_dynamic-${arch}${COMPILER_RT_OS_SUFFIX})
|
||||
set_output_name(output_name_${libname} ${name}_dynamic ${arch})
|
||||
else()
|
||||
set(output_name_${libname} ${name}-${arch}${COMPILER_RT_OS_SUFFIX})
|
||||
set_output_name(output_name_${libname} ${name} ${arch})
|
||||
endif()
|
||||
endif()
|
||||
set(sources_${libname} ${LIB_SOURCES})
|
||||
@ -178,9 +210,18 @@ function(add_compiler_rt_runtime name type)
|
||||
COMMAND "${CMAKE_COMMAND}"
|
||||
-DCMAKE_INSTALL_COMPONENT=${LIB_PARENT_TARGET}
|
||||
-P "${CMAKE_BINARY_DIR}/cmake_install.cmake")
|
||||
add_custom_target(install-${LIB_PARENT_TARGET}-stripped
|
||||
DEPENDS ${LIB_PARENT_TARGET}
|
||||
COMMAND "${CMAKE_COMMAND}"
|
||||
-DCMAKE_INSTALL_COMPONENT=${LIB_PARENT_TARGET}
|
||||
-DCMAKE_INSTALL_DO_STRIP=1
|
||||
-P "${CMAKE_BINARY_DIR}/cmake_install.cmake")
|
||||
set_target_properties(install-${LIB_PARENT_TARGET} PROPERTIES
|
||||
FOLDER "Compiler-RT Misc")
|
||||
set_target_properties(install-${LIB_PARENT_TARGET}-stripped PROPERTIES
|
||||
FOLDER "Compiler-RT Misc")
|
||||
add_dependencies(install-compiler-rt install-${LIB_PARENT_TARGET})
|
||||
add_dependencies(install-compiler-rt-stripped install-${LIB_PARENT_TARGET}-stripped)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@ -202,10 +243,10 @@ function(add_compiler_rt_runtime name type)
|
||||
set_target_properties(${libname} PROPERTIES
|
||||
OUTPUT_NAME ${output_name_${libname}})
|
||||
set_target_properties(${libname} PROPERTIES FOLDER "Compiler-RT Runtime")
|
||||
if(${type} STREQUAL "SHARED")
|
||||
if(LIB_LINK_LIBS)
|
||||
target_link_libraries(${libname} ${LIB_LINK_LIBS})
|
||||
endif()
|
||||
if(${type} STREQUAL "SHARED")
|
||||
if(WIN32 AND NOT CYGWIN AND NOT MINGW)
|
||||
set_target_properties(${libname} PROPERTIES IMPORT_PREFIX "")
|
||||
set_target_properties(${libname} PROPERTIES IMPORT_SUFFIX ".lib")
|
||||
@ -235,10 +276,17 @@ function(add_compiler_rt_runtime name type)
|
||||
COMMAND "${CMAKE_COMMAND}"
|
||||
-DCMAKE_INSTALL_COMPONENT=${libname}
|
||||
-P "${CMAKE_BINARY_DIR}/cmake_install.cmake")
|
||||
add_custom_target(install-${libname}-stripped
|
||||
DEPENDS ${libname}
|
||||
COMMAND "${CMAKE_COMMAND}"
|
||||
-DCMAKE_INSTALL_COMPONENT=${libname}
|
||||
-DCMAKE_INSTALL_DO_STRIP=1
|
||||
-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})
|
||||
add_dependencies(install-${LIB_PARENT_TARGET}-stripped install-${libname}-stripped)
|
||||
endif()
|
||||
endif()
|
||||
if(APPLE)
|
||||
@ -287,24 +335,65 @@ if(MSVC)
|
||||
list(APPEND COMPILER_RT_GTEST_CFLAGS -Wno-deprecated-declarations)
|
||||
endif()
|
||||
|
||||
# Compile and register compiler-rt tests.
|
||||
# generate_compiler_rt_tests(<output object files> <test_suite> <test_name>
|
||||
# <test architecture>
|
||||
# KIND <custom prefix>
|
||||
# SUBDIR <subdirectory for testing binary>
|
||||
# SOURCES <sources to compile>
|
||||
# RUNTIME <tests runtime to link in>
|
||||
# CFLAGS <compile-time flags>
|
||||
# COMPILE_DEPS <compile-time dependencies>
|
||||
# DEPS <dependencies>
|
||||
# LINK_FLAGS <flags to use during linking>
|
||||
# )
|
||||
function(generate_compiler_rt_tests test_objects test_suite testname arch)
|
||||
cmake_parse_arguments(TEST "" "KIND;RUNTIME;SUBDIR"
|
||||
"SOURCES;COMPILE_DEPS;DEPS;CFLAGS;LINK_FLAGS" ${ARGN})
|
||||
|
||||
foreach(source ${TEST_SOURCES})
|
||||
sanitizer_test_compile(
|
||||
"${test_objects}" "${source}" "${arch}"
|
||||
KIND ${TEST_KIND}
|
||||
COMPILE_DEPS ${TEST_COMPILE_DEPS}
|
||||
DEPS ${TEST_DEPS}
|
||||
CFLAGS ${TEST_CFLAGS}
|
||||
)
|
||||
endforeach()
|
||||
|
||||
set(TEST_DEPS ${${test_objects}})
|
||||
|
||||
if(NOT "${TEST_RUNTIME}" STREQUAL "")
|
||||
list(APPEND TEST_DEPS ${TEST_RUNTIME})
|
||||
list(APPEND "${test_objects}" $<TARGET_FILE:${TEST_RUNTIME}>)
|
||||
endif()
|
||||
|
||||
add_compiler_rt_test(${test_suite} "${testname}" "${arch}"
|
||||
SUBDIR ${TEST_SUBDIR}
|
||||
OBJECTS ${${test_objects}}
|
||||
DEPS ${TEST_DEPS}
|
||||
LINK_FLAGS ${TEST_LINK_FLAGS}
|
||||
)
|
||||
set("${test_objects}" "${${test_objects}}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Link objects into a single executable with COMPILER_RT_TEST_COMPILER,
|
||||
# using specified link flags. Make executable a part of provided
|
||||
# test_suite.
|
||||
# add_compiler_rt_test(<test_suite> <test_name>
|
||||
# add_compiler_rt_test(<test_suite> <test_name> <arch>
|
||||
# SUBDIR <subdirectory for binary>
|
||||
# OBJECTS <object files>
|
||||
# DEPS <deps (e.g. runtime libs)>
|
||||
# LINK_FLAGS <link flags>)
|
||||
macro(add_compiler_rt_test test_suite test_name)
|
||||
function(add_compiler_rt_test test_suite test_name arch)
|
||||
cmake_parse_arguments(TEST "" "SUBDIR" "OBJECTS;DEPS;LINK_FLAGS" "" ${ARGN})
|
||||
set(output_bin ${CMAKE_CURRENT_BINARY_DIR})
|
||||
set(output_dir ${CMAKE_CURRENT_BINARY_DIR})
|
||||
if(TEST_SUBDIR)
|
||||
set(output_bin "${output_bin}/${TEST_SUBDIR}")
|
||||
set(output_dir "${output_dir}/${TEST_SUBDIR}")
|
||||
endif()
|
||||
if(CMAKE_CONFIGURATION_TYPES)
|
||||
set(output_bin "${output_bin}/${CMAKE_CFG_INTDIR}")
|
||||
endif()
|
||||
set(output_bin "${output_bin}/${test_name}")
|
||||
set(output_dir "${output_dir}/${CMAKE_CFG_INTDIR}")
|
||||
file(MAKE_DIRECTORY "${output_dir}")
|
||||
set(output_bin "${output_dir}/${test_name}")
|
||||
if(MSVC)
|
||||
set(output_bin "${output_bin}.exe")
|
||||
endif()
|
||||
@ -313,6 +402,10 @@ macro(add_compiler_rt_test test_suite test_name)
|
||||
if(NOT COMPILER_RT_STANDALONE_BUILD)
|
||||
list(APPEND TEST_DEPS clang)
|
||||
endif()
|
||||
|
||||
get_target_flags_for_arch(${arch} TARGET_LINK_FLAGS)
|
||||
list(APPEND TEST_LINK_FLAGS ${TARGET_LINK_FLAGS})
|
||||
|
||||
# If we're not on MSVC, include the linker flags from CMAKE but override them
|
||||
# with the provided link flags. This ensures that flags which are required to
|
||||
# link programs at all are included, but the changes needed for the test
|
||||
@ -323,16 +416,18 @@ macro(add_compiler_rt_test test_suite test_name)
|
||||
set(TEST_LINK_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${TEST_LINK_FLAGS}")
|
||||
separate_arguments(TEST_LINK_FLAGS)
|
||||
endif()
|
||||
add_custom_target(${test_name}
|
||||
COMMAND ${COMPILER_RT_TEST_COMPILER} ${TEST_OBJECTS}
|
||||
-o "${output_bin}"
|
||||
add_custom_command(
|
||||
OUTPUT "${output_bin}"
|
||||
COMMAND ${COMPILER_RT_TEST_COMPILER} ${TEST_OBJECTS} -o "${output_bin}"
|
||||
${TEST_LINK_FLAGS}
|
||||
DEPENDS ${TEST_DEPS})
|
||||
set_target_properties(${test_name} PROPERTIES FOLDER "Compiler-RT Tests")
|
||||
DEPENDS ${TEST_DEPS}
|
||||
)
|
||||
add_custom_target(T${test_name} DEPENDS "${output_bin}")
|
||||
set_target_properties(T${test_name} PROPERTIES FOLDER "Compiler-RT Tests")
|
||||
|
||||
# Make the test suite depend on the binary.
|
||||
add_dependencies(${test_suite} ${test_name})
|
||||
endmacro()
|
||||
add_dependencies(${test_suite} T${test_name})
|
||||
endfunction()
|
||||
|
||||
macro(add_compiler_rt_resource_file target_name file_name component)
|
||||
set(src_file "${CMAKE_CURRENT_SOURCE_DIR}/${file_name}")
|
||||
@ -370,7 +465,7 @@ endmacro(add_compiler_rt_script src name)
|
||||
# DEPS <list of build deps>
|
||||
# CFLAGS <list of compile flags>)
|
||||
macro(add_custom_libcxx name prefix)
|
||||
if(NOT COMPILER_RT_HAS_LIBCXX_SOURCES)
|
||||
if(NOT COMPILER_RT_LIBCXX_PATH)
|
||||
message(FATAL_ERROR "libcxx not found!")
|
||||
endif()
|
||||
|
||||
@ -440,3 +535,14 @@ function(rt_externalize_debuginfo name)
|
||||
message(FATAL_ERROR "COMPILER_RT_EXTERNALIZE_DEBUGINFO isn't implemented for non-darwin platforms!")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
||||
# Configure lit configuration files, including compiler-rt specific variables.
|
||||
function(configure_compiler_rt_lit_site_cfg input output)
|
||||
set_llvm_build_mode()
|
||||
|
||||
string(REPLACE ${CMAKE_CFG_INTDIR} ${LLVM_BUILD_MODE} COMPILER_RT_RESOLVED_TEST_COMPILER ${COMPILER_RT_TEST_COMPILER})
|
||||
string(REPLACE ${CMAKE_CFG_INTDIR} ${LLVM_BUILD_MODE} COMPILER_RT_RESOLVED_LIBRARY_OUTPUT_DIR ${COMPILER_RT_LIBRARY_OUTPUT_DIR})
|
||||
|
||||
configure_lit_site_cfg(${input} ${output})
|
||||
endfunction()
|
||||
|
@ -24,12 +24,44 @@ function(translate_msvc_cflags out_flags msvc_flags)
|
||||
set(${out_flags} "${clang_flags}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Compile a sanitizer test with a freshly built clang
|
||||
# for a given architecture, adding the result to the object list.
|
||||
# - obj_list: output list of objects, populated by path
|
||||
# of a generated object file.
|
||||
# - source: source file of a test.
|
||||
# - arch: architecture to compile for.
|
||||
# sanitizer_test_compile(<obj_list> <source> <arch>
|
||||
# KIND <custom namespace>
|
||||
# COMPILE_DEPS <list of compile-time dependencies>
|
||||
# DEPS <list of dependencies>
|
||||
# CFLAGS <list of flags>
|
||||
# )
|
||||
function(sanitizer_test_compile obj_list source arch)
|
||||
cmake_parse_arguments(TEST
|
||||
"" "" "KIND;COMPILE_DEPS;DEPS;CFLAGS" ${ARGN})
|
||||
get_filename_component(basename ${source} NAME)
|
||||
set(output_obj
|
||||
"${CMAKE_CFG_RESOLVED_INTDIR}${obj_list}.${basename}.${arch}${TEST_KIND}.o")
|
||||
|
||||
# Write out architecture-specific flags into TARGET_CFLAGS variable.
|
||||
get_target_flags_for_arch(${arch} TARGET_CFLAGS)
|
||||
set(COMPILE_DEPS ${TEST_COMPILE_DEPS})
|
||||
if(NOT COMPILER_RT_STANDALONE_BUILD)
|
||||
list(APPEND COMPILE_DEPS ${TEST_DEPS})
|
||||
endif()
|
||||
clang_compile(${output_obj} ${source}
|
||||
CFLAGS ${TEST_CFLAGS} ${TARGET_CFLAGS}
|
||||
DEPS ${COMPILE_DEPS})
|
||||
list(APPEND ${obj_list} ${output_obj})
|
||||
set("${obj_list}" "${${obj_list}}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Compile a source into an object file with COMPILER_RT_TEST_COMPILER using
|
||||
# a provided compile flags and dependenices.
|
||||
# clang_compile(<object> <source>
|
||||
# CFLAGS <list of compile flags>
|
||||
# DEPS <list of dependencies>)
|
||||
macro(clang_compile object_file source)
|
||||
function(clang_compile object_file source)
|
||||
cmake_parse_arguments(SOURCE "" "" "CFLAGS;DEPS" ${ARGN})
|
||||
get_filename_component(source_rpath ${source} REALPATH)
|
||||
if(NOT COMPILER_RT_STANDALONE_BUILD)
|
||||
@ -39,6 +71,7 @@ macro(clang_compile object_file source)
|
||||
list(APPEND SOURCE_DEPS CompilerRTUnitTestCheckCxx)
|
||||
endif()
|
||||
string(REGEX MATCH "[.](cc|cpp)$" is_cxx ${source_rpath})
|
||||
string(REGEX MATCH "[.](m|mm)$" is_objc ${source_rpath})
|
||||
if(is_cxx)
|
||||
string(REPLACE " " ";" global_flags "${CMAKE_CXX_FLAGS}")
|
||||
else()
|
||||
@ -52,6 +85,9 @@ macro(clang_compile object_file source)
|
||||
if (APPLE)
|
||||
set(global_flags ${OSX_SYSROOT_FLAG} ${global_flags})
|
||||
endif()
|
||||
if (is_objc)
|
||||
list(APPEND global_flags -ObjC)
|
||||
endif()
|
||||
|
||||
# Ignore unknown warnings. CMAKE_CXX_FLAGS may contain GCC-specific options
|
||||
# which are not supported by Clang.
|
||||
@ -64,7 +100,7 @@ macro(clang_compile object_file source)
|
||||
${source_rpath}
|
||||
MAIN_DEPENDENCY ${source}
|
||||
DEPENDS ${SOURCE_DEPS})
|
||||
endmacro()
|
||||
endfunction()
|
||||
|
||||
# On Darwin, there are no system-wide C++ headers and the just-built clang is
|
||||
# therefore not able to compile C++ files unless they are copied/symlinked into
|
||||
@ -100,7 +136,7 @@ macro(clang_compiler_add_cxx_check)
|
||||
COMMAND bash -c "${CMD}"
|
||||
COMMENT "Checking that just-built clang can find C++ headers..."
|
||||
VERBATIM)
|
||||
if (TARGET clang)
|
||||
if (NOT COMPILER_RT_STANDALONE_BUILD)
|
||||
ADD_DEPENDENCIES(CompilerRTUnitTestCheckCxx clang)
|
||||
endif()
|
||||
endif()
|
||||
|
@ -200,10 +200,23 @@ macro(darwin_add_builtin_library name suffix)
|
||||
if(DARWIN_${LIB_OS}_SYSROOT)
|
||||
set(sysroot_flag -isysroot ${DARWIN_${LIB_OS}_SYSROOT})
|
||||
endif()
|
||||
|
||||
# Make a copy of the compilation flags.
|
||||
set(builtin_cflags ${LIB_CFLAGS})
|
||||
|
||||
# Strip out any inappropriate flags for the target.
|
||||
if("${LIB_ARCH}" MATCHES "^(armv7|armv7k|armv7s)$")
|
||||
set(builtin_cflags "")
|
||||
foreach(cflag "${LIB_CFLAGS}")
|
||||
string(REPLACE "-fomit-frame-pointer" "" cflag "${cflag}")
|
||||
list(APPEND builtin_cflags ${cflag})
|
||||
endforeach(cflag)
|
||||
endif()
|
||||
|
||||
set_target_compile_flags(${libname}
|
||||
${sysroot_flag}
|
||||
${DARWIN_${LIB_OS}_BUILTIN_MIN_VER_FLAG}
|
||||
${LIB_CFLAGS})
|
||||
${builtin_cflags})
|
||||
set_property(TARGET ${libname} APPEND PROPERTY
|
||||
COMPILE_DEFINITIONS ${LIB_DEFS})
|
||||
set_target_properties(${libname} PROPERTIES
|
||||
@ -243,35 +256,6 @@ function(darwin_lipo_libs name)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Filter out generic versions of routines that are re-implemented in
|
||||
# architecture specific manner. This prevents multiple definitions of the
|
||||
# same symbols, making the symbol selection non-deterministic.
|
||||
function(darwin_filter_builtin_sources output_var exclude_or_include excluded_list)
|
||||
if(exclude_or_include STREQUAL "EXCLUDE")
|
||||
set(filter_action GREATER)
|
||||
set(filter_value -1)
|
||||
elseif(exclude_or_include STREQUAL "INCLUDE")
|
||||
set(filter_action LESS)
|
||||
set(filter_value 0)
|
||||
else()
|
||||
message(FATAL_ERROR "darwin_filter_builtin_sources called without EXCLUDE|INCLUDE")
|
||||
endif()
|
||||
|
||||
set(intermediate ${ARGN})
|
||||
foreach (_file ${intermediate})
|
||||
get_filename_component(_name_we ${_file} NAME_WE)
|
||||
list(FIND ${excluded_list} ${_name_we} _found)
|
||||
if(_found ${filter_action} ${filter_value})
|
||||
list(REMOVE_ITEM intermediate ${_file})
|
||||
elseif(${_file} MATCHES ".*/.*\\.S" OR ${_file} MATCHES ".*/.*\\.c")
|
||||
get_filename_component(_name ${_file} NAME)
|
||||
string(REPLACE ".S" ".c" _cname "${_name}")
|
||||
list(REMOVE_ITEM intermediate ${_cname})
|
||||
endif ()
|
||||
endforeach ()
|
||||
set(${output_var} ${intermediate} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Generates builtin libraries for all operating systems specified in ARGN. Each
|
||||
# OS library is constructed by lipo-ing together single-architecture libraries.
|
||||
macro(darwin_add_builtin_libraries)
|
||||
@ -294,7 +278,7 @@ macro(darwin_add_builtin_libraries)
|
||||
ARCH ${arch}
|
||||
MIN_VERSION ${DARWIN_${os}_BUILTIN_MIN_VER})
|
||||
|
||||
darwin_filter_builtin_sources(filtered_sources
|
||||
filter_builtin_sources(filtered_sources
|
||||
EXCLUDE ${arch}_${os}_EXCLUDED_BUILTINS
|
||||
${${arch}_SOURCES})
|
||||
|
||||
@ -316,7 +300,7 @@ macro(darwin_add_builtin_libraries)
|
||||
OS ${os}
|
||||
ARCH ${arch})
|
||||
|
||||
darwin_filter_builtin_sources(filtered_sources
|
||||
filter_builtin_sources(filtered_sources
|
||||
EXCLUDE ${arch}_${os}_EXCLUDED_BUILTINS
|
||||
${${arch}_SOURCES})
|
||||
|
||||
@ -411,7 +395,7 @@ macro(darwin_add_embedded_builtin_libraries)
|
||||
set(x86_64_FUNCTIONS ${common_FUNCTIONS})
|
||||
|
||||
foreach(arch ${DARWIN_macho_embedded_ARCHS})
|
||||
darwin_filter_builtin_sources(${arch}_filtered_sources
|
||||
filter_builtin_sources(${arch}_filtered_sources
|
||||
INCLUDE ${arch}_FUNCTIONS
|
||||
${${arch}_SOURCES})
|
||||
if(NOT ${arch}_filtered_sources)
|
||||
|
@ -163,10 +163,11 @@ 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(__powerpc64__ "" __PPC64)
|
||||
check_symbol_exists(__powerpc64le__ "" __PPC64LE)
|
||||
check_symbol_exists(__s390x__ "" __S390X)
|
||||
check_symbol_exists(__wasm32__ "" __WEBASSEMBLY32)
|
||||
check_symbol_exists(__wasm64__ "" __WEBASSEMBLY64)
|
||||
@ -176,14 +177,16 @@ macro(detect_target_arch)
|
||||
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(__PPC64)
|
||||
add_default_target_arch(powerpc64)
|
||||
elseif(__PPC64LE)
|
||||
add_default_target_arch(powerpc64le)
|
||||
elseif(__S390X)
|
||||
add_default_target_arch(s390x)
|
||||
elseif(__WEBASSEMBLY32)
|
||||
@ -273,3 +276,32 @@ macro(construct_compiler_rt_default_triple)
|
||||
set(COMPILER_RT_HAS_EXPLICIT_DEFAULT_TARGET_TRIPLE FALSE)
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
# Filter out generic versions of routines that are re-implemented in
|
||||
# architecture specific manner. This prevents multiple definitions of the
|
||||
# same symbols, making the symbol selection non-deterministic.
|
||||
function(filter_builtin_sources output_var exclude_or_include excluded_list)
|
||||
if(exclude_or_include STREQUAL "EXCLUDE")
|
||||
set(filter_action GREATER)
|
||||
set(filter_value -1)
|
||||
elseif(exclude_or_include STREQUAL "INCLUDE")
|
||||
set(filter_action LESS)
|
||||
set(filter_value 0)
|
||||
else()
|
||||
message(FATAL_ERROR "filter_builtin_sources called without EXCLUDE|INCLUDE")
|
||||
endif()
|
||||
|
||||
set(intermediate ${ARGN})
|
||||
foreach (_file ${intermediate})
|
||||
get_filename_component(_name_we ${_file} NAME_WE)
|
||||
list(FIND ${excluded_list} ${_name_we} _found)
|
||||
if(_found ${filter_action} ${filter_value})
|
||||
list(REMOVE_ITEM intermediate ${_file})
|
||||
elseif(${_file} MATCHES ".*/.*\\.S" OR ${_file} MATCHES ".*/.*\\.c")
|
||||
get_filename_component(_name ${_file} NAME)
|
||||
string(REPLACE ".S" ".c" _cname "${_name}")
|
||||
list(REMOVE_ITEM intermediate ${_cname})
|
||||
endif ()
|
||||
endforeach ()
|
||||
set(${output_var} ${intermediate} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
21
cmake/Modules/HandleCompilerRT.cmake
Normal file
21
cmake/Modules/HandleCompilerRT.cmake
Normal file
@ -0,0 +1,21 @@
|
||||
function(find_compiler_rt_library name dest)
|
||||
set(dest "" PARENT_SCOPE)
|
||||
set(CLANG_COMMAND ${CMAKE_CXX_COMPILER} ${SANITIZER_COMMON_CFLAGS}
|
||||
"--rtlib=compiler-rt" "--print-libgcc-file-name")
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES Clang AND CMAKE_CXX_COMPILER_TARGET)
|
||||
list(APPEND CLANG_COMMAND "--target=${CMAKE_CXX_COMPILER_TARGET}")
|
||||
endif()
|
||||
execute_process(
|
||||
COMMAND ${CLANG_COMMAND}
|
||||
RESULT_VARIABLE HAD_ERROR
|
||||
OUTPUT_VARIABLE LIBRARY_FILE
|
||||
)
|
||||
string(STRIP "${LIBRARY_FILE}" LIBRARY_FILE)
|
||||
string(REPLACE "builtins" "${name}" LIBRARY_FILE "${LIBRARY_FILE}")
|
||||
if (NOT HAD_ERROR AND EXISTS "${LIBRARY_FILE}")
|
||||
message(STATUS "Found compiler-rt ${name} library: ${LIBRARY_FILE}")
|
||||
set(${dest} "${LIBRARY_FILE}" PARENT_SCOPE)
|
||||
else()
|
||||
message(STATUS "Failed to find compiler-rt ${name} library")
|
||||
endif()
|
||||
endfunction()
|
@ -4,11 +4,14 @@
|
||||
# runtime libraries.
|
||||
|
||||
include(CheckIncludeFile)
|
||||
include(CheckCXXSourceCompiles)
|
||||
|
||||
check_include_file(unwind.h HAVE_UNWIND_H)
|
||||
|
||||
# Top level target used to build all compiler-rt libraries.
|
||||
add_custom_target(compiler-rt ALL)
|
||||
add_custom_target(install-compiler-rt)
|
||||
add_custom_target(install-compiler-rt-stripped)
|
||||
set_target_properties(compiler-rt PROPERTIES FOLDER "Compiler-RT Misc")
|
||||
|
||||
# Setting these variables from an LLVM build is sufficient that compiler-rt can
|
||||
@ -86,6 +89,7 @@ if(APPLE)
|
||||
option(COMPILER_RT_ENABLE_IOS "Enable building for iOS" On)
|
||||
option(COMPILER_RT_ENABLE_WATCHOS "Enable building for watchOS - Experimental" Off)
|
||||
option(COMPILER_RT_ENABLE_TVOS "Enable building for tvOS - Experimental" Off)
|
||||
|
||||
else()
|
||||
option(COMPILER_RT_DEFAULT_TARGET_ONLY "Build builtins only for the default target" Off)
|
||||
endif()
|
||||
@ -136,10 +140,6 @@ macro(test_targets)
|
||||
elseif("${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)
|
||||
@ -149,7 +149,13 @@ macro(test_targets)
|
||||
endif()
|
||||
endif()
|
||||
elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "powerpc")
|
||||
# Strip out -nodefaultlibs when calling TEST_BIG_ENDIAN. Configuration
|
||||
# will fail with this option when building with a sanitizer.
|
||||
cmake_push_check_state()
|
||||
string(REPLACE "-nodefaultlibs" "" CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS})
|
||||
TEST_BIG_ENDIAN(HOST_IS_BIG_ENDIAN)
|
||||
cmake_pop_check_state()
|
||||
|
||||
if(HOST_IS_BIG_ENDIAN)
|
||||
test_target_arch(powerpc64 "" "-m64")
|
||||
else()
|
||||
|
@ -25,7 +25,7 @@ int foo(int x, int y) {
|
||||
|
||||
set(ARM64 aarch64)
|
||||
set(ARM32 arm armhf armv6m armv7m armv7em armv7 armv7s armv7k)
|
||||
set(X86 i386 i686)
|
||||
set(X86 i386)
|
||||
set(X86_64 x86_64)
|
||||
set(MIPS32 mips mipsel)
|
||||
set(MIPS64 mips64 mips64el)
|
||||
@ -40,7 +40,7 @@ if(APPLE)
|
||||
endif()
|
||||
|
||||
set(ALL_BUILTIN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64}
|
||||
${MIPS32} ${MIPS64} ${WASM32} ${WASM64})
|
||||
${MIPS32} ${MIPS64} ${PPC64} ${WASM32} ${WASM64})
|
||||
|
||||
include(CompilerRTUtils)
|
||||
include(CompilerRTDarwinUtils)
|
||||
|
@ -1,4 +1,5 @@
|
||||
include(CMakePushCheckState)
|
||||
include(CheckCCompilerFlag)
|
||||
include(CheckCXXCompilerFlag)
|
||||
include(CheckLibraryExists)
|
||||
include(CheckSymbolExists)
|
||||
@ -11,6 +12,32 @@ function(check_linker_flag flag out_var)
|
||||
cmake_pop_check_state()
|
||||
endfunction()
|
||||
|
||||
check_library_exists(c fopen "" COMPILER_RT_HAS_LIBC)
|
||||
if (NOT SANITIZER_USE_COMPILER_RT)
|
||||
if (ANDROID)
|
||||
check_library_exists(gcc __gcc_personality_v0 "" COMPILER_RT_HAS_GCC_LIB)
|
||||
else()
|
||||
check_library_exists(gcc_s __gcc_personality_v0 "" COMPILER_RT_HAS_GCC_S_LIB)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
check_c_compiler_flag(-nodefaultlibs COMPILER_RT_HAS_NODEFAULTLIBS_FLAG)
|
||||
if (COMPILER_RT_HAS_NODEFAULTLIBS_FLAG)
|
||||
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -nodefaultlibs")
|
||||
if (COMPILER_RT_HAS_LIBC)
|
||||
list(APPEND CMAKE_REQUIRED_LIBRARIES c)
|
||||
endif ()
|
||||
if (SANITIZER_USE_COMPILER_RT)
|
||||
list(APPEND CMAKE_REQUIRED_FLAGS -rtlib=compiler-rt)
|
||||
find_compiler_rt_library(builtins COMPILER_RT_BUILTINS_LIBRARY)
|
||||
list(APPEND CMAKE_REQUIRED_LIBRARIES "${COMPILER_RT_BUILTINS_LIBRARY}")
|
||||
elseif (COMPILER_RT_HAS_GCC_S_LIB)
|
||||
list(APPEND CMAKE_REQUIRED_LIBRARIES gcc_s)
|
||||
elseif (COMPILER_RT_HAS_GCC_LIB)
|
||||
list(APPEND CMAKE_REQUIRED_LIBRARIES gcc)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
# CodeGen options.
|
||||
check_cxx_compiler_flag(-fPIC COMPILER_RT_HAS_FPIC_FLAG)
|
||||
check_cxx_compiler_flag(-fPIE COMPILER_RT_HAS_FPIE_FLAG)
|
||||
@ -73,11 +100,14 @@ check_cxx_compiler_flag(/wd4800 COMPILER_RT_HAS_WD4800_FLAG)
|
||||
check_symbol_exists(__func__ "" COMPILER_RT_HAS_FUNC_SYMBOL)
|
||||
|
||||
# Libraries.
|
||||
check_library_exists(c fopen "" COMPILER_RT_HAS_LIBC)
|
||||
check_library_exists(dl dlopen "" COMPILER_RT_HAS_LIBDL)
|
||||
check_library_exists(rt shm_open "" COMPILER_RT_HAS_LIBRT)
|
||||
check_library_exists(m pow "" COMPILER_RT_HAS_LIBM)
|
||||
check_library_exists(pthread pthread_create "" COMPILER_RT_HAS_LIBPTHREAD)
|
||||
if (ANDROID AND COMPILER_RT_HAS_LIBDL)
|
||||
# Android's libstdc++ has a dependency on libdl.
|
||||
list(APPEND CMAKE_REQUIRED_LIBRARIES dl)
|
||||
endif()
|
||||
check_library_exists(stdc++ __cxa_throw "" COMPILER_RT_HAS_LIBSTDCXX)
|
||||
|
||||
# Linker flags.
|
||||
@ -144,7 +174,7 @@ endmacro()
|
||||
|
||||
set(ARM64 aarch64)
|
||||
set(ARM32 arm armhf)
|
||||
set(X86 i386 i686)
|
||||
set(X86 i386)
|
||||
set(X86_64 x86_64)
|
||||
set(MIPS32 mips mipsel)
|
||||
set(MIPS64 mips64 mips64el)
|
||||
@ -164,23 +194,29 @@ set(ALL_SANITIZER_COMMON_SUPPORTED_ARCH ${X86} ${X86_64} ${PPC64}
|
||||
set(ALL_ASAN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64}
|
||||
${MIPS32} ${MIPS64} ${PPC64} ${S390X})
|
||||
set(ALL_DFSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64})
|
||||
set(ALL_FUZZER_SUPPORTED_ARCH x86_64)
|
||||
|
||||
if(APPLE)
|
||||
set(ALL_LSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${MIPS64} ${ARM64})
|
||||
else()
|
||||
set(ALL_LSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${MIPS64} ${ARM64} ${ARM32})
|
||||
set(ALL_LSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${MIPS64} ${ARM64} ${ARM32} ${PPC64})
|
||||
endif()
|
||||
set(ALL_MSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64} ${PPC64})
|
||||
set(ALL_HWASAN_SUPPORTED_ARCH ${ARM64})
|
||||
set(ALL_PROFILE_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${PPC64}
|
||||
${MIPS32} ${MIPS64} ${S390X})
|
||||
set(ALL_TSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64} ${PPC64})
|
||||
set(ALL_UBSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64}
|
||||
${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_CFI_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${MIPS64})
|
||||
set(ALL_ESAN_SUPPORTED_ARCH ${X86_64} ${MIPS64})
|
||||
set(ALL_SCUDO_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${MIPS32} ${MIPS64})
|
||||
if(APPLE)
|
||||
set(ALL_XRAY_SUPPORTED_ARCH ${X86_64})
|
||||
else()
|
||||
set(ALL_XRAY_SUPPORTED_ARCH ${X86_64} ${ARM32} ${ARM64} ${MIPS32} ${MIPS64} powerpc64le)
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
include(CompilerRTDarwinUtils)
|
||||
@ -225,6 +261,7 @@ if(APPLE)
|
||||
set(SANITIZER_COMMON_SUPPORTED_OS osx)
|
||||
set(PROFILE_SUPPORTED_OS osx)
|
||||
set(TSAN_SUPPORTED_OS osx)
|
||||
set(XRAY_SUPPORTED_OS osx)
|
||||
if(NOT SANITIZER_MIN_OSX_VERSION)
|
||||
string(REGEX MATCH "-mmacosx-version-min=([.0-9]+)"
|
||||
MACOSX_VERSION_MIN_FLAG "${CMAKE_CXX_FLAGS}")
|
||||
@ -360,6 +397,9 @@ if(APPLE)
|
||||
list_intersect(MSAN_SUPPORTED_ARCH
|
||||
ALL_MSAN_SUPPORTED_ARCH
|
||||
SANITIZER_COMMON_SUPPORTED_ARCH)
|
||||
list_intersect(HWASAN_SUPPORTED_ARCH
|
||||
ALL_HWASAN_SUPPORTED_ARCH
|
||||
SANITIZER_COMMON_SUPPORTED_ARCH)
|
||||
list_intersect(PROFILE_SUPPORTED_ARCH
|
||||
ALL_PROFILE_SUPPORTED_ARCH
|
||||
SANITIZER_COMMON_SUPPORTED_ARCH)
|
||||
@ -381,9 +421,13 @@ if(APPLE)
|
||||
list_intersect(SCUDO_SUPPORTED_ARCH
|
||||
ALL_SCUDO_SUPPORTED_ARCH
|
||||
SANITIZER_COMMON_SUPPORTED_ARCH)
|
||||
list_intersect(FUZZER_SUPPORTED_ARCH
|
||||
ALL_FUZZER_SUPPORTED_ARCH
|
||||
ALL_SANITIZER_COMMON_SUPPORTED_ARCH)
|
||||
list_intersect(XRAY_SUPPORTED_ARCH
|
||||
ALL_XRAY_SUPPORTED_ARCH
|
||||
SANITIZER_COMMON_SUPPORTED_ARCH)
|
||||
|
||||
else()
|
||||
# Architectures supported by compiler-rt libraries.
|
||||
filter_available_targets(SANITIZER_COMMON_SUPPORTED_ARCH
|
||||
@ -395,9 +439,11 @@ else()
|
||||
filter_available_targets(UBSAN_COMMON_SUPPORTED_ARCH
|
||||
${SANITIZER_COMMON_SUPPORTED_ARCH})
|
||||
filter_available_targets(ASAN_SUPPORTED_ARCH ${ALL_ASAN_SUPPORTED_ARCH})
|
||||
filter_available_targets(FUZZER_SUPPORTED_ARCH ${ALL_FUZZER_SUPPORTED_ARCH})
|
||||
filter_available_targets(DFSAN_SUPPORTED_ARCH ${ALL_DFSAN_SUPPORTED_ARCH})
|
||||
filter_available_targets(LSAN_SUPPORTED_ARCH ${ALL_LSAN_SUPPORTED_ARCH})
|
||||
filter_available_targets(MSAN_SUPPORTED_ARCH ${ALL_MSAN_SUPPORTED_ARCH})
|
||||
filter_available_targets(HWASAN_SUPPORTED_ARCH ${ALL_HWASAN_SUPPORTED_ARCH})
|
||||
filter_available_targets(PROFILE_SUPPORTED_ARCH ${ALL_PROFILE_SUPPORTED_ARCH})
|
||||
filter_available_targets(TSAN_SUPPORTED_ARCH ${ALL_TSAN_SUPPORTED_ARCH})
|
||||
filter_available_targets(UBSAN_SUPPORTED_ARCH ${ALL_UBSAN_SUPPORTED_ARCH})
|
||||
@ -434,13 +480,13 @@ else()
|
||||
set(OS_NAME "${CMAKE_SYSTEM_NAME}")
|
||||
endif()
|
||||
|
||||
set(ALL_SANITIZERS asan;dfsan;msan;tsan;safestack;cfi;esan;scudo)
|
||||
set(COMPILER_RT_SANITIZERS_TO_BUILD ${ALL_SANITIZERS} CACHE STRING
|
||||
set(ALL_SANITIZERS asan;dfsan;msan;hwasan;tsan;safestack;cfi;esan;scudo;ubsan_minimal)
|
||||
set(COMPILER_RT_SANITIZERS_TO_BUILD all CACHE STRING
|
||||
"sanitizers to build if supported on the target (all;${ALL_SANITIZERS})")
|
||||
list_replace(COMPILER_RT_SANITIZERS_TO_BUILD all "${ALL_SANITIZERS}")
|
||||
|
||||
if (SANITIZER_COMMON_SUPPORTED_ARCH AND NOT LLVM_USE_SANITIZER AND
|
||||
(OS_NAME MATCHES "Android|Darwin|Linux|FreeBSD" OR
|
||||
(OS_NAME MATCHES "Android|Darwin|Linux|FreeBSD|NetBSD|Fuchsia" OR
|
||||
(OS_NAME MATCHES "Windows" AND (NOT MINGW AND NOT CYGWIN))))
|
||||
set(COMPILER_RT_HAS_SANITIZER_COMMON TRUE)
|
||||
else()
|
||||
@ -459,7 +505,7 @@ else()
|
||||
set(COMPILER_RT_HAS_ASAN FALSE)
|
||||
endif()
|
||||
|
||||
if (OS_NAME MATCHES "Linux|FreeBSD|Windows")
|
||||
if (OS_NAME MATCHES "Linux|FreeBSD|Windows|NetBSD")
|
||||
set(COMPILER_RT_ASAN_HAS_STATIC_RUNTIME TRUE)
|
||||
else()
|
||||
set(COMPILER_RT_ASAN_HAS_STATIC_RUNTIME FALSE)
|
||||
@ -475,49 +521,62 @@ else()
|
||||
endif()
|
||||
|
||||
if (COMPILER_RT_HAS_SANITIZER_COMMON AND LSAN_SUPPORTED_ARCH AND
|
||||
OS_NAME MATCHES "Darwin|Linux|FreeBSD")
|
||||
OS_NAME MATCHES "Darwin|Linux|FreeBSD|NetBSD")
|
||||
set(COMPILER_RT_HAS_LSAN TRUE)
|
||||
else()
|
||||
set(COMPILER_RT_HAS_LSAN FALSE)
|
||||
endif()
|
||||
|
||||
if (COMPILER_RT_HAS_SANITIZER_COMMON AND MSAN_SUPPORTED_ARCH AND
|
||||
OS_NAME MATCHES "Linux")
|
||||
OS_NAME MATCHES "Linux|NetBSD")
|
||||
set(COMPILER_RT_HAS_MSAN TRUE)
|
||||
else()
|
||||
set(COMPILER_RT_HAS_MSAN FALSE)
|
||||
endif()
|
||||
|
||||
if (COMPILER_RT_HAS_SANITIZER_COMMON AND HWASAN_SUPPORTED_ARCH AND
|
||||
OS_NAME MATCHES "Linux|Android")
|
||||
set(COMPILER_RT_HAS_HWASAN TRUE)
|
||||
else()
|
||||
set(COMPILER_RT_HAS_HWASAN FALSE)
|
||||
endif()
|
||||
|
||||
if (PROFILE_SUPPORTED_ARCH AND NOT LLVM_USE_SANITIZER AND
|
||||
OS_NAME MATCHES "Darwin|Linux|FreeBSD|Windows|Android")
|
||||
OS_NAME MATCHES "Darwin|Linux|FreeBSD|Windows|Android|SunOS")
|
||||
set(COMPILER_RT_HAS_PROFILE TRUE)
|
||||
else()
|
||||
set(COMPILER_RT_HAS_PROFILE FALSE)
|
||||
endif()
|
||||
|
||||
if (COMPILER_RT_HAS_SANITIZER_COMMON AND TSAN_SUPPORTED_ARCH AND
|
||||
OS_NAME MATCHES "Darwin|Linux|FreeBSD|Android")
|
||||
OS_NAME MATCHES "Darwin|Linux|FreeBSD|Android|NetBSD")
|
||||
set(COMPILER_RT_HAS_TSAN TRUE)
|
||||
else()
|
||||
set(COMPILER_RT_HAS_TSAN FALSE)
|
||||
endif()
|
||||
|
||||
if (COMPILER_RT_HAS_SANITIZER_COMMON AND UBSAN_SUPPORTED_ARCH AND
|
||||
OS_NAME MATCHES "Darwin|Linux|FreeBSD|Windows|Android")
|
||||
OS_NAME MATCHES "Darwin|Linux|FreeBSD|NetBSD|Windows|Android|Fuchsia")
|
||||
set(COMPILER_RT_HAS_UBSAN TRUE)
|
||||
else()
|
||||
set(COMPILER_RT_HAS_UBSAN FALSE)
|
||||
endif()
|
||||
|
||||
if (COMPILER_RT_HAS_SANITIZER_COMMON AND UBSAN_SUPPORTED_ARCH AND
|
||||
OS_NAME MATCHES "Linux|FreeBSD|NetBSD|Android|Darwin")
|
||||
set(COMPILER_RT_HAS_UBSAN_MINIMAL TRUE)
|
||||
else()
|
||||
set(COMPILER_RT_HAS_UBSAN_MINIMAL FALSE)
|
||||
endif()
|
||||
|
||||
if (COMPILER_RT_HAS_SANITIZER_COMMON AND SAFESTACK_SUPPORTED_ARCH AND
|
||||
OS_NAME MATCHES "Darwin|Linux|FreeBSD")
|
||||
OS_NAME MATCHES "Darwin|Linux|FreeBSD|NetBSD")
|
||||
set(COMPILER_RT_HAS_SAFESTACK TRUE)
|
||||
else()
|
||||
set(COMPILER_RT_HAS_SAFESTACK FALSE)
|
||||
endif()
|
||||
|
||||
if (COMPILER_RT_HAS_SANITIZER_COMMON AND CFI_SUPPORTED_ARCH AND
|
||||
OS_NAME MATCHES "Linux")
|
||||
if (COMPILER_RT_HAS_SANITIZER_COMMON AND CFI_SUPPORTED_ARCH)
|
||||
set(COMPILER_RT_HAS_CFI TRUE)
|
||||
else()
|
||||
set(COMPILER_RT_HAS_CFI FALSE)
|
||||
@ -531,15 +590,22 @@ else()
|
||||
endif()
|
||||
|
||||
if (COMPILER_RT_HAS_SANITIZER_COMMON AND SCUDO_SUPPORTED_ARCH AND
|
||||
OS_NAME MATCHES "Linux")
|
||||
OS_NAME MATCHES "Linux|Android")
|
||||
set(COMPILER_RT_HAS_SCUDO TRUE)
|
||||
else()
|
||||
set(COMPILER_RT_HAS_SCUDO FALSE)
|
||||
endif()
|
||||
|
||||
if (COMPILER_RT_HAS_SANITIZER_COMMON AND XRAY_SUPPORTED_ARCH AND
|
||||
OS_NAME MATCHES "Linux")
|
||||
OS_NAME MATCHES "Darwin|Linux")
|
||||
set(COMPILER_RT_HAS_XRAY TRUE)
|
||||
else()
|
||||
set(COMPILER_RT_HAS_XRAY FALSE)
|
||||
endif()
|
||||
|
||||
if (COMPILER_RT_HAS_SANITIZER_COMMON AND FUZZER_SUPPORTED_ARCH AND
|
||||
OS_NAME MATCHES "Android|Darwin|Linux|NetBSD")
|
||||
set(COMPILER_RT_HAS_FUZZER TRUE)
|
||||
else()
|
||||
set(COMPILER_RT_HAS_FUZZER FALSE)
|
||||
endif()
|
||||
|
@ -6,9 +6,11 @@ if (COMPILER_RT_BUILD_SANITIZERS)
|
||||
sanitizer/coverage_interface.h
|
||||
sanitizer/dfsan_interface.h
|
||||
sanitizer/esan_interface.h
|
||||
sanitizer/hwasan_interface.h
|
||||
sanitizer/linux_syscall_hooks.h
|
||||
sanitizer/lsan_interface.h
|
||||
sanitizer/msan_interface.h
|
||||
sanitizer/scudo_interface.h
|
||||
sanitizer/tsan_interface.h
|
||||
sanitizer/tsan_interface_atomic.h)
|
||||
endif(COMPILER_RT_BUILD_SANITIZERS)
|
||||
@ -43,9 +45,27 @@ set_target_properties(compiler-rt-headers PROPERTIES FOLDER "Compiler-RT Misc")
|
||||
|
||||
# Install sanitizer headers.
|
||||
install(FILES ${SANITIZER_HEADERS}
|
||||
COMPONENT compiler-rt-headers
|
||||
PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ
|
||||
DESTINATION ${COMPILER_RT_INSTALL_PATH}/include/sanitizer)
|
||||
# Install xray headers.
|
||||
install(FILES ${XRAY_HEADERS}
|
||||
COMPONENT compiler-rt-headers
|
||||
PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ
|
||||
DESTINATION ${COMPILER_RT_INSTALL_PATH}/include/xray)
|
||||
|
||||
if (NOT CMAKE_CONFIGURATION_TYPES) # don't add this for IDEs.
|
||||
add_custom_target(install-compiler-rt-headers
|
||||
DEPENDS compiler-rt-headers
|
||||
COMMAND "${CMAKE_COMMAND}"
|
||||
-DCMAKE_INSTALL_COMPONENT="compiler-rt-headers"
|
||||
-P "${CMAKE_BINARY_DIR}/cmake_install.cmake"
|
||||
USES_TERMINAL)
|
||||
add_custom_target(install-compiler-rt-headers-stripped
|
||||
DEPENDS compiler-rt-headers
|
||||
COMMAND "${CMAKE_COMMAND}"
|
||||
-DCMAKE_INSTALL_COMPONENT="compiler-rt-headers"
|
||||
-DCMAKE_INSTALL_DO_STRIP=1
|
||||
-P "${CMAKE_BINARY_DIR}/cmake_install.cmake"
|
||||
USES_TERMINAL)
|
||||
endif()
|
||||
|
@ -76,6 +76,13 @@ extern "C" {
|
||||
void (*malloc_hook)(const volatile void *, size_t),
|
||||
void (*free_hook)(const volatile void *));
|
||||
|
||||
/* Drains allocator quarantines (calling thread's and global ones), returns
|
||||
freed memory back to OS and releases other non-essential internal allocator
|
||||
resources in attempt to reduce process RSS.
|
||||
Currently available with ASan only.
|
||||
*/
|
||||
void __sanitizer_purge_allocator();
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
@ -144,6 +144,10 @@ extern "C" {
|
||||
void *__asan_addr_is_in_fake_stack(void *fake_stack, void *addr, void **beg,
|
||||
void **end);
|
||||
|
||||
// Performs cleanup before a [[noreturn]] function. Must be called
|
||||
// before things like _exit and execl to avoid false positives on stack.
|
||||
void __asan_handle_no_return(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
@ -22,8 +22,11 @@ extern "C" {
|
||||
// Record and dump coverage info.
|
||||
void __sanitizer_cov_dump();
|
||||
|
||||
// Dump collected coverage info. Sorts pcs by module into individual
|
||||
// .sancov files.
|
||||
// Clear collected coverage info.
|
||||
void __sanitizer_cov_reset();
|
||||
|
||||
// Dump collected coverage info. Sorts pcs by module into individual .sancov
|
||||
// files.
|
||||
void __sanitizer_dump_coverage(const uintptr_t *pcs, uintptr_t len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
33
include/sanitizer/hwasan_interface.h
Normal file
33
include/sanitizer/hwasan_interface.h
Normal file
@ -0,0 +1,33 @@
|
||||
//===-- sanitizer/asan_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 HWAddressSanitizer.
|
||||
//
|
||||
// Public interface header.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef SANITIZER_HWASAN_INTERFACE_H
|
||||
#define SANITIZER_HWASAN_INTERFACE_H
|
||||
|
||||
#include <sanitizer/common_interface_defs.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
// This function may be optionally provided by user and should return
|
||||
// a string containing HWASan runtime options. See asan_flags.h for details.
|
||||
const char* __hwasan_default_options();
|
||||
|
||||
void __hwasan_enable_allocator_tagging();
|
||||
void __hwasan_disable_allocator_tagging();
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // SANITIZER_HWASAN_INTERFACE_H
|
@ -64,8 +64,14 @@ extern "C" {
|
||||
// for the program it is linked into (if the return value is non-zero). This
|
||||
// function must be defined as returning a constant value; any behavior beyond
|
||||
// that is unsupported.
|
||||
// To avoid dead stripping, you may need to define this function with
|
||||
// __attribute__((used))
|
||||
int __lsan_is_turned_off();
|
||||
|
||||
// This function may be optionally provided by user and should return
|
||||
// a string containing LSan runtime options. See lsan_flags.inc for details.
|
||||
const char *__lsan_default_options();
|
||||
|
||||
// This function may be optionally provided by the user and should return
|
||||
// a string containing LSan suppressions.
|
||||
const char *__lsan_default_suppressions();
|
||||
|
34
include/sanitizer/scudo_interface.h
Normal file
34
include/sanitizer/scudo_interface.h
Normal file
@ -0,0 +1,34 @@
|
||||
//===-- sanitizer/scudo_interface.h -----------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
/// Public Scudo interface header.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef SANITIZER_SCUDO_INTERFACE_H_
|
||||
#define SANITIZER_SCUDO_INTERFACE_H_
|
||||
|
||||
#include <sanitizer/common_interface_defs.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
// This function may be optionally provided by a user and should return
|
||||
// a string containing Scudo runtime options. See scudo_flags.h for details.
|
||||
const char* __scudo_default_options();
|
||||
|
||||
// This function allows to set the RSS limit at runtime. This can be either
|
||||
// the hard limit (HardLimit=1) or the soft limit (HardLimit=0). The limit
|
||||
// can be removed by setting LimitMb to 0. This function's parameters should
|
||||
// be fully trusted to avoid security mishaps.
|
||||
void __scudo_set_rss_limit(unsigned long LimitMb, int HardLimit);
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // SANITIZER_SCUDO_INTERFACE_H_
|
@ -44,6 +44,11 @@ const unsigned __tsan_mutex_linker_init = 1 << 0;
|
||||
const unsigned __tsan_mutex_write_reentrant = 1 << 1;
|
||||
// Mutex is read reentrant.
|
||||
const unsigned __tsan_mutex_read_reentrant = 1 << 2;
|
||||
// Mutex does not have static storage duration, and must not be used after
|
||||
// its destructor runs. The opposite of __tsan_mutex_linker_init.
|
||||
// If this flag is passed to __tsan_mutex_destroy, then the destruction
|
||||
// is ignored unless this flag was previously set on the mutex.
|
||||
const unsigned __tsan_mutex_not_static = 1 << 8;
|
||||
|
||||
// Mutex operation flags:
|
||||
|
||||
@ -70,6 +75,7 @@ void __tsan_mutex_create(void *addr, unsigned flags);
|
||||
// Annotate destruction of a mutex.
|
||||
// Supported flags:
|
||||
// - __tsan_mutex_linker_init
|
||||
// - __tsan_mutex_not_static
|
||||
void __tsan_mutex_destroy(void *addr, unsigned flags);
|
||||
|
||||
// Annotate start of lock operation.
|
||||
|
@ -106,6 +106,14 @@ extern uintptr_t __xray_function_address(int32_t FuncId);
|
||||
/// encounter errors (when there are no instrumented functions, etc.).
|
||||
extern size_t __xray_max_function_id();
|
||||
|
||||
/// Initialize the required XRay data structures. This is useful in cases where
|
||||
/// users want to control precisely when the XRay instrumentation data
|
||||
/// structures are initialized, for example when the XRay library is built with
|
||||
/// the XRAY_NO_PREINIT preprocessor definition.
|
||||
///
|
||||
/// Calling __xray_init() more than once is safe across multiple threads.
|
||||
extern void __xray_init();
|
||||
|
||||
} // end extern "C"
|
||||
|
||||
#endif // XRAY_XRAY_INTERFACE_H
|
||||
|
@ -128,6 +128,16 @@ enum XRayLogFlushStatus {
|
||||
XRAY_LOG_FLUSHED = 2,
|
||||
};
|
||||
|
||||
/// This enum indicates the installation state of a logging implementation, when
|
||||
/// associating a mode to a particular logging implementation through
|
||||
/// `__xray_log_register_impl(...)` or through `__xray_log_select_mode(...`.
|
||||
enum XRayLogRegisterStatus {
|
||||
XRAY_REGISTRATION_OK = 0,
|
||||
XRAY_DUPLICATE_MODE = 1,
|
||||
XRAY_MODE_NOT_FOUND = 2,
|
||||
XRAY_INCOMPLETE_IMPL = 3,
|
||||
};
|
||||
|
||||
/// A valid XRay logging implementation MUST provide all of the function
|
||||
/// pointers in XRayLogImpl when being installed through `__xray_set_log_impl`.
|
||||
/// To be precise, ALL the functions pointers MUST NOT be nullptr.
|
||||
@ -159,6 +169,9 @@ struct XRayLogImpl {
|
||||
/// always have a handler for function entry and exit events. In case the
|
||||
/// implementation wants to support arg1 (or other future extensions to XRay
|
||||
/// logging) those MUST be installed by the installed 'log_init' handler.
|
||||
///
|
||||
/// Because we didn't want to change the ABI of this struct, the arg1 handler
|
||||
/// may be silently overwritten during initialization as well.
|
||||
void (*handle_arg0)(int32_t, XRayEntryType);
|
||||
|
||||
/// The log implementation provided routine for when __xray_log_flushLog() is
|
||||
@ -186,6 +199,34 @@ struct XRayLogImpl {
|
||||
/// called while in any other states.
|
||||
void __xray_set_log_impl(XRayLogImpl Impl);
|
||||
|
||||
/// This function registers a logging implementation against a "mode"
|
||||
/// identifier. This allows multiple modes to be registered, and chosen at
|
||||
/// runtime using the same mode identifier through
|
||||
/// `__xray_log_select_mode(...)`.
|
||||
///
|
||||
/// We treat the Mode identifier as a null-terminated byte string, as the
|
||||
/// identifier used when retrieving the log impl.
|
||||
///
|
||||
/// Returns:
|
||||
/// - XRAY_REGISTRATION_OK on success.
|
||||
/// - XRAY_DUPLICATE_MODE when an implementation is already associated with
|
||||
/// the provided Mode; does not update the already-registered
|
||||
/// implementation.
|
||||
XRayLogRegisterStatus __xray_log_register_mode(const char *Mode,
|
||||
XRayLogImpl Impl);
|
||||
|
||||
/// This function selects the implementation associated with Mode that has been
|
||||
/// registered through __xray_log_register_mode(...) and installs that
|
||||
/// implementation (as if through calling __xray_set_log_impl(...)). The same
|
||||
/// caveats apply to __xray_log_select_mode(...) as with
|
||||
/// __xray_log_set_log_impl(...).
|
||||
///
|
||||
/// Returns:
|
||||
/// - XRAY_REGISTRATION_OK on success.
|
||||
/// - XRAY_MODE_NOT_FOUND if there is no implementation associated with Mode;
|
||||
/// does not update the currently installed implementation.
|
||||
XRayLogRegisterStatus __xray_log_select_mode(const char *Mode);
|
||||
|
||||
/// This function removes the currently installed implementation. It will also
|
||||
/// uninstall any handlers that have been previously installed. It does NOT
|
||||
/// unpatch the instrumentation sleds.
|
||||
@ -220,12 +261,19 @@ XRayLogFlushStatus __xray_log_flushLog();
|
||||
|
||||
namespace __xray {
|
||||
|
||||
// Options used by the LLVM XRay FDR implementation.
|
||||
/// Options used by the LLVM XRay FDR logging implementation.
|
||||
struct FDRLoggingOptions {
|
||||
bool ReportErrors = false;
|
||||
int Fd = -1;
|
||||
};
|
||||
|
||||
/// Options used by the LLVM XRay Basic (Naive) logging implementation.
|
||||
struct BasicLoggingOptions {
|
||||
int DurationFilterMicros = 0;
|
||||
size_t MaxStackDepth = 0;
|
||||
size_t ThreadBufferSize = 0;
|
||||
};
|
||||
|
||||
} // namespace __xray
|
||||
|
||||
#endif // XRAY_XRAY_LOG_INTERFACE_H
|
||||
|
@ -17,6 +17,8 @@
|
||||
#ifndef XRAY_XRAY_RECORDS_H
|
||||
#define XRAY_XRAY_RECORDS_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace __xray {
|
||||
|
||||
enum FileTypes {
|
||||
@ -65,18 +67,23 @@ static_assert(sizeof(XRayFileHeader) == 32, "XRayFileHeader != 32 bytes");
|
||||
|
||||
enum RecordTypes {
|
||||
NORMAL = 0,
|
||||
ARG_PAYLOAD = 1,
|
||||
};
|
||||
|
||||
struct alignas(32) XRayRecord {
|
||||
// This is the type of the record being written. We use 16 bits to allow us to
|
||||
// treat this as a discriminant, and so that the first 4 bytes get packed
|
||||
// properly. See RecordTypes for more supported types.
|
||||
uint16_t RecordType = 0;
|
||||
uint16_t RecordType = RecordTypes::NORMAL;
|
||||
|
||||
// The CPU where the thread is running. We assume number of CPUs <= 256.
|
||||
uint8_t CPU = 0;
|
||||
|
||||
// The type of the event. Usually either ENTER = 0 or EXIT = 1.
|
||||
// The type of the event. One of the following:
|
||||
// ENTER = 0
|
||||
// EXIT = 1
|
||||
// TAIL_EXIT = 2
|
||||
// ENTER_ARG = 3
|
||||
uint8_t Type = 0;
|
||||
|
||||
// The function ID for the record.
|
||||
@ -94,6 +101,32 @@ struct alignas(32) XRayRecord {
|
||||
|
||||
static_assert(sizeof(XRayRecord) == 32, "XRayRecord != 32 bytes");
|
||||
|
||||
struct alignas(32) XRayArgPayload {
|
||||
// We use the same 16 bits as a discriminant for the records in the log here
|
||||
// too, and so that the first 4 bytes are packed properly.
|
||||
uint16_t RecordType = RecordTypes::ARG_PAYLOAD;
|
||||
|
||||
// Add a few bytes to pad.
|
||||
uint8_t Padding[2] = {};
|
||||
|
||||
// The function ID for the record.
|
||||
int32_t FuncId = 0;
|
||||
|
||||
// The thread ID for the currently running thread.
|
||||
uint32_t TId = 0;
|
||||
|
||||
// Add more padding.
|
||||
uint8_t Padding2[4] = {};
|
||||
|
||||
// The argument payload.
|
||||
uint64_t Arg = 0;
|
||||
|
||||
// The rest of this record ought to be left as padding.
|
||||
uint8_t TailPadding[8] = {};
|
||||
} __attribute__((packed));
|
||||
|
||||
static_assert(sizeof(XRayArgPayload) == 32, "XRayArgPayload != 32 bytes");
|
||||
|
||||
} // namespace __xray
|
||||
|
||||
#endif // XRAY_XRAY_RECORDS_H
|
||||
|
@ -39,10 +39,16 @@ if(COMPILER_RT_BUILD_SANITIZERS)
|
||||
foreach(sanitizer ${COMPILER_RT_SANITIZERS_TO_BUILD})
|
||||
compiler_rt_build_runtime(${sanitizer})
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if(COMPILER_RT_BUILD_PROFILE AND COMPILER_RT_HAS_PROFILE)
|
||||
compiler_rt_build_runtime(profile)
|
||||
endif()
|
||||
|
||||
if(COMPILER_RT_BUILD_XRAY)
|
||||
compiler_rt_build_runtime(xray)
|
||||
endif()
|
||||
|
||||
if(COMPILER_RT_BUILD_LIBFUZZER)
|
||||
compiler_rt_build_runtime(fuzzer)
|
||||
endif()
|
||||
|
@ -8,9 +8,11 @@ set(ASAN_SOURCES
|
||||
asan_errors.cc
|
||||
asan_fake_stack.cc
|
||||
asan_flags.cc
|
||||
asan_fuchsia.cc
|
||||
asan_globals.cc
|
||||
asan_globals_win.cc
|
||||
asan_interceptors.cc
|
||||
asan_interceptors_memintrinsics.cc
|
||||
asan_linux.cc
|
||||
asan_mac.cc
|
||||
asan_malloc_linux.cc
|
||||
@ -19,8 +21,10 @@ set(ASAN_SOURCES
|
||||
asan_memory_profile.cc
|
||||
asan_poisoning.cc
|
||||
asan_posix.cc
|
||||
asan_premap_shadow.cc
|
||||
asan_report.cc
|
||||
asan_rtl.cc
|
||||
asan_shadow_setup.cc
|
||||
asan_stack.cc
|
||||
asan_stats.cc
|
||||
asan_suppressions.cc
|
||||
@ -36,10 +40,11 @@ set(ASAN_PREINIT_SOURCES
|
||||
include_directories(..)
|
||||
|
||||
set(ASAN_CFLAGS ${SANITIZER_COMMON_CFLAGS})
|
||||
set(ASAN_COMMON_DEFINITIONS ${COMPILER_RT_ASAN_SHADOW_SCALE_DEFINITION})
|
||||
|
||||
append_rtti_flag(OFF ASAN_CFLAGS)
|
||||
|
||||
set(ASAN_DYNAMIC_LINK_FLAGS)
|
||||
set(ASAN_DYNAMIC_LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS})
|
||||
|
||||
if(ANDROID)
|
||||
# On Android, -z global does not do what it is documented to do.
|
||||
@ -64,12 +69,12 @@ append_list_if(COMPILER_RT_HAS_FTLS_MODEL_INITIAL_EXEC
|
||||
-ftls-model=initial-exec ASAN_DYNAMIC_CFLAGS)
|
||||
append_list_if(MSVC /DEBUG ASAN_DYNAMIC_LINK_FLAGS)
|
||||
|
||||
append_list_if(COMPILER_RT_HAS_LIBC c ASAN_DYNAMIC_LIBS)
|
||||
set(ASAN_DYNAMIC_LIBS ${SANITIZER_CXX_ABI_LIBRARY} ${SANITIZER_COMMON_LINK_LIBS})
|
||||
|
||||
append_list_if(COMPILER_RT_HAS_LIBDL dl ASAN_DYNAMIC_LIBS)
|
||||
append_list_if(COMPILER_RT_HAS_LIBRT rt ASAN_DYNAMIC_LIBS)
|
||||
append_list_if(COMPILER_RT_HAS_LIBM m ASAN_DYNAMIC_LIBS)
|
||||
append_list_if(COMPILER_RT_HAS_LIBPTHREAD pthread ASAN_DYNAMIC_LIBS)
|
||||
append_list_if(COMPILER_RT_HAS_LIBSTDCXX stdc++ ASAN_DYNAMIC_LIBS)
|
||||
append_list_if(COMPILER_RT_HAS_LIBLOG log ASAN_DYNAMIC_LIBS)
|
||||
|
||||
# Compile ASan sources into an object library.
|
||||
@ -164,15 +169,15 @@ else()
|
||||
PARENT_TARGET asan)
|
||||
|
||||
foreach(arch ${ASAN_SUPPORTED_ARCH})
|
||||
if (UNIX AND NOT ${arch} MATCHES "i386|i686")
|
||||
if (UNIX)
|
||||
add_sanitizer_rt_version_list(clang_rt.asan-dynamic-${arch}
|
||||
LIBS clang_rt.asan-${arch} clang_rt.asan_cxx-${arch}
|
||||
EXTRA asan.syms.extra)
|
||||
set(VERSION_SCRIPT_FLAG
|
||||
-Wl,--version-script,${CMAKE_CURRENT_BINARY_DIR}/clang_rt.asan-dynamic-${arch}.vers)
|
||||
set_source_files_properties(
|
||||
set_property(SOURCE
|
||||
${CMAKE_CURRENT_BINARY_DIR}/dummy.cc
|
||||
PROPERTIES
|
||||
APPEND PROPERTY
|
||||
OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/clang_rt.asan-dynamic-${arch}.vers)
|
||||
else()
|
||||
set(VERSION_SCRIPT_FLAG)
|
||||
@ -198,10 +203,11 @@ else()
|
||||
ARCHS ${arch}
|
||||
OBJECT_LIBS ${ASAN_COMMON_RUNTIME_OBJECT_LIBS}
|
||||
RTAsan_dynamic
|
||||
# The only purpose of RTAsan_dynamic_version_script_dummy is to carry
|
||||
# a dependency of the shared runtime on the version script. With CMake
|
||||
# 3.1 or later it can be replaced with a straightforward
|
||||
# The only purpose of RTAsan_dynamic_version_script_dummy is to
|
||||
# carry a dependency of the shared runtime on the version script.
|
||||
# Replacing it with a straightforward
|
||||
# add_dependencies(clang_rt.asan-dynamic-${arch} clang_rt.asan-dynamic-${arch}-version-list)
|
||||
# generates an order-only dependency in ninja.
|
||||
RTAsan_dynamic_version_script_dummy
|
||||
RTUbsan_cxx
|
||||
${ASAN_DYNAMIC_WEAK_INTERCEPTION}
|
||||
@ -212,7 +218,7 @@ else()
|
||||
DEFS ${ASAN_DYNAMIC_DEFINITIONS}
|
||||
PARENT_TARGET asan)
|
||||
|
||||
if (UNIX AND NOT ${arch} MATCHES "i386|i686")
|
||||
if (UNIX AND NOT ${arch} STREQUAL "i386")
|
||||
add_sanitizer_rt_symbols(clang_rt.asan_cxx
|
||||
ARCHS ${arch})
|
||||
add_dependencies(asan clang_rt.asan_cxx-${arch}-symbols)
|
||||
|
@ -16,8 +16,10 @@
|
||||
#include "asan_allocator.h"
|
||||
#include "asan_flags.h"
|
||||
#include "asan_internal.h"
|
||||
#include "asan_mapping.h"
|
||||
#include "asan_poisoning.h"
|
||||
#include "asan_stack.h"
|
||||
#include "sanitizer_common/sanitizer_common.h"
|
||||
#include "sanitizer_common/sanitizer_flags.h"
|
||||
|
||||
namespace __asan {
|
||||
@ -110,8 +112,9 @@ void AsanDeactivate() {
|
||||
AllocatorOptions disabled = asan_deactivated_flags.allocator_options;
|
||||
disabled.quarantine_size_mb = 0;
|
||||
disabled.thread_local_quarantine_size_kb = 0;
|
||||
disabled.min_redzone = 16; // Redzone must be at least 16 bytes long.
|
||||
disabled.max_redzone = 16;
|
||||
// Redzone must be at least Max(16, granularity) bytes long.
|
||||
disabled.min_redzone = Max(16, (int)SHADOW_GRANULARITY);
|
||||
disabled.max_redzone = disabled.min_redzone;
|
||||
disabled.alloc_dealloc_mismatch = false;
|
||||
disabled.may_return_null = true;
|
||||
ReInitializeAllocator(disabled);
|
||||
|
@ -84,7 +84,10 @@ struct ChunkHeader {
|
||||
// This field is used for small sizes. For large sizes it is equal to
|
||||
// SizeClassMap::kMaxSize and the actual size is stored in the
|
||||
// SecondaryAllocator's metadata.
|
||||
u32 user_requested_size;
|
||||
u32 user_requested_size : 29;
|
||||
// align < 8 -> 0
|
||||
// else -> log2(min(align, 512)) - 2
|
||||
u32 user_requested_alignment_log : 3;
|
||||
u32 alloc_context_id;
|
||||
};
|
||||
|
||||
@ -271,9 +274,9 @@ struct Allocator {
|
||||
atomic_store(&max_redzone, options.max_redzone, memory_order_release);
|
||||
}
|
||||
|
||||
void Initialize(const AllocatorOptions &options) {
|
||||
void InitLinkerInitialized(const AllocatorOptions &options) {
|
||||
SetAllocatorMayReturnNull(options.may_return_null);
|
||||
allocator.Init(options.release_to_os_interval_ms);
|
||||
allocator.InitLinkerInitialized(options.release_to_os_interval_ms);
|
||||
SharedInitCode(options);
|
||||
}
|
||||
|
||||
@ -351,6 +354,20 @@ struct Allocator {
|
||||
return Min(Max(rz_log, RZSize2Log(min_rz)), RZSize2Log(max_rz));
|
||||
}
|
||||
|
||||
static uptr ComputeUserRequestedAlignmentLog(uptr user_requested_alignment) {
|
||||
if (user_requested_alignment < 8)
|
||||
return 0;
|
||||
if (user_requested_alignment > 512)
|
||||
user_requested_alignment = 512;
|
||||
return Log2(user_requested_alignment) - 2;
|
||||
}
|
||||
|
||||
static uptr ComputeUserAlignment(uptr user_requested_alignment_log) {
|
||||
if (user_requested_alignment_log == 0)
|
||||
return 0;
|
||||
return 1LL << (user_requested_alignment_log + 2);
|
||||
}
|
||||
|
||||
// We have an address between two chunks, and we want to report just one.
|
||||
AsanChunk *ChooseChunk(uptr addr, AsanChunk *left_chunk,
|
||||
AsanChunk *right_chunk) {
|
||||
@ -385,6 +402,8 @@ struct Allocator {
|
||||
Flags &fl = *flags();
|
||||
CHECK(stack);
|
||||
const uptr min_alignment = SHADOW_GRANULARITY;
|
||||
const uptr user_requested_alignment_log =
|
||||
ComputeUserRequestedAlignmentLog(alignment);
|
||||
if (alignment < min_alignment)
|
||||
alignment = min_alignment;
|
||||
if (size == 0) {
|
||||
@ -472,6 +491,7 @@ struct Allocator {
|
||||
meta[0] = size;
|
||||
meta[1] = chunk_beg;
|
||||
}
|
||||
m->user_requested_alignment_log = user_requested_alignment_log;
|
||||
|
||||
m->alloc_context_id = StackDepotPut(*stack);
|
||||
|
||||
@ -573,8 +593,8 @@ struct Allocator {
|
||||
}
|
||||
}
|
||||
|
||||
void Deallocate(void *ptr, uptr delete_size, BufferedStackTrace *stack,
|
||||
AllocType alloc_type) {
|
||||
void Deallocate(void *ptr, uptr delete_size, uptr delete_alignment,
|
||||
BufferedStackTrace *stack, AllocType alloc_type) {
|
||||
uptr p = reinterpret_cast<uptr>(ptr);
|
||||
if (p == 0) return;
|
||||
|
||||
@ -601,11 +621,14 @@ struct Allocator {
|
||||
ReportAllocTypeMismatch((uptr)ptr, stack, (AllocType)m->alloc_type,
|
||||
(AllocType)alloc_type);
|
||||
}
|
||||
} else {
|
||||
if (flags()->new_delete_type_mismatch &&
|
||||
(alloc_type == FROM_NEW || alloc_type == FROM_NEW_BR) &&
|
||||
((delete_size && delete_size != m->UsedSize()) ||
|
||||
ComputeUserRequestedAlignmentLog(delete_alignment) !=
|
||||
m->user_requested_alignment_log)) {
|
||||
ReportNewDeleteTypeMismatch(p, delete_size, delete_alignment, stack);
|
||||
}
|
||||
|
||||
if (delete_size && flags()->new_delete_type_mismatch &&
|
||||
delete_size != m->UsedSize()) {
|
||||
ReportNewDeleteSizeMismatch(p, delete_size, stack);
|
||||
}
|
||||
|
||||
QuarantineChunk(m, ptr, stack);
|
||||
@ -631,7 +654,7 @@ struct Allocator {
|
||||
// If realloc() races with free(), we may start copying freed memory.
|
||||
// However, we will report racy double-free later anyway.
|
||||
REAL(memcpy)(new_ptr, old_ptr, memcpy_size);
|
||||
Deallocate(old_ptr, 0, stack, FROM_MALLOC);
|
||||
Deallocate(old_ptr, 0, 0, stack, FROM_MALLOC);
|
||||
}
|
||||
return new_ptr;
|
||||
}
|
||||
@ -716,6 +739,22 @@ struct Allocator {
|
||||
return AsanChunkView(m1);
|
||||
}
|
||||
|
||||
void Purge() {
|
||||
AsanThread *t = GetCurrentThread();
|
||||
if (t) {
|
||||
AsanThreadLocalMallocStorage *ms = &t->malloc_storage();
|
||||
quarantine.DrainAndRecycle(GetQuarantineCache(ms),
|
||||
QuarantineCallback(GetAllocatorCache(ms)));
|
||||
}
|
||||
{
|
||||
SpinMutexLock l(&fallback_mutex);
|
||||
quarantine.DrainAndRecycle(&fallback_quarantine_cache,
|
||||
QuarantineCallback(&fallback_allocator_cache));
|
||||
}
|
||||
|
||||
allocator.ForceReleaseToOS();
|
||||
}
|
||||
|
||||
void PrintStats() {
|
||||
allocator.PrintStats();
|
||||
quarantine.PrintStats();
|
||||
@ -750,6 +789,9 @@ bool AsanChunkView::IsQuarantined() const {
|
||||
uptr AsanChunkView::Beg() const { return chunk_->Beg(); }
|
||||
uptr AsanChunkView::End() const { return Beg() + UsedSize(); }
|
||||
uptr AsanChunkView::UsedSize() const { return chunk_->UsedSize(); }
|
||||
u32 AsanChunkView::UserRequestedAlignment() const {
|
||||
return Allocator::ComputeUserAlignment(chunk_->user_requested_alignment_log);
|
||||
}
|
||||
uptr AsanChunkView::AllocTid() const { return chunk_->alloc_tid; }
|
||||
uptr AsanChunkView::FreeTid() const { return chunk_->free_tid; }
|
||||
AllocType AsanChunkView::GetAllocType() const {
|
||||
@ -775,7 +817,7 @@ StackTrace AsanChunkView::GetFreeStack() const {
|
||||
}
|
||||
|
||||
void InitializeAllocator(const AllocatorOptions &options) {
|
||||
instance.Initialize(options);
|
||||
instance.InitLinkerInitialized(options);
|
||||
}
|
||||
|
||||
void ReInitializeAllocator(const AllocatorOptions &options) {
|
||||
@ -802,12 +844,12 @@ void PrintInternalAllocatorStats() {
|
||||
}
|
||||
|
||||
void asan_free(void *ptr, BufferedStackTrace *stack, AllocType alloc_type) {
|
||||
instance.Deallocate(ptr, 0, stack, alloc_type);
|
||||
instance.Deallocate(ptr, 0, 0, stack, alloc_type);
|
||||
}
|
||||
|
||||
void asan_sized_free(void *ptr, uptr size, BufferedStackTrace *stack,
|
||||
AllocType alloc_type) {
|
||||
instance.Deallocate(ptr, size, stack, alloc_type);
|
||||
void asan_delete(void *ptr, uptr size, uptr alignment,
|
||||
BufferedStackTrace *stack, AllocType alloc_type) {
|
||||
instance.Deallocate(ptr, size, alignment, stack, alloc_type);
|
||||
}
|
||||
|
||||
void *asan_malloc(uptr size, BufferedStackTrace *stack) {
|
||||
@ -823,7 +865,7 @@ void *asan_realloc(void *p, uptr size, BufferedStackTrace *stack) {
|
||||
return SetErrnoOnNull(instance.Allocate(size, 8, stack, FROM_MALLOC, true));
|
||||
if (size == 0) {
|
||||
if (flags()->allocator_frees_and_returns_null_on_realloc_zero) {
|
||||
instance.Deallocate(p, 0, stack, FROM_MALLOC);
|
||||
instance.Deallocate(p, 0, 0, stack, FROM_MALLOC);
|
||||
return nullptr;
|
||||
}
|
||||
// Allocate a size of 1 if we shouldn't free() on Realloc to 0
|
||||
@ -839,6 +881,10 @@ void *asan_valloc(uptr size, BufferedStackTrace *stack) {
|
||||
|
||||
void *asan_pvalloc(uptr size, BufferedStackTrace *stack) {
|
||||
uptr PageSize = GetPageSizeCached();
|
||||
if (UNLIKELY(CheckForPvallocOverflow(size, PageSize))) {
|
||||
errno = errno_ENOMEM;
|
||||
return AsanAllocator::FailureHandler::OnBadRequest();
|
||||
}
|
||||
// pvalloc(0) should allocate one page.
|
||||
size = size ? RoundUpTo(size, PageSize) : PageSize;
|
||||
return SetErrnoOnNull(
|
||||
@ -1007,6 +1053,10 @@ uptr __sanitizer_get_allocated_size(const void *p) {
|
||||
return allocated_size;
|
||||
}
|
||||
|
||||
void __sanitizer_purge_allocator() {
|
||||
instance.Purge();
|
||||
}
|
||||
|
||||
#if !SANITIZER_SUPPORTS_WEAK_HOOKS
|
||||
// Provide default (no-op) implementation of malloc hooks.
|
||||
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_malloc_hook,
|
||||
|
@ -58,6 +58,7 @@ class AsanChunkView {
|
||||
uptr Beg() const; // First byte of user memory.
|
||||
uptr End() const; // Last byte of user memory.
|
||||
uptr UsedSize() const; // Size requested by the user.
|
||||
u32 UserRequestedAlignment() const; // Originally requested alignment.
|
||||
uptr AllocTid() const;
|
||||
uptr FreeTid() const;
|
||||
bool Eq(const AsanChunkView &c) const { return chunk_ == c.chunk_; }
|
||||
@ -119,7 +120,11 @@ struct AsanMapUnmapCallback {
|
||||
};
|
||||
|
||||
#if SANITIZER_CAN_USE_ALLOCATOR64
|
||||
# if defined(__powerpc64__)
|
||||
# if SANITIZER_FUCHSIA
|
||||
const uptr kAllocatorSpace = ~(uptr)0;
|
||||
const uptr kAllocatorSize = 0x40000000000ULL; // 4T.
|
||||
typedef DefaultSizeClassMap SizeClassMap;
|
||||
# elif defined(__powerpc64__)
|
||||
const uptr kAllocatorSpace = 0xa0000000000ULL;
|
||||
const uptr kAllocatorSize = 0x20000000000ULL; // 2T.
|
||||
typedef DefaultSizeClassMap SizeClassMap;
|
||||
@ -193,8 +198,8 @@ struct AsanThreadLocalMallocStorage {
|
||||
void *asan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack,
|
||||
AllocType alloc_type);
|
||||
void asan_free(void *ptr, BufferedStackTrace *stack, AllocType alloc_type);
|
||||
void asan_sized_free(void *ptr, uptr size, BufferedStackTrace *stack,
|
||||
AllocType alloc_type);
|
||||
void asan_delete(void *ptr, uptr size, uptr alignment,
|
||||
BufferedStackTrace *stack, AllocType alloc_type);
|
||||
|
||||
void *asan_malloc(uptr size, BufferedStackTrace *stack);
|
||||
void *asan_calloc(uptr nmemb, uptr size, BufferedStackTrace *stack);
|
||||
|
@ -122,6 +122,7 @@ static void GetAccessToHeapChunkInformation(ChunkAccess *descr,
|
||||
}
|
||||
descr->chunk_begin = chunk.Beg();
|
||||
descr->chunk_size = chunk.UsedSize();
|
||||
descr->user_requested_alignment = chunk.UserRequestedAlignment();
|
||||
descr->alloc_type = chunk.GetAllocType();
|
||||
}
|
||||
|
||||
@ -150,7 +151,7 @@ static void PrintHeapChunkAccess(uptr addr, const ChunkAccess &descr) {
|
||||
str.append(" %zu-byte region [%p,%p)\n", descr.chunk_size,
|
||||
(void *)descr.chunk_begin,
|
||||
(void *)(descr.chunk_begin + descr.chunk_size));
|
||||
str.append("%s", d.EndLocation());
|
||||
str.append("%s", d.Default());
|
||||
Printf("%s", str.data());
|
||||
}
|
||||
|
||||
@ -260,7 +261,7 @@ static void PrintAccessAndVarIntersection(const StackVarDescr &var, uptr addr,
|
||||
// FIXME: we may want to also print the size of the access here,
|
||||
// but in case of accesses generated by memset it may be confusing.
|
||||
str.append("%s <== Memory access at offset %zd %s this variable%s\n",
|
||||
d.Location(), addr, pos_descr, d.EndLocation());
|
||||
d.Location(), addr, pos_descr, d.Default());
|
||||
} else {
|
||||
str.append("\n");
|
||||
}
|
||||
@ -295,7 +296,7 @@ static void DescribeAddressRelativeToGlobal(uptr addr, uptr access_size,
|
||||
MaybeDemangleGlobalName(g.name));
|
||||
PrintGlobalLocation(&str, g);
|
||||
str.append("' (0x%zx) of size %zu\n", g.beg, g.size);
|
||||
str.append("%s", d.EndLocation());
|
||||
str.append("%s", d.Default());
|
||||
PrintGlobalNameIfASCII(&str, g);
|
||||
Printf("%s", str.data());
|
||||
}
|
||||
@ -335,6 +336,26 @@ void GlobalAddressDescription::Print(const char *bug_type) const {
|
||||
}
|
||||
}
|
||||
|
||||
bool GlobalAddressDescription::PointsInsideTheSameVariable(
|
||||
const GlobalAddressDescription &other) const {
|
||||
if (size == 0 || other.size == 0) return false;
|
||||
|
||||
for (uptr i = 0; i < size; i++) {
|
||||
const __asan_global &a = globals[i];
|
||||
for (uptr j = 0; j < other.size; j++) {
|
||||
const __asan_global &b = other.globals[j];
|
||||
if (a.beg == b.beg &&
|
||||
a.beg <= addr &&
|
||||
b.beg <= other.addr &&
|
||||
(addr + access_size) < (a.beg + a.size) &&
|
||||
(other.addr + other.access_size) < (b.beg + b.size))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void StackAddressDescription::Print() const {
|
||||
Decorator d;
|
||||
char tname[128];
|
||||
@ -343,10 +364,10 @@ void StackAddressDescription::Print() const {
|
||||
ThreadNameWithParenthesis(tid, tname, sizeof(tname)));
|
||||
|
||||
if (!frame_descr) {
|
||||
Printf("%s\n", d.EndLocation());
|
||||
Printf("%s\n", d.Default());
|
||||
return;
|
||||
}
|
||||
Printf(" at offset %zu in frame%s\n", offset, d.EndLocation());
|
||||
Printf(" at offset %zu in frame%s\n", offset, d.Default());
|
||||
|
||||
// Now we print the frame where the alloca has happened.
|
||||
// We print this frame as a stack trace with one element.
|
||||
@ -355,7 +376,7 @@ void StackAddressDescription::Print() const {
|
||||
// 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).
|
||||
Printf("%s", d.EndLocation());
|
||||
Printf("%s", d.Default());
|
||||
StackTrace alloca_stack(&frame_pc, 1);
|
||||
alloca_stack.Print();
|
||||
|
||||
@ -405,18 +426,18 @@ void HeapAddressDescription::Print() const {
|
||||
Printf("%sfreed by thread T%d%s here:%s\n", d.Allocation(),
|
||||
free_thread->tid,
|
||||
ThreadNameWithParenthesis(free_thread, tname, sizeof(tname)),
|
||||
d.EndAllocation());
|
||||
d.Default());
|
||||
StackTrace free_stack = GetStackTraceFromId(free_stack_id);
|
||||
free_stack.Print();
|
||||
Printf("%spreviously allocated by thread T%d%s here:%s\n", d.Allocation(),
|
||||
alloc_thread->tid,
|
||||
ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)),
|
||||
d.EndAllocation());
|
||||
d.Default());
|
||||
} else {
|
||||
Printf("%sallocated by thread T%d%s here:%s\n", d.Allocation(),
|
||||
alloc_thread->tid,
|
||||
ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)),
|
||||
d.EndAllocation());
|
||||
d.Default());
|
||||
}
|
||||
alloc_stack.Print();
|
||||
DescribeThread(GetCurrentThread());
|
||||
|
@ -34,11 +34,8 @@ class Decorator : public __sanitizer::SanitizerCommonDecorator {
|
||||
public:
|
||||
Decorator() : SanitizerCommonDecorator() {}
|
||||
const char *Access() { return Blue(); }
|
||||
const char *EndAccess() { return Default(); }
|
||||
const char *Location() { return Green(); }
|
||||
const char *EndLocation() { return Default(); }
|
||||
const char *Allocation() { return Magenta(); }
|
||||
const char *EndAllocation() { return Default(); }
|
||||
|
||||
const char *ShadowByte(u8 byte) {
|
||||
switch (byte) {
|
||||
@ -72,9 +69,6 @@ class Decorator : public __sanitizer::SanitizerCommonDecorator {
|
||||
return Default();
|
||||
}
|
||||
}
|
||||
const char *EndShadowByte() { return Default(); }
|
||||
const char *MemoryByte() { return Magenta(); }
|
||||
const char *EndMemoryByte() { return Default(); }
|
||||
};
|
||||
|
||||
enum ShadowKind : u8 {
|
||||
@ -108,6 +102,7 @@ struct ChunkAccess {
|
||||
sptr offset;
|
||||
uptr chunk_begin;
|
||||
uptr chunk_size;
|
||||
u32 user_requested_alignment : 12;
|
||||
u32 access_type : 2;
|
||||
u32 alloc_type : 2;
|
||||
};
|
||||
@ -151,6 +146,10 @@ struct GlobalAddressDescription {
|
||||
u8 size;
|
||||
|
||||
void Print(const char *bug_type = "") const;
|
||||
|
||||
// Returns true when this descriptions points inside the same global variable
|
||||
// as other. Descriptions can have different address within the variable
|
||||
bool PointsInsideTheSameVariable(const GlobalAddressDescription &other) const;
|
||||
};
|
||||
|
||||
bool GetGlobalAddressInformation(uptr addr, uptr access_size,
|
||||
|
@ -13,7 +13,6 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "asan_errors.h"
|
||||
#include <signal.h>
|
||||
#include "asan_descriptions.h"
|
||||
#include "asan_mapping.h"
|
||||
#include "asan_report.h"
|
||||
@ -22,82 +21,26 @@
|
||||
|
||||
namespace __asan {
|
||||
|
||||
void ErrorStackOverflow::Print() {
|
||||
Decorator d;
|
||||
Printf("%s", d.Warning());
|
||||
Report(
|
||||
"ERROR: AddressSanitizer: %s on address %p"
|
||||
" (pc %p bp %p sp %p T%d)\n", scariness.GetDescription(),
|
||||
(void *)addr, (void *)pc, (void *)bp, (void *)sp, tid);
|
||||
Printf("%s", d.EndWarning());
|
||||
scariness.Print();
|
||||
BufferedStackTrace stack;
|
||||
GetStackTraceWithPcBpAndContext(&stack, kStackTraceMax, pc, bp, context,
|
||||
common_flags()->fast_unwind_on_fatal);
|
||||
stack.Print();
|
||||
ReportErrorSummary(scariness.GetDescription(), &stack);
|
||||
}
|
||||
|
||||
static void MaybeDumpInstructionBytes(uptr pc) {
|
||||
if (!flags()->dump_instruction_bytes || (pc < GetPageSizeCached())) return;
|
||||
InternalScopedString str(1024);
|
||||
str.append("First 16 instruction bytes at pc: ");
|
||||
if (IsAccessibleMemoryRange(pc, 16)) {
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
PrintMemoryByte(&str, "", ((u8 *)pc)[i], /*in_shadow*/ false, " ");
|
||||
}
|
||||
str.append("\n");
|
||||
} else {
|
||||
str.append("unaccessible\n");
|
||||
}
|
||||
Report("%s", str.data());
|
||||
}
|
||||
|
||||
static void MaybeDumpRegisters(void *context) {
|
||||
if (!flags()->dump_registers) return;
|
||||
SignalContext::DumpAllRegisters(context);
|
||||
}
|
||||
|
||||
static void MaybeReportNonExecRegion(uptr pc) {
|
||||
#if SANITIZER_FREEBSD || SANITIZER_LINUX
|
||||
MemoryMappingLayout proc_maps(/*cache_enabled*/ true);
|
||||
MemoryMappedSegment segment;
|
||||
while (proc_maps.Next(&segment)) {
|
||||
if (pc >= segment.start && pc < segment.end && !segment.IsExecutable())
|
||||
Report("Hint: PC is at a non-executable region. Maybe a wild jump?\n");
|
||||
}
|
||||
static void OnStackUnwind(const SignalContext &sig,
|
||||
const void *callback_context,
|
||||
BufferedStackTrace *stack) {
|
||||
bool fast = common_flags()->fast_unwind_on_fatal;
|
||||
#if SANITIZER_FREEBSD || SANITIZER_NETBSD
|
||||
// On FreeBSD the slow unwinding that leverages _Unwind_Backtrace()
|
||||
// yields the call stack of the signal's handler and not of the code
|
||||
// that raised the signal (as it does on Linux).
|
||||
fast = true;
|
||||
#endif
|
||||
// Tests and maybe some users expect that scariness is going to be printed
|
||||
// just before the stack. As only asan has scariness score we have no
|
||||
// corresponding code in the sanitizer_common and we use this callback to
|
||||
// print it.
|
||||
static_cast<const ScarinessScoreBase *>(callback_context)->Print();
|
||||
GetStackTrace(stack, kStackTraceMax, sig.pc, sig.bp, sig.context, fast);
|
||||
}
|
||||
|
||||
void ErrorDeadlySignal::Print() {
|
||||
Decorator d;
|
||||
Printf("%s", d.Warning());
|
||||
const char *description = __sanitizer::DescribeSignalOrException(signo);
|
||||
Report(
|
||||
"ERROR: AddressSanitizer: %s on unknown address %p (pc %p bp %p sp %p "
|
||||
"T%d)\n",
|
||||
description, (void *)addr, (void *)pc, (void *)bp, (void *)sp, tid);
|
||||
Printf("%s", d.EndWarning());
|
||||
if (pc < GetPageSizeCached()) Report("Hint: pc points to the zero page.\n");
|
||||
if (is_memory_access) {
|
||||
const char *access_type =
|
||||
write_flag == SignalContext::WRITE
|
||||
? "WRITE"
|
||||
: (write_flag == SignalContext::READ ? "READ" : "UNKNOWN");
|
||||
Report("The signal is caused by a %s memory access.\n", access_type);
|
||||
if (addr < GetPageSizeCached())
|
||||
Report("Hint: address points to the zero page.\n");
|
||||
}
|
||||
MaybeReportNonExecRegion(pc);
|
||||
scariness.Print();
|
||||
BufferedStackTrace stack;
|
||||
GetStackTraceWithPcBpAndContext(&stack, kStackTraceMax, pc, bp, context,
|
||||
common_flags()->fast_unwind_on_fatal);
|
||||
stack.Print();
|
||||
MaybeDumpInstructionBytes(pc);
|
||||
MaybeDumpRegisters(context);
|
||||
Printf("AddressSanitizer can not provide additional info.\n");
|
||||
ReportErrorSummary(description, &stack);
|
||||
ReportDeadlySignal(signal, tid, &OnStackUnwind, &scariness);
|
||||
}
|
||||
|
||||
void ErrorDoubleFree::Print() {
|
||||
@ -109,7 +52,7 @@ void ErrorDoubleFree::Print() {
|
||||
"thread T%d%s:\n",
|
||||
scariness.GetDescription(), addr_description.addr, tid,
|
||||
ThreadNameWithParenthesis(tid, tname, sizeof(tname)));
|
||||
Printf("%s", d.EndWarning());
|
||||
Printf("%s", d.Default());
|
||||
scariness.Print();
|
||||
GET_STACK_TRACE_FATAL(second_free_stack->trace[0],
|
||||
second_free_stack->top_frame_bp);
|
||||
@ -118,7 +61,7 @@ void ErrorDoubleFree::Print() {
|
||||
ReportErrorSummary(scariness.GetDescription(), &stack);
|
||||
}
|
||||
|
||||
void ErrorNewDeleteSizeMismatch::Print() {
|
||||
void ErrorNewDeleteTypeMismatch::Print() {
|
||||
Decorator d;
|
||||
Printf("%s", d.Warning());
|
||||
char tname[128];
|
||||
@ -127,11 +70,29 @@ void ErrorNewDeleteSizeMismatch::Print() {
|
||||
"T%d%s:\n",
|
||||
scariness.GetDescription(), addr_description.addr, tid,
|
||||
ThreadNameWithParenthesis(tid, tname, sizeof(tname)));
|
||||
Printf("%s object passed to delete has wrong type:\n", d.EndWarning());
|
||||
Printf("%s object passed to delete has wrong type:\n", d.Default());
|
||||
if (delete_size != 0) {
|
||||
Printf(
|
||||
" size of the allocated type: %zd bytes;\n"
|
||||
" size of the deallocated type: %zd bytes.\n",
|
||||
addr_description.chunk_access.chunk_size, delete_size);
|
||||
}
|
||||
const uptr user_alignment =
|
||||
addr_description.chunk_access.user_requested_alignment;
|
||||
if (delete_alignment != user_alignment) {
|
||||
char user_alignment_str[32];
|
||||
char delete_alignment_str[32];
|
||||
internal_snprintf(user_alignment_str, sizeof(user_alignment_str),
|
||||
"%zd bytes", user_alignment);
|
||||
internal_snprintf(delete_alignment_str, sizeof(delete_alignment_str),
|
||||
"%zd bytes", delete_alignment);
|
||||
static const char *kDefaultAlignment = "default-aligned";
|
||||
Printf(
|
||||
" alignment of the allocated type: %s;\n"
|
||||
" alignment of the deallocated type: %s.\n",
|
||||
user_alignment > 0 ? user_alignment_str : kDefaultAlignment,
|
||||
delete_alignment > 0 ? delete_alignment_str : kDefaultAlignment);
|
||||
}
|
||||
CHECK_GT(free_stack->size, 0);
|
||||
scariness.Print();
|
||||
GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp);
|
||||
@ -152,7 +113,7 @@ void ErrorFreeNotMalloced::Print() {
|
||||
"which was not malloc()-ed: %p in thread T%d%s\n",
|
||||
addr_description.Address(), tid,
|
||||
ThreadNameWithParenthesis(tid, tname, sizeof(tname)));
|
||||
Printf("%s", d.EndWarning());
|
||||
Printf("%s", d.Default());
|
||||
CHECK_GT(free_stack->size, 0);
|
||||
scariness.Print();
|
||||
GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp);
|
||||
@ -173,7 +134,7 @@ void ErrorAllocTypeMismatch::Print() {
|
||||
scariness.GetDescription(),
|
||||
alloc_names[alloc_type], dealloc_names[dealloc_type],
|
||||
addr_description.addr);
|
||||
Printf("%s", d.EndWarning());
|
||||
Printf("%s", d.Default());
|
||||
CHECK_GT(dealloc_stack->size, 0);
|
||||
scariness.Print();
|
||||
GET_STACK_TRACE_FATAL(dealloc_stack->trace[0], dealloc_stack->top_frame_bp);
|
||||
@ -192,7 +153,7 @@ void ErrorMallocUsableSizeNotOwned::Print() {
|
||||
"ERROR: AddressSanitizer: attempting to call malloc_usable_size() for "
|
||||
"pointer which is not owned: %p\n",
|
||||
addr_description.Address());
|
||||
Printf("%s", d.EndWarning());
|
||||
Printf("%s", d.Default());
|
||||
stack->Print();
|
||||
addr_description.Print();
|
||||
ReportErrorSummary(scariness.GetDescription(), stack);
|
||||
@ -205,7 +166,7 @@ void ErrorSanitizerGetAllocatedSizeNotOwned::Print() {
|
||||
"ERROR: AddressSanitizer: attempting to call "
|
||||
"__sanitizer_get_allocated_size() for pointer which is not owned: %p\n",
|
||||
addr_description.Address());
|
||||
Printf("%s", d.EndWarning());
|
||||
Printf("%s", d.Default());
|
||||
stack->Print();
|
||||
addr_description.Print();
|
||||
ReportErrorSummary(scariness.GetDescription(), stack);
|
||||
@ -222,7 +183,7 @@ void ErrorStringFunctionMemoryRangesOverlap::Print() {
|
||||
bug_type, addr1_description.Address(),
|
||||
addr1_description.Address() + length1, addr2_description.Address(),
|
||||
addr2_description.Address() + length2);
|
||||
Printf("%s", d.EndWarning());
|
||||
Printf("%s", d.Default());
|
||||
scariness.Print();
|
||||
stack->Print();
|
||||
addr1_description.Print();
|
||||
@ -235,7 +196,7 @@ void ErrorStringFunctionSizeOverflow::Print() {
|
||||
Printf("%s", d.Warning());
|
||||
Report("ERROR: AddressSanitizer: %s: (size=%zd)\n",
|
||||
scariness.GetDescription(), size);
|
||||
Printf("%s", d.EndWarning());
|
||||
Printf("%s", d.Default());
|
||||
scariness.Print();
|
||||
stack->Print();
|
||||
addr_description.Print();
|
||||
@ -263,7 +224,7 @@ void ErrorODRViolation::Print() {
|
||||
Printf("%s", d.Warning());
|
||||
Report("ERROR: AddressSanitizer: %s (%p):\n", scariness.GetDescription(),
|
||||
global1.beg);
|
||||
Printf("%s", d.EndWarning());
|
||||
Printf("%s", d.Default());
|
||||
InternalScopedString g1_loc(256), g2_loc(256);
|
||||
PrintGlobalLocation(&g1_loc, global1);
|
||||
PrintGlobalLocation(&g2_loc, global2);
|
||||
@ -292,7 +253,7 @@ void ErrorInvalidPointerPair::Print() {
|
||||
Printf("%s", d.Warning());
|
||||
Report("ERROR: AddressSanitizer: %s: %p %p\n", scariness.GetDescription(),
|
||||
addr1_description.Address(), addr2_description.Address());
|
||||
Printf("%s", d.EndWarning());
|
||||
Printf("%s", d.Default());
|
||||
GET_STACK_TRACE_FATAL(pc, bp);
|
||||
stack.Print();
|
||||
addr1_description.Print();
|
||||
@ -477,9 +438,14 @@ static void PrintShadowMemoryForAddress(uptr addr) {
|
||||
InternalScopedString str(4096 * 8);
|
||||
str.append("Shadow bytes around the buggy address:\n");
|
||||
for (int i = -5; i <= 5; i++) {
|
||||
uptr row_shadow_addr = aligned_shadow + i * n_bytes_per_row;
|
||||
// Skip rows that would be outside the shadow range. This can happen when
|
||||
// the user address is near the bottom, top, or shadow gap of the address
|
||||
// space.
|
||||
if (!AddrIsInShadow(row_shadow_addr)) continue;
|
||||
const char *prefix = (i == 0) ? "=>" : " ";
|
||||
PrintShadowBytes(&str, prefix, (u8 *)(aligned_shadow + i * n_bytes_per_row),
|
||||
(u8 *)shadow_addr, n_bytes_per_row);
|
||||
PrintShadowBytes(&str, prefix, (u8 *)row_shadow_addr, (u8 *)shadow_addr,
|
||||
n_bytes_per_row);
|
||||
}
|
||||
if (flags()->print_legend) PrintLegend(&str);
|
||||
Printf("%s", str.data());
|
||||
@ -491,13 +457,13 @@ void ErrorGeneric::Print() {
|
||||
uptr addr = addr_description.Address();
|
||||
Report("ERROR: AddressSanitizer: %s on address %p at pc %p bp %p sp %p\n",
|
||||
bug_descr, (void *)addr, pc, bp, sp);
|
||||
Printf("%s", d.EndWarning());
|
||||
Printf("%s", d.Default());
|
||||
|
||||
char tname[128];
|
||||
Printf("%s%s of size %zu at %p thread T%d%s%s\n", d.Access(),
|
||||
access_size ? (is_write ? "WRITE" : "READ") : "ACCESS", access_size,
|
||||
(void *)addr, tid,
|
||||
ThreadNameWithParenthesis(tid, tname, sizeof(tname)), d.EndAccess());
|
||||
ThreadNameWithParenthesis(tid, tname, sizeof(tname)), d.Default());
|
||||
|
||||
scariness.Print();
|
||||
GET_STACK_TRACE_FATAL(pc, bp);
|
||||
|
@ -27,62 +27,29 @@ struct ErrorBase {
|
||||
u32 tid;
|
||||
};
|
||||
|
||||
struct ErrorStackOverflow : ErrorBase {
|
||||
uptr addr, pc, bp, sp;
|
||||
// ErrorStackOverflow never owns the context.
|
||||
void *context;
|
||||
// VS2013 doesn't implement unrestricted unions, so we need a trivial default
|
||||
// constructor
|
||||
ErrorStackOverflow() = default;
|
||||
ErrorStackOverflow(u32 tid, const SignalContext &sig)
|
||||
: ErrorBase(tid),
|
||||
addr(sig.addr),
|
||||
pc(sig.pc),
|
||||
bp(sig.bp),
|
||||
sp(sig.sp),
|
||||
context(sig.context) {
|
||||
scariness.Clear();
|
||||
scariness.Scare(10, "stack-overflow");
|
||||
}
|
||||
void Print();
|
||||
};
|
||||
|
||||
struct ErrorDeadlySignal : ErrorBase {
|
||||
uptr addr, pc, bp, sp;
|
||||
// ErrorDeadlySignal never owns the context.
|
||||
void *context;
|
||||
int signo;
|
||||
SignalContext::WriteFlag write_flag;
|
||||
bool is_memory_access;
|
||||
SignalContext signal;
|
||||
// VS2013 doesn't implement unrestricted unions, so we need a trivial default
|
||||
// constructor
|
||||
ErrorDeadlySignal() = default;
|
||||
ErrorDeadlySignal(u32 tid, const SignalContext &sig, int signo_)
|
||||
: ErrorBase(tid),
|
||||
addr(sig.addr),
|
||||
pc(sig.pc),
|
||||
bp(sig.bp),
|
||||
sp(sig.sp),
|
||||
context(sig.context),
|
||||
signo(signo_),
|
||||
write_flag(sig.write_flag),
|
||||
is_memory_access(sig.is_memory_access) {
|
||||
ErrorDeadlySignal(u32 tid, const SignalContext &sig)
|
||||
: ErrorBase(tid), signal(sig) {
|
||||
scariness.Clear();
|
||||
if (is_memory_access) {
|
||||
if (addr < GetPageSizeCached()) {
|
||||
if (signal.IsStackOverflow()) {
|
||||
scariness.Scare(10, "stack-overflow");
|
||||
} else if (!signal.is_memory_access) {
|
||||
scariness.Scare(10, "signal");
|
||||
} else if (signal.addr < GetPageSizeCached()) {
|
||||
scariness.Scare(10, "null-deref");
|
||||
} else if (addr == pc) {
|
||||
} else if (signal.addr == signal.pc) {
|
||||
scariness.Scare(60, "wild-jump");
|
||||
} else if (write_flag == SignalContext::WRITE) {
|
||||
} else if (signal.write_flag == SignalContext::WRITE) {
|
||||
scariness.Scare(30, "wild-addr-write");
|
||||
} else if (write_flag == SignalContext::READ) {
|
||||
} else if (signal.write_flag == SignalContext::READ) {
|
||||
scariness.Scare(20, "wild-addr-read");
|
||||
} else {
|
||||
scariness.Scare(25, "wild-addr");
|
||||
}
|
||||
} else {
|
||||
scariness.Scare(10, "signal");
|
||||
}
|
||||
}
|
||||
void Print();
|
||||
};
|
||||
@ -104,17 +71,19 @@ struct ErrorDoubleFree : ErrorBase {
|
||||
void Print();
|
||||
};
|
||||
|
||||
struct ErrorNewDeleteSizeMismatch : ErrorBase {
|
||||
// ErrorNewDeleteSizeMismatch doesn't own the stack trace.
|
||||
struct ErrorNewDeleteTypeMismatch : ErrorBase {
|
||||
// ErrorNewDeleteTypeMismatch doesn't own the stack trace.
|
||||
const BufferedStackTrace *free_stack;
|
||||
HeapAddressDescription addr_description;
|
||||
uptr delete_size;
|
||||
uptr delete_alignment;
|
||||
// VS2013 doesn't implement unrestricted unions, so we need a trivial default
|
||||
// constructor
|
||||
ErrorNewDeleteSizeMismatch() = default;
|
||||
ErrorNewDeleteSizeMismatch(u32 tid, BufferedStackTrace *stack, uptr addr,
|
||||
uptr delete_size_)
|
||||
: ErrorBase(tid), free_stack(stack), delete_size(delete_size_) {
|
||||
ErrorNewDeleteTypeMismatch() = default;
|
||||
ErrorNewDeleteTypeMismatch(u32 tid, BufferedStackTrace *stack, uptr addr,
|
||||
uptr delete_size_, uptr delete_alignment_)
|
||||
: ErrorBase(tid), free_stack(stack), delete_size(delete_size_),
|
||||
delete_alignment(delete_alignment_) {
|
||||
GetHeapAddressInformation(addr, 1, &addr_description);
|
||||
scariness.Clear();
|
||||
scariness.Scare(10, "new-delete-type-mismatch");
|
||||
@ -324,10 +293,9 @@ struct ErrorGeneric : ErrorBase {
|
||||
|
||||
// clang-format off
|
||||
#define ASAN_FOR_EACH_ERROR_KIND(macro) \
|
||||
macro(StackOverflow) \
|
||||
macro(DeadlySignal) \
|
||||
macro(DoubleFree) \
|
||||
macro(NewDeleteSizeMismatch) \
|
||||
macro(NewDeleteTypeMismatch) \
|
||||
macro(FreeNotMalloced) \
|
||||
macro(AllocTypeMismatch) \
|
||||
macro(MallocUsableSizeNotOwned) \
|
||||
|
@ -28,9 +28,9 @@ static const u64 kAllocaRedzoneMask = 31UL;
|
||||
|
||||
// For small size classes inline PoisonShadow for better performance.
|
||||
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) {
|
||||
if (SHADOW_SCALE == 3 && class_id <= 6) {
|
||||
// This code expects SHADOW_SCALE=3.
|
||||
for (uptr i = 0; i < (((uptr)1) << class_id); i++) {
|
||||
shadow[i] = magic;
|
||||
// Make sure this does not become memset.
|
||||
@ -171,7 +171,7 @@ void FakeStack::ForEachFakeFrame(RangeIteratorCallback callback, void *arg) {
|
||||
}
|
||||
}
|
||||
|
||||
#if SANITIZER_LINUX && !SANITIZER_ANDROID
|
||||
#if (SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_FUCHSIA
|
||||
static THREADLOCAL FakeStack *fake_stack_tls;
|
||||
|
||||
FakeStack *GetTLSFakeStack() {
|
||||
@ -183,7 +183,7 @@ void SetTLSFakeStack(FakeStack *fs) {
|
||||
#else
|
||||
FakeStack *GetTLSFakeStack() { return 0; }
|
||||
void SetTLSFakeStack(FakeStack *fs) { }
|
||||
#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
|
||||
#endif // (SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_FUCHSIA
|
||||
|
||||
static FakeStack *GetFakeStack() {
|
||||
AsanThread *t = GetCurrentThread();
|
||||
|
@ -118,6 +118,10 @@ void InitializeFlags() {
|
||||
const char *ubsan_default_options = __ubsan::MaybeCallUbsanDefaultOptions();
|
||||
ubsan_parser.ParseString(ubsan_default_options);
|
||||
#endif
|
||||
#if CAN_SANITIZE_LEAKS
|
||||
const char *lsan_default_options = __lsan::MaybeCallLsanDefaultOptions();
|
||||
lsan_parser.ParseString(lsan_default_options);
|
||||
#endif
|
||||
|
||||
// Override from command line.
|
||||
asan_parser.ParseString(GetEnv("ASAN_OPTIONS"));
|
||||
@ -144,6 +148,9 @@ void InitializeFlags() {
|
||||
SanitizerToolName);
|
||||
Die();
|
||||
}
|
||||
// Ensure that redzone is at least SHADOW_GRANULARITY.
|
||||
if (f->redzone < (int)SHADOW_GRANULARITY)
|
||||
f->redzone = SHADOW_GRANULARITY;
|
||||
// Make "strict_init_order" imply "check_initialization_order".
|
||||
// TODO(samsonov): Use a single runtime flag for an init-order checker.
|
||||
if (f->strict_init_order) {
|
||||
|
@ -79,6 +79,10 @@ ASAN_FLAG(
|
||||
"Number of seconds to sleep between printing an error report and "
|
||||
"terminating the program. Useful for debugging purposes (e.g. when one "
|
||||
"needs to attach gdb).")
|
||||
ASAN_FLAG(
|
||||
int, sleep_after_init, 0,
|
||||
"Number of seconds to sleep after AddressSanitizer is initialized. "
|
||||
"Useful for debugging purposes (e.g. when one needs to attach gdb).")
|
||||
ASAN_FLAG(bool, check_malloc_usable_size, true,
|
||||
"Allows the users to work around the bug in Nvidia drivers prior to "
|
||||
"295.*.")
|
||||
@ -143,11 +147,6 @@ ASAN_FLAG(int, detect_odr_violation, 2,
|
||||
"If >=2, detect violation of One-Definition-Rule (ODR); "
|
||||
"If ==1, detect ODR-violation only if the two variables "
|
||||
"have different sizes")
|
||||
ASAN_FLAG(bool, dump_instruction_bytes, false,
|
||||
"If true, dump 16 bytes starting at the instruction that caused SEGV")
|
||||
ASAN_FLAG(bool, dump_registers, true,
|
||||
"If true, dump values of CPU registers when SEGV happens. Only "
|
||||
"available on OS X for now.")
|
||||
ASAN_FLAG(const char *, suppressions, "", "Suppressions file name.")
|
||||
ASAN_FLAG(bool, halt_on_error, true,
|
||||
"Crash the program after printing the first error report "
|
||||
|
218
lib/asan/asan_fuchsia.cc
Normal file
218
lib/asan/asan_fuchsia.cc
Normal file
@ -0,0 +1,218 @@
|
||||
//===-- asan_fuchsia.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.
|
||||
//
|
||||
// Fuchsia-specific details.
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
#include "sanitizer_common/sanitizer_fuchsia.h"
|
||||
#if SANITIZER_FUCHSIA
|
||||
|
||||
#include "asan_interceptors.h"
|
||||
#include "asan_internal.h"
|
||||
#include "asan_stack.h"
|
||||
#include "asan_thread.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <zircon/sanitizer.h>
|
||||
#include <zircon/syscalls.h>
|
||||
#include <zircon/threads.h>
|
||||
|
||||
namespace __asan {
|
||||
|
||||
// The system already set up the shadow memory for us.
|
||||
// __sanitizer::GetMaxUserVirtualAddress has already been called by
|
||||
// AsanInitInternal->InitializeHighMemEnd (asan_rtl.cc).
|
||||
// Just do some additional sanity checks here.
|
||||
void InitializeShadowMemory() {
|
||||
if (Verbosity()) PrintAddressSpaceLayout();
|
||||
|
||||
// Make sure SHADOW_OFFSET doesn't use __asan_shadow_memory_dynamic_address.
|
||||
__asan_shadow_memory_dynamic_address = kDefaultShadowSentinel;
|
||||
DCHECK(kLowShadowBeg != kDefaultShadowSentinel);
|
||||
__asan_shadow_memory_dynamic_address = kLowShadowBeg;
|
||||
|
||||
CHECK_EQ(kShadowGapEnd, kHighShadowBeg - 1);
|
||||
CHECK_EQ(kHighMemEnd, __sanitizer::ShadowBounds.memory_limit - 1);
|
||||
CHECK_EQ(kHighMemBeg, __sanitizer::ShadowBounds.shadow_limit);
|
||||
CHECK_EQ(kHighShadowBeg, __sanitizer::ShadowBounds.shadow_base);
|
||||
CHECK_EQ(kShadowGapEnd, __sanitizer::ShadowBounds.shadow_base - 1);
|
||||
CHECK_EQ(kLowShadowEnd, 0);
|
||||
CHECK_EQ(kLowShadowBeg, 0);
|
||||
}
|
||||
|
||||
void AsanApplyToGlobals(globals_op_fptr op, const void *needle) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
void AsanCheckDynamicRTPrereqs() {}
|
||||
void AsanCheckIncompatibleRT() {}
|
||||
void InitializeAsanInterceptors() {}
|
||||
|
||||
void *AsanDoesNotSupportStaticLinkage() { return nullptr; }
|
||||
|
||||
void InitializePlatformExceptionHandlers() {}
|
||||
void AsanOnDeadlySignal(int signo, void *siginfo, void *context) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
// We can use a plain thread_local variable for TSD.
|
||||
static thread_local void *per_thread;
|
||||
|
||||
void *AsanTSDGet() { return per_thread; }
|
||||
|
||||
void AsanTSDSet(void *tsd) { per_thread = tsd; }
|
||||
|
||||
// There's no initialization needed, and the passed-in destructor
|
||||
// will never be called. Instead, our own thread destruction hook
|
||||
// (below) will call AsanThread::TSDDtor directly.
|
||||
void AsanTSDInit(void (*destructor)(void *tsd)) {
|
||||
DCHECK(destructor == &PlatformTSDDtor);
|
||||
}
|
||||
|
||||
void PlatformTSDDtor(void *tsd) { UNREACHABLE(__func__); }
|
||||
|
||||
static inline size_t AsanThreadMmapSize() {
|
||||
return RoundUpTo(sizeof(AsanThread), PAGE_SIZE);
|
||||
}
|
||||
|
||||
struct AsanThread::InitOptions {
|
||||
uptr stack_bottom, stack_size;
|
||||
};
|
||||
|
||||
// Shared setup between thread creation and startup for the initial thread.
|
||||
static AsanThread *CreateAsanThread(StackTrace *stack, u32 parent_tid,
|
||||
uptr user_id, bool detached,
|
||||
const char *name, uptr stack_bottom,
|
||||
uptr stack_size) {
|
||||
// In lieu of AsanThread::Create.
|
||||
AsanThread *thread = (AsanThread *)MmapOrDie(AsanThreadMmapSize(), __func__);
|
||||
|
||||
AsanThreadContext::CreateThreadContextArgs args = {thread, stack};
|
||||
u32 tid =
|
||||
asanThreadRegistry().CreateThread(user_id, detached, parent_tid, &args);
|
||||
asanThreadRegistry().SetThreadName(tid, name);
|
||||
|
||||
// On other systems, AsanThread::Init() is called from the new
|
||||
// thread itself. But on Fuchsia we already know the stack address
|
||||
// range beforehand, so we can do most of the setup right now.
|
||||
const AsanThread::InitOptions options = {stack_bottom, stack_size};
|
||||
thread->Init(&options);
|
||||
|
||||
return thread;
|
||||
}
|
||||
|
||||
// This gets the same arguments passed to Init by CreateAsanThread, above.
|
||||
// We're in the creator thread before the new thread is actually started,
|
||||
// but its stack address range is already known. We don't bother tracking
|
||||
// the static TLS address range because the system itself already uses an
|
||||
// ASan-aware allocator for that.
|
||||
void AsanThread::SetThreadStackAndTls(const AsanThread::InitOptions *options) {
|
||||
DCHECK_NE(GetCurrentThread(), this);
|
||||
DCHECK_NE(GetCurrentThread(), nullptr);
|
||||
CHECK_NE(options->stack_bottom, 0);
|
||||
CHECK_NE(options->stack_size, 0);
|
||||
stack_bottom_ = options->stack_bottom;
|
||||
stack_top_ = options->stack_bottom + options->stack_size;
|
||||
}
|
||||
|
||||
// Called by __asan::AsanInitInternal (asan_rtl.c).
|
||||
AsanThread *CreateMainThread() {
|
||||
thrd_t self = thrd_current();
|
||||
char name[ZX_MAX_NAME_LEN];
|
||||
CHECK_NE(__sanitizer::MainThreadStackBase, 0);
|
||||
CHECK_GT(__sanitizer::MainThreadStackSize, 0);
|
||||
AsanThread *t = CreateAsanThread(
|
||||
nullptr, 0, reinterpret_cast<uptr>(self), true,
|
||||
_zx_object_get_property(thrd_get_zx_handle(self), ZX_PROP_NAME, name,
|
||||
sizeof(name)) == ZX_OK
|
||||
? name
|
||||
: nullptr,
|
||||
__sanitizer::MainThreadStackBase, __sanitizer::MainThreadStackSize);
|
||||
SetCurrentThread(t);
|
||||
return t;
|
||||
}
|
||||
|
||||
// This is called before each thread creation is attempted. So, in
|
||||
// its first call, the calling thread is the initial and sole thread.
|
||||
static void *BeforeThreadCreateHook(uptr user_id, bool detached,
|
||||
const char *name, uptr stack_bottom,
|
||||
uptr stack_size) {
|
||||
EnsureMainThreadIDIsCorrect();
|
||||
// Strict init-order checking is thread-hostile.
|
||||
if (flags()->strict_init_order) StopInitOrderChecking();
|
||||
|
||||
GET_STACK_TRACE_THREAD;
|
||||
u32 parent_tid = GetCurrentTidOrInvalid();
|
||||
|
||||
return CreateAsanThread(&stack, parent_tid, user_id, detached, name,
|
||||
stack_bottom, stack_size);
|
||||
}
|
||||
|
||||
// This is called after creating a new thread (in the creating thread),
|
||||
// with the pointer returned by BeforeThreadCreateHook (above).
|
||||
static void ThreadCreateHook(void *hook, bool aborted) {
|
||||
AsanThread *thread = static_cast<AsanThread *>(hook);
|
||||
if (!aborted) {
|
||||
// The thread was created successfully.
|
||||
// ThreadStartHook is already running in the new thread.
|
||||
} else {
|
||||
// The thread wasn't created after all.
|
||||
// Clean up everything we set up in BeforeThreadCreateHook.
|
||||
asanThreadRegistry().FinishThread(thread->tid());
|
||||
UnmapOrDie(thread, AsanThreadMmapSize());
|
||||
}
|
||||
}
|
||||
|
||||
// This is called in the newly-created thread before it runs anything else,
|
||||
// with the pointer returned by BeforeThreadCreateHook (above).
|
||||
// cf. asan_interceptors.cc:asan_thread_start
|
||||
static void ThreadStartHook(void *hook, uptr os_id) {
|
||||
AsanThread *thread = static_cast<AsanThread *>(hook);
|
||||
SetCurrentThread(thread);
|
||||
|
||||
// In lieu of AsanThread::ThreadStart.
|
||||
asanThreadRegistry().StartThread(thread->tid(), os_id, /*workerthread*/ false,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
// Each thread runs this just before it exits,
|
||||
// with the pointer returned by BeforeThreadCreateHook (above).
|
||||
// All per-thread destructors have already been called.
|
||||
static void ThreadExitHook(void *hook, uptr os_id) {
|
||||
AsanThread::TSDDtor(per_thread);
|
||||
}
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
// These are declared (in extern "C") by <zircon/sanitizer.h>.
|
||||
// The system runtime will call our definitions directly.
|
||||
|
||||
void *__sanitizer_before_thread_create_hook(thrd_t thread, bool detached,
|
||||
const char *name, void *stack_base,
|
||||
size_t stack_size) {
|
||||
return __asan::BeforeThreadCreateHook(
|
||||
reinterpret_cast<uptr>(thread), detached, name,
|
||||
reinterpret_cast<uptr>(stack_base), stack_size);
|
||||
}
|
||||
|
||||
void __sanitizer_thread_create_hook(void *hook, thrd_t thread, int error) {
|
||||
__asan::ThreadCreateHook(hook, error != thrd_success);
|
||||
}
|
||||
|
||||
void __sanitizer_thread_start_hook(void *hook, thrd_t self) {
|
||||
__asan::ThreadStartHook(hook, reinterpret_cast<uptr>(self));
|
||||
}
|
||||
|
||||
void __sanitizer_thread_exit_hook(void *hook, thrd_t self) {
|
||||
__asan::ThreadExitHook(hook, reinterpret_cast<uptr>(self));
|
||||
}
|
||||
|
||||
#endif // SANITIZER_FUCHSIA
|
@ -384,6 +384,10 @@ void __asan_register_globals(__asan_global *globals, uptr n) {
|
||||
}
|
||||
RegisterGlobal(&globals[i]);
|
||||
}
|
||||
|
||||
// Poison the metadata. It should not be accessible to user code.
|
||||
PoisonShadow(reinterpret_cast<uptr>(globals), n * sizeof(__asan_global),
|
||||
kAsanGlobalRedzoneMagic);
|
||||
}
|
||||
|
||||
// Unregister an array of globals.
|
||||
@ -399,6 +403,9 @@ void __asan_unregister_globals(__asan_global *globals, uptr n) {
|
||||
}
|
||||
UnregisterGlobal(&globals[i]);
|
||||
}
|
||||
|
||||
// Unpoison the metadata.
|
||||
PoisonShadow(reinterpret_cast<uptr>(globals), n * sizeof(__asan_global), 0);
|
||||
}
|
||||
|
||||
// This method runs immediately prior to dynamic initialization in each TU,
|
||||
|
@ -15,6 +15,8 @@
|
||||
#ifndef ASAN_INIT_VERSION_H
|
||||
#define ASAN_INIT_VERSION_H
|
||||
|
||||
#include "sanitizer_common/sanitizer_platform.h"
|
||||
|
||||
extern "C" {
|
||||
// Every time the ASan ABI changes we also change the version number in the
|
||||
// __asan_init function name. Objects built with incompatible ASan ABI
|
||||
@ -32,7 +34,12 @@ extern "C" {
|
||||
// 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
|
||||
#if SANITIZER_WORDSIZE == 32 && SANITIZER_ANDROID
|
||||
// v8=>v9: 32-bit Android switched to dynamic shadow
|
||||
#define __asan_version_mismatch_check __asan_version_mismatch_check_v9
|
||||
#else
|
||||
#define __asan_version_mismatch_check __asan_version_mismatch_check_v8
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // ASAN_INIT_VERSION_H
|
||||
|
@ -24,6 +24,11 @@
|
||||
#include "lsan/lsan_common.h"
|
||||
#include "sanitizer_common/sanitizer_libc.h"
|
||||
|
||||
// There is no general interception at all on Fuchsia.
|
||||
// Only the functions in asan_interceptors_memintrinsics.cc are
|
||||
// really defined to replace libc functions.
|
||||
#if !SANITIZER_FUCHSIA
|
||||
|
||||
#if SANITIZER_POSIX
|
||||
#include "sanitizer_common/sanitizer_posix.h"
|
||||
#endif
|
||||
@ -36,108 +41,6 @@
|
||||
|
||||
namespace __asan {
|
||||
|
||||
// Return true if we can quickly decide that the region is unpoisoned.
|
||||
// We assume that a redzone is at least 16 bytes.
|
||||
static inline bool QuickCheckForUnpoisonedRegion(uptr beg, uptr size) {
|
||||
if (size == 0) return true;
|
||||
if (size <= 32)
|
||||
return !AddressIsPoisoned(beg) &&
|
||||
!AddressIsPoisoned(beg + size - 1) &&
|
||||
!AddressIsPoisoned(beg + size / 2);
|
||||
if (size <= 64)
|
||||
return !AddressIsPoisoned(beg) &&
|
||||
!AddressIsPoisoned(beg + size / 4) &&
|
||||
!AddressIsPoisoned(beg + size - 1) &&
|
||||
!AddressIsPoisoned(beg + 3 * size / 4) &&
|
||||
!AddressIsPoisoned(beg + size / 2);
|
||||
return false;
|
||||
}
|
||||
|
||||
struct AsanInterceptorContext {
|
||||
const char *interceptor_name;
|
||||
};
|
||||
|
||||
// We implement ACCESS_MEMORY_RANGE, ASAN_READ_RANGE,
|
||||
// and ASAN_WRITE_RANGE as macro instead of function so
|
||||
// that no extra frames are created, and stack trace contains
|
||||
// relevant information only.
|
||||
// We check all shadow bytes.
|
||||
#define ACCESS_MEMORY_RANGE(ctx, offset, size, isWrite) do { \
|
||||
uptr __offset = (uptr)(offset); \
|
||||
uptr __size = (uptr)(size); \
|
||||
uptr __bad = 0; \
|
||||
if (__offset > __offset + __size) { \
|
||||
GET_STACK_TRACE_FATAL_HERE; \
|
||||
ReportStringFunctionSizeOverflow(__offset, __size, &stack); \
|
||||
} \
|
||||
if (!QuickCheckForUnpoisonedRegion(__offset, __size) && \
|
||||
(__bad = __asan_region_is_poisoned(__offset, __size))) { \
|
||||
AsanInterceptorContext *_ctx = (AsanInterceptorContext *)ctx; \
|
||||
bool suppressed = false; \
|
||||
if (_ctx) { \
|
||||
suppressed = IsInterceptorSuppressed(_ctx->interceptor_name); \
|
||||
if (!suppressed && HaveStackTraceBasedSuppressions()) { \
|
||||
GET_STACK_TRACE_FATAL_HERE; \
|
||||
suppressed = IsStackTraceSuppressed(&stack); \
|
||||
} \
|
||||
} \
|
||||
if (!suppressed) { \
|
||||
GET_CURRENT_PC_BP_SP; \
|
||||
ReportGenericError(pc, bp, sp, __bad, isWrite, __size, 0, false);\
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// memcpy is called during __asan_init() from the internals of printf(...).
|
||||
// We do not treat memcpy with to==from as a bug.
|
||||
// See http://llvm.org/bugs/show_bug.cgi?id=11763.
|
||||
#define ASAN_MEMCPY_IMPL(ctx, to, from, size) \
|
||||
do { \
|
||||
if (UNLIKELY(!asan_inited)) return internal_memcpy(to, from, size); \
|
||||
if (asan_init_is_running) { \
|
||||
return REAL(memcpy)(to, from, size); \
|
||||
} \
|
||||
ENSURE_ASAN_INITED(); \
|
||||
if (flags()->replace_intrin) { \
|
||||
if (to != from) { \
|
||||
CHECK_RANGES_OVERLAP("memcpy", to, size, from, size); \
|
||||
} \
|
||||
ASAN_READ_RANGE(ctx, from, size); \
|
||||
ASAN_WRITE_RANGE(ctx, to, size); \
|
||||
} \
|
||||
return REAL(memcpy)(to, from, size); \
|
||||
} while (0)
|
||||
|
||||
// memset is called inside Printf.
|
||||
#define ASAN_MEMSET_IMPL(ctx, block, c, size) \
|
||||
do { \
|
||||
if (UNLIKELY(!asan_inited)) return internal_memset(block, c, size); \
|
||||
if (asan_init_is_running) { \
|
||||
return REAL(memset)(block, c, size); \
|
||||
} \
|
||||
ENSURE_ASAN_INITED(); \
|
||||
if (flags()->replace_intrin) { \
|
||||
ASAN_WRITE_RANGE(ctx, block, size); \
|
||||
} \
|
||||
return REAL(memset)(block, c, size); \
|
||||
} while (0)
|
||||
|
||||
#define ASAN_MEMMOVE_IMPL(ctx, to, from, size) \
|
||||
do { \
|
||||
if (UNLIKELY(!asan_inited)) return internal_memmove(to, from, size); \
|
||||
ENSURE_ASAN_INITED(); \
|
||||
if (flags()->replace_intrin) { \
|
||||
ASAN_READ_RANGE(ctx, from, size); \
|
||||
ASAN_WRITE_RANGE(ctx, to, size); \
|
||||
} \
|
||||
return internal_memmove(to, from, size); \
|
||||
} while (0)
|
||||
|
||||
#define ASAN_READ_RANGE(ctx, offset, size) \
|
||||
ACCESS_MEMORY_RANGE(ctx, offset, size, false)
|
||||
#define ASAN_WRITE_RANGE(ctx, offset, size) \
|
||||
ACCESS_MEMORY_RANGE(ctx, offset, size, true)
|
||||
|
||||
#define ASAN_READ_STRING_OF_LEN(ctx, s, len, n) \
|
||||
ASAN_READ_RANGE((ctx), (s), \
|
||||
common_flags()->strict_string_checks ? (len) + 1 : (n))
|
||||
@ -145,23 +48,6 @@ struct AsanInterceptorContext {
|
||||
#define ASAN_READ_STRING(ctx, s, n) \
|
||||
ASAN_READ_STRING_OF_LEN((ctx), (s), REAL(strlen)(s), (n))
|
||||
|
||||
// Behavior of functions like "memcpy" or "strcpy" is undefined
|
||||
// if memory intervals overlap. We report error in this case.
|
||||
// Macro is used to avoid creation of new frames.
|
||||
static inline bool RangesOverlap(const char *offset1, uptr length1,
|
||||
const char *offset2, uptr length2) {
|
||||
return !((offset1 + length1 <= offset2) || (offset2 + length2 <= offset1));
|
||||
}
|
||||
#define CHECK_RANGES_OVERLAP(name, _offset1, length1, _offset2, length2) do { \
|
||||
const char *offset1 = (const char*)_offset1; \
|
||||
const char *offset2 = (const char*)_offset2; \
|
||||
if (RangesOverlap(offset1, length1, offset2, length2)) { \
|
||||
GET_STACK_TRACE_FATAL_HERE; \
|
||||
ReportStringFunctionMemoryRangesOverlap(name, offset1, length1, \
|
||||
offset2, length2, &stack); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static inline uptr MaybeRealStrnlen(const char *s, uptr maxlen) {
|
||||
#if SANITIZER_INTERCEPT_STRNLEN
|
||||
if (REAL(strnlen)) {
|
||||
@ -275,6 +161,7 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)
|
||||
} while (false)
|
||||
|
||||
#include "sanitizer_common/sanitizer_common_interceptors.inc"
|
||||
#include "sanitizer_common/sanitizer_signal_interceptors.inc"
|
||||
|
||||
// Syscall interceptors don't have contexts, we don't support suppressions
|
||||
// for them.
|
||||
@ -356,42 +243,6 @@ INTERCEPTOR(int, pthread_join, void *t, void **arg) {
|
||||
DEFINE_REAL_PTHREAD_FUNCTIONS
|
||||
#endif // ASAN_INTERCEPT_PTHREAD_CREATE
|
||||
|
||||
#if ASAN_INTERCEPT_SIGNAL_AND_SIGACTION
|
||||
|
||||
#if SANITIZER_ANDROID
|
||||
INTERCEPTOR(void*, bsd_signal, int signum, void *handler) {
|
||||
if (GetHandleSignalMode(signum) != kHandleSignalExclusive)
|
||||
return REAL(bsd_signal)(signum, handler);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
INTERCEPTOR(void*, signal, int signum, void *handler) {
|
||||
if (GetHandleSignalMode(signum) != kHandleSignalExclusive)
|
||||
return REAL(signal)(signum, handler);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
INTERCEPTOR(int, sigaction, int signum, const struct sigaction *act,
|
||||
struct sigaction *oldact) {
|
||||
if (GetHandleSignalMode(signum) != kHandleSignalExclusive)
|
||||
return REAL(sigaction)(signum, act, oldact);
|
||||
return 0;
|
||||
}
|
||||
|
||||
namespace __sanitizer {
|
||||
int real_sigaction(int signum, const void *act, void *oldact) {
|
||||
return REAL(sigaction)(signum, (const struct sigaction *)act,
|
||||
(struct sigaction *)oldact);
|
||||
}
|
||||
} // namespace __sanitizer
|
||||
|
||||
#elif SANITIZER_POSIX
|
||||
// We need to have defined REAL(sigaction) on posix systems.
|
||||
DEFINE_REAL(int, sigaction, int signum, const struct sigaction *act,
|
||||
struct sigaction *oldact)
|
||||
#endif // ASAN_INTERCEPT_SIGNAL_AND_SIGACTION
|
||||
|
||||
#if ASAN_INTERCEPT_SWAPCONTEXT
|
||||
static void ClearShadowMemoryForContextStack(uptr stack, uptr ssize) {
|
||||
// Align to page size.
|
||||
@ -428,6 +279,11 @@ INTERCEPTOR(int, swapcontext, struct ucontext_t *oucp,
|
||||
}
|
||||
#endif // ASAN_INTERCEPT_SWAPCONTEXT
|
||||
|
||||
#if SANITIZER_NETBSD
|
||||
#define longjmp __longjmp14
|
||||
#define siglongjmp __siglongjmp14
|
||||
#endif
|
||||
|
||||
INTERCEPTOR(void, longjmp, void *env, int val) {
|
||||
__asan_handle_no_return();
|
||||
REAL(longjmp)(env, val);
|
||||
@ -462,18 +318,6 @@ INTERCEPTOR(void, __cxa_throw, void *a, void *b, void *c) {
|
||||
}
|
||||
#endif
|
||||
|
||||
void *__asan_memcpy(void *to, const void *from, uptr size) {
|
||||
ASAN_MEMCPY_IMPL(nullptr, to, from, size);
|
||||
}
|
||||
|
||||
void *__asan_memset(void *block, int c, uptr size) {
|
||||
ASAN_MEMSET_IMPL(nullptr, block, c, size);
|
||||
}
|
||||
|
||||
void *__asan_memmove(void *to, const void *from, uptr size) {
|
||||
ASAN_MEMMOVE_IMPL(nullptr, to, from, size);
|
||||
}
|
||||
|
||||
#if ASAN_INTERCEPT_INDEX
|
||||
# if ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX
|
||||
INTERCEPTOR(char*, index, const char *string, int c)
|
||||
@ -711,6 +555,7 @@ void InitializeAsanInterceptors() {
|
||||
CHECK(!was_called_once);
|
||||
was_called_once = true;
|
||||
InitializeCommonInterceptors();
|
||||
InitializeSignalInterceptors();
|
||||
|
||||
// Intercept str* functions.
|
||||
ASAN_INTERCEPT_FUNC(strcat); // NOLINT
|
||||
@ -733,15 +578,9 @@ void InitializeAsanInterceptors() {
|
||||
ASAN_INTERCEPT_FUNC(strtoll);
|
||||
#endif
|
||||
|
||||
// Intecept signal- and jump-related functions.
|
||||
// Intecept jump-related functions.
|
||||
ASAN_INTERCEPT_FUNC(longjmp);
|
||||
#if ASAN_INTERCEPT_SIGNAL_AND_SIGACTION
|
||||
ASAN_INTERCEPT_FUNC(sigaction);
|
||||
#if SANITIZER_ANDROID
|
||||
ASAN_INTERCEPT_FUNC(bsd_signal);
|
||||
#endif
|
||||
ASAN_INTERCEPT_FUNC(signal);
|
||||
#endif
|
||||
|
||||
#if ASAN_INTERCEPT_SWAPCONTEXT
|
||||
ASAN_INTERCEPT_FUNC(swapcontext);
|
||||
#endif
|
||||
@ -785,3 +624,5 @@ void InitializeAsanInterceptors() {
|
||||
}
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
#endif // !SANITIZER_FUCHSIA
|
||||
|
@ -15,9 +15,30 @@
|
||||
#define ASAN_INTERCEPTORS_H
|
||||
|
||||
#include "asan_internal.h"
|
||||
#include "asan_interceptors_memintrinsics.h"
|
||||
#include "interception/interception.h"
|
||||
#include "sanitizer_common/sanitizer_platform_interceptors.h"
|
||||
|
||||
namespace __asan {
|
||||
|
||||
void InitializeAsanInterceptors();
|
||||
void InitializePlatformInterceptors();
|
||||
|
||||
#define ENSURE_ASAN_INITED() \
|
||||
do { \
|
||||
CHECK(!asan_init_is_running); \
|
||||
if (UNLIKELY(!asan_inited)) { \
|
||||
AsanInitFromRtl(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
// There is no general interception at all on Fuchsia.
|
||||
// Only the functions in asan_interceptors_memintrinsics.h are
|
||||
// really defined to replace libc functions.
|
||||
#if !SANITIZER_FUCHSIA
|
||||
|
||||
// Use macro to describe if specific function should be
|
||||
// intercepted on a given platform.
|
||||
#if !SANITIZER_WINDOWS
|
||||
@ -34,24 +55,19 @@
|
||||
# define ASAN_INTERCEPT_FORK 0
|
||||
#endif
|
||||
|
||||
#if SANITIZER_FREEBSD || SANITIZER_LINUX
|
||||
#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
|
||||
SANITIZER_SOLARIS
|
||||
# define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 1
|
||||
#else
|
||||
# define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 0
|
||||
#endif
|
||||
|
||||
#if SANITIZER_LINUX && !SANITIZER_ANDROID
|
||||
#if (SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_SOLARIS
|
||||
# define ASAN_INTERCEPT_SWAPCONTEXT 1
|
||||
#else
|
||||
# define ASAN_INTERCEPT_SWAPCONTEXT 0
|
||||
#endif
|
||||
|
||||
#if !SANITIZER_WINDOWS
|
||||
# define ASAN_INTERCEPT_SIGNAL_AND_SIGACTION 1
|
||||
#else
|
||||
# define ASAN_INTERCEPT_SIGNAL_AND_SIGACTION 0
|
||||
#endif
|
||||
|
||||
#if !SANITIZER_WINDOWS
|
||||
# define ASAN_INTERCEPT_SIGLONGJMP 1
|
||||
#else
|
||||
@ -66,7 +82,8 @@
|
||||
|
||||
// Android bug: https://code.google.com/p/android/issues/detail?id=61799
|
||||
#if ASAN_HAS_EXCEPTIONS && !SANITIZER_WINDOWS && \
|
||||
!(SANITIZER_ANDROID && defined(__i386))
|
||||
!(SANITIZER_ANDROID && defined(__i386)) && \
|
||||
!SANITIZER_SOLARIS
|
||||
# define ASAN_INTERCEPT___CXA_THROW 1
|
||||
#else
|
||||
# define ASAN_INTERCEPT___CXA_THROW 0
|
||||
@ -85,16 +102,11 @@
|
||||
#endif
|
||||
|
||||
DECLARE_REAL(int, memcmp, const void *a1, const void *a2, uptr size)
|
||||
DECLARE_REAL(void*, memcpy, void *to, const void *from, uptr size)
|
||||
DECLARE_REAL(void*, memset, void *block, int c, uptr size)
|
||||
DECLARE_REAL(char*, strchr, const char *str, int c)
|
||||
DECLARE_REAL(SIZE_T, strlen, const char *s)
|
||||
DECLARE_REAL(char*, strncpy, char *to, const char *from, uptr size)
|
||||
DECLARE_REAL(uptr, strnlen, const char *s, uptr maxlen)
|
||||
DECLARE_REAL(char*, strstr, const char *s1, const char *s2)
|
||||
struct sigaction;
|
||||
DECLARE_REAL(int, sigaction, int signum, const struct sigaction *act,
|
||||
struct sigaction *oldact)
|
||||
|
||||
#if !SANITIZER_MAC
|
||||
#define ASAN_INTERCEPT_FUNC(name) \
|
||||
@ -113,18 +125,6 @@ DECLARE_REAL(int, sigaction, int signum, const struct sigaction *act,
|
||||
#define ASAN_INTERCEPT_FUNC(name)
|
||||
#endif // SANITIZER_MAC
|
||||
|
||||
namespace __asan {
|
||||
|
||||
void InitializeAsanInterceptors();
|
||||
void InitializePlatformInterceptors();
|
||||
|
||||
#define ENSURE_ASAN_INITED() do { \
|
||||
CHECK(!asan_init_is_running); \
|
||||
if (UNLIKELY(!asan_inited)) { \
|
||||
AsanInitFromRtl(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
} // namespace __asan
|
||||
#endif // !SANITIZER_FUCHSIA
|
||||
|
||||
#endif // ASAN_INTERCEPTORS_H
|
||||
|
44
lib/asan/asan_interceptors_memintrinsics.cc
Normal file
44
lib/asan/asan_interceptors_memintrinsics.cc
Normal file
@ -0,0 +1,44 @@
|
||||
//===-- asan_interceptors_memintrinsics.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.
|
||||
//
|
||||
// ASan versions of memcpy, memmove, and memset.
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
#include "asan_interceptors_memintrinsics.h"
|
||||
#include "asan_report.h"
|
||||
#include "asan_stack.h"
|
||||
#include "asan_suppressions.h"
|
||||
|
||||
using namespace __asan; // NOLINT
|
||||
|
||||
void *__asan_memcpy(void *to, const void *from, uptr size) {
|
||||
ASAN_MEMCPY_IMPL(nullptr, to, from, size);
|
||||
}
|
||||
|
||||
void *__asan_memset(void *block, int c, uptr size) {
|
||||
ASAN_MEMSET_IMPL(nullptr, block, c, size);
|
||||
}
|
||||
|
||||
void *__asan_memmove(void *to, const void *from, uptr size) {
|
||||
ASAN_MEMMOVE_IMPL(nullptr, to, from, size);
|
||||
}
|
||||
|
||||
#if SANITIZER_FUCHSIA
|
||||
|
||||
// Fuchsia doesn't use sanitizer_common_interceptors.inc, but the only
|
||||
// things there it wants are these three. Just define them as aliases
|
||||
// here rather than repeating the contents.
|
||||
|
||||
decltype(memcpy) memcpy[[gnu::alias("__asan_memcpy")]];
|
||||
decltype(memmove) memmove[[gnu::alias("__asan_memmove")]];
|
||||
decltype(memset) memset[[gnu::alias("__asan_memset")]];
|
||||
|
||||
#endif // SANITIZER_FUCHSIA
|
148
lib/asan/asan_interceptors_memintrinsics.h
Normal file
148
lib/asan/asan_interceptors_memintrinsics.h
Normal file
@ -0,0 +1,148 @@
|
||||
//===-- asan_interceptors_memintrinsics.h -----------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===---------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// ASan-private header for asan_memintrin.cc
|
||||
//===---------------------------------------------------------------------===//
|
||||
#ifndef ASAN_MEMINTRIN_H
|
||||
#define ASAN_MEMINTRIN_H
|
||||
|
||||
#include "asan_interface_internal.h"
|
||||
#include "asan_internal.h"
|
||||
#include "asan_mapping.h"
|
||||
#include "interception/interception.h"
|
||||
|
||||
DECLARE_REAL(void*, memcpy, void *to, const void *from, uptr size)
|
||||
DECLARE_REAL(void*, memset, void *block, int c, uptr size)
|
||||
|
||||
namespace __asan {
|
||||
|
||||
// Return true if we can quickly decide that the region is unpoisoned.
|
||||
// We assume that a redzone is at least 16 bytes.
|
||||
static inline bool QuickCheckForUnpoisonedRegion(uptr beg, uptr size) {
|
||||
if (size == 0) return true;
|
||||
if (size <= 32)
|
||||
return !AddressIsPoisoned(beg) &&
|
||||
!AddressIsPoisoned(beg + size - 1) &&
|
||||
!AddressIsPoisoned(beg + size / 2);
|
||||
if (size <= 64)
|
||||
return !AddressIsPoisoned(beg) &&
|
||||
!AddressIsPoisoned(beg + size / 4) &&
|
||||
!AddressIsPoisoned(beg + size - 1) &&
|
||||
!AddressIsPoisoned(beg + 3 * size / 4) &&
|
||||
!AddressIsPoisoned(beg + size / 2);
|
||||
return false;
|
||||
}
|
||||
|
||||
struct AsanInterceptorContext {
|
||||
const char *interceptor_name;
|
||||
};
|
||||
|
||||
// We implement ACCESS_MEMORY_RANGE, ASAN_READ_RANGE,
|
||||
// and ASAN_WRITE_RANGE as macro instead of function so
|
||||
// that no extra frames are created, and stack trace contains
|
||||
// relevant information only.
|
||||
// We check all shadow bytes.
|
||||
#define ACCESS_MEMORY_RANGE(ctx, offset, size, isWrite) do { \
|
||||
uptr __offset = (uptr)(offset); \
|
||||
uptr __size = (uptr)(size); \
|
||||
uptr __bad = 0; \
|
||||
if (__offset > __offset + __size) { \
|
||||
GET_STACK_TRACE_FATAL_HERE; \
|
||||
ReportStringFunctionSizeOverflow(__offset, __size, &stack); \
|
||||
} \
|
||||
if (!QuickCheckForUnpoisonedRegion(__offset, __size) && \
|
||||
(__bad = __asan_region_is_poisoned(__offset, __size))) { \
|
||||
AsanInterceptorContext *_ctx = (AsanInterceptorContext *)ctx; \
|
||||
bool suppressed = false; \
|
||||
if (_ctx) { \
|
||||
suppressed = IsInterceptorSuppressed(_ctx->interceptor_name); \
|
||||
if (!suppressed && HaveStackTraceBasedSuppressions()) { \
|
||||
GET_STACK_TRACE_FATAL_HERE; \
|
||||
suppressed = IsStackTraceSuppressed(&stack); \
|
||||
} \
|
||||
} \
|
||||
if (!suppressed) { \
|
||||
GET_CURRENT_PC_BP_SP; \
|
||||
ReportGenericError(pc, bp, sp, __bad, isWrite, __size, 0, false);\
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// memcpy is called during __asan_init() from the internals of printf(...).
|
||||
// We do not treat memcpy with to==from as a bug.
|
||||
// See http://llvm.org/bugs/show_bug.cgi?id=11763.
|
||||
#define ASAN_MEMCPY_IMPL(ctx, to, from, size) \
|
||||
do { \
|
||||
if (UNLIKELY(!asan_inited)) return internal_memcpy(to, from, size); \
|
||||
if (asan_init_is_running) { \
|
||||
return REAL(memcpy)(to, from, size); \
|
||||
} \
|
||||
ENSURE_ASAN_INITED(); \
|
||||
if (flags()->replace_intrin) { \
|
||||
if (to != from) { \
|
||||
CHECK_RANGES_OVERLAP("memcpy", to, size, from, size); \
|
||||
} \
|
||||
ASAN_READ_RANGE(ctx, from, size); \
|
||||
ASAN_WRITE_RANGE(ctx, to, size); \
|
||||
} \
|
||||
return REAL(memcpy)(to, from, size); \
|
||||
} while (0)
|
||||
|
||||
// memset is called inside Printf.
|
||||
#define ASAN_MEMSET_IMPL(ctx, block, c, size) \
|
||||
do { \
|
||||
if (UNLIKELY(!asan_inited)) return internal_memset(block, c, size); \
|
||||
if (asan_init_is_running) { \
|
||||
return REAL(memset)(block, c, size); \
|
||||
} \
|
||||
ENSURE_ASAN_INITED(); \
|
||||
if (flags()->replace_intrin) { \
|
||||
ASAN_WRITE_RANGE(ctx, block, size); \
|
||||
} \
|
||||
return REAL(memset)(block, c, size); \
|
||||
} while (0)
|
||||
|
||||
#define ASAN_MEMMOVE_IMPL(ctx, to, from, size) \
|
||||
do { \
|
||||
if (UNLIKELY(!asan_inited)) return internal_memmove(to, from, size); \
|
||||
ENSURE_ASAN_INITED(); \
|
||||
if (flags()->replace_intrin) { \
|
||||
ASAN_READ_RANGE(ctx, from, size); \
|
||||
ASAN_WRITE_RANGE(ctx, to, size); \
|
||||
} \
|
||||
return internal_memmove(to, from, size); \
|
||||
} while (0)
|
||||
|
||||
#define ASAN_READ_RANGE(ctx, offset, size) \
|
||||
ACCESS_MEMORY_RANGE(ctx, offset, size, false)
|
||||
#define ASAN_WRITE_RANGE(ctx, offset, size) \
|
||||
ACCESS_MEMORY_RANGE(ctx, offset, size, true)
|
||||
|
||||
// Behavior of functions like "memcpy" or "strcpy" is undefined
|
||||
// if memory intervals overlap. We report error in this case.
|
||||
// Macro is used to avoid creation of new frames.
|
||||
static inline bool RangesOverlap(const char *offset1, uptr length1,
|
||||
const char *offset2, uptr length2) {
|
||||
return !((offset1 + length1 <= offset2) || (offset2 + length2 <= offset1));
|
||||
}
|
||||
#define CHECK_RANGES_OVERLAP(name, _offset1, length1, _offset2, length2) do { \
|
||||
const char *offset1 = (const char*)_offset1; \
|
||||
const char *offset2 = (const char*)_offset2; \
|
||||
if (RangesOverlap(offset1, length1, offset2, length2)) { \
|
||||
GET_STACK_TRACE_FATAL_HERE; \
|
||||
ReportStringFunctionMemoryRangesOverlap(name, offset1, length1, \
|
||||
offset2, length2, &stack); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
#endif // ASAN_MEMINTRIN_H
|
@ -69,8 +69,12 @@ void InitializePlatformExceptionHandlers();
|
||||
bool IsSystemHeapAddress(uptr addr);
|
||||
|
||||
// asan_rtl.cc
|
||||
void PrintAddressSpaceLayout();
|
||||
void NORETURN ShowStatsAndAbort();
|
||||
|
||||
// asan_shadow_setup.cc
|
||||
void InitializeShadowMemory();
|
||||
|
||||
// asan_malloc_linux.cc / asan_malloc_mac.cc
|
||||
void ReplaceSystemMalloc();
|
||||
|
||||
@ -80,6 +84,9 @@ void *AsanDoesNotSupportStaticLinkage();
|
||||
void AsanCheckDynamicRTPrereqs();
|
||||
void AsanCheckIncompatibleRT();
|
||||
|
||||
// asan_thread.cc
|
||||
AsanThread *CreateMainThread();
|
||||
|
||||
// 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.,
|
||||
|
@ -13,10 +13,12 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "sanitizer_common/sanitizer_platform.h"
|
||||
#if SANITIZER_FREEBSD || SANITIZER_LINUX
|
||||
#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
|
||||
SANITIZER_SOLARIS
|
||||
|
||||
#include "asan_interceptors.h"
|
||||
#include "asan_internal.h"
|
||||
#include "asan_premap_shadow.h"
|
||||
#include "asan_thread.h"
|
||||
#include "sanitizer_common/sanitizer_flags.h"
|
||||
#include "sanitizer_common/sanitizer_freebsd.h"
|
||||
@ -39,9 +41,17 @@
|
||||
#include <sys/link_elf.h>
|
||||
#endif
|
||||
|
||||
#if SANITIZER_ANDROID || SANITIZER_FREEBSD
|
||||
#if SANITIZER_SOLARIS
|
||||
#include <link.h>
|
||||
#endif
|
||||
|
||||
#if SANITIZER_ANDROID || SANITIZER_FREEBSD || SANITIZER_SOLARIS
|
||||
#include <ucontext.h>
|
||||
extern "C" void* _DYNAMIC;
|
||||
#elif SANITIZER_NETBSD
|
||||
#include <link_elf.h>
|
||||
#include <ucontext.h>
|
||||
extern Elf_Dyn _DYNAMIC;
|
||||
#else
|
||||
#include <sys/ucontext.h>
|
||||
#include <link.h>
|
||||
@ -77,9 +87,51 @@ void *AsanDoesNotSupportStaticLinkage() {
|
||||
return &_DYNAMIC; // defined in link.h
|
||||
}
|
||||
|
||||
static void UnmapFromTo(uptr from, uptr to) {
|
||||
CHECK(to >= from);
|
||||
if (to == from) return;
|
||||
uptr res = internal_munmap(reinterpret_cast<void *>(from), to - from);
|
||||
if (UNLIKELY(internal_iserror(res))) {
|
||||
Report(
|
||||
"ERROR: AddresSanitizer failed to unmap 0x%zx (%zd) bytes at address "
|
||||
"%p\n",
|
||||
to - from, to - from, from);
|
||||
CHECK("unable to unmap" && 0);
|
||||
}
|
||||
}
|
||||
|
||||
#if ASAN_PREMAP_SHADOW
|
||||
uptr FindPremappedShadowStart() {
|
||||
uptr granularity = GetMmapGranularity();
|
||||
uptr shadow_start = reinterpret_cast<uptr>(&__asan_shadow);
|
||||
uptr premap_shadow_size = PremapShadowSize();
|
||||
uptr shadow_size = RoundUpTo(kHighShadowEnd, granularity);
|
||||
// We may have mapped too much. Release extra memory.
|
||||
UnmapFromTo(shadow_start + shadow_size, shadow_start + premap_shadow_size);
|
||||
return shadow_start;
|
||||
}
|
||||
#endif
|
||||
|
||||
uptr FindDynamicShadowStart() {
|
||||
UNREACHABLE("FindDynamicShadowStart is not available");
|
||||
return 0;
|
||||
#if ASAN_PREMAP_SHADOW
|
||||
if (!PremapShadowFailed())
|
||||
return FindPremappedShadowStart();
|
||||
#endif
|
||||
|
||||
uptr granularity = GetMmapGranularity();
|
||||
uptr alignment = granularity * 8;
|
||||
uptr left_padding = granularity;
|
||||
uptr shadow_size = RoundUpTo(kHighShadowEnd, granularity);
|
||||
uptr map_size = shadow_size + left_padding + alignment;
|
||||
|
||||
uptr map_start = (uptr)MmapNoAccess(map_size);
|
||||
CHECK_NE(map_start, ~(uptr)0);
|
||||
|
||||
uptr shadow_start = RoundUpTo(map_start + left_padding, alignment);
|
||||
UnmapFromTo(map_start, shadow_start - left_padding);
|
||||
UnmapFromTo(shadow_start + shadow_size, map_start + map_size);
|
||||
|
||||
return shadow_start;
|
||||
}
|
||||
|
||||
void AsanApplyToGlobals(globals_op_fptr op, const void *needle) {
|
||||
@ -93,6 +145,9 @@ void AsanCheckIncompatibleRT() {}
|
||||
#else
|
||||
static int FindFirstDSOCallback(struct dl_phdr_info *info, size_t size,
|
||||
void *data) {
|
||||
VReport(2, "info->dlpi_name = %s\tinfo->dlpi_addr = %p\n",
|
||||
info->dlpi_name, info->dlpi_addr);
|
||||
|
||||
// Continue until the first dynamic library is found
|
||||
if (!info->dlpi_name || info->dlpi_name[0] == 0)
|
||||
return 0;
|
||||
@ -101,6 +156,21 @@ static int FindFirstDSOCallback(struct dl_phdr_info *info, size_t size,
|
||||
if (internal_strncmp(info->dlpi_name, "linux-", sizeof("linux-") - 1) == 0)
|
||||
return 0;
|
||||
|
||||
#if SANITIZER_FREEBSD || SANITIZER_NETBSD
|
||||
// Ignore first entry (the main program)
|
||||
char **p = (char **)data;
|
||||
if (!(*p)) {
|
||||
*p = (char *)-1;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SANITIZER_SOLARIS
|
||||
// Ignore executable on Solaris
|
||||
if (info->dlpi_addr == 0)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
*(const char **)data = info->dlpi_name;
|
||||
return 1;
|
||||
}
|
||||
@ -179,4 +249,5 @@ void *AsanDlSymNext(const char *sym) {
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
|
||||
#endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD ||
|
||||
// SANITIZER_SOLARIS
|
||||
|
@ -15,7 +15,8 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "sanitizer_common/sanitizer_platform.h"
|
||||
#if SANITIZER_FREEBSD || SANITIZER_LINUX
|
||||
#if SANITIZER_FREEBSD || SANITIZER_FUCHSIA || SANITIZER_LINUX || \
|
||||
SANITIZER_NETBSD || SANITIZER_SOLARIS
|
||||
|
||||
#include "sanitizer_common/sanitizer_tls_get_addr.h"
|
||||
#include "asan_allocator.h"
|
||||
@ -30,9 +31,9 @@ static uptr allocated_for_dlsym;
|
||||
static const uptr kDlsymAllocPoolSize = 1024;
|
||||
static uptr alloc_memory_for_dlsym[kDlsymAllocPoolSize];
|
||||
|
||||
static bool IsInDlsymAllocPool(const void *ptr) {
|
||||
static INLINE bool IsInDlsymAllocPool(const void *ptr) {
|
||||
uptr off = (uptr)ptr - (uptr)alloc_memory_for_dlsym;
|
||||
return off < sizeof(alloc_memory_for_dlsym);
|
||||
return off < allocated_for_dlsym * sizeof(alloc_memory_for_dlsym[0]);
|
||||
}
|
||||
|
||||
static void *AllocateFromLocalPool(uptr size_in_bytes) {
|
||||
@ -43,6 +44,26 @@ static void *AllocateFromLocalPool(uptr size_in_bytes) {
|
||||
return mem;
|
||||
}
|
||||
|
||||
static INLINE bool MaybeInDlsym() {
|
||||
// Fuchsia doesn't use dlsym-based interceptors.
|
||||
return !SANITIZER_FUCHSIA && asan_init_is_running;
|
||||
}
|
||||
|
||||
static void *ReallocFromLocalPool(void *ptr, uptr size) {
|
||||
const uptr offset = (uptr)ptr - (uptr)alloc_memory_for_dlsym;
|
||||
const uptr copy_size = Min(size, kDlsymAllocPoolSize - offset);
|
||||
void *new_ptr;
|
||||
if (UNLIKELY(MaybeInDlsym())) {
|
||||
new_ptr = AllocateFromLocalPool(size);
|
||||
} else {
|
||||
ENSURE_ASAN_INITED();
|
||||
GET_STACK_TRACE_MALLOC;
|
||||
new_ptr = asan_malloc(size, &stack);
|
||||
}
|
||||
internal_memcpy(new_ptr, ptr, copy_size);
|
||||
return new_ptr;
|
||||
}
|
||||
|
||||
INTERCEPTOR(void, free, void *ptr) {
|
||||
GET_STACK_TRACE_FREE;
|
||||
if (UNLIKELY(IsInDlsymAllocPool(ptr)))
|
||||
@ -60,7 +81,7 @@ INTERCEPTOR(void, cfree, void *ptr) {
|
||||
#endif // SANITIZER_INTERCEPT_CFREE
|
||||
|
||||
INTERCEPTOR(void*, malloc, uptr size) {
|
||||
if (UNLIKELY(asan_init_is_running))
|
||||
if (UNLIKELY(MaybeInDlsym()))
|
||||
// Hack: dlsym calls malloc before REAL(malloc) is retrieved from dlsym.
|
||||
return AllocateFromLocalPool(size);
|
||||
ENSURE_ASAN_INITED();
|
||||
@ -69,7 +90,7 @@ INTERCEPTOR(void*, malloc, uptr size) {
|
||||
}
|
||||
|
||||
INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
|
||||
if (UNLIKELY(asan_init_is_running))
|
||||
if (UNLIKELY(MaybeInDlsym()))
|
||||
// Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
|
||||
return AllocateFromLocalPool(nmemb * size);
|
||||
ENSURE_ASAN_INITED();
|
||||
@ -78,21 +99,9 @@ INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
|
||||
}
|
||||
|
||||
INTERCEPTOR(void*, realloc, void *ptr, uptr size) {
|
||||
if (UNLIKELY(IsInDlsymAllocPool(ptr))) {
|
||||
const uptr offset = (uptr)ptr - (uptr)alloc_memory_for_dlsym;
|
||||
const uptr copy_size = Min(size, kDlsymAllocPoolSize - offset);
|
||||
void *new_ptr;
|
||||
if (UNLIKELY(asan_init_is_running)) {
|
||||
new_ptr = AllocateFromLocalPool(size);
|
||||
} else {
|
||||
ENSURE_ASAN_INITED();
|
||||
GET_STACK_TRACE_MALLOC;
|
||||
new_ptr = asan_malloc(size, &stack);
|
||||
}
|
||||
internal_memcpy(new_ptr, ptr, copy_size);
|
||||
return new_ptr;
|
||||
}
|
||||
if (UNLIKELY(asan_init_is_running))
|
||||
if (UNLIKELY(IsInDlsymAllocPool(ptr)))
|
||||
return ReallocFromLocalPool(ptr, size);
|
||||
if (UNLIKELY(MaybeInDlsym()))
|
||||
return AllocateFromLocalPool(size);
|
||||
ENSURE_ASAN_INITED();
|
||||
GET_STACK_TRACE_MALLOC;
|
||||
@ -226,4 +235,5 @@ void ReplaceSystemMalloc() {
|
||||
} // namespace __asan
|
||||
#endif // SANITIZER_ANDROID
|
||||
|
||||
#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
|
||||
#endif // SANITIZER_FREEBSD || SANITIZER_FUCHSIA || SANITIZER_LINUX ||
|
||||
// SANITIZER_NETBSD || SANITIZER_SOLARIS
|
||||
|
@ -115,6 +115,13 @@
|
||||
// || `[0x40000000, 0x47ffffff]` || LowShadow ||
|
||||
// || `[0x00000000, 0x3fffffff]` || LowMem ||
|
||||
//
|
||||
// Shadow mapping on NetBSD/x86-64 with SHADOW_OFFSET == 0x400000000000:
|
||||
// || `[0x4feffffffe01, 0x7f7ffffff000]` || HighMem ||
|
||||
// || `[0x49fdffffffc0, 0x4feffffffe00]` || HighShadow ||
|
||||
// || `[0x480000000000, 0x49fdffffffbf]` || ShadowGap ||
|
||||
// || `[0x400000000000, 0x47ffffffffff]` || LowShadow ||
|
||||
// || `[0x000000000000, 0x3fffffffffff]` || LowMem ||
|
||||
//
|
||||
// Default Windows/i386 mapping:
|
||||
// (the exact location of HighShadow/HighMem may vary depending
|
||||
// on WoW64, /LARGEADDRESSAWARE, etc).
|
||||
@ -124,11 +131,16 @@
|
||||
// || `[0x30000000, 0x35ffffff]` || LowShadow ||
|
||||
// || `[0x00000000, 0x2fffffff]` || LowMem ||
|
||||
|
||||
#if defined(ASAN_SHADOW_SCALE)
|
||||
static const u64 kDefaultShadowScale = ASAN_SHADOW_SCALE;
|
||||
#else
|
||||
static const u64 kDefaultShadowScale = 3;
|
||||
#endif
|
||||
static const u64 kDefaultShadowSentinel = ~(uptr)0;
|
||||
static const u64 kDefaultShadowOffset32 = 1ULL << 29; // 0x20000000
|
||||
static const u64 kDefaultShadowOffset64 = 1ULL << 44;
|
||||
static const u64 kDefaultShort64bitShadowOffset = 0x7FFF8000; // < 2G.
|
||||
static const u64 kDefaultShort64bitShadowOffset =
|
||||
0x7FFFFFFF & (~0xFFFULL << kDefaultShadowScale); // < 2G.
|
||||
static const u64 kIosShadowOffset32 = 1ULL << 30; // 0x40000000
|
||||
static const u64 kIosShadowOffset64 = 0x120200000;
|
||||
static const u64 kIosSimShadowOffset32 = 1ULL << 30;
|
||||
@ -136,18 +148,20 @@ 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 kPPC64_ShadowOffset64 = 1ULL << 44;
|
||||
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 kNetBSD_ShadowOffset64 = 1ULL << 46; // 0x400000000000
|
||||
static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000
|
||||
|
||||
#define SHADOW_SCALE kDefaultShadowScale
|
||||
|
||||
|
||||
#if SANITIZER_WORDSIZE == 32
|
||||
# if SANITIZER_ANDROID
|
||||
#if SANITIZER_FUCHSIA
|
||||
# define SHADOW_OFFSET (0)
|
||||
#elif SANITIZER_WORDSIZE == 32
|
||||
# if SANITIZER_ANDROID
|
||||
# define SHADOW_OFFSET __asan_shadow_memory_dynamic_address
|
||||
# elif defined(__mips__)
|
||||
# define SHADOW_OFFSET kMIPS32_ShadowOffset32
|
||||
# elif SANITIZER_FREEBSD
|
||||
@ -178,6 +192,8 @@ static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000
|
||||
# define SHADOW_OFFSET kSystemZ_ShadowOffset64
|
||||
# elif SANITIZER_FREEBSD
|
||||
# define SHADOW_OFFSET kFreeBSD_ShadowOffset64
|
||||
# elif SANITIZER_NETBSD
|
||||
# define SHADOW_OFFSET kNetBSD_ShadowOffset64
|
||||
# elif SANITIZER_MAC
|
||||
# define SHADOW_OFFSET kDefaultShadowOffset64
|
||||
# elif defined(__mips64)
|
||||
@ -189,6 +205,12 @@ static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if SANITIZER_ANDROID && defined(__arm__)
|
||||
# define ASAN_PREMAP_SHADOW 1
|
||||
#else
|
||||
# define ASAN_PREMAP_SHADOW 0
|
||||
#endif
|
||||
|
||||
#define SHADOW_GRANULARITY (1ULL << SHADOW_SCALE)
|
||||
#define MEM_TO_SHADOW(mem) (((mem) >> SHADOW_SCALE) + (SHADOW_OFFSET))
|
||||
|
||||
|
@ -107,6 +107,9 @@ static void MemoryProfileCB(const SuspendedThreadsList &suspended_threads_list,
|
||||
__lsan::ForEachChunk(ChunkCallback, &hp);
|
||||
uptr *Arg = reinterpret_cast<uptr*>(argument);
|
||||
hp.Print(Arg[0], Arg[1]);
|
||||
|
||||
if (Verbosity())
|
||||
__asan_print_accumulated_stats();
|
||||
}
|
||||
|
||||
} // namespace __asan
|
||||
|
@ -125,77 +125,69 @@ INTERCEPTOR(void *, _ZnwmRKSt9nothrow_t, size_t size, std::nothrow_t const&) {
|
||||
INTERCEPTOR(void *, _ZnamRKSt9nothrow_t, size_t size, std::nothrow_t const&) {
|
||||
OPERATOR_NEW_BODY(FROM_NEW_BR, true /*nothrow*/);
|
||||
}
|
||||
#endif
|
||||
#endif // !SANITIZER_MAC
|
||||
|
||||
#define OPERATOR_DELETE_BODY(type) \
|
||||
GET_STACK_TRACE_FREE;\
|
||||
asan_free(ptr, &stack, type);
|
||||
asan_delete(ptr, 0, 0, &stack, type);
|
||||
|
||||
#define OPERATOR_DELETE_BODY_SIZE(type) \
|
||||
GET_STACK_TRACE_FREE;\
|
||||
asan_delete(ptr, size, 0, &stack, type);
|
||||
|
||||
#define OPERATOR_DELETE_BODY_ALIGN(type) \
|
||||
GET_STACK_TRACE_FREE;\
|
||||
asan_delete(ptr, 0, static_cast<uptr>(align), &stack, type);
|
||||
|
||||
#define OPERATOR_DELETE_BODY_SIZE_ALIGN(type) \
|
||||
GET_STACK_TRACE_FREE;\
|
||||
asan_delete(ptr, size, static_cast<uptr>(align), &stack, type);
|
||||
|
||||
#if !SANITIZER_MAC
|
||||
CXX_OPERATOR_ATTRIBUTE
|
||||
void operator delete(void *ptr) NOEXCEPT {
|
||||
OPERATOR_DELETE_BODY(FROM_NEW);
|
||||
}
|
||||
void operator delete(void *ptr) NOEXCEPT
|
||||
{ OPERATOR_DELETE_BODY(FROM_NEW); }
|
||||
CXX_OPERATOR_ATTRIBUTE
|
||||
void operator delete[](void *ptr) NOEXCEPT {
|
||||
OPERATOR_DELETE_BODY(FROM_NEW_BR);
|
||||
}
|
||||
void operator delete[](void *ptr) NOEXCEPT
|
||||
{ OPERATOR_DELETE_BODY(FROM_NEW_BR); }
|
||||
CXX_OPERATOR_ATTRIBUTE
|
||||
void operator delete(void *ptr, std::nothrow_t const&) {
|
||||
OPERATOR_DELETE_BODY(FROM_NEW);
|
||||
}
|
||||
void operator delete(void *ptr, std::nothrow_t const&)
|
||||
{ OPERATOR_DELETE_BODY(FROM_NEW); }
|
||||
CXX_OPERATOR_ATTRIBUTE
|
||||
void operator delete[](void *ptr, std::nothrow_t const&) {
|
||||
OPERATOR_DELETE_BODY(FROM_NEW_BR);
|
||||
}
|
||||
void operator delete[](void *ptr, std::nothrow_t const&)
|
||||
{ OPERATOR_DELETE_BODY(FROM_NEW_BR); }
|
||||
CXX_OPERATOR_ATTRIBUTE
|
||||
void operator delete(void *ptr, size_t size) NOEXCEPT {
|
||||
GET_STACK_TRACE_FREE;
|
||||
asan_sized_free(ptr, size, &stack, FROM_NEW);
|
||||
}
|
||||
void operator delete(void *ptr, size_t size) NOEXCEPT
|
||||
{ OPERATOR_DELETE_BODY_SIZE(FROM_NEW); }
|
||||
CXX_OPERATOR_ATTRIBUTE
|
||||
void operator delete[](void *ptr, size_t size) NOEXCEPT {
|
||||
GET_STACK_TRACE_FREE;
|
||||
asan_sized_free(ptr, size, &stack, FROM_NEW_BR);
|
||||
}
|
||||
void operator delete[](void *ptr, size_t size) NOEXCEPT
|
||||
{ OPERATOR_DELETE_BODY_SIZE(FROM_NEW_BR); }
|
||||
CXX_OPERATOR_ATTRIBUTE
|
||||
void operator delete(void *ptr, std::align_val_t) NOEXCEPT {
|
||||
OPERATOR_DELETE_BODY(FROM_NEW);
|
||||
}
|
||||
void operator delete(void *ptr, std::align_val_t align) NOEXCEPT
|
||||
{ OPERATOR_DELETE_BODY_ALIGN(FROM_NEW); }
|
||||
CXX_OPERATOR_ATTRIBUTE
|
||||
void operator delete[](void *ptr, std::align_val_t) NOEXCEPT {
|
||||
OPERATOR_DELETE_BODY(FROM_NEW_BR);
|
||||
}
|
||||
void operator delete[](void *ptr, std::align_val_t align) NOEXCEPT
|
||||
{ OPERATOR_DELETE_BODY_ALIGN(FROM_NEW_BR); }
|
||||
CXX_OPERATOR_ATTRIBUTE
|
||||
void operator delete(void *ptr, std::align_val_t, std::nothrow_t const&) {
|
||||
OPERATOR_DELETE_BODY(FROM_NEW);
|
||||
}
|
||||
void operator delete(void *ptr, std::align_val_t align, std::nothrow_t const&)
|
||||
{ OPERATOR_DELETE_BODY_ALIGN(FROM_NEW); }
|
||||
CXX_OPERATOR_ATTRIBUTE
|
||||
void operator delete[](void *ptr, std::align_val_t, std::nothrow_t const&) {
|
||||
OPERATOR_DELETE_BODY(FROM_NEW_BR);
|
||||
}
|
||||
void operator delete[](void *ptr, std::align_val_t align, std::nothrow_t const&)
|
||||
{ OPERATOR_DELETE_BODY_ALIGN(FROM_NEW_BR); }
|
||||
CXX_OPERATOR_ATTRIBUTE
|
||||
void operator delete(void *ptr, size_t size, std::align_val_t) NOEXCEPT {
|
||||
GET_STACK_TRACE_FREE;
|
||||
asan_sized_free(ptr, size, &stack, FROM_NEW);
|
||||
}
|
||||
void operator delete(void *ptr, size_t size, std::align_val_t align) NOEXCEPT
|
||||
{ OPERATOR_DELETE_BODY_SIZE_ALIGN(FROM_NEW); }
|
||||
CXX_OPERATOR_ATTRIBUTE
|
||||
void operator delete[](void *ptr, size_t size, std::align_val_t) NOEXCEPT {
|
||||
GET_STACK_TRACE_FREE;
|
||||
asan_sized_free(ptr, size, &stack, FROM_NEW_BR);
|
||||
}
|
||||
void operator delete[](void *ptr, size_t size, std::align_val_t align) NOEXCEPT
|
||||
{ OPERATOR_DELETE_BODY_SIZE_ALIGN(FROM_NEW_BR); }
|
||||
|
||||
#else // SANITIZER_MAC
|
||||
INTERCEPTOR(void, _ZdlPv, void *ptr) {
|
||||
OPERATOR_DELETE_BODY(FROM_NEW);
|
||||
}
|
||||
INTERCEPTOR(void, _ZdaPv, void *ptr) {
|
||||
OPERATOR_DELETE_BODY(FROM_NEW_BR);
|
||||
}
|
||||
INTERCEPTOR(void, _ZdlPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&) {
|
||||
OPERATOR_DELETE_BODY(FROM_NEW);
|
||||
}
|
||||
INTERCEPTOR(void, _ZdaPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&) {
|
||||
OPERATOR_DELETE_BODY(FROM_NEW_BR);
|
||||
}
|
||||
#endif
|
||||
INTERCEPTOR(void, _ZdlPv, void *ptr)
|
||||
{ OPERATOR_DELETE_BODY(FROM_NEW); }
|
||||
INTERCEPTOR(void, _ZdaPv, void *ptr)
|
||||
{ OPERATOR_DELETE_BODY(FROM_NEW_BR); }
|
||||
INTERCEPTOR(void, _ZdlPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&)
|
||||
{ OPERATOR_DELETE_BODY(FROM_NEW); }
|
||||
INTERCEPTOR(void, _ZdaPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&)
|
||||
{ OPERATOR_DELETE_BODY(FROM_NEW_BR); }
|
||||
#endif // !SANITIZER_MAC
|
||||
|
@ -217,7 +217,7 @@ uptr __asan_region_is_poisoned(uptr beg, uptr size) {
|
||||
uptr __bad = __asan_region_is_poisoned(__p, __size); \
|
||||
__asan_report_error(pc, bp, sp, __bad, isWrite, __size, 0);\
|
||||
} \
|
||||
} while (false); \
|
||||
} while (false)
|
||||
|
||||
|
||||
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
|
||||
|
@ -46,8 +46,11 @@ ALWAYS_INLINE void FastPoisonShadow(uptr aligned_beg, uptr aligned_size,
|
||||
// for mapping shadow and zeroing out pages doesn't "just work", so we should
|
||||
// probably provide higher-level interface for these operations.
|
||||
// For now, just memset on Windows.
|
||||
if (value ||
|
||||
SANITIZER_WINDOWS == 1 ||
|
||||
if (value || SANITIZER_WINDOWS == 1 ||
|
||||
// TODO(mcgrathr): Fuchsia doesn't allow the shadow mapping to be
|
||||
// changed at all. It doesn't currently have an efficient means
|
||||
// to zero a bunch of pages, but maybe we should add one.
|
||||
SANITIZER_FUCHSIA == 1 ||
|
||||
shadow_end - shadow_beg < common_flags()->clear_shadow_mmap_threshold) {
|
||||
REAL(memset)((void*)shadow_beg, value, shadow_end - shadow_beg);
|
||||
} else {
|
||||
|
@ -25,7 +25,6 @@
|
||||
#include "sanitizer_common/sanitizer_procmaps.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
@ -34,58 +33,9 @@
|
||||
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 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.
|
||||
// lis r0,-10000
|
||||
// stdux r1,r1,r0 # store sp to [sp-10000] and update sp by -10000
|
||||
// If the store faults then sp will not have been updated, so test above
|
||||
// will not work, because the fault address will be more than just "slightly"
|
||||
// below sp.
|
||||
if (!IsStackAccess && IsAccessibleMemoryRange(sig.pc, 4)) {
|
||||
u32 inst = *(unsigned *)sig.pc;
|
||||
u32 ra = (inst >> 16) & 0x1F;
|
||||
u32 opcd = inst >> 26;
|
||||
u32 xo = (inst >> 1) & 0x3FF;
|
||||
// Check for store-with-update to sp. The instructions we accept are:
|
||||
// stbu rs,d(ra) stbux rs,ra,rb
|
||||
// sthu rs,d(ra) sthux rs,ra,rb
|
||||
// stwu rs,d(ra) stwux rs,ra,rb
|
||||
// stdu rs,ds(ra) stdux rs,ra,rb
|
||||
// where ra is r1 (the stack pointer).
|
||||
if (ra == 1 &&
|
||||
(opcd == 39 || opcd == 45 || opcd == 37 || opcd == 62 ||
|
||||
(opcd == 31 && (xo == 247 || xo == 439 || xo == 183 || xo == 181))))
|
||||
IsStackAccess = true;
|
||||
}
|
||||
#endif // __powerpc__
|
||||
|
||||
// We also check si_code to filter out SEGV caused by something else other
|
||||
// then hitting the guard page or unmapped memory, like, for example,
|
||||
// unaligned memory access.
|
||||
if (IsStackAccess && (code == si_SEGV_MAPERR || code == si_SEGV_ACCERR))
|
||||
ReportStackOverflow(sig);
|
||||
else
|
||||
ReportDeadlySignal(signo, sig);
|
||||
StartReportDeadlySignal();
|
||||
SignalContext sig(siginfo, context);
|
||||
ReportDeadlySignal(sig);
|
||||
}
|
||||
|
||||
// ---------------------- TSD ---------------- {{{1
|
||||
|
79
lib/asan/asan_premap_shadow.cc
Normal file
79
lib/asan/asan_premap_shadow.cc
Normal file
@ -0,0 +1,79 @@
|
||||
//===-- asan_premap_shadow.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.
|
||||
//
|
||||
// Reserve shadow memory with an ifunc resolver.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "asan_mapping.h"
|
||||
|
||||
#if ASAN_PREMAP_SHADOW
|
||||
|
||||
#include "asan_premap_shadow.h"
|
||||
#include "sanitizer_common/sanitizer_posix.h"
|
||||
|
||||
namespace __asan {
|
||||
|
||||
// The code in this file needs to run in an unrelocated binary. It may not
|
||||
// access any external symbol, including its own non-hidden globals.
|
||||
|
||||
// Conservative upper limit.
|
||||
uptr PremapShadowSize() {
|
||||
uptr granularity = GetMmapGranularity();
|
||||
return RoundUpTo(GetMaxVirtualAddress() >> SHADOW_SCALE, granularity);
|
||||
}
|
||||
|
||||
// Returns an address aligned to 8 pages, such that one page on the left and
|
||||
// PremapShadowSize() bytes on the right of it are mapped r/o.
|
||||
uptr PremapShadow() {
|
||||
uptr granularity = GetMmapGranularity();
|
||||
uptr alignment = granularity * 8;
|
||||
uptr left_padding = granularity;
|
||||
uptr shadow_size = PremapShadowSize();
|
||||
uptr map_size = shadow_size + left_padding + alignment;
|
||||
|
||||
uptr map_start = (uptr)MmapNoAccess(map_size);
|
||||
CHECK_NE(map_start, ~(uptr)0);
|
||||
|
||||
uptr shadow_start = RoundUpTo(map_start + left_padding, alignment);
|
||||
uptr shadow_end = shadow_start + shadow_size;
|
||||
internal_munmap(reinterpret_cast<void *>(map_start),
|
||||
shadow_start - left_padding - map_start);
|
||||
internal_munmap(reinterpret_cast<void *>(shadow_end),
|
||||
map_start + map_size - shadow_end);
|
||||
return shadow_start;
|
||||
}
|
||||
|
||||
bool PremapShadowFailed() {
|
||||
uptr shadow = reinterpret_cast<uptr>(&__asan_shadow);
|
||||
uptr resolver = reinterpret_cast<uptr>(&__asan_premap_shadow);
|
||||
// shadow == resolver is how Android KitKat and older handles ifunc.
|
||||
// shadow == 0 just in case.
|
||||
if (shadow == 0 || shadow == resolver)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
} // namespace __asan
|
||||
|
||||
extern "C" {
|
||||
decltype(__asan_shadow)* __asan_premap_shadow() {
|
||||
// The resolver may be called multiple times. Map the shadow just once.
|
||||
static uptr premapped_shadow = 0;
|
||||
if (!premapped_shadow) premapped_shadow = __asan::PremapShadow();
|
||||
return reinterpret_cast<decltype(__asan_shadow)*>(premapped_shadow);
|
||||
}
|
||||
|
||||
// __asan_shadow is a "function" that has the same address as the first byte of
|
||||
// the shadow mapping.
|
||||
INTERFACE_ATTRIBUTE __attribute__((ifunc("__asan_premap_shadow"))) void
|
||||
__asan_shadow();
|
||||
}
|
||||
|
||||
#endif // ASAN_PREMAP_SHADOW
|
30
lib/asan/asan_premap_shadow.h
Normal file
30
lib/asan/asan_premap_shadow.h
Normal file
@ -0,0 +1,30 @@
|
||||
//===-- asan_mapping.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.
|
||||
//
|
||||
// Premap shadow range with an ifunc resolver.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
#ifndef ASAN_PREMAP_SHADOW_H
|
||||
#define ASAN_PREMAP_SHADOW_H
|
||||
|
||||
#if ASAN_PREMAP_SHADOW
|
||||
namespace __asan {
|
||||
// Conservative upper limit.
|
||||
uptr PremapShadowSize();
|
||||
bool PremapShadowFailed();
|
||||
}
|
||||
#endif
|
||||
|
||||
extern "C" INTERFACE_ATTRIBUTE void __asan_shadow();
|
||||
extern "C" decltype(__asan_shadow)* __asan_premap_shadow();
|
||||
|
||||
#endif // ASAN_PREMAP_SHADOW_H
|
@ -60,9 +60,8 @@ void PrintMemoryByte(InternalScopedString *str, const char *before, u8 byte,
|
||||
bool in_shadow, const char *after) {
|
||||
Decorator d;
|
||||
str->append("%s%s%x%x%s%s", before,
|
||||
in_shadow ? d.ShadowByte(byte) : d.MemoryByte(),
|
||||
byte >> 4, byte & 15,
|
||||
in_shadow ? d.EndShadowByte() : d.EndMemoryByte(), after);
|
||||
in_shadow ? d.ShadowByte(byte) : d.MemoryByte(), byte >> 4,
|
||||
byte & 15, d.Default(), after);
|
||||
}
|
||||
|
||||
static void PrintZoneForPointer(uptr ptr, uptr zone_ptr,
|
||||
@ -123,53 +122,15 @@ bool ParseFrameDescription(const char *frame_descr,
|
||||
// immediately after printing error report.
|
||||
class ScopedInErrorReport {
|
||||
public:
|
||||
explicit ScopedInErrorReport(bool fatal = false) {
|
||||
halt_on_error_ = fatal || flags()->halt_on_error;
|
||||
|
||||
if (lock_.TryLock()) {
|
||||
StartReporting();
|
||||
return;
|
||||
}
|
||||
|
||||
// ASan found two bugs in different threads simultaneously.
|
||||
|
||||
u32 current_tid = GetCurrentTidOrInvalid();
|
||||
if (reporting_thread_tid_ == current_tid ||
|
||||
reporting_thread_tid_ == kInvalidTid) {
|
||||
// This is either asynch signal or nested error during error reporting.
|
||||
// Fail simple to avoid deadlocks in Report().
|
||||
|
||||
// Can't use Report() here because of potential deadlocks
|
||||
// in nested signal handlers.
|
||||
const char msg[] = "AddressSanitizer: nested bug in the same thread, "
|
||||
"aborting.\n";
|
||||
WriteToFile(kStderrFd, msg, sizeof(msg));
|
||||
|
||||
internal__exit(common_flags()->exitcode);
|
||||
}
|
||||
|
||||
if (halt_on_error_) {
|
||||
// Do not print more than one report, otherwise they will mix up.
|
||||
// Error reporting functions shouldn't return at this situation, as
|
||||
// they are effectively no-returns.
|
||||
|
||||
Report("AddressSanitizer: while reporting a bug found another one. "
|
||||
"Ignoring.\n");
|
||||
|
||||
// Sleep long enough to make sure that the thread which started
|
||||
// to print an error report will finish doing it.
|
||||
SleepForSeconds(Max(100, flags()->sleep_before_dying + 1));
|
||||
|
||||
// If we're still not dead for some reason, use raw _exit() instead of
|
||||
// Die() to bypass any additional checks.
|
||||
internal__exit(common_flags()->exitcode);
|
||||
} else {
|
||||
// The other thread will eventually finish reporting
|
||||
// so it's safe to wait
|
||||
lock_.Lock();
|
||||
}
|
||||
|
||||
StartReporting();
|
||||
explicit ScopedInErrorReport(bool fatal = false)
|
||||
: halt_on_error_(fatal || flags()->halt_on_error) {
|
||||
// Make sure the registry and sanitizer report mutexes are locked while
|
||||
// we're printing an error report.
|
||||
// We can lock them only here to avoid self-deadlock in case of
|
||||
// recursive reports.
|
||||
asanThreadRegistry().Lock();
|
||||
Printf(
|
||||
"=================================================================\n");
|
||||
}
|
||||
|
||||
~ScopedInErrorReport() {
|
||||
@ -217,9 +178,6 @@ class ScopedInErrorReport {
|
||||
if (!halt_on_error_)
|
||||
internal_memset(¤t_error_, 0, sizeof(current_error_));
|
||||
|
||||
CommonSanitizerReportMutex.Unlock();
|
||||
reporting_thread_tid_ = kInvalidTid;
|
||||
lock_.Unlock();
|
||||
if (halt_on_error_) {
|
||||
Report("ABORTING\n");
|
||||
Die();
|
||||
@ -237,39 +195,18 @@ class ScopedInErrorReport {
|
||||
}
|
||||
|
||||
private:
|
||||
void StartReporting() {
|
||||
// Make sure the registry and sanitizer report mutexes are locked while
|
||||
// we're printing an error report.
|
||||
// We can lock them only here to avoid self-deadlock in case of
|
||||
// recursive reports.
|
||||
asanThreadRegistry().Lock();
|
||||
CommonSanitizerReportMutex.Lock();
|
||||
reporting_thread_tid_ = GetCurrentTidOrInvalid();
|
||||
Printf("===================================================="
|
||||
"=============\n");
|
||||
}
|
||||
|
||||
static StaticSpinMutex lock_;
|
||||
static u32 reporting_thread_tid_;
|
||||
ScopedErrorReportLock error_report_lock_;
|
||||
// Error currently being reported. This enables the destructor to interact
|
||||
// with the debugger and point it to an error description.
|
||||
static ErrorDescription current_error_;
|
||||
bool halt_on_error_;
|
||||
};
|
||||
|
||||
StaticSpinMutex ScopedInErrorReport::lock_;
|
||||
u32 ScopedInErrorReport::reporting_thread_tid_ = kInvalidTid;
|
||||
ErrorDescription ScopedInErrorReport::current_error_;
|
||||
|
||||
void ReportStackOverflow(const SignalContext &sig) {
|
||||
void ReportDeadlySignal(const SignalContext &sig) {
|
||||
ScopedInErrorReport in_report(/*fatal*/ true);
|
||||
ErrorStackOverflow error(GetCurrentTidOrInvalid(), sig);
|
||||
in_report.ReportError(error);
|
||||
}
|
||||
|
||||
void ReportDeadlySignal(int signo, const SignalContext &sig) {
|
||||
ScopedInErrorReport in_report(/*fatal*/ true);
|
||||
ErrorDeadlySignal error(GetCurrentTidOrInvalid(), sig, signo);
|
||||
ErrorDeadlySignal error(GetCurrentTidOrInvalid(), sig);
|
||||
in_report.ReportError(error);
|
||||
}
|
||||
|
||||
@ -279,11 +216,12 @@ void ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack) {
|
||||
in_report.ReportError(error);
|
||||
}
|
||||
|
||||
void ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size,
|
||||
void ReportNewDeleteTypeMismatch(uptr addr, uptr delete_size,
|
||||
uptr delete_alignment,
|
||||
BufferedStackTrace *free_stack) {
|
||||
ScopedInErrorReport in_report;
|
||||
ErrorNewDeleteSizeMismatch error(GetCurrentTidOrInvalid(), free_stack, addr,
|
||||
delete_size);
|
||||
ErrorNewDeleteTypeMismatch error(GetCurrentTidOrInvalid(), free_stack, addr,
|
||||
delete_size, delete_alignment);
|
||||
in_report.ReportError(error);
|
||||
}
|
||||
|
||||
@ -360,17 +298,58 @@ static NOINLINE void ReportInvalidPointerPair(uptr pc, uptr bp, uptr sp,
|
||||
in_report.ReportError(error);
|
||||
}
|
||||
|
||||
static bool IsInvalidPointerPair(uptr a1, uptr a2) {
|
||||
if (a1 == a2)
|
||||
return false;
|
||||
|
||||
// 256B in shadow memory can be iterated quite fast
|
||||
static const uptr kMaxOffset = 2048;
|
||||
|
||||
uptr left = a1 < a2 ? a1 : a2;
|
||||
uptr right = a1 < a2 ? a2 : a1;
|
||||
uptr offset = right - left;
|
||||
if (offset <= kMaxOffset)
|
||||
return __asan_region_is_poisoned(left, offset);
|
||||
|
||||
AsanThread *t = GetCurrentThread();
|
||||
|
||||
// check whether left is a stack memory pointer
|
||||
if (uptr shadow_offset1 = t->GetStackVariableShadowStart(left)) {
|
||||
uptr shadow_offset2 = t->GetStackVariableShadowStart(right);
|
||||
return shadow_offset2 == 0 || shadow_offset1 != shadow_offset2;
|
||||
}
|
||||
|
||||
// check whether left is a heap memory address
|
||||
HeapAddressDescription hdesc1, hdesc2;
|
||||
if (GetHeapAddressInformation(left, 0, &hdesc1) &&
|
||||
hdesc1.chunk_access.access_type == kAccessTypeInside)
|
||||
return !GetHeapAddressInformation(right, 0, &hdesc2) ||
|
||||
hdesc2.chunk_access.access_type != kAccessTypeInside ||
|
||||
hdesc1.chunk_access.chunk_begin != hdesc2.chunk_access.chunk_begin;
|
||||
|
||||
// check whether left is an address of a global variable
|
||||
GlobalAddressDescription gdesc1, gdesc2;
|
||||
if (GetGlobalAddressInformation(left, 0, &gdesc1))
|
||||
return !GetGlobalAddressInformation(right - 1, 0, &gdesc2) ||
|
||||
!gdesc1.PointsInsideTheSameVariable(gdesc2);
|
||||
|
||||
if (t->GetStackVariableShadowStart(right) ||
|
||||
GetHeapAddressInformation(right, 0, &hdesc2) ||
|
||||
GetGlobalAddressInformation(right - 1, 0, &gdesc2))
|
||||
return true;
|
||||
|
||||
// At this point we know nothing about both a1 and a2 addresses.
|
||||
return false;
|
||||
}
|
||||
|
||||
static INLINE void CheckForInvalidPointerPair(void *p1, void *p2) {
|
||||
if (!flags()->detect_invalid_pointer_pairs) return;
|
||||
uptr a1 = reinterpret_cast<uptr>(p1);
|
||||
uptr a2 = reinterpret_cast<uptr>(p2);
|
||||
AsanChunkView chunk1 = FindHeapChunkByAddress(a1);
|
||||
AsanChunkView chunk2 = FindHeapChunkByAddress(a2);
|
||||
bool valid1 = chunk1.IsAllocated();
|
||||
bool valid2 = chunk2.IsAllocated();
|
||||
if (!valid1 || !valid2 || !chunk1.Eq(chunk2)) {
|
||||
|
||||
if (IsInvalidPointerPair(a1, a2)) {
|
||||
GET_CALLER_PC_BP_SP;
|
||||
return ReportInvalidPointerPair(pc, bp, sp, a1, a2);
|
||||
ReportInvalidPointerPair(pc, bp, sp, a1, a2);
|
||||
}
|
||||
}
|
||||
// ----------------------- Mac-specific reports ----------------- {{{1
|
||||
|
@ -46,9 +46,9 @@ bool ParseFrameDescription(const char *frame_descr,
|
||||
// Different kinds of error reports.
|
||||
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(int signo, const SignalContext &sig);
|
||||
void ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size,
|
||||
void ReportDeadlySignal(const SignalContext &sig);
|
||||
void ReportNewDeleteTypeMismatch(uptr addr, uptr delete_size,
|
||||
uptr delete_alignment,
|
||||
BufferedStackTrace *free_stack);
|
||||
void ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack);
|
||||
void ReportFreeNotMalloced(uptr addr, BufferedStackTrace *free_stack);
|
||||
|
@ -84,26 +84,6 @@ void ShowStatsAndAbort() {
|
||||
Die();
|
||||
}
|
||||
|
||||
// ---------------------- mmap -------------------- {{{1
|
||||
// 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 % 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);
|
||||
if (res != (void*)beg) {
|
||||
Report("ReserveShadowMemoryRange failed while trying to map 0x%zx bytes. "
|
||||
"Perhaps you're using ulimit -v\n", size);
|
||||
Abort();
|
||||
}
|
||||
if (common_flags()->no_huge_pages_for_shadow)
|
||||
NoHugePagesInRegion(beg, size);
|
||||
if (common_flags()->use_madv_dontdump)
|
||||
DontDumpShadowMemory(beg, size);
|
||||
}
|
||||
|
||||
// --------------- LowLevelAllocateCallbac ---------- {{{1
|
||||
static void OnLowLevelAllocate(uptr ptr, uptr size) {
|
||||
PoisonShadow(ptr, size, kAsanInternalHeapMagic);
|
||||
@ -327,7 +307,7 @@ static void asan_atexit() {
|
||||
|
||||
static void InitializeHighMemEnd() {
|
||||
#if !ASAN_FIXED_MAPPING
|
||||
kHighMemEnd = GetMaxVirtualAddress();
|
||||
kHighMemEnd = GetMaxUserVirtualAddress();
|
||||
// Increase kHighMemEnd to make sure it's properly
|
||||
// aligned together with kHighMemBeg:
|
||||
kHighMemEnd |= SHADOW_GRANULARITY * GetMmapGranularity() - 1;
|
||||
@ -335,46 +315,7 @@ static void InitializeHighMemEnd() {
|
||||
CHECK_EQ((kHighMemBeg % GetMmapGranularity()), 0);
|
||||
}
|
||||
|
||||
static void ProtectGap(uptr addr, uptr size) {
|
||||
if (!flags()->protect_shadow_gap) {
|
||||
// The shadow gap is unprotected, so there is a chance that someone
|
||||
// is actually using this memory. Which means it needs a shadow...
|
||||
uptr GapShadowBeg = RoundDownTo(MEM_TO_SHADOW(addr), GetPageSizeCached());
|
||||
uptr GapShadowEnd =
|
||||
RoundUpTo(MEM_TO_SHADOW(addr + size), GetPageSizeCached()) - 1;
|
||||
if (Verbosity())
|
||||
Printf("protect_shadow_gap=0:"
|
||||
" not protecting shadow gap, allocating gap's shadow\n"
|
||||
"|| `[%p, %p]` || ShadowGap's shadow ||\n", GapShadowBeg,
|
||||
GapShadowEnd);
|
||||
ReserveShadowMemoryRange(GapShadowBeg, GapShadowEnd,
|
||||
"unprotected gap shadow");
|
||||
return;
|
||||
}
|
||||
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 = GetMmapGranularity();
|
||||
while (size > step && addr < kZeroBaseMaxShadowStart) {
|
||||
addr += step;
|
||||
size -= step;
|
||||
void *res = MmapFixedNoAccess(addr, size, "shadow gap");
|
||||
if (addr == (uptr)res)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Report("ERROR: Failed to protect the shadow gap. "
|
||||
"ASan cannot proceed correctly. ABORTING.\n");
|
||||
DumpProcessMap();
|
||||
Die();
|
||||
}
|
||||
|
||||
static void PrintAddressSpaceLayout() {
|
||||
void PrintAddressSpaceLayout() {
|
||||
Printf("|| `[%p, %p]` || HighMem ||\n",
|
||||
(void*)kHighMemBeg, (void*)kHighMemEnd);
|
||||
Printf("|| `[%p, %p]` || HighShadow ||\n",
|
||||
@ -426,71 +367,6 @@ static void PrintAddressSpaceLayout() {
|
||||
kHighShadowBeg > kMidMemEnd);
|
||||
}
|
||||
|
||||
static void InitializeShadowMemory() {
|
||||
// Set the shadow memory address to uninitialized.
|
||||
__asan_shadow_memory_dynamic_address = kDefaultShadowSentinel;
|
||||
|
||||
uptr shadow_start = kLowShadowBeg;
|
||||
// Detect if a dynamic shadow address must used and find a available location
|
||||
// when necessary. When dynamic address is used, the macro |kLowShadowBeg|
|
||||
// expands to |__asan_shadow_memory_dynamic_address| which is
|
||||
// |kDefaultShadowSentinel|.
|
||||
if (shadow_start == kDefaultShadowSentinel) {
|
||||
__asan_shadow_memory_dynamic_address = 0;
|
||||
CHECK_EQ(0, kLowShadowBeg);
|
||||
shadow_start = FindDynamicShadowStart();
|
||||
}
|
||||
// Update the shadow memory address (potentially) used by instrumentation.
|
||||
__asan_shadow_memory_dynamic_address = shadow_start;
|
||||
|
||||
if (kLowShadowBeg)
|
||||
shadow_start -= GetMmapGranularity();
|
||||
bool full_shadow_is_available =
|
||||
MemoryRangeIsAvailable(shadow_start, kHighShadowEnd);
|
||||
|
||||
#if SANITIZER_LINUX && defined(__x86_64__) && defined(_LP64) && \
|
||||
!ASAN_FIXED_MAPPING
|
||||
if (!full_shadow_is_available) {
|
||||
kMidMemBeg = kLowMemEnd < 0x3000000000ULL ? 0x3000000000ULL : 0;
|
||||
kMidMemEnd = kLowMemEnd < 0x3000000000ULL ? 0x4fffffffffULL : 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (Verbosity()) PrintAddressSpaceLayout();
|
||||
|
||||
if (full_shadow_is_available) {
|
||||
// mmap the low shadow plus at least one page at the left.
|
||||
if (kLowShadowBeg)
|
||||
ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow");
|
||||
// mmap the high shadow.
|
||||
ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow");
|
||||
// protect the gap.
|
||||
ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
|
||||
CHECK_EQ(kShadowGapEnd, kHighShadowBeg - 1);
|
||||
} else if (kMidMemBeg &&
|
||||
MemoryRangeIsAvailable(shadow_start, kMidMemBeg - 1) &&
|
||||
MemoryRangeIsAvailable(kMidMemEnd + 1, kHighShadowEnd)) {
|
||||
CHECK(kLowShadowBeg != kLowShadowEnd);
|
||||
// mmap the low shadow plus at least one page at the left.
|
||||
ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow");
|
||||
// mmap the mid shadow.
|
||||
ReserveShadowMemoryRange(kMidShadowBeg, kMidShadowEnd, "mid shadow");
|
||||
// mmap the high shadow.
|
||||
ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow");
|
||||
// protect the gaps.
|
||||
ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
|
||||
ProtectGap(kShadowGap2Beg, kShadowGap2End - kShadowGap2Beg + 1);
|
||||
ProtectGap(kShadowGap3Beg, kShadowGap3End - kShadowGap3Beg + 1);
|
||||
} else {
|
||||
Report("Shadow memory range interleaves with an existing memory mapping. "
|
||||
"ASan cannot proceed correctly. ABORTING.\n");
|
||||
Report("ASan shadow was supposed to be located in the [%p-%p] range.\n",
|
||||
shadow_start, kHighShadowEnd);
|
||||
DumpProcessMap();
|
||||
Die();
|
||||
}
|
||||
}
|
||||
|
||||
static void AsanInitInternal() {
|
||||
if (LIKELY(asan_inited)) return;
|
||||
SanitizerToolName = "AddressSanitizer";
|
||||
@ -531,6 +407,7 @@ static void AsanInitInternal() {
|
||||
MaybeReexec();
|
||||
|
||||
// Setup internal allocator callback.
|
||||
SetLowLevelAllocateMinAlignment(SHADOW_GRANULARITY);
|
||||
SetLowLevelAllocateCallback(OnLowLevelAllocate);
|
||||
|
||||
InitializeAsanInterceptors();
|
||||
@ -575,20 +452,18 @@ static void AsanInitInternal() {
|
||||
InitTlsSize();
|
||||
|
||||
// Create main thread.
|
||||
AsanThread *main_thread = AsanThread::Create(
|
||||
/* start_routine */ nullptr, /* arg */ nullptr, /* parent_tid */ 0,
|
||||
/* stack */ nullptr, /* detached */ true);
|
||||
AsanThread *main_thread = CreateMainThread();
|
||||
CHECK_EQ(0, main_thread->tid());
|
||||
SetCurrentThread(main_thread);
|
||||
main_thread->ThreadStart(internal_getpid(),
|
||||
/* signal_thread_is_registered */ nullptr);
|
||||
force_interface_symbols(); // no-op.
|
||||
SanitizerInitializeUnwinder();
|
||||
|
||||
if (CAN_SANITIZE_LEAKS) {
|
||||
__lsan::InitCommonLsan();
|
||||
if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) {
|
||||
if (flags()->halt_on_error)
|
||||
Atexit(__lsan::DoLeakCheck);
|
||||
else
|
||||
Atexit(__lsan::DoRecoverableLeakCheckVoid);
|
||||
}
|
||||
}
|
||||
|
||||
@ -608,6 +483,11 @@ static void AsanInitInternal() {
|
||||
}
|
||||
|
||||
VReport(1, "AddressSanitizer Init done\n");
|
||||
|
||||
if (flags()->sleep_after_init) {
|
||||
Report("Sleeping for %d second(s)\n", flags()->sleep_after_init);
|
||||
SleepForSeconds(flags()->sleep_after_init);
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize as requested from some part of ASan runtime library (interceptors,
|
||||
@ -647,6 +527,7 @@ void NOINLINE __asan_handle_no_return() {
|
||||
top = curr_thread->stack_top();
|
||||
bottom = ((uptr)&local_stack - PageSize) & ~(PageSize - 1);
|
||||
} else {
|
||||
CHECK(!SANITIZER_FUCHSIA);
|
||||
// If we haven't seen this thread, try asking the OS for stack bounds.
|
||||
uptr tls_addr, tls_size, stack_size;
|
||||
GetThreadStackAndTls(/*main=*/false, &bottom, &stack_size, &tls_addr,
|
||||
|
@ -47,7 +47,7 @@ struct ScarinessScoreBase {
|
||||
};
|
||||
int GetScore() const { return score; }
|
||||
const char *GetDescription() const { return descr; }
|
||||
void Print() {
|
||||
void Print() const {
|
||||
if (score && flags()->print_scariness)
|
||||
Printf("SCARINESS: %d (%s)\n", score, descr);
|
||||
}
|
||||
|
165
lib/asan/asan_shadow_setup.cc
Normal file
165
lib/asan/asan_shadow_setup.cc
Normal file
@ -0,0 +1,165 @@
|
||||
//===-- asan_shadow_setup.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.
|
||||
//
|
||||
// Set up the shadow memory.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "sanitizer_common/sanitizer_platform.h"
|
||||
|
||||
// asan_fuchsia.cc has its own InitializeShadowMemory implementation.
|
||||
#if !SANITIZER_FUCHSIA
|
||||
|
||||
#include "asan_internal.h"
|
||||
#include "asan_mapping.h"
|
||||
|
||||
namespace __asan {
|
||||
|
||||
// ---------------------- mmap -------------------- {{{1
|
||||
// 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 % 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);
|
||||
if (res != (void *)beg) {
|
||||
Report(
|
||||
"ReserveShadowMemoryRange failed while trying to map 0x%zx bytes. "
|
||||
"Perhaps you're using ulimit -v\n",
|
||||
size);
|
||||
Abort();
|
||||
}
|
||||
if (common_flags()->no_huge_pages_for_shadow) NoHugePagesInRegion(beg, size);
|
||||
if (common_flags()->use_madv_dontdump) DontDumpShadowMemory(beg, size);
|
||||
}
|
||||
|
||||
static void ProtectGap(uptr addr, uptr size) {
|
||||
if (!flags()->protect_shadow_gap) {
|
||||
// The shadow gap is unprotected, so there is a chance that someone
|
||||
// is actually using this memory. Which means it needs a shadow...
|
||||
uptr GapShadowBeg = RoundDownTo(MEM_TO_SHADOW(addr), GetPageSizeCached());
|
||||
uptr GapShadowEnd =
|
||||
RoundUpTo(MEM_TO_SHADOW(addr + size), GetPageSizeCached()) - 1;
|
||||
if (Verbosity())
|
||||
Printf(
|
||||
"protect_shadow_gap=0:"
|
||||
" not protecting shadow gap, allocating gap's shadow\n"
|
||||
"|| `[%p, %p]` || ShadowGap's shadow ||\n",
|
||||
GapShadowBeg, GapShadowEnd);
|
||||
ReserveShadowMemoryRange(GapShadowBeg, GapShadowEnd,
|
||||
"unprotected gap shadow");
|
||||
return;
|
||||
}
|
||||
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 = GetMmapGranularity();
|
||||
while (size > step && addr < kZeroBaseMaxShadowStart) {
|
||||
addr += step;
|
||||
size -= step;
|
||||
void *res = MmapFixedNoAccess(addr, size, "shadow gap");
|
||||
if (addr == (uptr)res) return;
|
||||
}
|
||||
}
|
||||
|
||||
Report(
|
||||
"ERROR: Failed to protect the shadow gap. "
|
||||
"ASan cannot proceed correctly. ABORTING.\n");
|
||||
DumpProcessMap();
|
||||
Die();
|
||||
}
|
||||
|
||||
static void MaybeReportLinuxPIEBug() {
|
||||
#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__aarch64__))
|
||||
Report("This might be related to ELF_ET_DYN_BASE change in Linux 4.12.\n");
|
||||
Report(
|
||||
"See https://github.com/google/sanitizers/issues/856 for possible "
|
||||
"workarounds.\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
void InitializeShadowMemory() {
|
||||
// Set the shadow memory address to uninitialized.
|
||||
__asan_shadow_memory_dynamic_address = kDefaultShadowSentinel;
|
||||
|
||||
uptr shadow_start = kLowShadowBeg;
|
||||
// Detect if a dynamic shadow address must used and find a available location
|
||||
// when necessary. When dynamic address is used, the macro |kLowShadowBeg|
|
||||
// expands to |__asan_shadow_memory_dynamic_address| which is
|
||||
// |kDefaultShadowSentinel|.
|
||||
bool full_shadow_is_available = false;
|
||||
if (shadow_start == kDefaultShadowSentinel) {
|
||||
__asan_shadow_memory_dynamic_address = 0;
|
||||
CHECK_EQ(0, kLowShadowBeg);
|
||||
shadow_start = FindDynamicShadowStart();
|
||||
if (SANITIZER_LINUX) full_shadow_is_available = true;
|
||||
}
|
||||
// Update the shadow memory address (potentially) used by instrumentation.
|
||||
__asan_shadow_memory_dynamic_address = shadow_start;
|
||||
|
||||
if (kLowShadowBeg) shadow_start -= GetMmapGranularity();
|
||||
|
||||
if (!full_shadow_is_available)
|
||||
full_shadow_is_available =
|
||||
MemoryRangeIsAvailable(shadow_start, kHighShadowEnd);
|
||||
|
||||
#if SANITIZER_LINUX && defined(__x86_64__) && defined(_LP64) && \
|
||||
!ASAN_FIXED_MAPPING
|
||||
if (!full_shadow_is_available) {
|
||||
kMidMemBeg = kLowMemEnd < 0x3000000000ULL ? 0x3000000000ULL : 0;
|
||||
kMidMemEnd = kLowMemEnd < 0x3000000000ULL ? 0x4fffffffffULL : 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (Verbosity()) PrintAddressSpaceLayout();
|
||||
|
||||
if (full_shadow_is_available) {
|
||||
// mmap the low shadow plus at least one page at the left.
|
||||
if (kLowShadowBeg)
|
||||
ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow");
|
||||
// mmap the high shadow.
|
||||
ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow");
|
||||
// protect the gap.
|
||||
ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
|
||||
CHECK_EQ(kShadowGapEnd, kHighShadowBeg - 1);
|
||||
} else if (kMidMemBeg &&
|
||||
MemoryRangeIsAvailable(shadow_start, kMidMemBeg - 1) &&
|
||||
MemoryRangeIsAvailable(kMidMemEnd + 1, kHighShadowEnd)) {
|
||||
CHECK(kLowShadowBeg != kLowShadowEnd);
|
||||
// mmap the low shadow plus at least one page at the left.
|
||||
ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow");
|
||||
// mmap the mid shadow.
|
||||
ReserveShadowMemoryRange(kMidShadowBeg, kMidShadowEnd, "mid shadow");
|
||||
// mmap the high shadow.
|
||||
ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow");
|
||||
// protect the gaps.
|
||||
ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
|
||||
ProtectGap(kShadowGap2Beg, kShadowGap2End - kShadowGap2Beg + 1);
|
||||
ProtectGap(kShadowGap3Beg, kShadowGap3End - kShadowGap3Beg + 1);
|
||||
} else {
|
||||
Report(
|
||||
"Shadow memory range interleaves with an existing memory mapping. "
|
||||
"ASan cannot proceed correctly. ABORTING.\n");
|
||||
Report("ASan shadow was supposed to be located in the [%p-%p] range.\n",
|
||||
shadow_start, kHighShadowEnd);
|
||||
MaybeReportLinuxPIEBug();
|
||||
DumpProcessMap();
|
||||
Die();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
#endif // !SANITIZER_FUCHSIA
|
@ -31,9 +31,8 @@ u32 GetMallocContextSize();
|
||||
// The pc will be in the position 0 of the resulting stack trace.
|
||||
// The bp may refer to the current frame or to the caller's frame.
|
||||
ALWAYS_INLINE
|
||||
void GetStackTraceWithPcBpAndContext(BufferedStackTrace *stack, uptr max_depth,
|
||||
uptr pc, uptr bp, void *context,
|
||||
bool fast) {
|
||||
void GetStackTrace(BufferedStackTrace *stack, uptr max_depth, uptr pc, uptr bp,
|
||||
void *context, bool fast) {
|
||||
#if SANITIZER_WINDOWS
|
||||
stack->Unwind(max_depth, pc, bp, context, 0, 0, fast);
|
||||
#else
|
||||
@ -41,10 +40,6 @@ void GetStackTraceWithPcBpAndContext(BufferedStackTrace *stack, uptr max_depth,
|
||||
stack->size = 0;
|
||||
if (LIKELY(asan_inited)) {
|
||||
if ((t = GetCurrentThread()) && !t->isUnwinding()) {
|
||||
// On FreeBSD the slow unwinding that leverages _Unwind_Backtrace()
|
||||
// yields the call stack of the signal's handler and not of the code
|
||||
// that raised the signal (as it does on Linux).
|
||||
if (SANITIZER_FREEBSD && t->isInDeadlySignal()) fast = true;
|
||||
uptr stack_top = t->stack_top();
|
||||
uptr stack_bottom = t->stack_bottom();
|
||||
ScopedUnwinding unwind_scope(t);
|
||||
@ -73,24 +68,21 @@ void GetStackTraceWithPcBpAndContext(BufferedStackTrace *stack, uptr max_depth,
|
||||
if (max_size > 0) { \
|
||||
stack.top_frame_bp = GET_CURRENT_FRAME(); \
|
||||
stack.trace_buffer[0] = StackTrace::GetCurrentPc(); \
|
||||
if (max_size > 1) \
|
||||
stack.trace_buffer[1] = GET_CALLER_PC(); \
|
||||
if (max_size > 1) stack.trace_buffer[1] = GET_CALLER_PC(); \
|
||||
} \
|
||||
} else { \
|
||||
GetStackTraceWithPcBpAndContext(&stack, max_size, \
|
||||
StackTrace::GetCurrentPc(), \
|
||||
GetStackTrace(&stack, max_size, StackTrace::GetCurrentPc(), \
|
||||
GET_CURRENT_FRAME(), 0, fast); \
|
||||
}
|
||||
|
||||
#define GET_STACK_TRACE_FATAL(pc, bp) \
|
||||
BufferedStackTrace stack; \
|
||||
GetStackTraceWithPcBpAndContext(&stack, kStackTraceMax, pc, bp, 0, \
|
||||
GetStackTrace(&stack, kStackTraceMax, pc, bp, 0, \
|
||||
common_flags()->fast_unwind_on_fatal)
|
||||
|
||||
#define GET_STACK_TRACE_SIGNAL(sig) \
|
||||
BufferedStackTrace stack; \
|
||||
GetStackTraceWithPcBpAndContext(&stack, kStackTraceMax, \
|
||||
(sig).pc, (sig).bp, (sig).context, \
|
||||
GetStackTrace(&stack, kStackTraceMax, (sig).pc, (sig).bp, (sig).context, \
|
||||
common_flags()->fast_unwind_on_fatal)
|
||||
|
||||
#define GET_STACK_TRACE_FATAL_HERE \
|
||||
|
@ -27,11 +27,6 @@ namespace __asan {
|
||||
|
||||
// AsanThreadContext implementation.
|
||||
|
||||
struct CreateThreadContextArgs {
|
||||
AsanThread *thread;
|
||||
StackTrace *stack;
|
||||
};
|
||||
|
||||
void AsanThreadContext::OnCreated(void *arg) {
|
||||
CreateThreadContextArgs *args = static_cast<CreateThreadContextArgs*>(arg);
|
||||
if (args->stack)
|
||||
@ -88,7 +83,7 @@ AsanThread *AsanThread::Create(thread_callback_t start_routine, void *arg,
|
||||
AsanThread *thread = (AsanThread*)MmapOrDie(size, __func__);
|
||||
thread->start_routine_ = start_routine;
|
||||
thread->arg_ = arg;
|
||||
CreateThreadContextArgs args = { thread, stack };
|
||||
AsanThreadContext::CreateThreadContextArgs args = {thread, stack};
|
||||
asanThreadRegistry().CreateThread(*reinterpret_cast<uptr *>(thread), detached,
|
||||
parent_tid, &args);
|
||||
|
||||
@ -223,12 +218,12 @@ FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void AsanThread::Init() {
|
||||
void AsanThread::Init(const InitOptions *options) {
|
||||
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();
|
||||
SetThreadStackAndTls(options);
|
||||
CHECK_GT(this->stack_size(), 0U);
|
||||
CHECK(AddrIsInMem(stack_bottom_));
|
||||
CHECK(AddrIsInMem(stack_top_ - 1));
|
||||
@ -239,6 +234,10 @@ void AsanThread::Init() {
|
||||
&local);
|
||||
}
|
||||
|
||||
// Fuchsia doesn't use ThreadStart.
|
||||
// asan_fuchsia.c defines CreateMainThread and SetThreadStackAndTls.
|
||||
#if !SANITIZER_FUCHSIA
|
||||
|
||||
thread_return_t AsanThread::ThreadStart(
|
||||
tid_t os_id, atomic_uintptr_t *signal_thread_is_registered) {
|
||||
Init();
|
||||
@ -270,7 +269,21 @@ thread_return_t AsanThread::ThreadStart(
|
||||
return res;
|
||||
}
|
||||
|
||||
void AsanThread::SetThreadStackAndTls() {
|
||||
AsanThread *CreateMainThread() {
|
||||
AsanThread *main_thread = AsanThread::Create(
|
||||
/* start_routine */ nullptr, /* arg */ nullptr, /* parent_tid */ 0,
|
||||
/* stack */ nullptr, /* detached */ true);
|
||||
SetCurrentThread(main_thread);
|
||||
main_thread->ThreadStart(internal_getpid(),
|
||||
/* signal_thread_is_registered */ nullptr);
|
||||
return main_thread;
|
||||
}
|
||||
|
||||
// This implementation doesn't use the argument, which is just passed down
|
||||
// from the caller of Init (which see, above). It's only there to support
|
||||
// OS-specific implementations that need more information passed through.
|
||||
void AsanThread::SetThreadStackAndTls(const InitOptions *options) {
|
||||
DCHECK_EQ(options, nullptr);
|
||||
uptr tls_size = 0;
|
||||
uptr stack_size = 0;
|
||||
GetThreadStackAndTls(tid() == 0, const_cast<uptr *>(&stack_bottom_),
|
||||
@ -283,6 +296,8 @@ void AsanThread::SetThreadStackAndTls() {
|
||||
CHECK(AddrIsInStack((uptr)&local));
|
||||
}
|
||||
|
||||
#endif // !SANITIZER_FUCHSIA
|
||||
|
||||
void AsanThread::ClearShadowForThreadStackAndTLS() {
|
||||
PoisonShadow(stack_bottom_, stack_top_ - stack_bottom_, 0);
|
||||
if (tls_begin_ != tls_end_)
|
||||
@ -302,7 +317,7 @@ bool AsanThread::GetStackFrameAccessByAddr(uptr addr,
|
||||
access->frame_descr = (const char *)((uptr*)bottom)[1];
|
||||
return true;
|
||||
}
|
||||
uptr aligned_addr = addr & ~(SANITIZER_WORDSIZE/8 - 1); // align addr.
|
||||
uptr aligned_addr = RoundDownTo(addr, SANITIZER_WORDSIZE / 8); // align addr.
|
||||
uptr mem_ptr = RoundDownTo(aligned_addr, SHADOW_GRANULARITY);
|
||||
u8 *shadow_ptr = (u8*)MemToShadow(aligned_addr);
|
||||
u8 *shadow_bottom = (u8*)MemToShadow(bottom);
|
||||
@ -331,6 +346,29 @@ bool AsanThread::GetStackFrameAccessByAddr(uptr addr,
|
||||
return true;
|
||||
}
|
||||
|
||||
uptr AsanThread::GetStackVariableShadowStart(uptr addr) {
|
||||
uptr bottom = 0;
|
||||
if (AddrIsInStack(addr)) {
|
||||
bottom = stack_bottom();
|
||||
} else if (has_fake_stack()) {
|
||||
bottom = fake_stack()->AddrIsInFakeStack(addr);
|
||||
CHECK(bottom);
|
||||
} else
|
||||
return 0;
|
||||
|
||||
uptr aligned_addr = RoundDownTo(addr, SANITIZER_WORDSIZE / 8); // align addr.
|
||||
u8 *shadow_ptr = (u8*)MemToShadow(aligned_addr);
|
||||
u8 *shadow_bottom = (u8*)MemToShadow(bottom);
|
||||
|
||||
while (shadow_ptr >= shadow_bottom &&
|
||||
(*shadow_ptr != kAsanStackLeftRedzoneMagic &&
|
||||
*shadow_ptr != kAsanStackMidRedzoneMagic &&
|
||||
*shadow_ptr != kAsanStackRightRedzoneMagic))
|
||||
shadow_ptr--;
|
||||
|
||||
return (uptr)shadow_ptr + 1;
|
||||
}
|
||||
|
||||
bool AsanThread::AddrIsInStack(uptr addr) {
|
||||
const auto bounds = GetStackBounds();
|
||||
return addr >= bounds.bottom && addr < bounds.top;
|
||||
|
@ -49,6 +49,11 @@ class AsanThreadContext : public ThreadContextBase {
|
||||
|
||||
void OnCreated(void *arg) override;
|
||||
void OnFinished() override;
|
||||
|
||||
struct CreateThreadContextArgs {
|
||||
AsanThread *thread;
|
||||
StackTrace *stack;
|
||||
};
|
||||
};
|
||||
|
||||
// AsanThreadContext objects are never freed, so we need many of them.
|
||||
@ -62,7 +67,9 @@ class AsanThread {
|
||||
static void TSDDtor(void *tsd);
|
||||
void Destroy();
|
||||
|
||||
void Init(); // Should be called from the thread itself.
|
||||
struct InitOptions;
|
||||
void Init(const InitOptions *options = nullptr);
|
||||
|
||||
thread_return_t ThreadStart(tid_t os_id,
|
||||
atomic_uintptr_t *signal_thread_is_registered);
|
||||
|
||||
@ -83,6 +90,9 @@ class AsanThread {
|
||||
};
|
||||
bool GetStackFrameAccessByAddr(uptr addr, StackFrameAccess *access);
|
||||
|
||||
// Returns a pointer to the start of the stack variable's shadow memory.
|
||||
uptr GetStackVariableShadowStart(uptr addr);
|
||||
|
||||
bool AddrIsInStack(uptr addr);
|
||||
|
||||
void DeleteFakeStack(int tid) {
|
||||
@ -118,17 +128,15 @@ class AsanThread {
|
||||
bool isUnwinding() const { return unwinding_; }
|
||||
void setUnwinding(bool b) { unwinding_ = b; }
|
||||
|
||||
// True if we are in a deadly signal handler.
|
||||
bool isInDeadlySignal() const { return in_deadly_signal_; }
|
||||
void setInDeadlySignal(bool b) { in_deadly_signal_ = b; }
|
||||
|
||||
AsanThreadLocalMallocStorage &malloc_storage() { return malloc_storage_; }
|
||||
AsanStats &stats() { return stats_; }
|
||||
|
||||
private:
|
||||
// NOTE: There is no AsanThread constructor. It is allocated
|
||||
// via mmap() and *must* be valid in zero-initialized state.
|
||||
void SetThreadStackAndTls();
|
||||
|
||||
void SetThreadStackAndTls(const InitOptions *options);
|
||||
|
||||
void ClearShadowForThreadStackAndTLS();
|
||||
FakeStack *AsyncSignalSafeLazyInitFakeStack();
|
||||
|
||||
@ -158,7 +166,6 @@ class AsanThread {
|
||||
AsanThreadLocalMallocStorage malloc_storage_;
|
||||
AsanStats stats_;
|
||||
bool unwinding_;
|
||||
bool in_deadly_signal_;
|
||||
};
|
||||
|
||||
// ScopedUnwinding is a scope for stacktracing member of a context
|
||||
@ -173,20 +180,6 @@ class ScopedUnwinding {
|
||||
AsanThread *thread;
|
||||
};
|
||||
|
||||
// ScopedDeadlySignal is a scope for handling deadly signals.
|
||||
class ScopedDeadlySignal {
|
||||
public:
|
||||
explicit ScopedDeadlySignal(AsanThread *t) : thread(t) {
|
||||
if (thread) thread->setInDeadlySignal(true);
|
||||
}
|
||||
~ScopedDeadlySignal() {
|
||||
if (thread) thread->setInDeadlySignal(false);
|
||||
}
|
||||
|
||||
private:
|
||||
AsanThread *thread;
|
||||
};
|
||||
|
||||
// Returns a single instance of registry.
|
||||
ThreadRegistry &asanThreadRegistry();
|
||||
|
||||
|
@ -57,8 +57,8 @@ long __asan_unhandled_exception_filter(EXCEPTION_POINTERS *info) {
|
||||
|
||||
// FIXME: Handle EXCEPTION_STACK_OVERFLOW here.
|
||||
|
||||
SignalContext sig = SignalContext::Create(exception_record, context);
|
||||
ReportDeadlySignal(exception_record->ExceptionCode, sig);
|
||||
SignalContext sig(exception_record, context);
|
||||
ReportDeadlySignal(sig);
|
||||
UNREACHABLE("returned from reporting deadly signal");
|
||||
}
|
||||
|
||||
|
@ -95,7 +95,7 @@ function get_device_arch { # OUT OUT64
|
||||
local _ARCH=
|
||||
local _ARCH64=
|
||||
if [[ $_ABI == x86* ]]; then
|
||||
_ARCH=i686
|
||||
_ARCH=i386
|
||||
elif [[ $_ABI == armeabi* ]]; then
|
||||
_ARCH=arm
|
||||
elif [[ $_ABI == arm64-v8a* ]]; then
|
||||
@ -181,6 +181,17 @@ if [[ -n $ARCH64 ]]; then
|
||||
ASAN_RT64="libclang_rt.asan-$ARCH64-android.so"
|
||||
fi
|
||||
|
||||
RELEASE=$(adb_shell getprop ro.build.version.release)
|
||||
PRE_L=0
|
||||
if echo "$RELEASE" | grep '^4\.' >&/dev/null; then
|
||||
PRE_L=1
|
||||
fi
|
||||
ANDROID_O=0
|
||||
if echo "$RELEASE" | grep '^8\.0\.' >&/dev/null; then
|
||||
# 8.0.x is for Android O
|
||||
ANDROID_O=1
|
||||
fi
|
||||
|
||||
if [[ x$revert == xyes ]]; then
|
||||
echo '>> Uninstalling ASan'
|
||||
|
||||
@ -202,6 +213,10 @@ if [[ x$revert == xyes ]]; then
|
||||
adb_shell ln -s /system/bin/app_process32 /system/bin/app_process
|
||||
fi
|
||||
|
||||
if [[ ANDROID_O -eq 1 ]]; then
|
||||
adb_shell mv /system/etc/ld.config.txt.saved /system/etc/ld.config.txt
|
||||
fi
|
||||
|
||||
echo '>> Restarting shell'
|
||||
adb_shell stop
|
||||
adb_shell start
|
||||
@ -251,12 +266,6 @@ TMPDIROLD="$TMPDIRBASE/old"
|
||||
TMPDIR="$TMPDIRBASE/new"
|
||||
mkdir "$TMPDIROLD"
|
||||
|
||||
RELEASE=$(adb_shell getprop ro.build.version.release)
|
||||
PRE_L=0
|
||||
if echo "$RELEASE" | grep '^4\.' >&/dev/null; then
|
||||
PRE_L=1
|
||||
fi
|
||||
|
||||
if ! adb_shell ls -l /system/bin/app_process | grep -o '\->.*app_process' >&/dev/null; then
|
||||
|
||||
if adb_pull /system/bin/app_process.real /dev/null >&/dev/null; then
|
||||
@ -410,15 +419,18 @@ if ! ( cd "$TMPDIRBASE" && diff -qr old/ new/ ) ; then
|
||||
install "$TMPDIR/asanwrapper" /system/bin 755
|
||||
install "$TMPDIR/asanwrapper64" /system/bin 755
|
||||
|
||||
adb_shell ln -sf $ASAN_RT /system/lib/$ASAN_RT_SYMLINK
|
||||
adb_shell ln -sf $ASAN_RT64 /system/lib64/$ASAN_RT_SYMLINK
|
||||
adb_shell rm -f /system/lib/$ASAN_RT_SYMLINK
|
||||
adb_shell ln -s $ASAN_RT /system/lib/$ASAN_RT_SYMLINK
|
||||
adb_shell rm -f /system/lib64/$ASAN_RT_SYMLINK
|
||||
adb_shell ln -s $ASAN_RT64 /system/lib64/$ASAN_RT_SYMLINK
|
||||
else
|
||||
install "$TMPDIR/$ASAN_RT" /system/lib 644
|
||||
install "$TMPDIR/app_process32" /system/bin 755 $CTX
|
||||
install "$TMPDIR/app_process.wrap" /system/bin 755 $CTX
|
||||
install "$TMPDIR/asanwrapper" /system/bin 755 $CTX
|
||||
|
||||
adb_shell ln -sf $ASAN_RT /system/lib/$ASAN_RT_SYMLINK
|
||||
adb_shell rm -f /system/lib/$ASAN_RT_SYMLINK
|
||||
adb_shell ln -s $ASAN_RT /system/lib/$ASAN_RT_SYMLINK
|
||||
|
||||
adb_shell rm /system/bin/app_process
|
||||
adb_shell ln -s /system/bin/app_process.wrap /system/bin/app_process
|
||||
@ -427,6 +439,11 @@ if ! ( cd "$TMPDIRBASE" && diff -qr old/ new/ ) ; then
|
||||
adb_shell cp /system/bin/sh /system/bin/sh-from-zygote
|
||||
adb_shell chcon $CTX /system/bin/sh-from-zygote
|
||||
|
||||
if [[ ANDROID_O -eq 1 ]]; then
|
||||
# For Android O, the linker namespace is temporarily disabled.
|
||||
adb_shell mv /system/etc/ld.config.txt /system/etc/ld.config.txt.saved
|
||||
fi
|
||||
|
||||
if [ $ENFORCING == 1 ]; then
|
||||
adb_shell setenforce 1
|
||||
fi
|
||||
|
@ -280,7 +280,7 @@ def BreakpadSymbolizerFactory(binary):
|
||||
def SystemSymbolizerFactory(system, addr, binary, arch):
|
||||
if system == 'Darwin':
|
||||
return DarwinSymbolizer(addr, binary, arch)
|
||||
elif system == 'Linux' or system == 'FreeBSD':
|
||||
elif system in ['Linux', 'FreeBSD', 'NetBSD']:
|
||||
return Addr2LineSymbolizer(binary)
|
||||
|
||||
|
||||
@ -370,7 +370,7 @@ def __init__(self, binary_name_filter=None, dsym_hint_producer=None):
|
||||
self.binary_name_filter = binary_name_filter
|
||||
self.dsym_hint_producer = dsym_hint_producer
|
||||
self.system = os.uname()[0]
|
||||
if self.system not in ['Linux', 'Darwin', 'FreeBSD']:
|
||||
if self.system not in ['Linux', 'Darwin', 'FreeBSD', 'NetBSD']:
|
||||
raise Exception('Unknown system')
|
||||
self.llvm_symbolizers = {}
|
||||
self.last_llvm_symbolizer = None
|
||||
|
@ -23,6 +23,7 @@ set(ASAN_UNITTEST_HEADERS
|
||||
set(ASAN_UNITTEST_COMMON_CFLAGS
|
||||
${COMPILER_RT_UNITTEST_CFLAGS}
|
||||
${COMPILER_RT_GTEST_CFLAGS}
|
||||
${COMPILER_RT_ASAN_SHADOW_SCALE_LLVM_FLAG}
|
||||
-I${COMPILER_RT_SOURCE_DIR}/include
|
||||
-I${COMPILER_RT_SOURCE_DIR}/lib
|
||||
-I${COMPILER_RT_SOURCE_DIR}/lib/asan
|
||||
@ -52,6 +53,7 @@ list(APPEND ASAN_UNITTEST_COMMON_LINK_FLAGS -g)
|
||||
|
||||
# Use -D instead of definitions to please custom compile command.
|
||||
list(APPEND ASAN_UNITTEST_COMMON_CFLAGS
|
||||
${COMPILER_RT_ASAN_SHADOW_SCALE_FLAG}
|
||||
-DASAN_HAS_BLACKLIST=1
|
||||
-DASAN_HAS_EXCEPTIONS=1
|
||||
-DASAN_UAR=0)
|
||||
@ -125,57 +127,6 @@ append_list_if(COMPILER_RT_HAS_LIBLOG log ASAN_UNITTEST_NOINST_LIBS)
|
||||
# NDK r10 requires -latomic almost always.
|
||||
append_list_if(ANDROID atomic ASAN_UNITTEST_NOINST_LIBS)
|
||||
|
||||
# Compile source for the given architecture, using compiler
|
||||
# options in ${ARGN}, and add it to the object list.
|
||||
macro(asan_compile obj_list source arch kind)
|
||||
get_filename_component(basename ${source} NAME)
|
||||
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)
|
||||
list(APPEND COMPILE_DEPS gtest asan)
|
||||
endif()
|
||||
clang_compile(${output_obj} ${source}
|
||||
CFLAGS ${ARGN} ${TARGET_CFLAGS}
|
||||
DEPS ${COMPILE_DEPS})
|
||||
list(APPEND ${obj_list} ${output_obj})
|
||||
endmacro()
|
||||
|
||||
# Link ASan unit test for a given architecture from a set
|
||||
# of objects in with given linker flags.
|
||||
macro(add_asan_test test_suite test_name arch kind)
|
||||
cmake_parse_arguments(TEST "WITH_TEST_RUNTIME" "" "OBJECTS;LINK_FLAGS;SUBDIR" ${ARGN})
|
||||
get_target_flags_for_arch(${arch} TARGET_LINK_FLAGS)
|
||||
set(TEST_DEPS ${TEST_OBJECTS})
|
||||
if(NOT COMPILER_RT_STANDALONE_BUILD)
|
||||
list(APPEND TEST_DEPS asan)
|
||||
endif()
|
||||
if(TEST_WITH_TEST_RUNTIME)
|
||||
list(APPEND TEST_DEPS ${ASAN_TEST_RUNTIME})
|
||||
if(CMAKE_CONFIGURATION_TYPES)
|
||||
set(configuration_path "${CMAKE_CFG_INTDIR}/")
|
||||
else()
|
||||
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}
|
||||
OBJECTS ${TEST_OBJECTS}
|
||||
DEPS ${TEST_DEPS}
|
||||
LINK_FLAGS ${TEST_LINK_FLAGS}
|
||||
${TARGET_LINK_FLAGS})
|
||||
endmacro()
|
||||
|
||||
# Main AddressSanitizer unit tests.
|
||||
add_custom_target(AsanUnitTests)
|
||||
set_target_properties(AsanUnitTests PROPERTIES FOLDER "Compiler-RT Tests")
|
||||
@ -206,75 +157,91 @@ set(ASAN_INST_TEST_SOURCES
|
||||
asan_str_test.cc
|
||||
asan_test_main.cc)
|
||||
if(APPLE)
|
||||
list(APPEND ASAN_INST_TEST_SOURCES asan_mac_test.cc)
|
||||
list(APPEND ASAN_INST_TEST_SOURCES asan_mac_test.cc asan_mac_test_helpers.mm)
|
||||
endif()
|
||||
|
||||
set(ASAN_BENCHMARKS_SOURCES
|
||||
${COMPILER_RT_GTEST_SOURCE}
|
||||
asan_benchmarks_test.cc)
|
||||
|
||||
# Adds ASan unit tests and benchmarks for architecture.
|
||||
macro(add_asan_tests_for_arch_and_kind arch kind)
|
||||
# Instrumented tests.
|
||||
set(ASAN_INST_TEST_OBJECTS)
|
||||
foreach(src ${ASAN_INST_TEST_SOURCES})
|
||||
asan_compile(ASAN_INST_TEST_OBJECTS ${src} ${arch} ${kind}
|
||||
${ASAN_UNITTEST_INSTRUMENTED_CFLAGS} ${ARGN})
|
||||
endforeach()
|
||||
if (APPLE)
|
||||
# Add Mac-specific helper.
|
||||
asan_compile(ASAN_INST_TEST_OBJECTS asan_mac_test_helpers.mm ${arch} ${kind}
|
||||
${ASAN_UNITTEST_INSTRUMENTED_CFLAGS} -ObjC ${ARGN})
|
||||
endif()
|
||||
function(add_asan_tests arch test_runtime)
|
||||
cmake_parse_arguments(TEST "" "KIND" "CFLAGS" ${ARGN})
|
||||
|
||||
# Closure to keep the values.
|
||||
function(generate_asan_tests test_objects test_suite testname)
|
||||
generate_compiler_rt_tests(${test_objects} ${test_suite} ${testname} ${arch}
|
||||
COMPILE_DEPS ${ASAN_UNITTEST_HEADERS} ${ASAN_BLACKLIST_FILE}
|
||||
DEPS gtest asan
|
||||
KIND ${TEST_KIND}
|
||||
${ARGN}
|
||||
)
|
||||
set("${test_objects}" "${${test_objects}}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
set(ASAN_INST_TEST_OBJECTS)
|
||||
generate_asan_tests(ASAN_INST_TEST_OBJECTS AsanUnitTests
|
||||
"Asan-${arch}${TEST_KIND}-Test"
|
||||
SUBDIR "default"
|
||||
LINK_FLAGS ${ASAN_UNITTEST_INSTRUMENTED_LINK_FLAGS}
|
||||
SOURCES ${ASAN_INST_TEST_SOURCES}
|
||||
CFLAGS ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS} ${TEST_CFLAGS})
|
||||
|
||||
if(COMPILER_RT_ASAN_HAS_STATIC_RUNTIME)
|
||||
set(dynamic_test_name "Asan-${arch}${TEST_KIND}-Dynamic-Test")
|
||||
if(MSVC)
|
||||
|
||||
# With the MSVC CRT, the choice between static and dynamic CRT is made at
|
||||
# compile time with a macro. Simulate the effect of passing /MD to clang-cl.
|
||||
set(ASAN_INST_DYNAMIC_TEST_OBJECTS)
|
||||
foreach(src ${ASAN_INST_TEST_SOURCES})
|
||||
asan_compile(ASAN_INST_DYNAMIC_TEST_OBJECTS ${src} ${arch} ${kind}
|
||||
${ASAN_UNITTEST_INSTRUMENTED_CFLAGS} -D_MT -D_DLL ${ARGN})
|
||||
endforeach()
|
||||
# Clang links the static CRT by default. Override that to use the dynamic
|
||||
# CRT.
|
||||
set(ASAN_DYNAMIC_UNITTEST_INSTRUMENTED_LINK_FLAGS
|
||||
${ASAN_DYNAMIC_UNITTEST_INSTRUMENTED_LINK_FLAGS}
|
||||
-Wl,-nodefaultlib:libcmt,-defaultlib:msvcrt,-defaultlib:oldnames)
|
||||
set(ASAN_DYNAMIC_TEST_OBJECTS)
|
||||
generate_asan_tests(ASAN_DYNAMIC_TEST_OBJECTS
|
||||
AsanDynamicUnitTests "${dynamic_test_name}"
|
||||
SUBDIR "dynamic"
|
||||
CFLAGS ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS} -D_MT -D_DLL
|
||||
SOURCES ${ASAN_INST_TEST_SOURCES}
|
||||
LINK_FLAGS ${ASAN_DYNAMIC_UNITTEST_INSTRUMENTED_LINK_FLAGS}
|
||||
-Wl,-nodefaultlib:libcmt,-defaultlib:msvcrt,-defaultlib:oldnames
|
||||
)
|
||||
else()
|
||||
set(ASAN_INST_DYNAMIC_TEST_OBJECTS ${ASAN_INST_TEST_OBJECTS})
|
||||
endif()
|
||||
|
||||
# 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"
|
||||
# Otherwise, reuse ASAN_INST_TEST_OBJECTS.
|
||||
add_compiler_rt_test(AsanDynamicUnitTests "${dynamic_test_name}" "${arch}"
|
||||
SUBDIR "dynamic"
|
||||
OBJECTS ${ASAN_INST_TEST_OBJECTS}
|
||||
LINK_FLAGS ${ASAN_UNITTEST_INSTRUMENTED_LINK_FLAGS})
|
||||
if(COMPILER_RT_ASAN_HAS_STATIC_RUNTIME)
|
||||
# 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")
|
||||
DEPS asan ${ASAN_INST_TEST_OBJECTS}
|
||||
LINK_FLAGS ${ASAN_DYNAMIC_UNITTEST_INSTRUMENTED_LINK_FLAGS}
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_asan_test(AsanDynamicUnitTests "Asan-${arch}${kind}-Dynamic-Test"
|
||||
${arch} ${kind} SUBDIR "dynamic"
|
||||
OBJECTS ${ASAN_INST_DYNAMIC_TEST_OBJECTS}
|
||||
LINK_FLAGS ${ASAN_DYNAMIC_UNITTEST_INSTRUMENTED_LINK_FLAGS})
|
||||
# Uninstrumented tests.
|
||||
set(ASAN_NOINST_TEST_OBJECTS)
|
||||
generate_asan_tests(ASAN_NOINST_TEST_OBJECTS
|
||||
AsanUnitTests "Asan-${arch}${TEST_KIND}-Noinst-Test"
|
||||
SUBDIR "default"
|
||||
CFLAGS ${ASAN_UNITTEST_COMMON_CFLAGS}
|
||||
LINK_FLAGS ${ASAN_UNITTEST_NOINST_LINK_FLAGS}
|
||||
SOURCES ${ASAN_NOINST_TEST_SOURCES}
|
||||
RUNTIME ${test_runtime})
|
||||
|
||||
set(ASAN_BENCHMARK_OBJECTS)
|
||||
generate_asan_tests(ASAN_BENCHMARK_OBJECTS
|
||||
AsanBenchmarks "Asan-${arch}${TEST_KIND}-Benchmark"
|
||||
SUBDIR "default"
|
||||
CFLAGS ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS}
|
||||
SOURCES ${ASAN_BENCHMARKS_SOURCES}
|
||||
LINK_FLAGS ${ASAN_UNITTEST_INSTRUMENTED_LINK_FLAGS})
|
||||
endfunction()
|
||||
|
||||
if(COMPILER_RT_CAN_EXECUTE_TESTS AND NOT ANDROID)
|
||||
set(ASAN_TEST_ARCH ${ASAN_SUPPORTED_ARCH})
|
||||
if(APPLE)
|
||||
darwin_filter_host_archs(ASAN_SUPPORTED_ARCH ASAN_TEST_ARCH)
|
||||
endif()
|
||||
|
||||
foreach(arch ${ASAN_TEST_ARCH})
|
||||
|
||||
# Add static ASan runtime that will be linked with uninstrumented tests.
|
||||
set(ASAN_TEST_RUNTIME RTAsanTest.${arch}${kind})
|
||||
set(ASAN_TEST_RUNTIME RTAsanTest.${arch})
|
||||
if(APPLE)
|
||||
set(ASAN_TEST_RUNTIME_OBJECTS
|
||||
$<TARGET_OBJECTS:RTAsan_dynamic.osx>
|
||||
@ -298,39 +265,10 @@ macro(add_asan_tests_for_arch_and_kind arch kind)
|
||||
set_target_properties(${ASAN_TEST_RUNTIME} PROPERTIES
|
||||
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})
|
||||
asan_compile(ASAN_NOINST_TEST_OBJECTS ${src} ${arch} ${kind}
|
||||
${ASAN_UNITTEST_COMMON_CFLAGS} ${ARGN})
|
||||
endforeach()
|
||||
add_asan_test(AsanUnitTests "Asan-${arch}${kind}-Noinst-Test"
|
||||
${arch} ${kind} SUBDIR "default"
|
||||
OBJECTS ${ASAN_NOINST_TEST_OBJECTS}
|
||||
LINK_FLAGS ${ASAN_UNITTEST_NOINST_LINK_FLAGS}
|
||||
WITH_TEST_RUNTIME)
|
||||
|
||||
# Benchmarks.
|
||||
set(ASAN_BENCHMARKS_OBJECTS)
|
||||
foreach(src ${ASAN_BENCHMARKS_SOURCES})
|
||||
asan_compile(ASAN_BENCHMARKS_OBJECTS ${src} ${arch} ${kind}
|
||||
${ASAN_UNITTEST_INSTRUMENTED_CFLAGS} ${ARGN})
|
||||
endforeach()
|
||||
add_asan_test(AsanBenchmarks "Asan-${arch}${kind}-Benchmark"
|
||||
${arch} ${kind} SUBDIR "default"
|
||||
OBJECTS ${ASAN_BENCHMARKS_OBJECTS}
|
||||
LINK_FLAGS ${ASAN_UNITTEST_INSTRUMENTED_LINK_FLAGS})
|
||||
endmacro()
|
||||
|
||||
if(COMPILER_RT_CAN_EXECUTE_TESTS AND NOT ANDROID)
|
||||
set(ASAN_TEST_ARCH ${ASAN_SUPPORTED_ARCH})
|
||||
if(APPLE)
|
||||
darwin_filter_host_archs(ASAN_SUPPORTED_ARCH ASAN_TEST_ARCH)
|
||||
endif()
|
||||
foreach(arch ${ASAN_TEST_ARCH})
|
||||
add_asan_tests_for_arch_and_kind(${arch} "-inline")
|
||||
add_asan_tests_for_arch_and_kind(${arch} "-with-calls"
|
||||
-mllvm -asan-instrumentation-with-call-threshold=0)
|
||||
add_asan_tests(${arch} ${ASAN_TEST_RUNTIME} KIND "-inline")
|
||||
add_asan_tests(${arch} ${ASAN_TEST_RUNTIME} KIND "-calls"
|
||||
CFLAGS -mllvm -asan-instrumentation-with-call-threshold=0)
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
|
@ -12,7 +12,8 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "asan_test_utils.h"
|
||||
|
||||
#if defined(__linux__)
|
||||
#if defined(__linux__) && \
|
||||
(!defined(ASAN_SHADOW_SCALE) || ASAN_SHADOW_SCALE == 3)
|
||||
|
||||
// Assembly instrumentation is broken on x86 Android (x86 + PIC + shared runtime
|
||||
// library). See https://github.com/google/sanitizers/issues/353
|
||||
|
@ -153,14 +153,15 @@ TEST(AddressSanitizerInterface, DeathCallbackTest) {
|
||||
__asan_set_death_callback(NULL);
|
||||
}
|
||||
|
||||
static const char* kUseAfterPoisonErrorMessage = "use-after-poison";
|
||||
|
||||
#define GOOD_ACCESS(ptr, offset) \
|
||||
EXPECT_FALSE(__asan_address_is_poisoned(ptr + offset))
|
||||
|
||||
#define BAD_ACCESS(ptr, offset) \
|
||||
EXPECT_TRUE(__asan_address_is_poisoned(ptr + offset))
|
||||
|
||||
#if !defined(ASAN_SHADOW_SCALE) || ASAN_SHADOW_SCALE == 3
|
||||
static const char* kUseAfterPoisonErrorMessage = "use-after-poison";
|
||||
|
||||
TEST(AddressSanitizerInterface, SimplePoisonMemoryRegionTest) {
|
||||
char *array = Ident((char*)malloc(120));
|
||||
// poison array[40..80)
|
||||
@ -199,6 +200,7 @@ TEST(AddressSanitizerInterface, OverlappingPoisonMemoryRegionTest) {
|
||||
BAD_ACCESS(array, 96);
|
||||
free(array);
|
||||
}
|
||||
#endif // !defined(ASAN_SHADOW_SCALE) || ASAN_SHADOW_SCALE == 3
|
||||
|
||||
TEST(AddressSanitizerInterface, PushAndPopWithPoisoningTest) {
|
||||
// Vector of capacity 20
|
||||
@ -219,6 +221,7 @@ TEST(AddressSanitizerInterface, PushAndPopWithPoisoningTest) {
|
||||
free(vec);
|
||||
}
|
||||
|
||||
#if !defined(ASAN_SHADOW_SCALE) || ASAN_SHADOW_SCALE == 3
|
||||
// Make sure that each aligned block of size "2^granularity" doesn't have
|
||||
// "true" value before "false" value.
|
||||
static void MakeShadowValid(bool *shadow, int length, int granularity) {
|
||||
@ -272,6 +275,7 @@ TEST(AddressSanitizerInterface, PoisoningStressTest) {
|
||||
}
|
||||
free(arr);
|
||||
}
|
||||
#endif // !defined(ASAN_SHADOW_SCALE) || ASAN_SHADOW_SCALE == 3
|
||||
|
||||
TEST(AddressSanitizerInterface, GlobalRedzones) {
|
||||
GOOD_ACCESS(glob1, 1 - 1);
|
||||
@ -386,23 +390,6 @@ TEST(AddressSanitizerInterface, DISABLED_InvalidPoisonAndUnpoisonCallsTest) {
|
||||
free(array);
|
||||
}
|
||||
|
||||
#if !defined(_WIN32) // FIXME: This should really be a lit test.
|
||||
static void ErrorReportCallbackOneToZ(const char *report) {
|
||||
int report_len = strlen(report);
|
||||
ASSERT_EQ(6, write(2, "ABCDEF", 6));
|
||||
ASSERT_EQ(report_len, write(2, report, report_len));
|
||||
ASSERT_EQ(6, write(2, "ABCDEF", 6));
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
TEST(AddressSanitizerInterface, SetErrorReportCallbackTest) {
|
||||
__asan_set_error_report_callback(ErrorReportCallbackOneToZ);
|
||||
EXPECT_DEATH(__asan_report_error((void *)GET_CALLER_PC(), 0, 0, 0, true, 1),
|
||||
ASAN_PCRE_DOTALL "ABCDEF.*AddressSanitizer.*WRITE.*ABCDEF");
|
||||
__asan_set_error_report_callback(NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(AddressSanitizerInterface, GetOwnershipStressTest) {
|
||||
std::vector<char *> pointers;
|
||||
std::vector<size_t> sizes;
|
||||
@ -423,3 +410,11 @@ TEST(AddressSanitizerInterface, GetOwnershipStressTest) {
|
||||
free(pointers[i]);
|
||||
}
|
||||
|
||||
TEST(AddressSanitizerInterface, HandleNoReturnTest) {
|
||||
char array[40];
|
||||
__asan_poison_memory_region(array, sizeof(array));
|
||||
BAD_ACCESS(array, 20);
|
||||
__asan_handle_no_return();
|
||||
// It unpoisons the whole thread stack.
|
||||
GOOD_ACCESS(array, 20);
|
||||
}
|
||||
|
@ -95,6 +95,9 @@ TEST(AddressSanitizer, StrLenOOBTest) {
|
||||
free(heap_string);
|
||||
}
|
||||
|
||||
// 32-bit android libc++-based NDK toolchain links wcslen statically, disabling
|
||||
// the interceptor.
|
||||
#if !defined(__ANDROID__) || defined(__LP64__)
|
||||
TEST(AddressSanitizer, WcsLenTest) {
|
||||
EXPECT_EQ(0U, wcslen(Ident(L"")));
|
||||
size_t hello_len = 13;
|
||||
@ -106,6 +109,7 @@ TEST(AddressSanitizer, WcsLenTest) {
|
||||
EXPECT_DEATH(Ident(wcslen(heap_string + 14)), RightOOBReadMessage(0));
|
||||
free(heap_string);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SANITIZER_TEST_HAS_STRNLEN
|
||||
TEST(AddressSanitizer, StrNLenOOBTest) {
|
||||
@ -629,5 +633,3 @@ TEST(AddressSanitizer, StrtolOOBTest) {
|
||||
RunStrtolOOBTest(&CallStrtol);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -13,6 +13,17 @@
|
||||
#include "asan_test_utils.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef _LIBCPP_GET_C_LOCALE
|
||||
#define SANITIZER_GET_C_LOCALE _LIBCPP_GET_C_LOCALE
|
||||
#else
|
||||
#if defined(__FreeBSD__)
|
||||
#define SANITIZER_GET_C_LOCALE 0
|
||||
#elif defined(__NetBSD__)
|
||||
#define SANITIZER_GET_C_LOCALE LC_C_LOCALE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
NOINLINE void *malloc_fff(size_t size) {
|
||||
void *res = malloc/**/(size); break_optimization(0); return res;}
|
||||
@ -1328,19 +1339,18 @@ static int vsnprintf_l_wrapper(char *s, size_t n,
|
||||
TEST(AddressSanitizer, snprintf_l) {
|
||||
char buff[5];
|
||||
// Check that snprintf_l() works fine with Asan.
|
||||
int res = snprintf_l(buff, 5,
|
||||
_LIBCPP_GET_C_LOCALE, "%s", "snprintf_l()");
|
||||
int res = snprintf_l(buff, 5, SANITIZER_GET_C_LOCALE, "%s", "snprintf_l()");
|
||||
EXPECT_EQ(12, res);
|
||||
// Check that vsnprintf_l() works fine with Asan.
|
||||
res = vsnprintf_l_wrapper(buff, 5,
|
||||
_LIBCPP_GET_C_LOCALE, "%s", "vsnprintf_l()");
|
||||
res = vsnprintf_l_wrapper(buff, 5, SANITIZER_GET_C_LOCALE, "%s",
|
||||
"vsnprintf_l()");
|
||||
EXPECT_EQ(13, res);
|
||||
|
||||
EXPECT_DEATH(snprintf_l(buff, 10,
|
||||
_LIBCPP_GET_C_LOCALE, "%s", "snprintf_l()"),
|
||||
EXPECT_DEATH(
|
||||
snprintf_l(buff, 10, SANITIZER_GET_C_LOCALE, "%s", "snprintf_l()"),
|
||||
"AddressSanitizer: stack-buffer-overflow");
|
||||
EXPECT_DEATH(vsnprintf_l_wrapper(buff, 10,
|
||||
_LIBCPP_GET_C_LOCALE, "%s", "vsnprintf_l()"),
|
||||
EXPECT_DEATH(vsnprintf_l_wrapper(buff, 10, SANITIZER_GET_C_LOCALE, "%s",
|
||||
"vsnprintf_l()"),
|
||||
"AddressSanitizer: stack-buffer-overflow");
|
||||
}
|
||||
#endif
|
||||
|
@ -45,7 +45,7 @@
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if !defined(__APPLE__) && !defined(__FreeBSD__)
|
||||
#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__NetBSD__)
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
|
@ -51,7 +51,6 @@ set(GENERIC_SOURCES
|
||||
cmpti2.c
|
||||
comparedf2.c
|
||||
comparesf2.c
|
||||
cpu_model.c
|
||||
ctzdi2.c
|
||||
ctzsi2.c
|
||||
ctzti2.c
|
||||
@ -66,7 +65,6 @@ set(GENERIC_SOURCES
|
||||
divtc3.c
|
||||
divti3.c
|
||||
divtf3.c
|
||||
divxc3.c
|
||||
extendsfdf2.c
|
||||
extendhfsf2.c
|
||||
ffsdi2.c
|
||||
@ -84,27 +82,18 @@ set(GENERIC_SOURCES
|
||||
fixunssfdi.c
|
||||
fixunssfsi.c
|
||||
fixunssfti.c
|
||||
fixunsxfdi.c
|
||||
fixunsxfsi.c
|
||||
fixunsxfti.c
|
||||
fixxfdi.c
|
||||
fixxfti.c
|
||||
floatdidf.c
|
||||
floatdisf.c
|
||||
floatdixf.c
|
||||
floatsidf.c
|
||||
floatsisf.c
|
||||
floattidf.c
|
||||
floattisf.c
|
||||
floattixf.c
|
||||
floatundidf.c
|
||||
floatundisf.c
|
||||
floatundixf.c
|
||||
floatunsidf.c
|
||||
floatunsisf.c
|
||||
floatuntidf.c
|
||||
floatuntisf.c
|
||||
floatuntixf.c
|
||||
int_util.c
|
||||
lshrdi3.c
|
||||
lshrti3.c
|
||||
@ -124,7 +113,6 @@ set(GENERIC_SOURCES
|
||||
mulvdi3.c
|
||||
mulvsi3.c
|
||||
mulvti3.c
|
||||
mulxc3.c
|
||||
negdf2.c
|
||||
negdi2.c
|
||||
negsf2.c
|
||||
@ -142,7 +130,6 @@ set(GENERIC_SOURCES
|
||||
powidf2.c
|
||||
powisf2.c
|
||||
powitf2.c
|
||||
powixf2.c
|
||||
subdf3.c
|
||||
subsf3.c
|
||||
subvdi3.c
|
||||
@ -226,6 +213,23 @@ if (NOT FUCHSIA)
|
||||
clear_cache.c)
|
||||
endif()
|
||||
|
||||
# These sources work on all x86 variants, but only x86 variants.
|
||||
set(x86_ARCH_SOURCES
|
||||
cpu_model.c
|
||||
divxc3.c
|
||||
fixxfdi.c
|
||||
fixxfti.c
|
||||
fixunsxfdi.c
|
||||
fixunsxfsi.c
|
||||
fixunsxfti.c
|
||||
floatdixf.c
|
||||
floattixf.c
|
||||
floatundixf.c
|
||||
floatuntixf.c
|
||||
mulxc3.c
|
||||
powixf2.c
|
||||
)
|
||||
|
||||
if (NOT MSVC)
|
||||
set(x86_64_SOURCES
|
||||
x86_64/chkstk.S
|
||||
@ -235,8 +239,8 @@ if (NOT MSVC)
|
||||
x86_64/floatdixf.c
|
||||
x86_64/floatundidf.S
|
||||
x86_64/floatundisf.S
|
||||
x86_64/floatundixf.S
|
||||
${GENERIC_SOURCES})
|
||||
x86_64/floatundixf.S)
|
||||
filter_builtin_sources(x86_64_SOURCES EXCLUDE x86_64_SOURCES "${x86_64_SOURCES};${GENERIC_SOURCES}")
|
||||
set(x86_64h_SOURCES ${x86_64_SOURCES})
|
||||
|
||||
if (WIN32)
|
||||
@ -262,8 +266,8 @@ if (NOT MSVC)
|
||||
i386/moddi3.S
|
||||
i386/muldi3.S
|
||||
i386/udivdi3.S
|
||||
i386/umoddi3.S
|
||||
${GENERIC_SOURCES})
|
||||
i386/umoddi3.S)
|
||||
filter_builtin_sources(i386_SOURCES EXCLUDE i386_SOURCES "${i386_SOURCES};${GENERIC_SOURCES}")
|
||||
|
||||
if (WIN32)
|
||||
set(i386_SOURCES
|
||||
@ -271,9 +275,6 @@ if (NOT MSVC)
|
||||
i386/chkstk.S
|
||||
i386/chkstk2.S)
|
||||
endif()
|
||||
|
||||
set(i686_SOURCES
|
||||
${i386_SOURCES})
|
||||
else () # MSVC
|
||||
# Use C versions of functions when building on MSVC
|
||||
# MSVC's assembler takes Intel syntax, not AT&T syntax.
|
||||
@ -285,9 +286,13 @@ else () # MSVC
|
||||
${GENERIC_SOURCES})
|
||||
set(x86_64h_SOURCES ${x86_64_SOURCES})
|
||||
set(i386_SOURCES ${GENERIC_SOURCES})
|
||||
set(i686_SOURCES ${i386_SOURCES})
|
||||
endif () # if (NOT MSVC)
|
||||
|
||||
set(x86_64h_SOURCES ${x86_64h_SOURCES} ${x86_ARCH_SOURCES})
|
||||
set(x86_64_SOURCES ${x86_64_SOURCES} ${x86_ARCH_SOURCES})
|
||||
set(i386_SOURCES ${i386_SOURCES} ${x86_ARCH_SOURCES})
|
||||
set(i686_SOURCES ${i686_SOURCES} ${x86_ARCH_SOURCES})
|
||||
|
||||
set(arm_SOURCES
|
||||
arm/bswapdi2.S
|
||||
arm/bswapsi2.S
|
||||
@ -319,8 +324,8 @@ set(arm_SOURCES
|
||||
arm/sync_fetch_and_xor_8.S
|
||||
arm/udivmodsi4.S
|
||||
arm/udivsi3.S
|
||||
arm/umodsi3.S
|
||||
${GENERIC_SOURCES})
|
||||
arm/umodsi3.S)
|
||||
filter_builtin_sources(arm_SOURCES EXCLUDE arm_SOURCES "${arm_SOURCES};${GENERIC_SOURCES}")
|
||||
|
||||
set(thumb1_SOURCES
|
||||
arm/divsi3.S
|
||||
@ -424,6 +429,7 @@ if(MINGW)
|
||||
udivsi3.c
|
||||
umoddi3.c
|
||||
emutls.c)
|
||||
filter_builtin_sources(arm_SOURCES EXCLUDE arm_SOURCES "${arm_SOURCES};${GENERIC_SOURCES}")
|
||||
elseif(NOT WIN32)
|
||||
# TODO the EABI sources should only be added to EABI targets
|
||||
set(arm_SOURCES
|
||||
@ -458,8 +464,26 @@ set(mips64_SOURCES ${GENERIC_TF_SOURCES}
|
||||
set(mips64el_SOURCES ${GENERIC_TF_SOURCES}
|
||||
${mips_SOURCES})
|
||||
|
||||
set(wasm32_SOURCES ${GENERIC_SOURCES})
|
||||
set(wasm64_SOURCES ${GENERIC_SOURCES})
|
||||
set(powerpc64_SOURCES
|
||||
ppc/divtc3.c
|
||||
ppc/fixtfdi.c
|
||||
ppc/fixunstfdi.c
|
||||
ppc/floatditf.c
|
||||
ppc/floatunditf.c
|
||||
ppc/gcc_qadd.c
|
||||
ppc/gcc_qdiv.c
|
||||
ppc/gcc_qmul.c
|
||||
ppc/gcc_qsub.c
|
||||
ppc/multc3.c
|
||||
${GENERIC_SOURCES})
|
||||
set(powerpc64le_SOURCES ${powerpc64_SOURCES})
|
||||
|
||||
set(wasm32_SOURCES
|
||||
${GENERIC_TF_SOURCES}
|
||||
${GENERIC_SOURCES})
|
||||
set(wasm64_SOURCES
|
||||
${GENERIC_TF_SOURCES}
|
||||
${GENERIC_SOURCES})
|
||||
|
||||
add_custom_target(builtins)
|
||||
set_target_properties(builtins PROPERTIES FOLDER "Compiler-RT Misc")
|
||||
@ -493,8 +517,10 @@ else ()
|
||||
# NOTE: some architectures (e.g. i386) have multiple names. Ensure that
|
||||
# we catch them all.
|
||||
set(_arch ${arch})
|
||||
if("${arch}" STREQUAL "i686")
|
||||
set(_arch "i386|i686")
|
||||
if("${arch}" STREQUAL "armv6m")
|
||||
set(_arch "arm|armv6m")
|
||||
elseif("${arch}" MATCHES "^(armhf|armv7|armv7s|armv7k|armv7m|armv7em)$")
|
||||
set(_arch "arm")
|
||||
endif()
|
||||
|
||||
# Filter out generic versions of routines that are re-implemented in
|
||||
|
@ -20,8 +20,11 @@ COMPILER_RT_ABI double __adddf3(double a, double b){
|
||||
}
|
||||
|
||||
#if defined(__ARM_EABI__)
|
||||
#if defined(COMPILER_RT_ARMHF_TARGET)
|
||||
AEABI_RTABI double __aeabi_dadd(double a, double b) {
|
||||
return __adddf3(a, b);
|
||||
}
|
||||
#else
|
||||
AEABI_RTABI double __aeabi_dadd(double a, double b) COMPILER_RT_ALIAS(__adddf3);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -20,8 +20,11 @@ COMPILER_RT_ABI float __addsf3(float a, float b) {
|
||||
}
|
||||
|
||||
#if defined(__ARM_EABI__)
|
||||
#if defined(COMPILER_RT_ARMHF_TARGET)
|
||||
AEABI_RTABI float __aeabi_fadd(float a, float b) {
|
||||
return __addsf3(a, b);
|
||||
}
|
||||
#else
|
||||
AEABI_RTABI float __aeabi_fadd(float a, float b) COMPILER_RT_ALIAS(__addsf3);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -30,7 +30,7 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cdcmpeq)
|
||||
push {r0-r3, lr}
|
||||
bl __aeabi_cdcmpeq_check_nan
|
||||
cmp r0, #1
|
||||
#if __ARM_ARCH_ISA_THUMB == 1
|
||||
#if defined(USE_THUMB_1)
|
||||
beq 1f
|
||||
// NaN has been ruled out, so __aeabi_cdcmple can't trap
|
||||
mov r0, sp
|
||||
@ -46,9 +46,12 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cdcmpeq)
|
||||
pop {r0-r3, lr}
|
||||
|
||||
// NaN has been ruled out, so __aeabi_cdcmple can't trap
|
||||
// Use "it ne" + unconditional branch to guarantee a supported relocation if
|
||||
// __aeabi_cdcmple is in a different section for some builds.
|
||||
IT(ne)
|
||||
bne __aeabi_cdcmple
|
||||
|
||||
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
|
||||
#if defined(USE_THUMB_2)
|
||||
mov ip, #APSR_C
|
||||
msr APSR_nzcvq, ip
|
||||
#else
|
||||
@ -78,7 +81,7 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cdcmple)
|
||||
|
||||
bl __aeabi_dcmplt
|
||||
cmp r0, #1
|
||||
#if __ARM_ARCH_ISA_THUMB == 1
|
||||
#if defined(USE_THUMB_1)
|
||||
bne 1f
|
||||
// Z = 0, C = 0
|
||||
movs r0, #1
|
||||
|
@ -30,7 +30,7 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cfcmpeq)
|
||||
push {r0-r3, lr}
|
||||
bl __aeabi_cfcmpeq_check_nan
|
||||
cmp r0, #1
|
||||
#if __ARM_ARCH_ISA_THUMB == 1
|
||||
#if defined(USE_THUMB_1)
|
||||
beq 1f
|
||||
// NaN has been ruled out, so __aeabi_cfcmple can't trap
|
||||
mov r0, sp
|
||||
@ -46,9 +46,12 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cfcmpeq)
|
||||
pop {r0-r3, lr}
|
||||
|
||||
// NaN has been ruled out, so __aeabi_cfcmple can't trap
|
||||
// Use "it ne" + unconditional branch to guarantee a supported relocation if
|
||||
// __aeabi_cfcmple is in a different section for some builds.
|
||||
IT(ne)
|
||||
bne __aeabi_cfcmple
|
||||
|
||||
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
|
||||
#if defined(USE_THUMB_2)
|
||||
mov ip, #APSR_C
|
||||
msr APSR_nzcvq, ip
|
||||
#else
|
||||
@ -78,7 +81,7 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cfcmple)
|
||||
|
||||
bl __aeabi_fcmplt
|
||||
cmp r0, #1
|
||||
#if __ARM_ARCH_ISA_THUMB == 1
|
||||
#if defined(USE_THUMB_1)
|
||||
bne 1f
|
||||
// Z = 0, C = 0
|
||||
movs r0, #1
|
||||
|
@ -20,16 +20,18 @@
|
||||
#endif
|
||||
|
||||
.syntax unified
|
||||
.text
|
||||
DEFINE_CODE_STATE
|
||||
.p2align 2
|
||||
DEFINE_COMPILERRT_FUNCTION(__aeabi_idivmod)
|
||||
#if __ARM_ARCH_ISA_THUMB == 1
|
||||
#if defined(USE_THUMB_1)
|
||||
push {r0, r1, lr}
|
||||
bl SYMBOL_NAME(__divsi3)
|
||||
pop {r1, r2, r3} // now r0 = quot, r1 = num, r2 = denom
|
||||
muls r2, r0, r2 // r2 = quot * denom
|
||||
subs r1, r1, r2
|
||||
JMP (r3)
|
||||
#else
|
||||
#else // defined(USE_THUMB_1)
|
||||
push { lr }
|
||||
sub sp, sp, #4
|
||||
mov r2, sp
|
||||
@ -42,7 +44,7 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_idivmod)
|
||||
ldr r1, [sp]
|
||||
add sp, sp, #4
|
||||
pop { pc }
|
||||
#endif // __ARM_ARCH_ISA_THUMB == 1
|
||||
#endif // defined(USE_THUMB_1)
|
||||
END_COMPILERRT_FUNCTION(__aeabi_idivmod)
|
||||
|
||||
NO_EXEC_STACK_DIRECTIVE
|
||||
|
@ -14,7 +14,13 @@
|
||||
.syntax unified
|
||||
.p2align 2
|
||||
DEFINE_COMPILERRT_FUNCTION(__aeabi_memcmp)
|
||||
#ifdef USE_THUMB_1
|
||||
push {r7, lr}
|
||||
bl memcmp
|
||||
pop {r7, pc}
|
||||
#else
|
||||
b memcmp
|
||||
#endif
|
||||
END_COMPILERRT_FUNCTION(__aeabi_memcmp)
|
||||
|
||||
DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memcmp4, __aeabi_memcmp)
|
||||
|
@ -14,7 +14,13 @@
|
||||
.syntax unified
|
||||
.p2align 2
|
||||
DEFINE_COMPILERRT_FUNCTION(__aeabi_memcpy)
|
||||
#ifdef USE_THUMB_1
|
||||
push {r7, lr}
|
||||
bl memcpy
|
||||
pop {r7, pc}
|
||||
#else
|
||||
b memcpy
|
||||
#endif
|
||||
END_COMPILERRT_FUNCTION(__aeabi_memcpy)
|
||||
|
||||
DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memcpy4, __aeabi_memcpy)
|
||||
|
@ -13,7 +13,13 @@
|
||||
|
||||
.p2align 2
|
||||
DEFINE_COMPILERRT_FUNCTION(__aeabi_memmove)
|
||||
#ifdef USE_THUMB_1
|
||||
push {r7, lr}
|
||||
bl memmove
|
||||
pop {r7, pc}
|
||||
#else
|
||||
b memmove
|
||||
#endif
|
||||
END_COMPILERRT_FUNCTION(__aeabi_memmove)
|
||||
|
||||
DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memmove4, __aeabi_memmove)
|
||||
|
@ -18,16 +18,29 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_memset)
|
||||
mov r3, r1
|
||||
mov r1, r2
|
||||
mov r2, r3
|
||||
#ifdef USE_THUMB_1
|
||||
push {r7, lr}
|
||||
bl memset
|
||||
pop {r7, pc}
|
||||
#else
|
||||
b memset
|
||||
#endif
|
||||
END_COMPILERRT_FUNCTION(__aeabi_memset)
|
||||
|
||||
DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memset4, __aeabi_memset)
|
||||
DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memset8, __aeabi_memset)
|
||||
|
||||
.p2align 2
|
||||
DEFINE_COMPILERRT_FUNCTION(__aeabi_memclr)
|
||||
mov r2, r1
|
||||
movs r1, #0
|
||||
#ifdef USE_THUMB_1
|
||||
push {r7, lr}
|
||||
bl memset
|
||||
pop {r7, pc}
|
||||
#else
|
||||
b memset
|
||||
#endif
|
||||
END_COMPILERRT_FUNCTION(__aeabi_memclr)
|
||||
|
||||
DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memclr4, __aeabi_memclr)
|
||||
|
@ -21,9 +21,11 @@
|
||||
#endif
|
||||
|
||||
.syntax unified
|
||||
.text
|
||||
DEFINE_CODE_STATE
|
||||
.p2align 2
|
||||
DEFINE_COMPILERRT_FUNCTION(__aeabi_uidivmod)
|
||||
#if __ARM_ARCH_ISA_THUMB == 1
|
||||
#if defined(USE_THUMB_1)
|
||||
cmp r0, r1
|
||||
bcc LOCAL_LABEL(case_denom_larger)
|
||||
push {r0, r1, lr}
|
||||
@ -36,7 +38,7 @@ LOCAL_LABEL(case_denom_larger):
|
||||
movs r1, r0
|
||||
movs r0, #0
|
||||
JMP (lr)
|
||||
#else
|
||||
#else // defined(USE_THUMB_1)
|
||||
push { lr }
|
||||
sub sp, sp, #4
|
||||
mov r2, sp
|
||||
|
@ -11,9 +11,7 @@
|
||||
|
||||
.syntax unified
|
||||
.text
|
||||
#if __ARM_ARCH_ISA_THUMB == 2
|
||||
.thumb
|
||||
#endif
|
||||
DEFINE_CODE_STATE
|
||||
|
||||
//
|
||||
// extern uint64_t __bswapdi2(uint64_t);
|
||||
@ -21,11 +19,7 @@
|
||||
// Reverse all the bytes in a 64-bit integer.
|
||||
//
|
||||
.p2align 2
|
||||
#if __ARM_ARCH_ISA_THUMB == 2
|
||||
DEFINE_COMPILERRT_THUMB_FUNCTION(__bswapdi2)
|
||||
#else
|
||||
DEFINE_COMPILERRT_FUNCTION(__bswapdi2)
|
||||
#endif
|
||||
#if __ARM_ARCH < 6
|
||||
// before armv6 does not have "rev" instruction
|
||||
// r2 = rev(r0)
|
||||
|
@ -11,9 +11,7 @@
|
||||
|
||||
.syntax unified
|
||||
.text
|
||||
#if __ARM_ARCH_ISA_THUMB == 2
|
||||
.thumb
|
||||
#endif
|
||||
DEFINE_CODE_STATE
|
||||
|
||||
//
|
||||
// extern uint32_t __bswapsi2(uint32_t);
|
||||
@ -21,11 +19,7 @@
|
||||
// Reverse all the bytes in a 32-bit integer.
|
||||
//
|
||||
.p2align 2
|
||||
#if __ARM_ARCH_ISA_THUMB == 2
|
||||
DEFINE_COMPILERRT_THUMB_FUNCTION(__bswapsi2)
|
||||
#else
|
||||
DEFINE_COMPILERRT_FUNCTION(__bswapsi2)
|
||||
#endif
|
||||
#if __ARM_ARCH < 6
|
||||
// before armv6 does not have "rev" instruction
|
||||
eor r1, r0, r0, ror #16
|
||||
|
@ -15,17 +15,10 @@
|
||||
|
||||
.syntax unified
|
||||
.text
|
||||
#if __ARM_ARCH_ISA_THUMB == 2
|
||||
.thumb
|
||||
#endif
|
||||
|
||||
DEFINE_CODE_STATE
|
||||
|
||||
.p2align 2
|
||||
#if __ARM_ARCH_ISA_THUMB == 2
|
||||
DEFINE_COMPILERRT_THUMB_FUNCTION(__clzdi2)
|
||||
#else
|
||||
DEFINE_COMPILERRT_FUNCTION(__clzdi2)
|
||||
#endif
|
||||
#ifdef __ARM_FEATURE_CLZ
|
||||
#ifdef __ARMEB__
|
||||
cmp r0, 0
|
||||
|
@ -15,16 +15,10 @@
|
||||
|
||||
.syntax unified
|
||||
.text
|
||||
#if __ARM_ARCH_ISA_THUMB == 2
|
||||
.thumb
|
||||
#endif
|
||||
DEFINE_CODE_STATE
|
||||
|
||||
.p2align 2
|
||||
#if __ARM_ARCH_ISA_THUMB == 2
|
||||
DEFINE_COMPILERRT_THUMB_FUNCTION(__clzsi2)
|
||||
#else
|
||||
DEFINE_COMPILERRT_FUNCTION(__clzsi2)
|
||||
#endif
|
||||
#ifdef __ARM_FEATURE_CLZ
|
||||
clz r0, r0
|
||||
JMP(lr)
|
||||
|
@ -39,9 +39,8 @@
|
||||
|
||||
#include "../assembly.h"
|
||||
.syntax unified
|
||||
#if __ARM_ARCH_ISA_THUMB == 2
|
||||
.thumb
|
||||
#endif
|
||||
.text
|
||||
DEFINE_CODE_STATE
|
||||
|
||||
@ int __eqsf2(float a, float b)
|
||||
|
||||
@ -53,7 +52,7 @@ DEFINE_COMPILERRT_FUNCTION(__eqsf2)
|
||||
#endif
|
||||
// Make copies of a and b with the sign bit shifted off the top. These will
|
||||
// be used to detect zeros and NaNs.
|
||||
#if __ARM_ARCH_ISA_THUMB == 1
|
||||
#if defined(USE_THUMB_1)
|
||||
push {r6, lr}
|
||||
lsls r2, r0, #1
|
||||
lsls r3, r1, #1
|
||||
@ -67,7 +66,7 @@ DEFINE_COMPILERRT_FUNCTION(__eqsf2)
|
||||
// flag if both a and b are zero (of either sign). The shift of r3 doesn't
|
||||
// effect this at all, but it *does* make sure that the C flag is clear for
|
||||
// the subsequent operations.
|
||||
#if __ARM_ARCH_ISA_THUMB == 1
|
||||
#if defined(USE_THUMB_1)
|
||||
lsrs r6, r3, #1
|
||||
orrs r6, r2
|
||||
#else
|
||||
@ -75,7 +74,7 @@ DEFINE_COMPILERRT_FUNCTION(__eqsf2)
|
||||
#endif
|
||||
// Next, we check if a and b have the same or different signs. If they have
|
||||
// opposite signs, this eor will set the N flag.
|
||||
#if __ARM_ARCH_ISA_THUMB == 1
|
||||
#if defined(USE_THUMB_1)
|
||||
beq 1f
|
||||
movs r6, r0
|
||||
eors r6, r1
|
||||
@ -89,7 +88,7 @@ DEFINE_COMPILERRT_FUNCTION(__eqsf2)
|
||||
// ignoring NaNs for now), this subtract will zero out r0. If they have the
|
||||
// same sign, the flags are updated as they would be for a comparison of the
|
||||
// absolute values of a and b.
|
||||
#if __ARM_ARCH_ISA_THUMB == 1
|
||||
#if defined(USE_THUMB_1)
|
||||
bmi 1f
|
||||
subs r0, r2, r3
|
||||
1:
|
||||
@ -108,7 +107,7 @@ DEFINE_COMPILERRT_FUNCTION(__eqsf2)
|
||||
// still clear from the shift argument in orrs; if a is positive and b
|
||||
// negative, this places 0 in r0; if a is negative and b positive, -1 is
|
||||
// placed in r0.
|
||||
#if __ARM_ARCH_ISA_THUMB == 1
|
||||
#if defined(USE_THUMB_1)
|
||||
bhs 1f
|
||||
// Here if a and b have the same sign and absA < absB, the result is thus
|
||||
// b < 0 ? 1 : -1. Same if a and b have the opposite sign (ignoring Nan).
|
||||
@ -127,7 +126,7 @@ DEFINE_COMPILERRT_FUNCTION(__eqsf2)
|
||||
// the sign of b in r0. Thus, if both are negative and a < b, -1 is placed
|
||||
// in r0, which is the desired result. Conversely, if both are positive
|
||||
// and a > b, zero is placed in r0.
|
||||
#if __ARM_ARCH_ISA_THUMB == 1
|
||||
#if defined(USE_THUMB_1)
|
||||
bls 1f
|
||||
// Here both have the same sign and absA > absB.
|
||||
movs r0, #1
|
||||
@ -145,14 +144,14 @@ DEFINE_COMPILERRT_FUNCTION(__eqsf2)
|
||||
// If a == b, then the Z flag is set, so we can get the correct final value
|
||||
// into r0 by simply or'ing with 1 if Z is clear.
|
||||
// For Thumb-1, r0 contains -1 if a < b, 0 if a > b and 0 if a == b.
|
||||
#if __ARM_ARCH_ISA_THUMB != 1
|
||||
#if !defined(USE_THUMB_1)
|
||||
it ne
|
||||
orrne r0, r0, #1
|
||||
#endif
|
||||
|
||||
// Finally, we need to deal with NaNs. If either argument is NaN, replace
|
||||
// the value in r0 with 1.
|
||||
#if __ARM_ARCH_ISA_THUMB == 1
|
||||
#if defined(USE_THUMB_1)
|
||||
LOCAL_LABEL(CHECK_NAN):
|
||||
movs r6, #0xff
|
||||
lsls r6, #24
|
||||
@ -189,7 +188,7 @@ DEFINE_COMPILERRT_FUNCTION(__gtsf2)
|
||||
vmov r0, s0
|
||||
vmov r1, s1
|
||||
#endif
|
||||
#if __ARM_ARCH_ISA_THUMB == 1
|
||||
#if defined(USE_THUMB_1)
|
||||
push {r6, lr}
|
||||
lsls r2, r0, #1
|
||||
lsls r3, r1, #1
|
||||
@ -255,6 +254,7 @@ DEFINE_COMPILERRT_FUNCTION_ALIAS(__gesf2, __gtsf2)
|
||||
|
||||
.p2align 2
|
||||
DEFINE_COMPILERRT_FUNCTION(__unordsf2)
|
||||
|
||||
#if defined(COMPILER_RT_ARMHF_TARGET)
|
||||
vmov r0, s0
|
||||
vmov r1, s1
|
||||
@ -263,7 +263,7 @@ DEFINE_COMPILERRT_FUNCTION(__unordsf2)
|
||||
lsls r2, r0, #1
|
||||
lsls r3, r1, #1
|
||||
movs r0, #0
|
||||
#if __ARM_ARCH_ISA_THUMB == 1
|
||||
#if defined(USE_THUMB_1)
|
||||
movs r1, #0xff
|
||||
lsls r1, #24
|
||||
cmp r2, r1
|
||||
|
@ -23,20 +23,14 @@
|
||||
|
||||
.syntax unified
|
||||
.text
|
||||
#if __ARM_ARCH_ISA_THUMB == 2
|
||||
.thumb
|
||||
#endif
|
||||
DEFINE_CODE_STATE
|
||||
|
||||
@ int __divmodsi4(int divident, int divisor, int *remainder)
|
||||
@ Calculate the quotient and remainder of the (signed) division. The return
|
||||
@ value is the quotient, the remainder is placed in the variable.
|
||||
|
||||
.p2align 3
|
||||
#if __ARM_ARCH_ISA_THUMB == 2
|
||||
DEFINE_COMPILERRT_THUMB_FUNCTION(__divmodsi4)
|
||||
#else
|
||||
DEFINE_COMPILERRT_FUNCTION(__divmodsi4)
|
||||
#endif
|
||||
#if __ARM_ARCH_EXT_IDIV__
|
||||
tst r1, r1
|
||||
beq LOCAL_LABEL(divzero)
|
||||
|
@ -22,9 +22,7 @@
|
||||
|
||||
.syntax unified
|
||||
.text
|
||||
#if __ARM_ARCH_ISA_THUMB == 2
|
||||
.thumb
|
||||
#endif
|
||||
DEFINE_CODE_STATE
|
||||
|
||||
.p2align 3
|
||||
// Ok, APCS and AAPCS agree on 32 bit args, so it's safe to use the same routine.
|
||||
@ -33,11 +31,7 @@ DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_idiv, __divsi3)
|
||||
@ int __divsi3(int divident, int divisor)
|
||||
@ Calculate and return the quotient of the (signed) division.
|
||||
|
||||
#if __ARM_ARCH_ISA_THUMB == 2
|
||||
DEFINE_COMPILERRT_THUMB_FUNCTION(__divsi3)
|
||||
#else
|
||||
DEFINE_COMPILERRT_FUNCTION(__divsi3)
|
||||
#endif
|
||||
#if __ARM_ARCH_EXT_IDIV__
|
||||
tst r1,r1
|
||||
beq LOCAL_LABEL(divzero)
|
||||
@ -49,14 +43,14 @@ LOCAL_LABEL(divzero):
|
||||
#else
|
||||
ESTABLISH_FRAME
|
||||
// Set aside the sign of the quotient.
|
||||
# if __ARM_ARCH_ISA_THUMB == 1
|
||||
# if defined(USE_THUMB_1)
|
||||
movs r4, r0
|
||||
eors r4, r1
|
||||
# else
|
||||
eor r4, r0, r1
|
||||
# endif
|
||||
// Take absolute value of a and b via abs(x) = (x^(x >> 31)) - (x >> 31).
|
||||
# if __ARM_ARCH_ISA_THUMB == 1
|
||||
# if defined(USE_THUMB_1)
|
||||
asrs r2, r0, #31
|
||||
asrs r3, r1, #31
|
||||
eors r0, r2
|
||||
@ -72,7 +66,7 @@ ESTABLISH_FRAME
|
||||
// abs(a) / abs(b)
|
||||
bl SYMBOL_NAME(__udivsi3)
|
||||
// Apply sign of quotient to result and return.
|
||||
# if __ARM_ARCH_ISA_THUMB == 1
|
||||
# if defined(USE_THUMB_1)
|
||||
asrs r4, #31
|
||||
eors r0, r4
|
||||
subs r0, r0, r4
|
||||
|
@ -22,19 +22,13 @@
|
||||
|
||||
.syntax unified
|
||||
.text
|
||||
#if __ARM_ARCH_ISA_THUMB == 2
|
||||
.thumb
|
||||
#endif
|
||||
DEFINE_CODE_STATE
|
||||
|
||||
@ int __modsi3(int divident, int divisor)
|
||||
@ Calculate and return the remainder of the (signed) division.
|
||||
|
||||
.p2align 3
|
||||
#if __ARM_ARCH_ISA_THUMB == 2
|
||||
DEFINE_COMPILERRT_THUMB_FUNCTION(__modsi3)
|
||||
#else
|
||||
DEFINE_COMPILERRT_FUNCTION(__modsi3)
|
||||
#endif
|
||||
#if __ARM_ARCH_EXT_IDIV__
|
||||
tst r1, r1
|
||||
beq LOCAL_LABEL(divzero)
|
||||
|
@ -16,10 +16,7 @@
|
||||
|
||||
.syntax unified
|
||||
.text
|
||||
|
||||
#if __ARM_ARCH_ISA_THUMB == 2
|
||||
.thumb
|
||||
#endif
|
||||
DEFINE_CODE_STATE
|
||||
|
||||
@ unsigned int __udivmodsi4(unsigned int divident, unsigned int divisor,
|
||||
@ unsigned int *remainder)
|
||||
@ -27,11 +24,7 @@
|
||||
@ value is the quotient, the remainder is placed in the variable.
|
||||
|
||||
.p2align 2
|
||||
#if __ARM_ARCH_ISA_THUMB == 2
|
||||
DEFINE_COMPILERRT_THUMB_FUNCTION(__udivmodsi4)
|
||||
#else
|
||||
DEFINE_COMPILERRT_FUNCTION(__udivmodsi4)
|
||||
#endif
|
||||
#if __ARM_ARCH_EXT_IDIV__
|
||||
tst r1, r1
|
||||
beq LOCAL_LABEL(divby0)
|
||||
@ -67,7 +60,7 @@ DEFINE_COMPILERRT_FUNCTION(__udivmodsi4)
|
||||
clz r3, r1
|
||||
/* r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3. */
|
||||
sub r3, r3, ip
|
||||
# if __ARM_ARCH_ISA_THUMB == 2
|
||||
# if defined(USE_THUMB_2)
|
||||
adr ip, LOCAL_LABEL(div0block) + 1
|
||||
sub ip, ip, r3, lsl #1
|
||||
# else
|
||||
@ -78,7 +71,7 @@ DEFINE_COMPILERRT_FUNCTION(__udivmodsi4)
|
||||
mov r3, #0
|
||||
bx ip
|
||||
# else
|
||||
# if __ARM_ARCH_ISA_THUMB == 2
|
||||
# if defined(USE_THUMB_2)
|
||||
# error THUMB mode requires CLZ or UDIV
|
||||
# endif
|
||||
str r4, [sp, #-8]!
|
||||
|
@ -17,9 +17,7 @@
|
||||
.syntax unified
|
||||
.text
|
||||
|
||||
#if __ARM_ARCH_ISA_THUMB == 2
|
||||
.thumb
|
||||
#endif
|
||||
DEFINE_CODE_STATE
|
||||
|
||||
.p2align 2
|
||||
DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_uidiv, __udivsi3)
|
||||
@ -27,11 +25,7 @@ DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_uidiv, __udivsi3)
|
||||
@ unsigned int __udivsi3(unsigned int divident, unsigned int divisor)
|
||||
@ Calculate and return the quotient of the (unsigned) division.
|
||||
|
||||
#if __ARM_ARCH_ISA_THUMB == 2
|
||||
DEFINE_COMPILERRT_THUMB_FUNCTION(__udivsi3)
|
||||
#else
|
||||
DEFINE_COMPILERRT_FUNCTION(__udivsi3)
|
||||
#endif
|
||||
#if __ARM_ARCH_EXT_IDIV__
|
||||
tst r1, r1
|
||||
beq LOCAL_LABEL(divby0)
|
||||
@ -49,7 +43,7 @@ LOCAL_LABEL(divby0):
|
||||
#else /* ! __ARM_ARCH_EXT_IDIV__ */
|
||||
cmp r1, #1
|
||||
bcc LOCAL_LABEL(divby0)
|
||||
#if __ARM_ARCH_ISA_THUMB == 1
|
||||
#if defined(USE_THUMB_1)
|
||||
bne LOCAL_LABEL(num_neq_denom)
|
||||
JMP(lr)
|
||||
LOCAL_LABEL(num_neq_denom):
|
||||
@ -58,7 +52,7 @@ LOCAL_LABEL(num_neq_denom):
|
||||
JMPc(lr, eq)
|
||||
#endif
|
||||
cmp r0, r1
|
||||
#if __ARM_ARCH_ISA_THUMB == 1
|
||||
#if defined(USE_THUMB_1)
|
||||
bhs LOCAL_LABEL(num_ge_denom)
|
||||
movs r0, #0
|
||||
JMP(lr)
|
||||
@ -90,7 +84,7 @@ LOCAL_LABEL(num_ge_denom):
|
||||
clz r3, r1
|
||||
/* r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3. */
|
||||
sub r3, r3, ip
|
||||
# if __ARM_ARCH_ISA_THUMB == 2
|
||||
# if defined(USE_THUMB_2)
|
||||
adr ip, LOCAL_LABEL(div0block) + 1
|
||||
sub ip, ip, r3, lsl #1
|
||||
# else
|
||||
@ -101,17 +95,17 @@ LOCAL_LABEL(num_ge_denom):
|
||||
mov r3, #0
|
||||
bx ip
|
||||
# else /* No CLZ Feature */
|
||||
# if __ARM_ARCH_ISA_THUMB == 2
|
||||
# if defined(USE_THUMB_2)
|
||||
# error THUMB mode requires CLZ or UDIV
|
||||
# endif
|
||||
# if __ARM_ARCH_ISA_THUMB == 1
|
||||
# if defined(USE_THUMB_1)
|
||||
# define BLOCK_SIZE 10
|
||||
# else
|
||||
# define BLOCK_SIZE 12
|
||||
# endif
|
||||
|
||||
mov r2, r0
|
||||
# if __ARM_ARCH_ISA_THUMB == 1
|
||||
# if defined(USE_THUMB_1)
|
||||
mov ip, r0
|
||||
adr r0, LOCAL_LABEL(div0block)
|
||||
adds r0, #1
|
||||
@ -120,7 +114,7 @@ LOCAL_LABEL(num_ge_denom):
|
||||
# endif
|
||||
lsrs r3, r2, #16
|
||||
cmp r3, r1
|
||||
# if __ARM_ARCH_ISA_THUMB == 1
|
||||
# if defined(USE_THUMB_1)
|
||||
blo LOCAL_LABEL(skip_16)
|
||||
movs r2, r3
|
||||
subs r0, r0, #(16 * BLOCK_SIZE)
|
||||
@ -132,7 +126,7 @@ LOCAL_LABEL(skip_16):
|
||||
|
||||
lsrs r3, r2, #8
|
||||
cmp r3, r1
|
||||
# if __ARM_ARCH_ISA_THUMB == 1
|
||||
# if defined(USE_THUMB_1)
|
||||
blo LOCAL_LABEL(skip_8)
|
||||
movs r2, r3
|
||||
subs r0, r0, #(8 * BLOCK_SIZE)
|
||||
@ -144,7 +138,7 @@ LOCAL_LABEL(skip_8):
|
||||
|
||||
lsrs r3, r2, #4
|
||||
cmp r3, r1
|
||||
# if __ARM_ARCH_ISA_THUMB == 1
|
||||
# if defined(USE_THUMB_1)
|
||||
blo LOCAL_LABEL(skip_4)
|
||||
movs r2, r3
|
||||
subs r0, r0, #(4 * BLOCK_SIZE)
|
||||
@ -156,7 +150,7 @@ LOCAL_LABEL(skip_4):
|
||||
|
||||
lsrs r3, r2, #2
|
||||
cmp r3, r1
|
||||
# if __ARM_ARCH_ISA_THUMB == 1
|
||||
# if defined(USE_THUMB_1)
|
||||
blo LOCAL_LABEL(skip_2)
|
||||
movs r2, r3
|
||||
subs r0, r0, #(2 * BLOCK_SIZE)
|
||||
@ -167,7 +161,7 @@ LOCAL_LABEL(skip_2):
|
||||
# endif
|
||||
|
||||
/* Last block, no need to update r2 or r3. */
|
||||
# if __ARM_ARCH_ISA_THUMB == 1
|
||||
# if defined(USE_THUMB_1)
|
||||
lsrs r3, r2, #1
|
||||
cmp r3, r1
|
||||
blo LOCAL_LABEL(skip_1)
|
||||
@ -203,7 +197,7 @@ LOCAL_LABEL(divby0):
|
||||
# endif
|
||||
|
||||
|
||||
#if __ARM_ARCH_ISA_THUMB == 1
|
||||
#if defined(USE_THUMB_1)
|
||||
#define block(shift) \
|
||||
lsls r2, r1, IMM shift; \
|
||||
cmp r0, r2; \
|
||||
|
@ -16,19 +16,13 @@
|
||||
|
||||
.syntax unified
|
||||
.text
|
||||
#if __ARM_ARCH_ISA_THUMB == 2
|
||||
.thumb
|
||||
#endif
|
||||
DEFINE_CODE_STATE
|
||||
|
||||
@ unsigned int __umodsi3(unsigned int divident, unsigned int divisor)
|
||||
@ Calculate and return the remainder of the (unsigned) division.
|
||||
|
||||
.p2align 2
|
||||
#if __ARM_ARCH_ISA_THUMB == 2
|
||||
DEFINE_COMPILERRT_THUMB_FUNCTION(__umodsi3)
|
||||
#else
|
||||
DEFINE_COMPILERRT_FUNCTION(__umodsi3)
|
||||
#endif
|
||||
#if __ARM_ARCH_EXT_IDIV__
|
||||
tst r1, r1
|
||||
beq LOCAL_LABEL(divby0)
|
||||
@ -65,7 +59,7 @@ DEFINE_COMPILERRT_FUNCTION(__umodsi3)
|
||||
clz r3, r1
|
||||
/* r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3. */
|
||||
sub r3, r3, ip
|
||||
# if __ARM_ARCH_ISA_THUMB == 2
|
||||
# if defined(USE_THUMB_2)
|
||||
adr ip, LOCAL_LABEL(div0block) + 1
|
||||
sub ip, ip, r3, lsl #1
|
||||
# else
|
||||
@ -74,7 +68,7 @@ DEFINE_COMPILERRT_FUNCTION(__umodsi3)
|
||||
sub ip, ip, r3, lsl #3
|
||||
bx ip
|
||||
# else
|
||||
# if __ARM_ARCH_ISA_THUMB == 2
|
||||
# if defined(USE_THUMB_2)
|
||||
# error THUMB mode requires CLZ or UDIV
|
||||
# endif
|
||||
mov r2, r0
|
||||
|
@ -41,8 +41,5 @@ __ashldi3(di_int a, si_int b)
|
||||
}
|
||||
|
||||
#if defined(__ARM_EABI__)
|
||||
AEABI_RTABI di_int __aeabi_llsl(di_int a, si_int b) {
|
||||
return __ashldi3(a, b);
|
||||
}
|
||||
AEABI_RTABI di_int __aeabi_llsl(di_int a, si_int b) COMPILER_RT_ALIAS(__ashldi3);
|
||||
#endif
|
||||
|
||||
|
@ -42,8 +42,5 @@ __ashrdi3(di_int a, si_int b)
|
||||
}
|
||||
|
||||
#if defined(__ARM_EABI__)
|
||||
AEABI_RTABI di_int __aeabi_lasr(di_int a, si_int b) {
|
||||
return __ashrdi3(a, b);
|
||||
}
|
||||
AEABI_RTABI di_int __aeabi_lasr(di_int a, si_int b) COMPILER_RT_ALIAS(__ashrdi3);
|
||||
#endif
|
||||
|
||||
|
@ -68,10 +68,42 @@
|
||||
#endif
|
||||
|
||||
#if defined(__arm__)
|
||||
|
||||
/*
|
||||
* Determine actual [ARM][THUMB[1][2]] ISA using compiler predefined macros:
|
||||
* - for '-mthumb -march=armv6' compiler defines '__thumb__'
|
||||
* - for '-mthumb -march=armv7' compiler defines '__thumb__' and '__thumb2__'
|
||||
*/
|
||||
#if defined(__thumb2__) || defined(__thumb__)
|
||||
#define DEFINE_CODE_STATE .thumb SEPARATOR
|
||||
#define DECLARE_FUNC_ENCODING .thumb_func SEPARATOR
|
||||
#if defined(__thumb2__)
|
||||
#define USE_THUMB_2
|
||||
#define IT(cond) it cond
|
||||
#define ITT(cond) itt cond
|
||||
#define ITE(cond) ite cond
|
||||
#else
|
||||
#define USE_THUMB_1
|
||||
#define IT(cond)
|
||||
#define ITT(cond)
|
||||
#define ITE(cond)
|
||||
#endif // defined(__thumb__2)
|
||||
#else // !defined(__thumb2__) && !defined(__thumb__)
|
||||
#define DEFINE_CODE_STATE .arm SEPARATOR
|
||||
#define DECLARE_FUNC_ENCODING
|
||||
#define IT(cond)
|
||||
#define ITT(cond)
|
||||
#define ITE(cond)
|
||||
#endif
|
||||
|
||||
#if defined(USE_THUMB_1) && defined(USE_THUMB_2)
|
||||
#error "USE_THUMB_1 and USE_THUMB_2 can't be defined together."
|
||||
#endif
|
||||
|
||||
#if defined(__ARM_ARCH_4T__) || __ARM_ARCH >= 5
|
||||
#define ARM_HAS_BX
|
||||
#endif
|
||||
#if !defined(__ARM_FEATURE_CLZ) && __ARM_ARCH_ISA_THUMB != 1 && \
|
||||
#if !defined(__ARM_FEATURE_CLZ) && !defined(USE_THUMB_1) && \
|
||||
(__ARM_ARCH >= 6 || (__ARM_ARCH == 5 && !defined(__ARM_ARCH_5__)))
|
||||
#define __ARM_FEATURE_CLZ
|
||||
#endif
|
||||
@ -93,21 +125,14 @@
|
||||
JMP(ip)
|
||||
#endif
|
||||
|
||||
#if __ARM_ARCH_ISA_THUMB == 2
|
||||
#define IT(cond) it cond
|
||||
#define ITT(cond) itt cond
|
||||
#define ITE(cond) ite cond
|
||||
#else
|
||||
#define IT(cond)
|
||||
#define ITT(cond)
|
||||
#define ITE(cond)
|
||||
#endif
|
||||
|
||||
#if __ARM_ARCH_ISA_THUMB == 2
|
||||
#if defined(USE_THUMB_2)
|
||||
#define WIDE(op) op.w
|
||||
#else
|
||||
#define WIDE(op) op
|
||||
#endif
|
||||
#else // !defined(__arm)
|
||||
#define DECLARE_FUNC_ENCODING
|
||||
#define DEFINE_CODE_STATE
|
||||
#endif
|
||||
|
||||
#define GLUE2(a, b) a##b
|
||||
@ -122,13 +147,16 @@
|
||||
#endif
|
||||
|
||||
#define DEFINE_COMPILERRT_FUNCTION(name) \
|
||||
DEFINE_CODE_STATE \
|
||||
FILE_LEVEL_DIRECTIVE SEPARATOR \
|
||||
.globl SYMBOL_NAME(name) SEPARATOR \
|
||||
SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
|
||||
DECLARE_SYMBOL_VISIBILITY(name) \
|
||||
DECLARE_FUNC_ENCODING \
|
||||
SYMBOL_NAME(name):
|
||||
|
||||
#define DEFINE_COMPILERRT_THUMB_FUNCTION(name) \
|
||||
DEFINE_CODE_STATE \
|
||||
FILE_LEVEL_DIRECTIVE SEPARATOR \
|
||||
.globl SYMBOL_NAME(name) SEPARATOR \
|
||||
SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
|
||||
@ -137,16 +165,20 @@
|
||||
SYMBOL_NAME(name):
|
||||
|
||||
#define DEFINE_COMPILERRT_PRIVATE_FUNCTION(name) \
|
||||
DEFINE_CODE_STATE \
|
||||
FILE_LEVEL_DIRECTIVE SEPARATOR \
|
||||
.globl SYMBOL_NAME(name) SEPARATOR \
|
||||
SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
|
||||
HIDDEN(SYMBOL_NAME(name)) SEPARATOR \
|
||||
DECLARE_FUNC_ENCODING \
|
||||
SYMBOL_NAME(name):
|
||||
|
||||
#define DEFINE_COMPILERRT_PRIVATE_FUNCTION_UNMANGLED(name) \
|
||||
DEFINE_CODE_STATE \
|
||||
.globl name SEPARATOR \
|
||||
SYMBOL_IS_FUNC(name) SEPARATOR \
|
||||
HIDDEN(name) SEPARATOR \
|
||||
DECLARE_FUNC_ENCODING \
|
||||
name:
|
||||
|
||||
#define DEFINE_COMPILERRT_FUNCTION_ALIAS(name, target) \
|
||||
|
@ -9,6 +9,7 @@
|
||||
*/
|
||||
|
||||
#include "int_lib.h"
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#if __APPLE__
|
||||
@ -23,7 +24,7 @@ uint32_t FlushInstructionCache(uintptr_t hProcess, void *lpBaseAddress,
|
||||
uintptr_t GetCurrentProcess(void);
|
||||
#endif
|
||||
|
||||
#if (defined(__FreeBSD__) || defined(__Bitrig__)) && defined(__arm__)
|
||||
#if defined(__FreeBSD__) && defined(__arm__)
|
||||
#include <sys/types.h>
|
||||
#include <machine/sysarch.h>
|
||||
#endif
|
||||
@ -32,7 +33,7 @@ uintptr_t GetCurrentProcess(void);
|
||||
#include <machine/sysarch.h>
|
||||
#endif
|
||||
|
||||
#if defined(__mips__)
|
||||
#if defined(__linux__) && defined(__mips__)
|
||||
#include <sys/cachectl.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
@ -41,7 +42,7 @@ uintptr_t GetCurrentProcess(void);
|
||||
* clear_mips_cache - Invalidates instruction cache for Mips.
|
||||
*/
|
||||
static void clear_mips_cache(const void* Addr, size_t Size) {
|
||||
asm volatile (
|
||||
__asm__ volatile (
|
||||
".set push\n"
|
||||
".set noreorder\n"
|
||||
".set noat\n"
|
||||
@ -96,7 +97,7 @@ void __clear_cache(void *start, void *end) {
|
||||
* so there is nothing to do
|
||||
*/
|
||||
#elif defined(__arm__) && !defined(__APPLE__)
|
||||
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__Bitrig__)
|
||||
#if defined(__FreeBSD__) || defined(__NetBSD__)
|
||||
struct arm_sync_icache_args arg;
|
||||
|
||||
arg.addr = (uintptr_t)start;
|
||||
@ -121,15 +122,13 @@ void __clear_cache(void *start, void *end) {
|
||||
: "=r"(start_reg)
|
||||
: "r"(syscall_nr), "r"(start_reg), "r"(end_reg),
|
||||
"r"(flags));
|
||||
if (start_reg != 0) {
|
||||
compilerrt_abort();
|
||||
}
|
||||
assert(start_reg == 0 && "Cache flush syscall failed.");
|
||||
#elif defined(_WIN32)
|
||||
FlushInstructionCache(GetCurrentProcess(), start, end - start);
|
||||
#else
|
||||
compilerrt_abort();
|
||||
#endif
|
||||
#elif defined(__mips__)
|
||||
#elif defined(__linux__) && defined(__mips__)
|
||||
const uintptr_t start_int = (uintptr_t) start;
|
||||
const uintptr_t end_int = (uintptr_t) end;
|
||||
#if defined(__ANDROID__) && defined(__LP64__)
|
||||
@ -165,6 +164,21 @@ void __clear_cache(void *start, void *end) {
|
||||
for (addr = xstart; addr < xend; addr += icache_line_size)
|
||||
__asm __volatile("ic ivau, %0" :: "r"(addr));
|
||||
__asm __volatile("isb sy");
|
||||
#elif defined (__powerpc64__)
|
||||
const size_t line_size = 32;
|
||||
const size_t len = (uintptr_t)end - (uintptr_t)start;
|
||||
|
||||
const uintptr_t mask = ~(line_size - 1);
|
||||
const uintptr_t start_line = ((uintptr_t)start) & mask;
|
||||
const uintptr_t end_line = ((uintptr_t)start + len + line_size - 1) & mask;
|
||||
|
||||
for (uintptr_t line = start_line; line < end_line; line += line_size)
|
||||
__asm__ volatile("dcbf 0, %0" : : "r"(line));
|
||||
__asm__ volatile("sync");
|
||||
|
||||
for (uintptr_t line = start_line; line < end_line; line += line_size)
|
||||
__asm__ volatile("icbi 0, %0" : : "r"(line));
|
||||
__asm__ volatile("isync");
|
||||
#else
|
||||
#if __APPLE__
|
||||
/* On Darwin, sys_icache_invalidate() provides this functionality */
|
||||
@ -174,4 +188,3 @@ void __clear_cache(void *start, void *end) {
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -143,8 +143,11 @@ __gtdf2(fp_t a, fp_t b) {
|
||||
}
|
||||
|
||||
#if defined(__ARM_EABI__)
|
||||
#if defined(COMPILER_RT_ARMHF_TARGET)
|
||||
AEABI_RTABI int __aeabi_dcmpun(fp_t a, fp_t b) {
|
||||
return __unorddf2(a, b);
|
||||
}
|
||||
#else
|
||||
AEABI_RTABI int __aeabi_dcmpun(fp_t a, fp_t b) COMPILER_RT_ALIAS(__unorddf2);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -143,8 +143,11 @@ __gtsf2(fp_t a, fp_t b) {
|
||||
}
|
||||
|
||||
#if defined(__ARM_EABI__)
|
||||
#if defined(COMPILER_RT_ARMHF_TARGET)
|
||||
AEABI_RTABI int __aeabi_fcmpun(fp_t a, fp_t b) {
|
||||
return __unordsf2(a, b);
|
||||
}
|
||||
#else
|
||||
AEABI_RTABI int __aeabi_fcmpun(fp_t a, fp_t b) COMPILER_RT_ALIAS(__unordsf2);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -54,6 +54,7 @@ enum ProcessorTypes {
|
||||
AMD_BTVER1,
|
||||
AMD_BTVER2,
|
||||
AMDFAM17H,
|
||||
INTEL_KNM,
|
||||
CPU_TYPE_MAX
|
||||
};
|
||||
|
||||
@ -74,6 +75,7 @@ enum ProcessorSubtypes {
|
||||
INTEL_COREI7_BROADWELL,
|
||||
INTEL_COREI7_SKYLAKE,
|
||||
INTEL_COREI7_SKYLAKE_AVX512,
|
||||
INTEL_COREI7_CANNONLAKE,
|
||||
CPU_SUBTYPE_MAX
|
||||
};
|
||||
|
||||
@ -339,6 +341,12 @@ getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model,
|
||||
*Subtype = INTEL_COREI7_SKYLAKE_AVX512; // "skylake-avx512"
|
||||
break;
|
||||
|
||||
// Cannonlake:
|
||||
case 0x66:
|
||||
*Type = INTEL_COREI7;
|
||||
*Subtype = INTEL_COREI7_CANNONLAKE; // "cannonlake"
|
||||
break;
|
||||
|
||||
case 0x1c: // Most 45 nm Intel Atom processors
|
||||
case 0x26: // 45 nm Atom Lincroft
|
||||
case 0x27: // 32 nm Atom Medfield
|
||||
@ -361,6 +369,10 @@ getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model,
|
||||
*Type = INTEL_KNL; // knl
|
||||
break;
|
||||
|
||||
case 0x85:
|
||||
*Type = INTEL_KNM; // knm
|
||||
break;
|
||||
|
||||
default: // Unknown family 6 CPU.
|
||||
break;
|
||||
break;
|
||||
|
@ -183,8 +183,11 @@ __divdf3(fp_t a, fp_t b) {
|
||||
}
|
||||
|
||||
#if defined(__ARM_EABI__)
|
||||
#if defined(COMPILER_RT_ARMHF_TARGET)
|
||||
AEABI_RTABI fp_t __aeabi_ddiv(fp_t a, fp_t b) {
|
||||
return __divdf3(a, b);
|
||||
}
|
||||
#else
|
||||
AEABI_RTABI fp_t __aeabi_ddiv(fp_t a, fp_t b) COMPILER_RT_ALIAS(__divdf3);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -167,8 +167,11 @@ __divsf3(fp_t a, fp_t b) {
|
||||
}
|
||||
|
||||
#if defined(__ARM_EABI__)
|
||||
#if defined(COMPILER_RT_ARMHF_TARGET)
|
||||
AEABI_RTABI fp_t __aeabi_fdiv(fp_t a, fp_t b) {
|
||||
return __divsf3(a, b);
|
||||
}
|
||||
#else
|
||||
AEABI_RTABI fp_t __aeabi_fdiv(fp_t a, fp_t b) COMPILER_RT_ALIAS(__divsf3);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user