Remove upstream files and directories from vendor/compiler-rt/dist that
we do not use. This saves on repository space, and reduces the number of tree conflicts when merging.
This commit is contained in:
parent
0646903fc1
commit
63714eb580
@ -1,4 +0,0 @@
|
||||
{
|
||||
"repository.callsign" : "CRT",
|
||||
"conduit_uri" : "https://reviews.llvm.org/"
|
||||
}
|
6
.gitignore
vendored
6
.gitignore
vendored
@ -1,6 +0,0 @@
|
||||
*~
|
||||
darwin_fat
|
||||
clang_darwin
|
||||
multi_arch
|
||||
*.sw?
|
||||
*.pyc
|
474
CMakeLists.txt
474
CMakeLists.txt
@ -1,474 +0,0 @@
|
||||
# CMake build for CompilerRT.
|
||||
#
|
||||
# An important constraint of the build is that it only produces libraries
|
||||
# based on the ability of the host toolchain to target various platforms.
|
||||
|
||||
cmake_minimum_required(VERSION 3.4.3)
|
||||
|
||||
# Check if compiler-rt is built as a standalone project.
|
||||
if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR OR COMPILER_RT_STANDALONE_BUILD)
|
||||
project(CompilerRT C CXX ASM)
|
||||
set(COMPILER_RT_STANDALONE_BUILD TRUE)
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
endif()
|
||||
|
||||
# Add path for custom compiler-rt modules.
|
||||
list(INSERT CMAKE_MODULE_PATH 0
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules"
|
||||
)
|
||||
|
||||
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)
|
||||
|
||||
option(COMPILER_RT_BUILD_BUILTINS "Build builtins" ON)
|
||||
mark_as_advanced(COMPILER_RT_BUILD_BUILTINS)
|
||||
option(COMPILER_RT_BUILD_SANITIZERS "Build sanitizers" ON)
|
||||
mark_as_advanced(COMPILER_RT_BUILD_SANITIZERS)
|
||||
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_HWASAN_WITH_INTERCEPTORS ON CACHE BOOLEAN
|
||||
"Enable libc interceptors in HWASan (testing mode)")
|
||||
|
||||
set(COMPILER_RT_BAREMETAL_BUILD OFF CACHE BOOLEAN
|
||||
"Build for a bare-metal target.")
|
||||
|
||||
if (COMPILER_RT_STANDALONE_BUILD)
|
||||
load_llvm_config()
|
||||
if (TARGET intrinsics_gen)
|
||||
# Loading the llvm config causes this target to be imported so place it
|
||||
# under the appropriate folder in an IDE.
|
||||
set_target_properties(intrinsics_gen PROPERTIES FOLDER "Compiler-RT Misc")
|
||||
endif()
|
||||
|
||||
# Find Python interpreter.
|
||||
set(Python_ADDITIONAL_VERSIONS 2.7 2.6 2.5)
|
||||
include(FindPythonInterp)
|
||||
if(NOT PYTHONINTERP_FOUND)
|
||||
message(FATAL_ERROR "
|
||||
Unable to find Python interpreter required testing. Please install Python
|
||||
or specify the PYTHON_EXECUTABLE CMake variable.")
|
||||
endif()
|
||||
|
||||
# Ensure that fat libraries are built correctly on Darwin
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL Darwin)
|
||||
if(NOT CMAKE_LIBTOOL)
|
||||
find_program(CMAKE_XCRUN
|
||||
NAMES
|
||||
xcrun)
|
||||
if(CMAKE_XCRUN)
|
||||
execute_process(COMMAND
|
||||
${CMAKE_XCRUN} -find libtool
|
||||
OUTPUT_VARIABLE
|
||||
CMAKE_LIBTOOL
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_LIBTOOL OR NOT EXISTS CMAKE_LIBTOOL)
|
||||
find_program(CMAKE_LIBTOOL
|
||||
NAMES
|
||||
libtool)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
get_property(languages GLOBAL PROPERTY ENABLED_LANGUAGES)
|
||||
|
||||
if(CMAKE_LIBTOOL)
|
||||
set(CMAKE_LIBTOOL ${CMAKE_LIBTOOL} CACHE PATH "libtool executable")
|
||||
message(STATUS "Found libtool - ${CMAKE_LIBTOOL}")
|
||||
|
||||
execute_process(COMMAND
|
||||
${CMAKE_LIBTOOL} -V
|
||||
OUTPUT_VARIABLE
|
||||
LIBTOOL_V_OUTPUT
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
if("${LIBTOOL_V_OUTPUT}" MATCHES ".*cctools-([0-9]+).*")
|
||||
string(REGEX REPLACE ".*cctools-([0-9]+).*" "\\1" LIBTOOL_VERSION ${LIBTOOL_V_OUTPUT})
|
||||
if(NOT LIBTOOL_VERSION VERSION_LESS "862")
|
||||
set(LIBTOOL_NO_WARNING_FLAG "-no_warning_for_no_symbols")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
foreach(lang ${languages})
|
||||
set(CMAKE_${lang}_CREATE_STATIC_LIBRARY "\"${CMAKE_LIBTOOL}\" -static ${LIBTOOL_NO_WARNING_FLAG} -o <TARGET> <LINK_FLAGS> <OBJECTS>")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
# Workaround SIP :-(
|
||||
if(DYLD_LIBRARY_PATH)
|
||||
set(dyld_envar "DYLD_LIBRARY_PATH=${DYLD_LIBRARY_PATH}")
|
||||
foreach(lang ${languages})
|
||||
foreach(cmd ${CMAKE_${lang}_CREATE_STATIC_LIBRARY})
|
||||
list(APPEND CMAKE_${lang}_CREATE_STATIC_LIBRARY_NEW "${dyld_envar} ${cmd}")
|
||||
endforeach()
|
||||
endforeach()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Define default arguments to lit.
|
||||
set(LIT_ARGS_DEFAULT "-sv")
|
||||
if (MSVC OR XCODE)
|
||||
set(LIT_ARGS_DEFAULT "${LIT_ARGS_DEFAULT} --no-progress-bar")
|
||||
endif()
|
||||
set(LLVM_LIT_ARGS "${LIT_ARGS_DEFAULT}" CACHE STRING "Default options for lit")
|
||||
set(LLVM_LIT_OUTPUT_DIR "${COMPILER_RT_EXEC_OUTPUT_DIR}")
|
||||
endif()
|
||||
|
||||
construct_compiler_rt_default_triple()
|
||||
if ("${COMPILER_RT_DEFAULT_TARGET_TRIPLE}" MATCHES ".*hf$")
|
||||
if (${COMPILER_RT_DEFAULT_TARGET_ARCH} MATCHES "^arm")
|
||||
set(COMPILER_RT_DEFAULT_TARGET_ARCH "armhf")
|
||||
endif()
|
||||
endif()
|
||||
if ("${COMPILER_RT_DEFAULT_TARGET_TRIPLE}" 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})
|
||||
|
||||
pythonize_bool(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR)
|
||||
|
||||
# We support running instrumented tests when we're not cross compiling
|
||||
# and target a UNIX-like system or Windows.
|
||||
# We can run tests on Android even when we are cross-compiling.
|
||||
if(("${CMAKE_HOST_SYSTEM}" STREQUAL "${CMAKE_SYSTEM}" AND (UNIX OR WIN32)) OR ANDROID
|
||||
OR COMPILER_RT_EMULATOR)
|
||||
option(COMPILER_RT_CAN_EXECUTE_TESTS "Can we execute instrumented tests" ON)
|
||||
else()
|
||||
option(COMPILER_RT_CAN_EXECUTE_TESTS "Can we execute instrumented tests" OFF)
|
||||
endif()
|
||||
|
||||
option(COMPILER_RT_DEBUG "Build runtimes with full debug info" OFF)
|
||||
option(COMPILER_RT_EXTERNALIZE_DEBUGINFO
|
||||
"Generate dSYM files and strip executables and libraries (Darwin Only)" OFF)
|
||||
# COMPILER_RT_DEBUG_PYBOOL is used by lit.common.configured.in.
|
||||
pythonize_bool(COMPILER_RT_DEBUG)
|
||||
|
||||
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(cxxabi_supported OFF)
|
||||
else()
|
||||
set(cxxabi_supported ON)
|
||||
endif()
|
||||
|
||||
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 libstdc++ libc++)
|
||||
set_property(CACHE SANITIZER_CXX_ABI PROPERTY STRINGS ;${CXXABIS})
|
||||
|
||||
if (SANITIZER_CXX_ABI STREQUAL "default")
|
||||
if (APPLE OR CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
|
||||
set(SANITIZER_CXX_ABI_LIBNAME "libc++")
|
||||
set(SANITIZER_CXX_ABI_SYSTEM 1)
|
||||
elseif (FUCHSIA)
|
||||
set(SANITIZER_CXX_ABI_LIBNAME "libc++")
|
||||
set(SANITIZER_CXX_ABI_INTREE 1)
|
||||
else()
|
||||
set(SANITIZER_CXX_ABI_LIBNAME "libstdc++")
|
||||
set(SANITIZER_CXX_ABI_SYSTEM 1)
|
||||
endif()
|
||||
else()
|
||||
set(SANITIZER_CXX_ABI_LIBNAME "${SANITIZER_CXX_ABI}")
|
||||
set(SANITIZER_CXX_ABI_SYSTEM 1)
|
||||
endif()
|
||||
|
||||
set(DEFAULT_COMPILER_RT_USE_BUILTINS_LIBRARY OFF)
|
||||
if (FUCHSIA)
|
||||
set(DEFAULT_COMPILER_RT_USE_BUILTINS_LIBRARY ON)
|
||||
endif()
|
||||
|
||||
option(COMPILER_RT_USE_BUILTINS_LIBRARY
|
||||
"Use compiler-rt builtins instead of libgcc" ${DEFAULT_COMPILER_RT_USE_BUILTINS_LIBRARY})
|
||||
|
||||
include(config-ix)
|
||||
|
||||
#================================
|
||||
# Setup Compiler Flags
|
||||
#================================
|
||||
|
||||
if(MSVC)
|
||||
# Override any existing /W flags with /W4. This is what LLVM does. Failing to
|
||||
# remove other /W[0-4] flags will result in a warning about overriding a
|
||||
# previous flag.
|
||||
if (COMPILER_RT_HAS_W4_FLAG)
|
||||
string(REGEX REPLACE " /W[0-4]" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
|
||||
string(REGEX REPLACE " /W[0-4]" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
append_string_if(COMPILER_RT_HAS_W4_FLAG /W4 CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
|
||||
endif()
|
||||
else()
|
||||
append_string_if(COMPILER_RT_HAS_WALL_FLAG -Wall CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
|
||||
endif()
|
||||
if(COMPILER_RT_ENABLE_WERROR)
|
||||
append_string_if(COMPILER_RT_HAS_WERROR_FLAG -Werror CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
|
||||
append_string_if(COMPILER_RT_HAS_WX_FLAG /WX CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
|
||||
endif()
|
||||
|
||||
append_string_if(COMPILER_RT_HAS_STD_CXX11_FLAG -std=c++11 CMAKE_CXX_FLAGS)
|
||||
|
||||
# Emulate C99 and C++11's __func__ for MSVC prior to 2013 CTP.
|
||||
if(NOT COMPILER_RT_HAS_FUNC_SYMBOL)
|
||||
add_definitions(-D__func__=__FUNCTION__)
|
||||
endif()
|
||||
|
||||
# Provide some common commmandline flags for Sanitizer runtimes.
|
||||
if(NOT WIN32)
|
||||
append_list_if(COMPILER_RT_HAS_FPIC_FLAG -fPIC SANITIZER_COMMON_CFLAGS)
|
||||
endif()
|
||||
append_list_if(COMPILER_RT_HAS_FNO_BUILTIN_FLAG -fno-builtin SANITIZER_COMMON_CFLAGS)
|
||||
append_list_if(COMPILER_RT_HAS_FNO_EXCEPTIONS_FLAG -fno-exceptions SANITIZER_COMMON_CFLAGS)
|
||||
if(NOT COMPILER_RT_DEBUG AND NOT APPLE)
|
||||
append_list_if(COMPILER_RT_HAS_FOMIT_FRAME_POINTER_FLAG -fomit-frame-pointer SANITIZER_COMMON_CFLAGS)
|
||||
endif()
|
||||
append_list_if(COMPILER_RT_HAS_FUNWIND_TABLES_FLAG -funwind-tables SANITIZER_COMMON_CFLAGS)
|
||||
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
|
||||
# that requires -fno-function-sections to work properly. If lacking, the ASan
|
||||
# Linux test function-sections-are-bad.cc fails with the following error:
|
||||
# 'undefined symbol: __sanitizer_unaligned_load32'.
|
||||
if(DEFINED TARGET_powerpc64le_CFLAGS)
|
||||
append_list_if(COMPILER_RT_HAS_FNO_FUNCTION_SECTIONS_FLAG -fno-function-sections TARGET_powerpc64le_CFLAGS)
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
# Replace the /M[DT][d] flags with /MT, and strip any definitions of _DEBUG,
|
||||
# which cause definition mismatches at link time.
|
||||
# FIXME: In fact, sanitizers should support both /MT and /MD, see PR20214.
|
||||
if(COMPILER_RT_HAS_MT_FLAG)
|
||||
foreach(flag_var
|
||||
CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
|
||||
CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO
|
||||
CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
|
||||
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
|
||||
string(REGEX REPLACE "/M[DT]d" "/MT" ${flag_var} "${${flag_var}}")
|
||||
string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
|
||||
string(REGEX REPLACE "/D_DEBUG" "" ${flag_var} "${${flag_var}}")
|
||||
endforeach()
|
||||
endif()
|
||||
append_list_if(COMPILER_RT_HAS_Oy_FLAG /Oy- SANITIZER_COMMON_CFLAGS)
|
||||
append_list_if(COMPILER_RT_HAS_GS_FLAG /GS- SANITIZER_COMMON_CFLAGS)
|
||||
# VS 2015 (version 1900) added support for thread safe static initialization.
|
||||
# However, ASan interceptors run before CRT initialization, which causes the
|
||||
# new thread safe code to crash. Disable this feature for now.
|
||||
if (MSVC_VERSION GREATER 1899 OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
|
||||
list(APPEND SANITIZER_COMMON_CFLAGS /Zc:threadSafeInit-)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
append_list_if(COMPILER_RT_DEBUG -DSANITIZER_DEBUG=1 SANITIZER_COMMON_CFLAGS)
|
||||
|
||||
# If we're using MSVC,
|
||||
# always respect the optimization flags set by CMAKE_BUILD_TYPE instead.
|
||||
if (NOT MSVC)
|
||||
|
||||
# Build with optimization, unless we're in debug mode.
|
||||
if(COMPILER_RT_DEBUG)
|
||||
list(APPEND SANITIZER_COMMON_CFLAGS -O0)
|
||||
else()
|
||||
list(APPEND SANITIZER_COMMON_CFLAGS -O3)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Determine if we should restrict stack frame sizes.
|
||||
# Stack frames on PowerPC and Mips and in debug biuld can be much larger than
|
||||
# anticipated.
|
||||
# FIXME: Fix all sanitizers and add -Wframe-larger-than to
|
||||
# SANITIZER_COMMON_FLAGS
|
||||
if(COMPILER_RT_HAS_WFRAME_LARGER_THAN_FLAG AND NOT COMPILER_RT_DEBUG
|
||||
AND NOT ${COMPILER_RT_DEFAULT_TARGET_ARCH} MATCHES "powerpc|mips")
|
||||
set(SANITIZER_LIMIT_FRAME_SIZE TRUE)
|
||||
else()
|
||||
set(SANITIZER_LIMIT_FRAME_SIZE FALSE)
|
||||
endif()
|
||||
|
||||
if(FUCHSIA OR UNIX)
|
||||
set(SANITIZER_USE_SYMBOLS TRUE)
|
||||
else()
|
||||
set(SANITIZER_USE_SYMBOLS FALSE)
|
||||
endif()
|
||||
|
||||
# Build sanitizer runtimes with debug info.
|
||||
if(MSVC)
|
||||
# Use /Z7 instead of /Zi for the asan runtime. This avoids the LNK4099
|
||||
# warning from the MS linker complaining that it can't find the 'vc140.pdb'
|
||||
# file used by our object library compilations.
|
||||
list(APPEND SANITIZER_COMMON_CFLAGS /Z7)
|
||||
llvm_replace_compiler_option(CMAKE_CXX_FLAGS "/Z[i7I]" "/Z7")
|
||||
llvm_replace_compiler_option(CMAKE_CXX_FLAGS_DEBUG "/Z[i7I]" "/Z7")
|
||||
llvm_replace_compiler_option(CMAKE_CXX_FLAGS_RELWITHDEBINFO "/Z[i7I]" "/Z7")
|
||||
elseif(COMPILER_RT_HAS_GLINE_TABLES_ONLY_FLAG AND NOT COMPILER_RT_DEBUG)
|
||||
list(APPEND SANITIZER_COMMON_CFLAGS -gline-tables-only)
|
||||
elseif(COMPILER_RT_HAS_G_FLAG)
|
||||
list(APPEND SANITIZER_COMMON_CFLAGS -g)
|
||||
endif()
|
||||
|
||||
if(LLVM_ENABLE_MODULES)
|
||||
# Sanitizers cannot be built with -fmodules. The interceptors intentionally
|
||||
# don't include system headers, which is incompatible with modules.
|
||||
list(APPEND SANITIZER_COMMON_CFLAGS -fno-modules)
|
||||
endif()
|
||||
|
||||
# Turn off several warnings.
|
||||
append_list_if(COMPILER_RT_HAS_WGNU_FLAG -Wno-gnu SANITIZER_COMMON_CFLAGS)
|
||||
append_list_if(COMPILER_RT_HAS_WVARIADIC_MACROS_FLAG -Wno-variadic-macros SANITIZER_COMMON_CFLAGS)
|
||||
append_list_if(COMPILER_RT_HAS_WC99_EXTENSIONS_FLAG -Wno-c99-extensions SANITIZER_COMMON_CFLAGS)
|
||||
append_list_if(COMPILER_RT_HAS_WNON_VIRTUAL_DTOR_FLAG -Wno-non-virtual-dtor SANITIZER_COMMON_CFLAGS)
|
||||
append_list_if(COMPILER_RT_HAS_WD4146_FLAG /wd4146 SANITIZER_COMMON_CFLAGS)
|
||||
append_list_if(COMPILER_RT_HAS_WD4291_FLAG /wd4291 SANITIZER_COMMON_CFLAGS)
|
||||
append_list_if(COMPILER_RT_HAS_WD4391_FLAG /wd4391 SANITIZER_COMMON_CFLAGS)
|
||||
append_list_if(COMPILER_RT_HAS_WD4722_FLAG /wd4722 SANITIZER_COMMON_CFLAGS)
|
||||
append_list_if(COMPILER_RT_HAS_WD4800_FLAG /wd4800 SANITIZER_COMMON_CFLAGS)
|
||||
|
||||
append_list_if(MINGW -fms-extensions SANITIZER_COMMON_CFLAGS)
|
||||
|
||||
# Set common link flags.
|
||||
append_list_if(COMPILER_RT_HAS_NODEFAULTLIBS_FLAG -nodefaultlibs SANITIZER_COMMON_LINK_FLAGS)
|
||||
|
||||
if (COMPILER_RT_USE_BUILTINS_LIBRARY)
|
||||
list(APPEND SANITIZER_COMMON_LINK_LIBS ${COMPILER_RT_BUILTINS_LIBRARY})
|
||||
string(REPLACE "-Wl,-z,defs" "" CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}")
|
||||
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()
|
||||
|
||||
if (SANITIZER_CXX_ABI_LIBNAME STREQUAL "libc++")
|
||||
if (SANITIZER_CXX_ABI_INTREE)
|
||||
if (NOT LIBCXXABI_ENABLE_STATIC_UNWINDER AND (TARGET unwind_shared OR HAVE_LIBUNWIND))
|
||||
list(APPEND SANITIZER_CXX_ABI_LIBRARY unwind_shared)
|
||||
elseif (LIBCXXABI_ENABLE_STATIC_UNWINDER AND (TARGET unwind_static OR HAVE_LIBUNWIND))
|
||||
list(APPEND SANITIZER_CXX_ABI_LIBRARY unwind_static)
|
||||
endif()
|
||||
if (NOT LIBCXX_ENABLE_STATIC_ABI_LIBRARY AND (TARGET cxxabi_shared OR HAVE_LIBCXXABI))
|
||||
list(APPEND SANITIZER_CXX_ABI_LIBRARY cxxabi_shared)
|
||||
elseif (LIBCXX_ENABLE_STATIC_ABI_LIBRARY AND (TARGET cxxabi_static OR HAVE_LIBCXXABI))
|
||||
list(APPEND SANITIZER_CXX_ABI_LIBRARY cxxabi_static)
|
||||
endif()
|
||||
else()
|
||||
append_list_if(COMPILER_RT_HAS_LIBCXX c++ SANITIZER_CXX_ABI_LIBRARY)
|
||||
endif()
|
||||
elseif (SANITIZER_CXX_ABI_LIBNAME STREQUAL "libcxxabi")
|
||||
list(APPEND SANITIZER_CXX_ABI_LIBRARY "c++abi")
|
||||
elseif (SANITIZER_CXX_ABI_LIBNAME STREQUAL "libstdc++")
|
||||
append_list_if(COMPILER_RT_HAS_LIBSTDCXX stdc++ SANITIZER_CXX_ABI_LIBRARY)
|
||||
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)
|
||||
|
||||
if (CMAKE_LINKER MATCHES "link.exe$")
|
||||
# Silence MSVC linker warnings caused by empty object files. The
|
||||
# sanitizer libraries intentionally use ifdefs that result in empty
|
||||
# files, rather than skipping these files in the build system.
|
||||
# Ideally, we would pass this flag only for the libraries that need
|
||||
# it, but CMake doesn't seem to have a way to set linker flags for
|
||||
# individual static libraries, so we enable the suppression flag for
|
||||
# the whole compiler-rt project.
|
||||
set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /IGNORE:4221")
|
||||
endif()
|
||||
|
||||
add_subdirectory(include)
|
||||
|
||||
option(COMPILER_RT_USE_LIBCXX
|
||||
"Enable compiler-rt to use libc++ from the source tree" ON)
|
||||
if(COMPILER_RT_USE_LIBCXX)
|
||||
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()
|
||||
endif()
|
||||
|
||||
set(COMPILER_RT_LLD_PATH ${LLVM_MAIN_SRC_DIR}/tools/lld)
|
||||
if(EXISTS ${COMPILER_RT_LLD_PATH}/ AND LLVM_TOOL_LLD_BUILD)
|
||||
set(COMPILER_RT_HAS_LLD TRUE)
|
||||
else()
|
||||
set(COMPILER_RT_LLD_PATH ${LLVM_MAIN_SRC_DIR}/../lld)
|
||||
if(EXISTS ${COMPILER_RT_LLD_PATH}/ AND LLVM_TOOL_LLD_BUILD)
|
||||
set(COMPILER_RT_HAS_LLD TRUE)
|
||||
else()
|
||||
set(COMPILER_RT_HAS_LLD FALSE)
|
||||
endif()
|
||||
endif()
|
||||
pythonize_bool(COMPILER_RT_HAS_LLD)
|
||||
|
||||
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()
|
@ -1,53 +0,0 @@
|
||||
This file is a list of the people responsible for ensuring that patches for a
|
||||
particular part of compiler-rt are reviewed, either by themself or by
|
||||
someone else. They are also the gatekeepers for their part of compiler-rt, with
|
||||
the final word on what goes in or not.
|
||||
|
||||
The list is sorted by surname and formatted to allow easy grepping and
|
||||
beautification by scripts. The fields are: name (N), email (E), web-address
|
||||
(W), PGP key ID and fingerprint (P), description (D), and snail-mail address
|
||||
(S).
|
||||
|
||||
N: Peter Collingbourne
|
||||
E: peter@pcc.me.uk
|
||||
D: DataFlowSanitizer
|
||||
|
||||
N: Daniel Dunbar
|
||||
E: daniel@zuster.org
|
||||
D: Makefile build
|
||||
|
||||
N: Timur Iskhodzhanov
|
||||
E: timurrrr@google.com
|
||||
D: AddressSanitizer for Windows
|
||||
|
||||
N: Howard Hinnant
|
||||
E: howard.hinnant@gmail.com
|
||||
D: builtins library
|
||||
|
||||
N: Alexander Potapenko
|
||||
E: glider@google.com
|
||||
D: MacOS/iOS port of sanitizers
|
||||
|
||||
N: Alexey Samsonov
|
||||
E: samsonov@google.com
|
||||
D: CMake build, test suite
|
||||
|
||||
N: Kostya Serebryany
|
||||
E: kcc@google.com
|
||||
D: AddressSanitizer, sanitizer_common, porting sanitizers to another platforms, LeakSanitizer
|
||||
|
||||
N: Richard Smith
|
||||
E: richard-llvm@metafoo.co.uk
|
||||
D: UndefinedBehaviorSanitizer
|
||||
|
||||
N: Evgeniy Stepanov
|
||||
E: eugenis@google.com
|
||||
D: MemorySanitizer, Android port of sanitizers
|
||||
|
||||
N: Dmitry Vyukov
|
||||
E: dvyukov@google.com
|
||||
D: ThreadSanitizer
|
||||
|
||||
N: Bill Wendling
|
||||
E: isanbard@gmail.com
|
||||
D: Profile runtime library
|
@ -1,670 +0,0 @@
|
||||
include(ExternalProject)
|
||||
include(CompilerRTUtils)
|
||||
|
||||
function(set_target_output_directories target output_dir)
|
||||
# For RUNTIME_OUTPUT_DIRECTORY variable, Multi-configuration generators
|
||||
# append a per-configuration subdirectory to the specified directory.
|
||||
# To avoid the appended folder, the configuration specific variable must be
|
||||
# set 'RUNTIME_OUTPUT_DIRECTORY_${CONF}':
|
||||
# RUNTIME_OUTPUT_DIRECTORY_DEBUG, RUNTIME_OUTPUT_DIRECTORY_RELEASE, ...
|
||||
if(CMAKE_CONFIGURATION_TYPES)
|
||||
foreach(build_mode ${CMAKE_CONFIGURATION_TYPES})
|
||||
string(TOUPPER "${build_mode}" CONFIG_SUFFIX)
|
||||
set_target_properties("${target}" PROPERTIES
|
||||
"ARCHIVE_OUTPUT_DIRECTORY_${CONFIG_SUFFIX}" ${output_dir}
|
||||
"LIBRARY_OUTPUT_DIRECTORY_${CONFIG_SUFFIX}" ${output_dir}
|
||||
"RUNTIME_OUTPUT_DIRECTORY_${CONFIG_SUFFIX}" ${output_dir})
|
||||
endforeach()
|
||||
else()
|
||||
set_target_properties("${target}" PROPERTIES
|
||||
ARCHIVE_OUTPUT_DIRECTORY ${output_dir}
|
||||
LIBRARY_OUTPUT_DIRECTORY ${output_dir}
|
||||
RUNTIME_OUTPUT_DIRECTORY ${output_dir})
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Tries to add an "object library" target for a given list of OSs and/or
|
||||
# architectures with name "<name>.<arch>" for non-Darwin platforms if
|
||||
# architecture can be targeted, and "<name>.<os>" for Darwin platforms.
|
||||
# add_compiler_rt_object_libraries(<name>
|
||||
# OS <os names>
|
||||
# ARCHS <architectures>
|
||||
# SOURCES <source files>
|
||||
# CFLAGS <compile flags>
|
||||
# DEFS <compile definitions>
|
||||
# DEPS <dependencies>
|
||||
# ADDITIONAL_HEADERS <header files>)
|
||||
function(add_compiler_rt_object_libraries name)
|
||||
cmake_parse_arguments(LIB "" "" "OS;ARCHS;SOURCES;CFLAGS;DEFS;DEPS;ADDITIONAL_HEADERS"
|
||||
${ARGN})
|
||||
set(libnames)
|
||||
if(APPLE)
|
||||
foreach(os ${LIB_OS})
|
||||
set(libname "${name}.${os}")
|
||||
set(libnames ${libnames} ${libname})
|
||||
set(extra_cflags_${libname} ${DARWIN_${os}_CFLAGS})
|
||||
list_intersect(LIB_ARCHS_${libname} DARWIN_${os}_ARCHS LIB_ARCHS)
|
||||
endforeach()
|
||||
else()
|
||||
foreach(arch ${LIB_ARCHS})
|
||||
set(libname "${name}.${arch}")
|
||||
set(libnames ${libnames} ${libname})
|
||||
set(extra_cflags_${libname} ${TARGET_${arch}_CFLAGS})
|
||||
if(NOT CAN_TARGET_${arch})
|
||||
message(FATAL_ERROR "Architecture ${arch} can't be targeted")
|
||||
return()
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
# Add headers to LIB_SOURCES for IDEs
|
||||
compiler_rt_process_sources(LIB_SOURCES
|
||||
${LIB_SOURCES}
|
||||
ADDITIONAL_HEADERS
|
||||
${LIB_ADDITIONAL_HEADERS}
|
||||
)
|
||||
|
||||
foreach(libname ${libnames})
|
||||
add_library(${libname} OBJECT ${LIB_SOURCES})
|
||||
if(LIB_DEPS)
|
||||
add_dependencies(${libname} ${LIB_DEPS})
|
||||
endif()
|
||||
|
||||
# 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}
|
||||
${extra_cflags_${libname}} ${target_flags})
|
||||
set_property(TARGET ${libname} APPEND PROPERTY
|
||||
COMPILE_DEFINITIONS ${LIB_DEFS})
|
||||
set_target_properties(${libname} PROPERTIES FOLDER "Compiler-RT Libraries")
|
||||
if(APPLE)
|
||||
set_target_properties(${libname} PROPERTIES
|
||||
OSX_ARCHITECTURES "${LIB_ARCHS_${libname}}")
|
||||
endif()
|
||||
endforeach()
|
||||
endfunction()
|
||||
|
||||
# Takes a list of object library targets, and a suffix and appends the proper
|
||||
# TARGET_OBJECTS string to the output variable.
|
||||
# format_object_libs(<output> <suffix> ...)
|
||||
macro(format_object_libs output suffix)
|
||||
foreach(lib ${ARGN})
|
||||
list(APPEND ${output} $<TARGET_OBJECTS:${lib}.${suffix}>)
|
||||
endforeach()
|
||||
endmacro()
|
||||
|
||||
function(add_compiler_rt_component name)
|
||||
add_custom_target(${name})
|
||||
set_target_properties(${name} PROPERTIES FOLDER "Compiler-RT Misc")
|
||||
if(COMMAND runtime_register_component)
|
||||
runtime_register_component(${name})
|
||||
endif()
|
||||
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(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR)
|
||||
set(${output} ${name})
|
||||
else()
|
||||
if(ANDROID AND ${arch} STREQUAL "i386")
|
||||
set(${output} "${name}-i686${COMPILER_RT_OS_SUFFIX}")
|
||||
else()
|
||||
set(${output} "${name}-${arch}${COMPILER_RT_OS_SUFFIX}")
|
||||
endif()
|
||||
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>
|
||||
# {STATIC|SHARED}
|
||||
# ARCHS <architectures>
|
||||
# OS <os list>
|
||||
# SOURCES <source files>
|
||||
# CFLAGS <compile flags>
|
||||
# LINK_FLAGS <linker flags>
|
||||
# DEFS <compile definitions>
|
||||
# LINK_LIBS <linked libraries> (only for shared library)
|
||||
# OBJECT_LIBS <object libraries to use as sources>
|
||||
# PARENT_TARGET <convenience parent target>
|
||||
# ADDITIONAL_HEADERS <header files>)
|
||||
function(add_compiler_rt_runtime name type)
|
||||
if(NOT type MATCHES "^(STATIC|SHARED)$")
|
||||
message(FATAL_ERROR "type argument must be STATIC or SHARED")
|
||||
return()
|
||||
endif()
|
||||
cmake_parse_arguments(LIB
|
||||
""
|
||||
"PARENT_TARGET"
|
||||
"OS;ARCHS;SOURCES;CFLAGS;LINK_FLAGS;DEFS;LINK_LIBS;OBJECT_LIBS;ADDITIONAL_HEADERS"
|
||||
${ARGN})
|
||||
set(libnames)
|
||||
# Until we support this some other way, build compiler-rt runtime without LTO
|
||||
# to allow non-LTO projects to link with it.
|
||||
if(COMPILER_RT_HAS_FNO_LTO_FLAG)
|
||||
set(NO_LTO_FLAGS "-fno-lto")
|
||||
else()
|
||||
set(NO_LTO_FLAGS "")
|
||||
endif()
|
||||
|
||||
list(LENGTH LIB_SOURCES LIB_SOURCES_LENGTH)
|
||||
if (${LIB_SOURCES_LENGTH} GREATER 0)
|
||||
# Add headers to LIB_SOURCES for IDEs. It doesn't make sense to
|
||||
# do this for a runtime library that only consists of OBJECT
|
||||
# libraries, so only add the headers when source files are present.
|
||||
compiler_rt_process_sources(LIB_SOURCES
|
||||
${LIB_SOURCES}
|
||||
ADDITIONAL_HEADERS
|
||||
${LIB_ADDITIONAL_HEADERS}
|
||||
)
|
||||
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()
|
||||
set(libname "${name}_${os}_dynamic")
|
||||
set(extra_link_flags_${libname} ${DARWIN_${os}_LINK_FLAGS} ${LIB_LINK_FLAGS})
|
||||
endif()
|
||||
list_intersect(LIB_ARCHS_${libname} DARWIN_${os}_ARCHS LIB_ARCHS)
|
||||
if(LIB_ARCHS_${libname})
|
||||
list(APPEND libnames ${libname})
|
||||
set(extra_cflags_${libname} ${DARWIN_${os}_CFLAGS} ${NO_LTO_FLAGS} ${LIB_CFLAGS})
|
||||
set(output_name_${libname} ${libname}${COMPILER_RT_OS_SUFFIX})
|
||||
set(sources_${libname} ${LIB_SOURCES})
|
||||
format_object_libs(sources_${libname} ${os} ${LIB_OBJECT_LIBS})
|
||||
get_compiler_rt_output_dir(${COMPILER_RT_DEFAULT_TARGET_ARCH} output_dir_${libname})
|
||||
get_compiler_rt_install_dir(${COMPILER_RT_DEFAULT_TARGET_ARCH} install_dir_${libname})
|
||||
endif()
|
||||
endforeach()
|
||||
else()
|
||||
foreach(arch ${LIB_ARCHS})
|
||||
if(NOT CAN_TARGET_${arch})
|
||||
message(FATAL_ERROR "Architecture ${arch} can't be targeted")
|
||||
return()
|
||||
endif()
|
||||
if(type STREQUAL "STATIC")
|
||||
set(libname "${name}-${arch}")
|
||||
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(output_name_${libname} ${name}_dynamic ${arch})
|
||||
else()
|
||||
set_output_name(output_name_${libname} ${name} ${arch})
|
||||
endif()
|
||||
endif()
|
||||
set(sources_${libname} ${LIB_SOURCES})
|
||||
format_object_libs(sources_${libname} ${arch} ${LIB_OBJECT_LIBS})
|
||||
set(libnames ${libnames} ${libname})
|
||||
set(extra_cflags_${libname} ${TARGET_${arch}_CFLAGS} ${NO_LTO_FLAGS} ${LIB_CFLAGS})
|
||||
get_compiler_rt_output_dir(${arch} output_dir_${libname})
|
||||
get_compiler_rt_install_dir(${arch} install_dir_${libname})
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if(NOT libnames)
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(LIB_PARENT_TARGET)
|
||||
# If the parent targets aren't created we should create them
|
||||
if(NOT TARGET ${LIB_PARENT_TARGET})
|
||||
add_custom_target(${LIB_PARENT_TARGET})
|
||||
set_target_properties(${LIB_PARENT_TARGET} PROPERTIES
|
||||
FOLDER "Compiler-RT Misc")
|
||||
endif()
|
||||
if(NOT TARGET install-${LIB_PARENT_TARGET})
|
||||
# The parent install target specifies the parent component to scrape up
|
||||
# anything not installed by the individual install targets, and to handle
|
||||
# installation when running the multi-configuration generators.
|
||||
add_custom_target(install-${LIB_PARENT_TARGET}
|
||||
DEPENDS ${LIB_PARENT_TARGET}
|
||||
COMMAND "${CMAKE_COMMAND}"
|
||||
-DCMAKE_INSTALL_COMPONENT=${LIB_PARENT_TARGET}
|
||||
-P "${CMAKE_BINARY_DIR}/cmake_install.cmake")
|
||||
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()
|
||||
|
||||
foreach(libname ${libnames})
|
||||
# If you are using a multi-configuration generator we don't generate
|
||||
# per-library install rules, so we fall back to the parent target COMPONENT
|
||||
if(CMAKE_CONFIGURATION_TYPES AND LIB_PARENT_TARGET)
|
||||
set(COMPONENT_OPTION COMPONENT ${LIB_PARENT_TARGET})
|
||||
else()
|
||||
set(COMPONENT_OPTION COMPONENT ${libname})
|
||||
endif()
|
||||
|
||||
add_library(${libname} ${type} ${sources_${libname}})
|
||||
set_target_compile_flags(${libname} ${extra_cflags_${libname}})
|
||||
set_target_link_flags(${libname} ${extra_link_flags_${libname}})
|
||||
set_property(TARGET ${libname} APPEND PROPERTY
|
||||
COMPILE_DEFINITIONS ${LIB_DEFS})
|
||||
set_target_output_directories(${libname} ${output_dir_${libname}})
|
||||
set_target_properties(${libname} PROPERTIES
|
||||
OUTPUT_NAME ${output_name_${libname}})
|
||||
set_target_properties(${libname} PROPERTIES FOLDER "Compiler-RT Runtime")
|
||||
if(LIB_LINK_LIBS)
|
||||
target_link_libraries(${libname} ${LIB_LINK_LIBS})
|
||||
endif()
|
||||
if(${type} STREQUAL "SHARED")
|
||||
if(COMMAND llvm_setup_rpath)
|
||||
llvm_setup_rpath(${libname})
|
||||
endif()
|
||||
if(WIN32 AND NOT CYGWIN AND NOT MINGW)
|
||||
set_target_properties(${libname} PROPERTIES IMPORT_PREFIX "")
|
||||
set_target_properties(${libname} PROPERTIES IMPORT_SUFFIX ".lib")
|
||||
endif()
|
||||
if(APPLE)
|
||||
# Ad-hoc sign the dylibs
|
||||
add_custom_command(TARGET ${libname}
|
||||
POST_BUILD
|
||||
COMMAND codesign --sign - $<TARGET_FILE:${libname}>
|
||||
WORKING_DIRECTORY ${COMPILER_RT_LIBRARY_OUTPUT_DIR}
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
install(TARGETS ${libname}
|
||||
ARCHIVE DESTINATION ${install_dir_${libname}}
|
||||
${COMPONENT_OPTION}
|
||||
LIBRARY DESTINATION ${install_dir_${libname}}
|
||||
${COMPONENT_OPTION}
|
||||
RUNTIME DESTINATION ${install_dir_${libname}}
|
||||
${COMPONENT_OPTION})
|
||||
|
||||
# We only want to generate per-library install targets if you aren't using
|
||||
# an IDE because the extra targets get cluttered in IDEs.
|
||||
if(NOT CMAKE_CONFIGURATION_TYPES)
|
||||
add_custom_target(install-${libname}
|
||||
DEPENDS ${libname}
|
||||
COMMAND "${CMAKE_COMMAND}"
|
||||
-DCMAKE_INSTALL_COMPONENT=${libname}
|
||||
-P "${CMAKE_BINARY_DIR}/cmake_install.cmake")
|
||||
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)
|
||||
set_target_properties(${libname} PROPERTIES
|
||||
OSX_ARCHITECTURES "${LIB_ARCHS_${libname}}")
|
||||
endif()
|
||||
|
||||
if(type STREQUAL "SHARED")
|
||||
rt_externalize_debuginfo(${libname})
|
||||
endif()
|
||||
endforeach()
|
||||
if(LIB_PARENT_TARGET)
|
||||
add_dependencies(${LIB_PARENT_TARGET} ${libnames})
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# when cross compiling, COMPILER_RT_TEST_COMPILER_CFLAGS help
|
||||
# in compilation and linking of unittests.
|
||||
string(REPLACE " " ";" COMPILER_RT_UNITTEST_CFLAGS "${COMPILER_RT_TEST_COMPILER_CFLAGS}")
|
||||
set(COMPILER_RT_UNITTEST_LINK_FLAGS ${COMPILER_RT_UNITTEST_CFLAGS})
|
||||
|
||||
# Unittests support.
|
||||
set(COMPILER_RT_GTEST_PATH ${LLVM_MAIN_SRC_DIR}/utils/unittest/googletest)
|
||||
set(COMPILER_RT_GTEST_SOURCE ${COMPILER_RT_GTEST_PATH}/src/gtest-all.cc)
|
||||
set(COMPILER_RT_GTEST_CFLAGS
|
||||
-DGTEST_NO_LLVM_RAW_OSTREAM=1
|
||||
-DGTEST_HAS_RTTI=0
|
||||
-I${COMPILER_RT_GTEST_PATH}/include
|
||||
-I${COMPILER_RT_GTEST_PATH}
|
||||
)
|
||||
|
||||
# Mocking support.
|
||||
set(COMPILER_RT_GMOCK_PATH ${LLVM_MAIN_SRC_DIR}/utils/unittest/googlemock)
|
||||
set(COMPILER_RT_GMOCK_SOURCE ${COMPILER_RT_GMOCK_PATH}/src/gmock-all.cc)
|
||||
set(COMPILER_RT_GMOCK_CFLAGS
|
||||
-DGTEST_NO_LLVM_RAW_OSTREAM=1
|
||||
-DGTEST_HAS_RTTI=0
|
||||
-I${COMPILER_RT_GMOCK_PATH}/include
|
||||
-I${COMPILER_RT_GMOCK_PATH}
|
||||
)
|
||||
|
||||
append_list_if(COMPILER_RT_DEBUG -DSANITIZER_DEBUG=1 COMPILER_RT_UNITTEST_CFLAGS)
|
||||
append_list_if(COMPILER_RT_HAS_WCOVERED_SWITCH_DEFAULT_FLAG -Wno-covered-switch-default COMPILER_RT_UNITTEST_CFLAGS)
|
||||
|
||||
if(MSVC)
|
||||
# gtest use a lot of stuff marked as deprecated on Windows.
|
||||
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> <arch>
|
||||
# SUBDIR <subdirectory for binary>
|
||||
# OBJECTS <object files>
|
||||
# DEPS <deps (e.g. runtime libs)>
|
||||
# LINK_FLAGS <link flags>)
|
||||
function(add_compiler_rt_test test_suite test_name arch)
|
||||
cmake_parse_arguments(TEST "" "SUBDIR" "OBJECTS;DEPS;LINK_FLAGS" "" ${ARGN})
|
||||
set(output_dir ${CMAKE_CURRENT_BINARY_DIR})
|
||||
if(TEST_SUBDIR)
|
||||
set(output_dir "${output_dir}/${TEST_SUBDIR}")
|
||||
endif()
|
||||
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()
|
||||
|
||||
# Use host compiler in a standalone build, and just-built Clang otherwise.
|
||||
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
|
||||
# trump. With MSVC we can't do that because CMake is set up to run link.exe
|
||||
# when linking, not the compiler. Here, we hack it to use the compiler
|
||||
# because we want to use -fsanitize flags.
|
||||
if(NOT MSVC)
|
||||
set(TEST_LINK_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${TEST_LINK_FLAGS}")
|
||||
separate_arguments(TEST_LINK_FLAGS)
|
||||
endif()
|
||||
add_custom_command(
|
||||
OUTPUT "${output_bin}"
|
||||
COMMAND ${COMPILER_RT_TEST_COMPILER} ${TEST_OBJECTS} -o "${output_bin}"
|
||||
${TEST_LINK_FLAGS}
|
||||
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} T${test_name})
|
||||
endfunction()
|
||||
|
||||
macro(add_compiler_rt_resource_file target_name file_name component)
|
||||
set(src_file "${CMAKE_CURRENT_SOURCE_DIR}/${file_name}")
|
||||
set(dst_file "${COMPILER_RT_OUTPUT_DIR}/share/${file_name}")
|
||||
add_custom_command(OUTPUT ${dst_file}
|
||||
DEPENDS ${src_file}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${src_file} ${dst_file}
|
||||
COMMENT "Copying ${file_name}...")
|
||||
add_custom_target(${target_name} DEPENDS ${dst_file})
|
||||
# Install in Clang resource directory.
|
||||
install(FILES ${file_name}
|
||||
DESTINATION ${COMPILER_RT_INSTALL_PATH}/share
|
||||
COMPONENT ${component})
|
||||
add_dependencies(${component} ${target_name})
|
||||
|
||||
set_target_properties(${target_name} PROPERTIES FOLDER "Compiler-RT Misc")
|
||||
endmacro()
|
||||
|
||||
macro(add_compiler_rt_script name)
|
||||
set(dst ${COMPILER_RT_EXEC_OUTPUT_DIR}/${name})
|
||||
set(src ${CMAKE_CURRENT_SOURCE_DIR}/${name})
|
||||
add_custom_command(OUTPUT ${dst}
|
||||
DEPENDS ${src}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${src} ${dst}
|
||||
COMMENT "Copying ${name}...")
|
||||
add_custom_target(${name} DEPENDS ${dst})
|
||||
install(FILES ${dst}
|
||||
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
|
||||
DESTINATION ${COMPILER_RT_INSTALL_PATH}/bin)
|
||||
endmacro(add_compiler_rt_script src name)
|
||||
|
||||
# Builds custom version of libc++ and installs it in <prefix>.
|
||||
# Can be used to build sanitized versions of libc++ for running unit tests.
|
||||
# add_custom_libcxx(<name> <prefix>
|
||||
# DEPS <list of build deps>
|
||||
# CFLAGS <list of compile flags>
|
||||
# USE_TOOLCHAIN)
|
||||
macro(add_custom_libcxx name prefix)
|
||||
if(NOT COMPILER_RT_LIBCXX_PATH)
|
||||
message(FATAL_ERROR "libcxx not found!")
|
||||
endif()
|
||||
|
||||
cmake_parse_arguments(LIBCXX "USE_TOOLCHAIN" "" "DEPS;CFLAGS;CMAKE_ARGS" ${ARGN})
|
||||
|
||||
if(LIBCXX_USE_TOOLCHAIN)
|
||||
set(compiler_args -DCMAKE_C_COMPILER=${COMPILER_RT_TEST_COMPILER}
|
||||
-DCMAKE_CXX_COMPILER=${COMPILER_RT_TEST_CXX_COMPILER})
|
||||
if(NOT COMPILER_RT_STANDALONE_BUILD)
|
||||
set(toolchain_deps $<TARGET_FILE:clang>)
|
||||
set(force_deps DEPENDS $<TARGET_FILE:clang>)
|
||||
endif()
|
||||
else()
|
||||
set(compiler_args -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}
|
||||
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER})
|
||||
endif()
|
||||
|
||||
set(STAMP_DIR ${prefix}-stamps/)
|
||||
set(BINARY_DIR ${prefix}-bins/)
|
||||
|
||||
add_custom_target(${name}-clear
|
||||
COMMAND ${CMAKE_COMMAND} -E remove_directory ${BINARY_DIR}
|
||||
COMMAND ${CMAKE_COMMAND} -E remove_directory ${STAMP_DIR}
|
||||
COMMENT "Clobbering ${name} build and stamp directories"
|
||||
USES_TERMINAL
|
||||
)
|
||||
set_target_properties(${name}-clear PROPERTIES FOLDER "Compiler-RT Misc")
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${name}-clobber-stamp
|
||||
DEPENDS ${LIBCXX_DEPS} ${toolchain_deps}
|
||||
COMMAND ${CMAKE_COMMAND} -E touch ${BINARY_DIR}/CMakeCache.txt
|
||||
COMMAND ${CMAKE_COMMAND} -E touch ${STAMP_DIR}/${name}-mkdir
|
||||
COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/${name}-clobber-stamp
|
||||
COMMENT "Clobbering bootstrap build and stamp directories"
|
||||
)
|
||||
|
||||
add_custom_target(${name}-clobber
|
||||
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${name}-clobber-stamp)
|
||||
set_target_properties(${name}-clobber PROPERTIES FOLDER "Compiler-RT Misc")
|
||||
|
||||
set(PASSTHROUGH_VARIABLES
|
||||
CMAKE_C_COMPILER_TARGET
|
||||
CMAKE_CXX_COMPILER_TARGET
|
||||
CMAKE_SHARED_LINKER_FLAGS
|
||||
CMAKE_MODULE_LINKER_FLAGS
|
||||
CMAKE_EXE_LINKER_FLAGS
|
||||
CMAKE_INSTALL_PREFIX
|
||||
CMAKE_MAKE_PROGRAM
|
||||
CMAKE_LINKER
|
||||
CMAKE_AR
|
||||
CMAKE_RANLIB
|
||||
CMAKE_NM
|
||||
CMAKE_OBJCOPY
|
||||
CMAKE_OBJDUMP
|
||||
CMAKE_STRIP
|
||||
CMAKE_SYSROOT
|
||||
CMAKE_SYSTEM_NAME)
|
||||
foreach(variable ${PASSTHROUGH_VARIABLES})
|
||||
get_property(is_value_set CACHE ${variable} PROPERTY VALUE SET)
|
||||
if(${is_value_set})
|
||||
get_property(value CACHE ${variable} PROPERTY VALUE)
|
||||
list(APPEND CMAKE_PASSTHROUGH_VARIABLES -D${variable}=${value})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
string(REPLACE ";" " " LIBCXX_C_FLAGS "${LIBCXX_CFLAGS}")
|
||||
get_property(C_FLAGS CACHE CMAKE_C_FLAGS PROPERTY VALUE)
|
||||
set(LIBCXX_C_FLAGS "${LIBCXX_C_FLAGS} ${C_FLAGS}")
|
||||
|
||||
string(REPLACE ";" " " LIBCXX_CXX_FLAGS "${LIBCXX_CFLAGS}")
|
||||
get_property(CXX_FLAGS CACHE CMAKE_CXX_FLAGS PROPERTY VALUE)
|
||||
set(LIBCXX_CXX_FLAGS "${LIBCXX_CXX_FLAGS} ${CXX_FLAGS}")
|
||||
|
||||
ExternalProject_Add(${name}
|
||||
DEPENDS ${name}-clobber ${LIBCXX_DEPS}
|
||||
PREFIX ${prefix}
|
||||
SOURCE_DIR ${COMPILER_RT_LIBCXX_PATH}
|
||||
STAMP_DIR ${STAMP_DIR}
|
||||
BINARY_DIR ${BINARY_DIR}
|
||||
CMAKE_ARGS ${CMAKE_PASSTHROUGH_VARIABLES}
|
||||
${compiler_args}
|
||||
-DCMAKE_C_FLAGS=${LIBCXX_C_FLAGS}
|
||||
-DCMAKE_CXX_FLAGS=${LIBCXX_CXX_FLAGS}
|
||||
-DCMAKE_BUILD_TYPE=Release
|
||||
-DLLVM_PATH=${LLVM_MAIN_SRC_DIR}
|
||||
-DLLVM_BINARY_DIR=${prefix}
|
||||
-DLLVM_LIBRARY_OUTPUT_INTDIR=${prefix}/lib
|
||||
-DLIBCXX_STANDALONE_BUILD=ON
|
||||
${LIBCXX_CMAKE_ARGS}
|
||||
INSTALL_COMMAND ""
|
||||
STEP_TARGETS configure build
|
||||
BUILD_ALWAYS 1
|
||||
USES_TERMINAL_CONFIGURE 1
|
||||
USES_TERMINAL_BUILD 1
|
||||
USES_TERMINAL_INSTALL 1
|
||||
EXCLUDE_FROM_ALL TRUE
|
||||
)
|
||||
|
||||
if (CMAKE_GENERATOR MATCHES "Make")
|
||||
set(run_clean "$(MAKE)" "-C" "${BINARY_DIR}" "clean")
|
||||
else()
|
||||
set(run_clean ${CMAKE_COMMAND} --build ${BINARY_DIR} --target clean
|
||||
--config "$<CONFIGURATION>")
|
||||
endif()
|
||||
|
||||
ExternalProject_Add_Step(${name} clean
|
||||
COMMAND ${run_clean}
|
||||
COMMENT "Cleaning ${name}..."
|
||||
DEPENDEES configure
|
||||
${force_deps}
|
||||
WORKING_DIRECTORY ${BINARY_DIR}
|
||||
EXCLUDE_FROM_MAIN 1
|
||||
USES_TERMINAL 1
|
||||
)
|
||||
ExternalProject_Add_StepTargets(${name} clean)
|
||||
|
||||
if(LIBCXX_USE_TOOLCHAIN)
|
||||
add_dependencies(${name}-clean ${name}-clobber)
|
||||
set_target_properties(${name}-clean PROPERTIES
|
||||
SOURCES ${CMAKE_CURRENT_BINARY_DIR}/${name}-clobber-stamp)
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
function(rt_externalize_debuginfo name)
|
||||
if(NOT COMPILER_RT_EXTERNALIZE_DEBUGINFO)
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(NOT COMPILER_RT_EXTERNALIZE_DEBUGINFO_SKIP_STRIP)
|
||||
set(strip_command COMMAND xcrun strip -Sl $<TARGET_FILE:${name}>)
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
if(CMAKE_CXX_FLAGS MATCHES "-flto"
|
||||
OR CMAKE_CXX_FLAGS_${uppercase_CMAKE_BUILD_TYPE} MATCHES "-flto")
|
||||
|
||||
set(lto_object ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${name}-lto.o)
|
||||
set_property(TARGET ${name} APPEND_STRING PROPERTY
|
||||
LINK_FLAGS " -Wl,-object_path_lto -Wl,${lto_object}")
|
||||
endif()
|
||||
add_custom_command(TARGET ${name} POST_BUILD
|
||||
COMMAND xcrun dsymutil $<TARGET_FILE:${name}>
|
||||
${strip_command})
|
||||
else()
|
||||
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()
|
||||
|
||||
get_compiler_rt_output_dir(${COMPILER_RT_DEFAULT_TARGET_ARCH} output_dir)
|
||||
|
||||
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 ${output_dir})
|
||||
|
||||
configure_lit_site_cfg(${input} ${output})
|
||||
endfunction()
|
@ -1,98 +0,0 @@
|
||||
include(CMakeCheckCompilerFlagCommonPatterns)
|
||||
|
||||
# This function takes an OS and a list of architectures and identifies the
|
||||
# subset of the architectures list that the installed toolchain can target.
|
||||
function(try_compile_only output)
|
||||
cmake_parse_arguments(ARG "" "" "SOURCE;FLAGS" ${ARGN})
|
||||
if(NOT ARG_SOURCE)
|
||||
set(ARG_SOURCE "int foo(int x, int y) { return x + y; }\n")
|
||||
endif()
|
||||
set(SIMPLE_C ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/src.c)
|
||||
file(WRITE ${SIMPLE_C} "${ARG_SOURCE}\n")
|
||||
string(REGEX MATCHALL "<[A-Za-z0-9_]*>" substitutions
|
||||
${CMAKE_C_COMPILE_OBJECT})
|
||||
|
||||
set(TRY_COMPILE_FLAGS "${ARG_FLAGS}")
|
||||
if(CMAKE_C_COMPILER_ID MATCHES Clang AND CMAKE_C_COMPILER_TARGET)
|
||||
list(APPEND TRY_COMPILE_FLAGS "-target ${CMAKE_C_COMPILER_TARGET}")
|
||||
endif()
|
||||
|
||||
string(REPLACE ";" " " extra_flags "${TRY_COMPILE_FLAGS}")
|
||||
|
||||
set(test_compile_command "${CMAKE_C_COMPILE_OBJECT}")
|
||||
foreach(substitution ${substitutions})
|
||||
if(substitution STREQUAL "<CMAKE_C_COMPILER>")
|
||||
string(REPLACE "<CMAKE_C_COMPILER>"
|
||||
"${CMAKE_C_COMPILER}" test_compile_command ${test_compile_command})
|
||||
elseif(substitution STREQUAL "<OBJECT>")
|
||||
string(REPLACE "<OBJECT>"
|
||||
"${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/test.o"
|
||||
test_compile_command ${test_compile_command})
|
||||
elseif(substitution STREQUAL "<SOURCE>")
|
||||
string(REPLACE "<SOURCE>" "${SIMPLE_C}" test_compile_command
|
||||
${test_compile_command})
|
||||
elseif(substitution STREQUAL "<FLAGS>")
|
||||
string(REPLACE "<FLAGS>" "${CMAKE_C_FLAGS} ${extra_flags}"
|
||||
test_compile_command ${test_compile_command})
|
||||
else()
|
||||
string(REPLACE "${substitution}" "" test_compile_command
|
||||
${test_compile_command})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
string(REPLACE " " ";" test_compile_command "${test_compile_command}")
|
||||
|
||||
execute_process(
|
||||
COMMAND ${test_compile_command}
|
||||
RESULT_VARIABLE result
|
||||
OUTPUT_VARIABLE TEST_OUTPUT
|
||||
ERROR_VARIABLE TEST_ERROR
|
||||
)
|
||||
|
||||
CHECK_COMPILER_FLAG_COMMON_PATTERNS(_CheckCCompilerFlag_COMMON_PATTERNS)
|
||||
set(ERRORS_FOUND OFF)
|
||||
foreach(var ${_CheckCCompilerFlag_COMMON_PATTERNS})
|
||||
if("${var}" STREQUAL "FAIL_REGEX")
|
||||
continue()
|
||||
endif()
|
||||
if("${TEST_ERROR}" MATCHES "${var}" OR "${TEST_OUTPUT}" MATCHES "${var}")
|
||||
set(ERRORS_FOUND ON)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(result EQUAL 0 AND NOT ERRORS_FOUND)
|
||||
set(${output} True PARENT_SCOPE)
|
||||
else()
|
||||
file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
|
||||
"Testing compiler for supporting " ${ARGN} ":\n"
|
||||
"Command: ${test_compile_command}\n"
|
||||
"${TEST_OUTPUT}\n${TEST_ERROR}\n${result}\n")
|
||||
set(${output} False PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(builtin_check_c_compiler_flag flag output)
|
||||
if(NOT DEFINED ${output})
|
||||
message(STATUS "Performing Test ${output}")
|
||||
try_compile_only(result FLAGS ${flag})
|
||||
set(${output} ${result} CACHE INTERNAL "Compiler supports ${flag}")
|
||||
if(${result})
|
||||
message(STATUS "Performing Test ${output} - Success")
|
||||
else()
|
||||
message(STATUS "Performing Test ${output} - Failed")
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(builtin_check_c_compiler_source output source)
|
||||
if(NOT DEFINED ${output})
|
||||
message(STATUS "Performing Test ${output}")
|
||||
try_compile_only(result SOURCE ${source})
|
||||
set(${output} ${result} CACHE INTERNAL "Compiler supports ${flag}")
|
||||
if(${result})
|
||||
message(STATUS "Performing Test ${output} - Success")
|
||||
else()
|
||||
message(STATUS "Performing Test ${output} - Failed")
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
@ -1,143 +0,0 @@
|
||||
# On Windows, CMAKE_*_FLAGS are built for MSVC but we use the GCC clang.exe,
|
||||
# which uses completely different flags. Translate some common flag types, and
|
||||
# drop the rest.
|
||||
function(translate_msvc_cflags out_flags msvc_flags)
|
||||
# Insert an empty string in the list to simplify processing.
|
||||
set(msvc_flags ";${msvc_flags}")
|
||||
|
||||
# Canonicalize /flag to -flag.
|
||||
string(REPLACE ";/" ";-" msvc_flags "${msvc_flags}")
|
||||
|
||||
# Make space separated -D and -U flags into joined flags.
|
||||
string(REGEX REPLACE ";-\([DU]\);" ";-\\1" msvc_flags "${msvc_flags}")
|
||||
|
||||
set(clang_flags "")
|
||||
foreach(flag ${msvc_flags})
|
||||
if ("${flag}" MATCHES "^-[DU]")
|
||||
# Pass through basic command line macro definitions (-DNDEBUG).
|
||||
list(APPEND clang_flags "${flag}")
|
||||
elseif ("${flag}" MATCHES "^-O[2x]")
|
||||
# Canonicalize normal optimization flags to -O2.
|
||||
list(APPEND clang_flags "-O2")
|
||||
endif()
|
||||
endforeach()
|
||||
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>)
|
||||
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)
|
||||
list(APPEND SOURCE_DEPS clang compiler-rt-headers)
|
||||
endif()
|
||||
if (TARGET CompilerRTUnitTestCheckCxx)
|
||||
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()
|
||||
string(REPLACE " " ";" global_flags "${CMAKE_C_FLAGS}")
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
translate_msvc_cflags(global_flags "${global_flags}")
|
||||
endif()
|
||||
|
||||
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.
|
||||
list(APPEND global_flags -Wno-unknown-warning-option)
|
||||
set(compile_flags ${global_flags} ${SOURCE_CFLAGS})
|
||||
add_custom_command(
|
||||
OUTPUT ${object_file}
|
||||
COMMAND ${COMPILER_RT_TEST_COMPILER} ${compile_flags} -c
|
||||
-o "${object_file}"
|
||||
${source_rpath}
|
||||
MAIN_DEPENDENCY ${source}
|
||||
DEPENDS ${SOURCE_DEPS})
|
||||
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
|
||||
# ${LLVM_BINARY_DIR}/include/c++
|
||||
# The just-built clang is used to build compiler-rt unit tests. Let's detect
|
||||
# this before we try to build the tests and print out a suggestion how to fix
|
||||
# it.
|
||||
# On other platforms, this is currently not an issue.
|
||||
macro(clang_compiler_add_cxx_check)
|
||||
if (APPLE)
|
||||
set(CMD
|
||||
"echo '#include <iostream>' | ${COMPILER_RT_TEST_COMPILER} ${OSX_SYSROOT_FLAG} -E -x c++ - > /dev/null"
|
||||
"if [ $? != 0 ] "
|
||||
" then echo"
|
||||
" echo 'Your just-built clang cannot find C++ headers, which are needed to build and run compiler-rt tests.'"
|
||||
" echo 'You should copy or symlink your system C++ headers into ${LLVM_BINARY_DIR}/include/c++'"
|
||||
" if [ -d $(dirname $(dirname $(xcrun -f clang)))/include/c++ ]"
|
||||
" then echo 'e.g. with:'"
|
||||
" echo ' cp -r' $(dirname $(dirname $(xcrun -f clang)))/include/c++ '${LLVM_BINARY_DIR}/include/'"
|
||||
" elif [ -d $(dirname $(dirname $(xcrun -f clang)))/lib/c++ ]"
|
||||
" then echo 'e.g. with:'"
|
||||
" echo ' cp -r' $(dirname $(dirname $(xcrun -f clang)))/lib/c++ '${LLVM_BINARY_DIR}/include/'"
|
||||
" fi"
|
||||
" echo 'This can also be fixed by checking out the libcxx project from llvm.org and installing the headers'"
|
||||
" echo 'into your build directory:'"
|
||||
" echo ' cd ${LLVM_MAIN_SRC_DIR}/projects && svn co http://llvm.org/svn/llvm-project/libcxx/trunk libcxx'"
|
||||
" echo ' cd ${LLVM_BINARY_DIR} && make -C ${LLVM_MAIN_SRC_DIR}/projects/libcxx installheaders HEADER_DIR=${LLVM_BINARY_DIR}/include'"
|
||||
" echo"
|
||||
" false"
|
||||
"fi"
|
||||
)
|
||||
add_custom_target(CompilerRTUnitTestCheckCxx
|
||||
COMMAND bash -c "${CMD}"
|
||||
COMMENT "Checking that just-built clang can find C++ headers..."
|
||||
VERBATIM)
|
||||
if (NOT COMPILER_RT_STANDALONE_BUILD)
|
||||
ADD_DEPENDENCIES(CompilerRTUnitTestCheckCxx clang)
|
||||
endif()
|
||||
endif()
|
||||
endmacro()
|
@ -1,440 +0,0 @@
|
||||
include(CMakeParseArguments)
|
||||
|
||||
# On OS X SDKs can be installed anywhere on the base system and xcode-select can
|
||||
# set the default Xcode to use. This function finds the SDKs that are present in
|
||||
# the current Xcode.
|
||||
function(find_darwin_sdk_dir var sdk_name)
|
||||
set(DARWIN_${sdk_name}_CACHED_SYSROOT "" CACHE STRING "Darwin SDK path for SDK ${sdk_name}.")
|
||||
set(DARWIN_PREFER_PUBLIC_SDK OFF CACHE BOOL "Prefer Darwin public SDK, even when an internal SDK is present.")
|
||||
|
||||
if(DARWIN_${sdk_name}_CACHED_SYSROOT)
|
||||
set(${var} ${DARWIN_${sdk_name}_CACHED_SYSROOT} PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
if(NOT DARWIN_PREFER_PUBLIC_SDK)
|
||||
# Let's first try the internal SDK, otherwise use the public SDK.
|
||||
execute_process(
|
||||
COMMAND xcodebuild -version -sdk ${sdk_name}.internal Path
|
||||
RESULT_VARIABLE result_process
|
||||
OUTPUT_VARIABLE var_internal
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_FILE /dev/null
|
||||
)
|
||||
endif()
|
||||
if((NOT result_process EQUAL 0) OR "" STREQUAL "${var_internal}")
|
||||
execute_process(
|
||||
COMMAND xcodebuild -version -sdk ${sdk_name} Path
|
||||
RESULT_VARIABLE result_process
|
||||
OUTPUT_VARIABLE var_internal
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_FILE /dev/null
|
||||
)
|
||||
else()
|
||||
set(${var}_INTERNAL ${var_internal} PARENT_SCOPE)
|
||||
endif()
|
||||
if(result_process EQUAL 0)
|
||||
set(${var} ${var_internal} PARENT_SCOPE)
|
||||
endif()
|
||||
set(DARWIN_${sdk_name}_CACHED_SYSROOT ${var_internal} CACHE STRING "Darwin SDK path for SDK ${sdk_name}." FORCE)
|
||||
endfunction()
|
||||
|
||||
# There isn't a clear mapping of what architectures are supported with a given
|
||||
# target platform, but ld's version output does list the architectures it can
|
||||
# link for.
|
||||
function(darwin_get_toolchain_supported_archs output_var)
|
||||
execute_process(
|
||||
COMMAND "${CMAKE_LINKER}" -v
|
||||
ERROR_VARIABLE LINKER_VERSION)
|
||||
|
||||
string(REGEX MATCH "configured to support archs: ([^\n]+)"
|
||||
ARCHES_MATCHED "${LINKER_VERSION}")
|
||||
if(ARCHES_MATCHED)
|
||||
set(ARCHES "${CMAKE_MATCH_1}")
|
||||
message(STATUS "Got ld supported ARCHES: ${ARCHES}")
|
||||
string(REPLACE " " ";" ARCHES ${ARCHES})
|
||||
else()
|
||||
# If auto-detecting fails, fall back to a default set
|
||||
message(WARNING "Detecting supported architectures from 'ld -v' failed. Returning default set.")
|
||||
set(ARCHES "i386;x86_64;armv7;armv7s;arm64")
|
||||
endif()
|
||||
|
||||
set(${output_var} ${ARCHES} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# This function takes an OS and a list of architectures and identifies the
|
||||
# subset of the architectures list that the installed toolchain can target.
|
||||
function(darwin_test_archs os valid_archs)
|
||||
if(${valid_archs})
|
||||
message(STATUS "Using cached valid architectures for ${os}.")
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(archs ${ARGN})
|
||||
if(NOT TEST_COMPILE_ONLY)
|
||||
message(STATUS "Finding valid architectures for ${os}...")
|
||||
set(SIMPLE_C ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/src.c)
|
||||
file(WRITE ${SIMPLE_C} "#include <stdio.h>\nint main() { printf(__FILE__); return 0; }\n")
|
||||
|
||||
set(os_linker_flags)
|
||||
foreach(flag ${DARWIN_${os}_LINK_FLAGS})
|
||||
set(os_linker_flags "${os_linker_flags} ${flag}")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
# The simple program will build for x86_64h on the simulator because it is
|
||||
# compatible with x86_64 libraries (mostly), but since x86_64h isn't actually
|
||||
# a valid or useful architecture for the iOS simulator we should drop it.
|
||||
if(${os} MATCHES "^(iossim|tvossim|watchossim)$")
|
||||
list(REMOVE_ITEM archs "x86_64h")
|
||||
endif()
|
||||
|
||||
set(working_archs)
|
||||
foreach(arch ${archs})
|
||||
|
||||
set(arch_linker_flags "-arch ${arch} ${os_linker_flags}")
|
||||
if(TEST_COMPILE_ONLY)
|
||||
try_compile_only(CAN_TARGET_${os}_${arch} -v -arch ${arch} ${DARWIN_${os}_CFLAGS})
|
||||
else()
|
||||
set(SAVED_CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS})
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${arch_linker_flags}")
|
||||
try_compile(CAN_TARGET_${os}_${arch} ${CMAKE_BINARY_DIR} ${SIMPLE_C}
|
||||
COMPILE_DEFINITIONS "-v -arch ${arch}" ${DARWIN_${os}_CFLAGS}
|
||||
OUTPUT_VARIABLE TEST_OUTPUT)
|
||||
set(CMAKE_EXE_LINKER_FLAGS ${SAVED_CMAKE_EXE_LINKER_FLAGS})
|
||||
endif()
|
||||
if(${CAN_TARGET_${os}_${arch}})
|
||||
list(APPEND working_archs ${arch})
|
||||
else()
|
||||
file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
|
||||
"Testing compiler for supporting ${os}-${arch}:\n"
|
||||
"${TEST_OUTPUT}\n")
|
||||
endif()
|
||||
endforeach()
|
||||
set(${valid_archs} ${working_archs}
|
||||
CACHE STRING "List of valid architectures for platform ${os}.")
|
||||
endfunction()
|
||||
|
||||
# This function checks the host cpusubtype to see if it is post-haswell. Haswell
|
||||
# and later machines can run x86_64h binaries. Haswell is cpusubtype 8.
|
||||
function(darwin_filter_host_archs input output)
|
||||
list_intersect(tmp_var DARWIN_osx_ARCHS ${input})
|
||||
execute_process(
|
||||
COMMAND sysctl hw.cpusubtype
|
||||
OUTPUT_VARIABLE SUBTYPE)
|
||||
|
||||
string(REGEX MATCH "hw.cpusubtype: ([0-9]*)"
|
||||
SUBTYPE_MATCHED "${SUBTYPE}")
|
||||
set(HASWELL_SUPPORTED Off)
|
||||
if(SUBTYPE_MATCHED)
|
||||
if(${CMAKE_MATCH_1} GREATER 7)
|
||||
set(HASWELL_SUPPORTED On)
|
||||
endif()
|
||||
endif()
|
||||
if(NOT HASWELL_SUPPORTED)
|
||||
list(REMOVE_ITEM tmp_var x86_64h)
|
||||
endif()
|
||||
set(${output} ${tmp_var} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Read and process the exclude file into a list of symbols
|
||||
function(darwin_read_list_from_file output_var file)
|
||||
if(EXISTS ${file})
|
||||
file(READ ${file} EXCLUDES)
|
||||
string(REPLACE "\n" ";" EXCLUDES ${EXCLUDES})
|
||||
set(${output_var} ${EXCLUDES} PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# this function takes an OS, architecture and minimum version and provides a
|
||||
# list of builtin functions to exclude
|
||||
function(darwin_find_excluded_builtins_list output_var)
|
||||
cmake_parse_arguments(LIB
|
||||
""
|
||||
"OS;ARCH;MIN_VERSION"
|
||||
""
|
||||
${ARGN})
|
||||
|
||||
if(NOT LIB_OS OR NOT LIB_ARCH)
|
||||
message(FATAL_ERROR "Must specify OS and ARCH to darwin_find_excluded_builtins_list!")
|
||||
endif()
|
||||
|
||||
darwin_read_list_from_file(${LIB_OS}_BUILTINS
|
||||
${DARWIN_EXCLUDE_DIR}/${LIB_OS}.txt)
|
||||
darwin_read_list_from_file(${LIB_OS}_${LIB_ARCH}_BASE_BUILTINS
|
||||
${DARWIN_EXCLUDE_DIR}/${LIB_OS}-${LIB_ARCH}.txt)
|
||||
|
||||
if(LIB_MIN_VERSION)
|
||||
file(GLOB builtin_lists ${DARWIN_EXCLUDE_DIR}/${LIB_OS}*-${LIB_ARCH}.txt)
|
||||
foreach(builtin_list ${builtin_lists})
|
||||
string(REGEX MATCH "${LIB_OS}([0-9\\.]*)-${LIB_ARCH}.txt" VERSION_MATCHED "${builtin_list}")
|
||||
if (VERSION_MATCHED AND NOT CMAKE_MATCH_1 VERSION_LESS LIB_MIN_VERSION)
|
||||
if(NOT smallest_version)
|
||||
set(smallest_version ${CMAKE_MATCH_1})
|
||||
elseif(CMAKE_MATCH_1 VERSION_LESS smallest_version)
|
||||
set(smallest_version ${CMAKE_MATCH_1})
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(smallest_version)
|
||||
darwin_read_list_from_file(${LIB_ARCH}_${LIB_OS}_BUILTINS
|
||||
${DARWIN_EXCLUDE_DIR}/${LIB_OS}${smallest_version}-${LIB_ARCH}.txt)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(${output_var}
|
||||
${${LIB_ARCH}_${LIB_OS}_BUILTINS}
|
||||
${${LIB_OS}_${LIB_ARCH}_BASE_BUILTINS}
|
||||
${${LIB_OS}_BUILTINS} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# adds a single builtin library for a single OS & ARCH
|
||||
macro(darwin_add_builtin_library name suffix)
|
||||
cmake_parse_arguments(LIB
|
||||
""
|
||||
"PARENT_TARGET;OS;ARCH"
|
||||
"SOURCES;CFLAGS;DEFS"
|
||||
${ARGN})
|
||||
set(libname "${name}.${suffix}_${LIB_ARCH}_${LIB_OS}")
|
||||
add_library(${libname} STATIC ${LIB_SOURCES})
|
||||
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}
|
||||
${builtin_cflags})
|
||||
set_property(TARGET ${libname} APPEND PROPERTY
|
||||
COMPILE_DEFINITIONS ${LIB_DEFS})
|
||||
set_target_properties(${libname} PROPERTIES
|
||||
OUTPUT_NAME ${libname}${COMPILER_RT_OS_SUFFIX})
|
||||
set_target_properties(${libname} PROPERTIES
|
||||
OSX_ARCHITECTURES ${LIB_ARCH})
|
||||
|
||||
if(LIB_PARENT_TARGET)
|
||||
add_dependencies(${LIB_PARENT_TARGET} ${libname})
|
||||
endif()
|
||||
|
||||
list(APPEND ${LIB_OS}_${suffix}_libs ${libname})
|
||||
list(APPEND ${LIB_OS}_${suffix}_lipo_flags -arch ${arch} $<TARGET_FILE:${libname}>)
|
||||
set_target_properties(${libname} PROPERTIES FOLDER "Compiler-RT Libraries")
|
||||
endmacro()
|
||||
|
||||
function(darwin_lipo_libs name)
|
||||
cmake_parse_arguments(LIB
|
||||
""
|
||||
"PARENT_TARGET;OUTPUT_DIR;INSTALL_DIR"
|
||||
"LIPO_FLAGS;DEPENDS"
|
||||
${ARGN})
|
||||
if(LIB_DEPENDS AND LIB_LIPO_FLAGS)
|
||||
add_custom_command(OUTPUT ${LIB_OUTPUT_DIR}/lib${name}.a
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${LIB_OUTPUT_DIR}
|
||||
COMMAND lipo -output
|
||||
${LIB_OUTPUT_DIR}/lib${name}.a
|
||||
-create ${LIB_LIPO_FLAGS}
|
||||
DEPENDS ${LIB_DEPENDS}
|
||||
)
|
||||
add_custom_target(${name}
|
||||
DEPENDS ${LIB_OUTPUT_DIR}/lib${name}.a)
|
||||
add_dependencies(${LIB_PARENT_TARGET} ${name})
|
||||
install(FILES ${LIB_OUTPUT_DIR}/lib${name}.a
|
||||
DESTINATION ${LIB_INSTALL_DIR})
|
||||
set_target_properties(${name} PROPERTIES FOLDER "Compiler-RT Misc")
|
||||
else()
|
||||
message(WARNING "Not generating lipo target for ${name} because no input libraries exist.")
|
||||
endif()
|
||||
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)
|
||||
set(DARWIN_EXCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Darwin-excludes)
|
||||
|
||||
set(CFLAGS "-fPIC -O3 -fvisibility=hidden -DVISIBILITY_HIDDEN -Wall -fomit-frame-pointer")
|
||||
set(CMAKE_C_FLAGS "")
|
||||
set(CMAKE_CXX_FLAGS "")
|
||||
set(CMAKE_ASM_FLAGS "")
|
||||
|
||||
set(PROFILE_SOURCES ../profile/InstrProfiling
|
||||
../profile/InstrProfilingBuffer
|
||||
../profile/InstrProfilingPlatformDarwin
|
||||
../profile/InstrProfilingWriter)
|
||||
foreach (os ${ARGN})
|
||||
list_intersect(DARWIN_BUILTIN_ARCHS DARWIN_${os}_ARCHS BUILTIN_SUPPORTED_ARCH)
|
||||
foreach (arch ${DARWIN_BUILTIN_ARCHS})
|
||||
darwin_find_excluded_builtins_list(${arch}_${os}_EXCLUDED_BUILTINS
|
||||
OS ${os}
|
||||
ARCH ${arch}
|
||||
MIN_VERSION ${DARWIN_${os}_BUILTIN_MIN_VER})
|
||||
|
||||
filter_builtin_sources(filtered_sources
|
||||
EXCLUDE ${arch}_${os}_EXCLUDED_BUILTINS
|
||||
${${arch}_SOURCES})
|
||||
|
||||
darwin_add_builtin_library(clang_rt builtins
|
||||
OS ${os}
|
||||
ARCH ${arch}
|
||||
SOURCES ${filtered_sources}
|
||||
CFLAGS ${CFLAGS} -arch ${arch}
|
||||
PARENT_TARGET builtins)
|
||||
endforeach()
|
||||
|
||||
# Don't build cc_kext libraries for simulator platforms
|
||||
if(NOT DARWIN_${os}_SKIP_CC_KEXT)
|
||||
foreach (arch ${DARWIN_BUILTIN_ARCHS})
|
||||
# By not specifying MIN_VERSION this only reads the OS and OS-arch lists.
|
||||
# We don't want to filter out the builtins that are present in libSystem
|
||||
# because kexts can't link libSystem.
|
||||
darwin_find_excluded_builtins_list(${arch}_${os}_EXCLUDED_BUILTINS
|
||||
OS ${os}
|
||||
ARCH ${arch})
|
||||
|
||||
filter_builtin_sources(filtered_sources
|
||||
EXCLUDE ${arch}_${os}_EXCLUDED_BUILTINS
|
||||
${${arch}_SOURCES})
|
||||
|
||||
# In addition to the builtins cc_kext includes some profile sources
|
||||
darwin_add_builtin_library(clang_rt cc_kext
|
||||
OS ${os}
|
||||
ARCH ${arch}
|
||||
SOURCES ${filtered_sources} ${PROFILE_SOURCES}
|
||||
CFLAGS ${CFLAGS} -arch ${arch} -mkernel
|
||||
DEFS KERNEL_USE
|
||||
PARENT_TARGET builtins)
|
||||
endforeach()
|
||||
set(archive_name clang_rt.cc_kext_${os})
|
||||
if(${os} STREQUAL "osx")
|
||||
set(archive_name clang_rt.cc_kext)
|
||||
endif()
|
||||
darwin_lipo_libs(${archive_name}
|
||||
PARENT_TARGET builtins
|
||||
LIPO_FLAGS ${${os}_cc_kext_lipo_flags}
|
||||
DEPENDS ${${os}_cc_kext_libs}
|
||||
OUTPUT_DIR ${COMPILER_RT_LIBRARY_OUTPUT_DIR}
|
||||
INSTALL_DIR ${COMPILER_RT_LIBRARY_INSTALL_DIR})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# We put the x86 sim slices into the archives for their base OS
|
||||
foreach (os ${ARGN})
|
||||
if(NOT ${os} MATCHES ".*sim$")
|
||||
darwin_lipo_libs(clang_rt.${os}
|
||||
PARENT_TARGET builtins
|
||||
LIPO_FLAGS ${${os}_builtins_lipo_flags} ${${os}sim_builtins_lipo_flags}
|
||||
DEPENDS ${${os}_builtins_libs} ${${os}sim_builtins_libs}
|
||||
OUTPUT_DIR ${COMPILER_RT_LIBRARY_OUTPUT_DIR}
|
||||
INSTALL_DIR ${COMPILER_RT_LIBRARY_INSTALL_DIR})
|
||||
endif()
|
||||
endforeach()
|
||||
darwin_add_embedded_builtin_libraries()
|
||||
endmacro()
|
||||
|
||||
macro(darwin_add_embedded_builtin_libraries)
|
||||
# this is a hacky opt-out. If you can't target both intel and arm
|
||||
# architectures we bail here.
|
||||
set(DARWIN_SOFT_FLOAT_ARCHS armv6m armv7m armv7em armv7)
|
||||
set(DARWIN_HARD_FLOAT_ARCHS armv7em armv7)
|
||||
if(COMPILER_RT_SUPPORTED_ARCH MATCHES ".*armv.*")
|
||||
list(FIND COMPILER_RT_SUPPORTED_ARCH i386 i386_idx)
|
||||
if(i386_idx GREATER -1)
|
||||
list(APPEND DARWIN_HARD_FLOAT_ARCHS i386)
|
||||
endif()
|
||||
|
||||
list(FIND COMPILER_RT_SUPPORTED_ARCH x86_64 x86_64_idx)
|
||||
if(x86_64_idx GREATER -1)
|
||||
list(APPEND DARWIN_HARD_FLOAT_ARCHS x86_64)
|
||||
endif()
|
||||
|
||||
set(MACHO_SYM_DIR ${CMAKE_CURRENT_SOURCE_DIR}/macho_embedded)
|
||||
|
||||
set(CFLAGS "-Oz -Wall -fomit-frame-pointer -ffreestanding")
|
||||
set(CMAKE_C_FLAGS "")
|
||||
set(CMAKE_CXX_FLAGS "")
|
||||
set(CMAKE_ASM_FLAGS "")
|
||||
|
||||
set(SOFT_FLOAT_FLAG -mfloat-abi=soft)
|
||||
set(HARD_FLOAT_FLAG -mfloat-abi=hard)
|
||||
|
||||
set(ENABLE_PIC Off)
|
||||
set(PIC_FLAG -fPIC)
|
||||
set(STATIC_FLAG -static)
|
||||
|
||||
set(DARWIN_macho_embedded_ARCHS armv6m armv7m armv7em armv7 i386 x86_64)
|
||||
|
||||
set(DARWIN_macho_embedded_LIBRARY_OUTPUT_DIR
|
||||
${COMPILER_RT_OUTPUT_DIR}/lib/macho_embedded)
|
||||
set(DARWIN_macho_embedded_LIBRARY_INSTALL_DIR
|
||||
${COMPILER_RT_INSTALL_PATH}/lib/macho_embedded)
|
||||
|
||||
set(CFLAGS_armv7 "-target thumbv7-apple-darwin-eabi")
|
||||
set(CFLAGS_i386 "-march=pentium")
|
||||
|
||||
darwin_read_list_from_file(common_FUNCTIONS ${MACHO_SYM_DIR}/common.txt)
|
||||
darwin_read_list_from_file(thumb2_FUNCTIONS ${MACHO_SYM_DIR}/thumb2.txt)
|
||||
darwin_read_list_from_file(thumb2_64_FUNCTIONS ${MACHO_SYM_DIR}/thumb2-64.txt)
|
||||
darwin_read_list_from_file(arm_FUNCTIONS ${MACHO_SYM_DIR}/arm.txt)
|
||||
darwin_read_list_from_file(i386_FUNCTIONS ${MACHO_SYM_DIR}/i386.txt)
|
||||
|
||||
|
||||
set(armv6m_FUNCTIONS ${common_FUNCTIONS} ${arm_FUNCTIONS})
|
||||
set(armv7m_FUNCTIONS ${common_FUNCTIONS} ${arm_FUNCTIONS} ${thumb2_FUNCTIONS})
|
||||
set(armv7em_FUNCTIONS ${common_FUNCTIONS} ${arm_FUNCTIONS} ${thumb2_FUNCTIONS})
|
||||
set(armv7_FUNCTIONS ${common_FUNCTIONS} ${arm_FUNCTIONS} ${thumb2_FUNCTIONS} ${thumb2_64_FUNCTIONS})
|
||||
set(i386_FUNCTIONS ${common_FUNCTIONS} ${i386_FUNCTIONS})
|
||||
set(x86_64_FUNCTIONS ${common_FUNCTIONS})
|
||||
|
||||
foreach(arch ${DARWIN_macho_embedded_ARCHS})
|
||||
filter_builtin_sources(${arch}_filtered_sources
|
||||
INCLUDE ${arch}_FUNCTIONS
|
||||
${${arch}_SOURCES})
|
||||
if(NOT ${arch}_filtered_sources)
|
||||
message("${arch}_SOURCES: ${${arch}_SOURCES}")
|
||||
message("${arch}_FUNCTIONS: ${${arch}_FUNCTIONS}")
|
||||
message(FATAL_ERROR "Empty filtered sources!")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
foreach(float_type SOFT HARD)
|
||||
foreach(type PIC STATIC)
|
||||
string(TOLOWER "${float_type}_${type}" lib_suffix)
|
||||
foreach(arch ${DARWIN_${float_type}_FLOAT_ARCHS})
|
||||
set(DARWIN_macho_embedded_SYSROOT ${DARWIN_osx_SYSROOT})
|
||||
set(float_flag)
|
||||
if(${arch} MATCHES "^arm")
|
||||
# x86 targets are hard float by default, but the complain about the
|
||||
# float ABI flag, so don't pass it unless we're targeting arm.
|
||||
set(float_flag ${${float_type}_FLOAT_FLAG})
|
||||
endif()
|
||||
darwin_add_builtin_library(clang_rt ${lib_suffix}
|
||||
OS macho_embedded
|
||||
ARCH ${arch}
|
||||
SOURCES ${${arch}_filtered_sources}
|
||||
CFLAGS ${CFLAGS} -arch ${arch} ${${type}_FLAG} ${float_flag} ${CFLAGS_${arch}}
|
||||
PARENT_TARGET builtins)
|
||||
endforeach()
|
||||
foreach(lib ${macho_embedded_${lib_suffix}_libs})
|
||||
set_target_properties(${lib} PROPERTIES LINKER_LANGUAGE C)
|
||||
endforeach()
|
||||
darwin_lipo_libs(clang_rt.${lib_suffix}
|
||||
PARENT_TARGET builtins
|
||||
LIPO_FLAGS ${macho_embedded_${lib_suffix}_lipo_flags}
|
||||
DEPENDS ${macho_embedded_${lib_suffix}_libs}
|
||||
OUTPUT_DIR ${DARWIN_macho_embedded_LIBRARY_OUTPUT_DIR}
|
||||
INSTALL_DIR ${DARWIN_macho_embedded_LIBRARY_INSTALL_DIR})
|
||||
endforeach()
|
||||
endforeach()
|
||||
endif()
|
||||
endmacro()
|
@ -1,16 +0,0 @@
|
||||
# Link a shared library with COMPILER_RT_TEST_COMPILER.
|
||||
# clang_link_shared(<output.so>
|
||||
# OBJECTS <list of input objects>
|
||||
# LINK_FLAGS <list of link flags>
|
||||
# DEPS <list of dependencies>)
|
||||
macro(clang_link_shared so_file)
|
||||
cmake_parse_arguments(SOURCE "" "" "OBJECTS;LINK_FLAGS;DEPS" ${ARGN})
|
||||
if(NOT COMPILER_RT_STANDALONE_BUILD)
|
||||
list(APPEND SOURCE_DEPS clang)
|
||||
endif()
|
||||
add_custom_command(
|
||||
OUTPUT ${so_file}
|
||||
COMMAND ${COMPILER_RT_TEST_COMPILER} -o "${so_file}" -shared
|
||||
${SOURCE_LINK_FLAGS} ${SOURCE_OBJECTS}
|
||||
DEPENDS ${SOURCE_DEPS})
|
||||
endmacro()
|
@ -1,415 +0,0 @@
|
||||
include(CMakePushCheckState)
|
||||
include(CheckSymbolExists)
|
||||
|
||||
# Because compiler-rt spends a lot of time setting up custom compile flags,
|
||||
# define a handy helper function for it. The compile flags setting in CMake
|
||||
# has serious issues that make its syntax challenging at best.
|
||||
function(set_target_compile_flags target)
|
||||
set(argstring "")
|
||||
foreach(arg ${ARGN})
|
||||
set(argstring "${argstring} ${arg}")
|
||||
endforeach()
|
||||
set_property(TARGET ${target} PROPERTY COMPILE_FLAGS "${argstring}")
|
||||
endfunction()
|
||||
|
||||
function(set_target_link_flags target)
|
||||
set(argstring "")
|
||||
foreach(arg ${ARGN})
|
||||
set(argstring "${argstring} ${arg}")
|
||||
endforeach()
|
||||
set_property(TARGET ${target} PROPERTY LINK_FLAGS "${argstring}")
|
||||
endfunction()
|
||||
|
||||
# Set the variable var_PYBOOL to True if var holds a true-ish string,
|
||||
# otherwise set it to False.
|
||||
macro(pythonize_bool var)
|
||||
if (${var})
|
||||
set(${var}_PYBOOL True)
|
||||
else()
|
||||
set(${var}_PYBOOL False)
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
# Appends value to all lists in ARGN, if the condition is true.
|
||||
macro(append_list_if condition value)
|
||||
if(${condition})
|
||||
foreach(list ${ARGN})
|
||||
list(APPEND ${list} ${value})
|
||||
endforeach()
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
# Appends value to all strings in ARGN, if the condition is true.
|
||||
macro(append_string_if condition value)
|
||||
if(${condition})
|
||||
foreach(str ${ARGN})
|
||||
set(${str} "${${str}} ${value}")
|
||||
endforeach()
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro(append_rtti_flag polarity list)
|
||||
if(${polarity})
|
||||
append_list_if(COMPILER_RT_HAS_FRTTI_FLAG -frtti ${list})
|
||||
append_list_if(COMPILER_RT_HAS_GR_FLAG /GR ${list})
|
||||
else()
|
||||
append_list_if(COMPILER_RT_HAS_FNO_RTTI_FLAG -fno-rtti ${list})
|
||||
append_list_if(COMPILER_RT_HAS_GR_FLAG /GR- ${list})
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro(list_intersect output input1 input2)
|
||||
set(${output})
|
||||
foreach(it ${${input1}})
|
||||
list(FIND ${input2} ${it} index)
|
||||
if( NOT (index EQUAL -1))
|
||||
list(APPEND ${output} ${it})
|
||||
endif()
|
||||
endforeach()
|
||||
endmacro()
|
||||
|
||||
function(list_replace input_list old new)
|
||||
set(replaced_list)
|
||||
foreach(item ${${input_list}})
|
||||
if(${item} STREQUAL ${old})
|
||||
list(APPEND replaced_list ${new})
|
||||
else()
|
||||
list(APPEND replaced_list ${item})
|
||||
endif()
|
||||
endforeach()
|
||||
set(${input_list} "${replaced_list}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Takes ${ARGN} and puts only supported architectures in @out_var list.
|
||||
function(filter_available_targets out_var)
|
||||
set(archs ${${out_var}})
|
||||
foreach(arch ${ARGN})
|
||||
list(FIND COMPILER_RT_SUPPORTED_ARCH ${arch} ARCH_INDEX)
|
||||
if(NOT (ARCH_INDEX EQUAL -1) AND CAN_TARGET_${arch})
|
||||
list(APPEND archs ${arch})
|
||||
endif()
|
||||
endforeach()
|
||||
set(${out_var} ${archs} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Add $arch as supported with no additional flags.
|
||||
macro(add_default_target_arch arch)
|
||||
set(TARGET_${arch}_CFLAGS "")
|
||||
set(CAN_TARGET_${arch} 1)
|
||||
list(APPEND COMPILER_RT_SUPPORTED_ARCH ${arch})
|
||||
endmacro()
|
||||
|
||||
function(check_compile_definition def argstring out_var)
|
||||
if("${def}" STREQUAL "")
|
||||
set(${out_var} TRUE PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
cmake_push_check_state()
|
||||
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${argstring}")
|
||||
check_symbol_exists(${def} "" ${out_var})
|
||||
cmake_pop_check_state()
|
||||
endfunction()
|
||||
|
||||
# test_target_arch(<arch> <def> <target flags...>)
|
||||
# Checks if architecture is supported: runs host compiler with provided
|
||||
# flags to verify that:
|
||||
# 1) <def> is defined (if non-empty)
|
||||
# 2) simple file can be successfully built.
|
||||
# If successful, saves target flags for this architecture.
|
||||
macro(test_target_arch arch def)
|
||||
set(TARGET_${arch}_CFLAGS ${ARGN})
|
||||
set(TARGET_${arch}_LINK_FLAGS ${ARGN})
|
||||
set(argstring "")
|
||||
foreach(arg ${ARGN})
|
||||
set(argstring "${argstring} ${arg}")
|
||||
endforeach()
|
||||
check_compile_definition("${def}" "${argstring}" HAS_${arch}_DEF)
|
||||
if(NOT DEFINED CAN_TARGET_${arch})
|
||||
if(NOT HAS_${arch}_DEF)
|
||||
set(CAN_TARGET_${arch} FALSE)
|
||||
elseif(TEST_COMPILE_ONLY)
|
||||
try_compile_only(CAN_TARGET_${arch} ${TARGET_${arch}_CFLAGS})
|
||||
else()
|
||||
set(FLAG_NO_EXCEPTIONS "")
|
||||
if(COMPILER_RT_HAS_FNO_EXCEPTIONS_FLAG)
|
||||
set(FLAG_NO_EXCEPTIONS " -fno-exceptions ")
|
||||
endif()
|
||||
set(SAVED_CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS})
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${argstring}")
|
||||
try_compile(CAN_TARGET_${arch} ${CMAKE_BINARY_DIR} ${SIMPLE_SOURCE}
|
||||
COMPILE_DEFINITIONS "${TARGET_${arch}_CFLAGS} ${FLAG_NO_EXCEPTIONS}"
|
||||
OUTPUT_VARIABLE TARGET_${arch}_OUTPUT)
|
||||
set(CMAKE_EXE_LINKER_FLAGS ${SAVED_CMAKE_EXE_LINKER_FLAGS})
|
||||
endif()
|
||||
endif()
|
||||
if(${CAN_TARGET_${arch}})
|
||||
list(APPEND COMPILER_RT_SUPPORTED_ARCH ${arch})
|
||||
elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" STREQUAL "${arch}" AND
|
||||
COMPILER_RT_HAS_EXPLICIT_DEFAULT_TARGET_TRIPLE)
|
||||
# Bail out if we cannot target the architecture we plan to test.
|
||||
message(FATAL_ERROR "Cannot compile for ${arch}:\n${TARGET_${arch}_OUTPUT}")
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro(detect_target_arch)
|
||||
check_symbol_exists(__arm__ "" __ARM)
|
||||
check_symbol_exists(__aarch64__ "" __AARCH64)
|
||||
check_symbol_exists(__x86_64__ "" __X86_64)
|
||||
check_symbol_exists(__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(__riscv "" __RISCV)
|
||||
check_symbol_exists(__s390x__ "" __S390X)
|
||||
check_symbol_exists(__wasm32__ "" __WEBASSEMBLY32)
|
||||
check_symbol_exists(__wasm64__ "" __WEBASSEMBLY64)
|
||||
if(__ARM)
|
||||
add_default_target_arch(arm)
|
||||
elseif(__AARCH64)
|
||||
add_default_target_arch(aarch64)
|
||||
elseif(__X86_64)
|
||||
add_default_target_arch(x86_64)
|
||||
elseif(__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(__RISCV)
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL "4")
|
||||
add_default_target_arch(riscv32)
|
||||
elseif(CMAKE_SIZEOF_VOID_P EQUAL "8")
|
||||
add_default_target_arch(riscv64)
|
||||
else()
|
||||
message(FATAL_ERROR "Unsupport XLEN for RISC-V")
|
||||
endif()
|
||||
elseif(__S390X)
|
||||
add_default_target_arch(s390x)
|
||||
elseif(__WEBASSEMBLY32)
|
||||
add_default_target_arch(wasm32)
|
||||
elseif(__WEBASSEMBLY64)
|
||||
add_default_target_arch(wasm64)
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro(load_llvm_config)
|
||||
if (NOT LLVM_CONFIG_PATH)
|
||||
find_program(LLVM_CONFIG_PATH "llvm-config"
|
||||
DOC "Path to llvm-config binary")
|
||||
if (NOT LLVM_CONFIG_PATH)
|
||||
message(WARNING "UNSUPPORTED COMPILER-RT CONFIGURATION DETECTED: "
|
||||
"llvm-config not found.\n"
|
||||
"Reconfigure with -DLLVM_CONFIG_PATH=path/to/llvm-config.")
|
||||
endif()
|
||||
endif()
|
||||
if (LLVM_CONFIG_PATH)
|
||||
execute_process(
|
||||
COMMAND ${LLVM_CONFIG_PATH} "--obj-root" "--bindir" "--libdir" "--src-root" "--includedir"
|
||||
RESULT_VARIABLE HAD_ERROR
|
||||
OUTPUT_VARIABLE CONFIG_OUTPUT)
|
||||
if (HAD_ERROR)
|
||||
message(FATAL_ERROR "llvm-config failed with status ${HAD_ERROR}")
|
||||
endif()
|
||||
string(REGEX REPLACE "[ \t]*[\r\n]+[ \t]*" ";" CONFIG_OUTPUT ${CONFIG_OUTPUT})
|
||||
list(GET CONFIG_OUTPUT 0 BINARY_DIR)
|
||||
list(GET CONFIG_OUTPUT 1 TOOLS_BINARY_DIR)
|
||||
list(GET CONFIG_OUTPUT 2 LIBRARY_DIR)
|
||||
list(GET CONFIG_OUTPUT 3 MAIN_SRC_DIR)
|
||||
list(GET CONFIG_OUTPUT 4 INCLUDE_DIR)
|
||||
|
||||
set(LLVM_BINARY_DIR ${BINARY_DIR} CACHE PATH "Path to LLVM build tree")
|
||||
set(LLVM_LIBRARY_DIR ${LIBRARY_DIR} CACHE PATH "Path to llvm/lib")
|
||||
set(LLVM_MAIN_SRC_DIR ${MAIN_SRC_DIR} CACHE PATH "Path to LLVM source tree")
|
||||
set(LLVM_TOOLS_BINARY_DIR ${TOOLS_BINARY_DIR} CACHE PATH "Path to llvm/bin")
|
||||
set(LLVM_INCLUDE_DIR ${INCLUDE_DIR} CACHE PATH "Paths to LLVM headers")
|
||||
|
||||
# Detect if we have the LLVMXRay and TestingSupport library installed and
|
||||
# available from llvm-config.
|
||||
execute_process(
|
||||
COMMAND ${LLVM_CONFIG_PATH} "--ldflags" "--libs" "xray"
|
||||
RESULT_VARIABLE HAD_ERROR
|
||||
OUTPUT_VARIABLE CONFIG_OUTPUT)
|
||||
if (HAD_ERROR)
|
||||
message(WARNING "llvm-config finding xray failed with status ${HAD_ERROR}")
|
||||
set(COMPILER_RT_HAS_LLVMXRAY FALSE)
|
||||
else()
|
||||
string(REGEX REPLACE "[ \t]*[\r\n]+[ \t]*" ";" CONFIG_OUTPUT ${CONFIG_OUTPUT})
|
||||
list(GET CONFIG_OUTPUT 0 LDFLAGS)
|
||||
list(GET CONFIG_OUTPUT 1 LIBLIST)
|
||||
set(LLVM_XRAY_LDFLAGS ${LDFLAGS} CACHE STRING "Linker flags for LLVMXRay library")
|
||||
set(LLVM_XRAY_LIBLIST ${LIBLIST} CACHE STRING "Library list for LLVMXRay")
|
||||
set(COMPILER_RT_HAS_LLVMXRAY TRUE)
|
||||
endif()
|
||||
|
||||
set(COMPILER_RT_HAS_LLVMTESTINGSUPPORT FALSE)
|
||||
execute_process(
|
||||
COMMAND ${LLVM_CONFIG_PATH} "--ldflags" "--libs" "testingsupport"
|
||||
RESULT_VARIABLE HAD_ERROR
|
||||
OUTPUT_VARIABLE CONFIG_OUTPUT)
|
||||
if (HAD_ERROR)
|
||||
message(WARNING "llvm-config finding testingsupport failed with status ${HAD_ERROR}")
|
||||
else()
|
||||
string(REGEX REPLACE "[ \t]*[\r\n]+[ \t]*" ";" CONFIG_OUTPUT ${CONFIG_OUTPUT})
|
||||
list(GET CONFIG_OUTPUT 0 LDFLAGS)
|
||||
list(GET CONFIG_OUTPUT 1 LIBLIST)
|
||||
if (LIBLIST STREQUAL "")
|
||||
message(WARNING "testingsupport library not installed, some tests will be skipped")
|
||||
else()
|
||||
set(LLVM_TESTINGSUPPORT_LDFLAGS ${LDFLAGS} CACHE STRING "Linker flags for LLVMTestingSupport library")
|
||||
set(LLVM_TESTINGSUPPORT_LIBLIST ${LIBLIST} CACHE STRING "Library list for LLVMTestingSupport")
|
||||
set(COMPILER_RT_HAS_LLVMTESTINGSUPPORT TRUE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Make use of LLVM CMake modules.
|
||||
# --cmakedir is supported since llvm r291218 (4.0 release)
|
||||
execute_process(
|
||||
COMMAND ${LLVM_CONFIG_PATH} --cmakedir
|
||||
RESULT_VARIABLE HAD_ERROR
|
||||
OUTPUT_VARIABLE CONFIG_OUTPUT)
|
||||
if(NOT HAD_ERROR)
|
||||
string(STRIP "${CONFIG_OUTPUT}" LLVM_CMAKE_PATH_FROM_LLVM_CONFIG)
|
||||
file(TO_CMAKE_PATH ${LLVM_CMAKE_PATH_FROM_LLVM_CONFIG} LLVM_CMAKE_PATH)
|
||||
else()
|
||||
file(TO_CMAKE_PATH ${LLVM_BINARY_DIR} LLVM_BINARY_DIR_CMAKE_STYLE)
|
||||
set(LLVM_CMAKE_PATH "${LLVM_BINARY_DIR_CMAKE_STYLE}/lib${LLVM_LIBDIR_SUFFIX}/cmake/llvm")
|
||||
endif()
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_PATH}")
|
||||
# Get some LLVM variables from LLVMConfig.
|
||||
include("${LLVM_CMAKE_PATH}/LLVMConfig.cmake")
|
||||
|
||||
set(LLVM_LIBRARY_OUTPUT_INTDIR
|
||||
${LLVM_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib${LLVM_LIBDIR_SUFFIX})
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro(construct_compiler_rt_default_triple)
|
||||
if(COMPILER_RT_DEFAULT_TARGET_ONLY)
|
||||
if(DEFINED COMPILER_RT_DEFAULT_TARGET_TRIPLE)
|
||||
message(FATAL_ERROR "COMPILER_RT_DEFAULT_TARGET_TRIPLE isn't supported when building for default target only")
|
||||
endif()
|
||||
set(COMPILER_RT_DEFAULT_TARGET_TRIPLE ${CMAKE_C_COMPILER_TARGET})
|
||||
else()
|
||||
set(COMPILER_RT_DEFAULT_TARGET_TRIPLE ${TARGET_TRIPLE} CACHE STRING
|
||||
"Default triple for which compiler-rt runtimes will be built.")
|
||||
endif()
|
||||
|
||||
if(DEFINED COMPILER_RT_TEST_TARGET_TRIPLE)
|
||||
# Backwards compatibility: this variable used to be called
|
||||
# COMPILER_RT_TEST_TARGET_TRIPLE.
|
||||
set(COMPILER_RT_DEFAULT_TARGET_TRIPLE ${COMPILER_RT_TEST_TARGET_TRIPLE})
|
||||
endif()
|
||||
|
||||
string(REPLACE "-" ";" TARGET_TRIPLE_LIST ${COMPILER_RT_DEFAULT_TARGET_TRIPLE})
|
||||
list(GET TARGET_TRIPLE_LIST 0 COMPILER_RT_DEFAULT_TARGET_ARCH)
|
||||
# Determine if test target triple is specified explicitly, and doesn't match the
|
||||
# default.
|
||||
if(NOT COMPILER_RT_DEFAULT_TARGET_TRIPLE STREQUAL TARGET_TRIPLE)
|
||||
set(COMPILER_RT_HAS_EXPLICIT_DEFAULT_TARGET_TRIPLE TRUE)
|
||||
else()
|
||||
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()
|
||||
|
||||
function(get_compiler_rt_target arch variable)
|
||||
string(FIND ${COMPILER_RT_DEFAULT_TARGET_TRIPLE} "-" dash_index)
|
||||
string(SUBSTRING ${COMPILER_RT_DEFAULT_TARGET_TRIPLE} ${dash_index} -1 triple_suffix)
|
||||
if(COMPILER_RT_DEFAULT_TARGET_ONLY)
|
||||
# Use exact spelling when building only for the target specified to CMake.
|
||||
set(target "${COMPILER_RT_DEFAULT_TARGET_TRIPLE}")
|
||||
elseif(ANDROID AND ${arch} STREQUAL "i386")
|
||||
set(target "i686${COMPILER_RT_OS_SUFFIX}${triple_suffix}")
|
||||
else()
|
||||
set(target "${arch}${triple_suffix}")
|
||||
endif()
|
||||
set(${variable} ${target} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(get_compiler_rt_install_dir arch install_dir)
|
||||
if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND NOT APPLE)
|
||||
get_compiler_rt_target(${arch} target)
|
||||
set(${install_dir} ${COMPILER_RT_INSTALL_PATH}/${target}/lib PARENT_SCOPE)
|
||||
else()
|
||||
set(${install_dir} ${COMPILER_RT_LIBRARY_INSTALL_DIR} PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(get_compiler_rt_output_dir arch output_dir)
|
||||
if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND NOT APPLE)
|
||||
get_compiler_rt_target(${arch} target)
|
||||
set(${output_dir} ${COMPILER_RT_OUTPUT_DIR}/${target}/lib PARENT_SCOPE)
|
||||
else()
|
||||
set(${output_dir} ${COMPILER_RT_LIBRARY_OUTPUT_DIR} PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# compiler_rt_process_sources(
|
||||
# <OUTPUT_VAR>
|
||||
# <SOURCE_FILE> ...
|
||||
# [ADDITIONAL_HEADERS <header> ...]
|
||||
# )
|
||||
#
|
||||
# Process the provided sources and write the list of new sources
|
||||
# into `<OUTPUT_VAR>`.
|
||||
#
|
||||
# ADDITIONAL_HEADERS - Adds the supplied header to list of sources for IDEs.
|
||||
#
|
||||
# This function is very similar to `llvm_process_sources()` but exists here
|
||||
# because we need to support standalone builds of compiler-rt.
|
||||
function(compiler_rt_process_sources OUTPUT_VAR)
|
||||
cmake_parse_arguments(
|
||||
ARG
|
||||
""
|
||||
""
|
||||
"ADDITIONAL_HEADERS"
|
||||
${ARGN}
|
||||
)
|
||||
set(sources ${ARG_UNPARSED_ARGUMENTS})
|
||||
set(headers "")
|
||||
if (XCODE OR MSVC_IDE OR CMAKE_EXTRA_GENERATOR)
|
||||
# For IDEs we need to tell CMake about header files.
|
||||
# Otherwise they won't show up in UI.
|
||||
set(headers ${ARG_ADDITIONAL_HEADERS})
|
||||
list(LENGTH headers headers_length)
|
||||
if (${headers_length} GREATER 0)
|
||||
set_source_files_properties(${headers}
|
||||
PROPERTIES HEADER_FILE_ONLY ON)
|
||||
endif()
|
||||
endif()
|
||||
set("${OUTPUT_VAR}" ${sources} ${headers} PARENT_SCOPE)
|
||||
endfunction()
|
@ -1,24 +0,0 @@
|
||||
function(find_compiler_rt_library name variable)
|
||||
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()
|
||||
get_property(SANITIZER_CXX_FLAGS CACHE CMAKE_CXX_FLAGS PROPERTY VALUE)
|
||||
string(REPLACE " " ";" SANITIZER_CXX_FLAGS "${SANITIZER_CXX_FLAGS}")
|
||||
list(APPEND CLANG_COMMAND ${SANITIZER_CXX_FLAGS})
|
||||
execute_process(
|
||||
COMMAND ${CLANG_COMMAND}
|
||||
RESULT_VARIABLE HAD_ERROR
|
||||
OUTPUT_VARIABLE LIBRARY_FILE
|
||||
)
|
||||
string(STRIP "${LIBRARY_FILE}" LIBRARY_FILE)
|
||||
file(TO_CMAKE_PATH "${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(${variable} "${LIBRARY_FILE}" PARENT_SCOPE)
|
||||
else()
|
||||
message(STATUS "Failed to find compiler-rt ${name} library")
|
||||
endif()
|
||||
endfunction()
|
@ -1,108 +0,0 @@
|
||||
include(CompilerRTUtils)
|
||||
|
||||
set(SANITIZER_GEN_DYNAMIC_LIST
|
||||
${COMPILER_RT_SOURCE_DIR}/lib/sanitizer_common/scripts/gen_dynamic_list.py)
|
||||
|
||||
set(SANITIZER_LINT_SCRIPT
|
||||
${COMPILER_RT_SOURCE_DIR}/lib/sanitizer_common/scripts/check_lint.sh)
|
||||
|
||||
# Create a target "<name>-<arch>-symbols" that would generate the list of
|
||||
# symbols that need to be exported from sanitizer runtime "<name>". Function
|
||||
# interceptors are exported automatically, user can also provide files with
|
||||
# symbol names that should be exported as well.
|
||||
# add_sanitizer_rt_symbols(<name>
|
||||
# ARCHS <architectures>
|
||||
# PARENT_TARGET <convenience parent target>
|
||||
# EXTRA <files with extra symbols to export>)
|
||||
macro(add_sanitizer_rt_symbols name)
|
||||
cmake_parse_arguments(ARG
|
||||
""
|
||||
"PARENT_TARGET"
|
||||
"ARCHS;EXTRA"
|
||||
${ARGN})
|
||||
foreach(arch ${ARG_ARCHS})
|
||||
set(target_name ${name}-${arch})
|
||||
set(stamp ${CMAKE_CURRENT_BINARY_DIR}/${target_name}.syms-stamp)
|
||||
set(extra_args)
|
||||
foreach(arg ${ARG_EXTRA})
|
||||
list(APPEND extra_args "--extra" ${arg})
|
||||
endforeach()
|
||||
add_custom_command(OUTPUT ${stamp}
|
||||
COMMAND ${PYTHON_EXECUTABLE}
|
||||
${SANITIZER_GEN_DYNAMIC_LIST} ${extra_args} $<TARGET_FILE:${target_name}>
|
||||
-o $<TARGET_FILE:${target_name}>.syms
|
||||
COMMAND ${CMAKE_COMMAND} -E touch ${stamp}
|
||||
DEPENDS ${target_name} ${SANITIZER_GEN_DYNAMIC_LIST} ${ARG_EXTRA}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
COMMENT "Generating exported symbols for ${target_name}"
|
||||
VERBATIM)
|
||||
add_custom_target(${target_name}-symbols ALL
|
||||
DEPENDS ${stamp}
|
||||
SOURCES ${SANITIZER_GEN_DYNAMIC_LIST} ${ARG_EXTRA})
|
||||
get_compiler_rt_install_dir(${arch} install_dir)
|
||||
install(FILES $<TARGET_FILE:${target_name}>.syms
|
||||
DESTINATION ${install_dir})
|
||||
if(ARG_PARENT_TARGET)
|
||||
add_dependencies(${ARG_PARENT_TARGET} ${target_name}-symbols)
|
||||
endif()
|
||||
endforeach()
|
||||
endmacro()
|
||||
|
||||
# This function is only used on Darwin, where undefined symbols must be specified
|
||||
# in the linker invocation.
|
||||
function(add_weak_symbols libname link_flags)
|
||||
set(weak_symbols_file "${COMPILER_RT_SOURCE_DIR}/lib/${libname}/weak_symbols.txt")
|
||||
file(STRINGS "${weak_symbols_file}" WEAK_SYMBOLS)
|
||||
# Add this file as a configure-time dependency so that changes to this
|
||||
# file trigger a re-configure. This is necessary so that `${link_flags}`
|
||||
# is changed when appropriate.
|
||||
set_property(
|
||||
DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
APPEND
|
||||
PROPERTY CMAKE_CONFIGURE_DEPENDS "${weak_symbols_file}")
|
||||
set(local_link_flags ${${link_flags}})
|
||||
foreach(SYMBOL ${WEAK_SYMBOLS})
|
||||
set(local_link_flags ${local_link_flags} -Wl,-U,${SYMBOL})
|
||||
endforeach()
|
||||
set(${link_flags} ${local_link_flags} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
macro(add_sanitizer_rt_version_list name)
|
||||
set(vers ${CMAKE_CURRENT_BINARY_DIR}/${name}.vers)
|
||||
cmake_parse_arguments(ARG "" "" "LIBS;EXTRA" ${ARGN})
|
||||
set(args)
|
||||
foreach(arg ${ARG_EXTRA})
|
||||
list(APPEND args "--extra" ${arg})
|
||||
endforeach()
|
||||
foreach(arg ${ARG_LIBS})
|
||||
list(APPEND args "$<TARGET_FILE:${arg}>")
|
||||
endforeach()
|
||||
add_custom_command(OUTPUT ${vers}
|
||||
COMMAND ${PYTHON_EXECUTABLE}
|
||||
${SANITIZER_GEN_DYNAMIC_LIST} --version-list ${args}
|
||||
-o ${vers}
|
||||
DEPENDS ${SANITIZER_GEN_DYNAMIC_LIST} ${ARG_EXTRA} ${ARG_LIBS}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
COMMENT "Generating version list for ${name}"
|
||||
VERBATIM)
|
||||
|
||||
add_custom_target(${name}-version-list ALL
|
||||
DEPENDS ${vers})
|
||||
endmacro()
|
||||
|
||||
# Add target to check code style for sanitizer runtimes.
|
||||
if(CMAKE_HOST_UNIX AND NOT OS_NAME MATCHES "OpenBSD")
|
||||
add_custom_target(SanitizerLintCheck
|
||||
COMMAND env LLVM_CHECKOUT=${LLVM_MAIN_SRC_DIR} SILENT=1 TMPDIR=
|
||||
PYTHON_EXECUTABLE=${PYTHON_EXECUTABLE}
|
||||
COMPILER_RT=${COMPILER_RT_SOURCE_DIR}
|
||||
${SANITIZER_LINT_SCRIPT}
|
||||
DEPENDS ${SANITIZER_LINT_SCRIPT}
|
||||
COMMENT "Running lint check for sanitizer sources..."
|
||||
VERBATIM)
|
||||
else()
|
||||
add_custom_target(SanitizerLintCheck
|
||||
COMMAND echo "No lint check")
|
||||
endif()
|
||||
set_target_properties(SanitizerLintCheck
|
||||
PROPERTIES FOLDER "Compiler-RT Misc")
|
@ -1,226 +0,0 @@
|
||||
# The CompilerRT build system requires CMake version 2.8.8 or higher in order
|
||||
# to use its support for building convenience "libraries" as a collection of
|
||||
# .o files. This is particularly useful in producing larger, more complex
|
||||
# runtime libraries.
|
||||
|
||||
include(CheckIncludeFile)
|
||||
include(CheckCXXSourceCompiles)
|
||||
|
||||
check_include_file(unwind.h HAVE_UNWIND_H)
|
||||
|
||||
# Used by sanitizer_common and tests.
|
||||
check_include_file(rpc/xdr.h HAVE_RPC_XDR_H)
|
||||
if (NOT HAVE_RPC_XDR_H)
|
||||
set(HAVE_RPC_XDR_H 0)
|
||||
endif()
|
||||
|
||||
# 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_property(
|
||||
TARGET
|
||||
compiler-rt
|
||||
install-compiler-rt
|
||||
install-compiler-rt-stripped
|
||||
PROPERTY
|
||||
FOLDER "Compiler-RT Misc"
|
||||
)
|
||||
|
||||
# Setting these variables from an LLVM build is sufficient that compiler-rt can
|
||||
# construct the output paths, so it can behave as if it were in-tree here.
|
||||
if (LLVM_LIBRARY_OUTPUT_INTDIR AND LLVM_RUNTIME_OUTPUT_INTDIR AND PACKAGE_VERSION)
|
||||
set(LLVM_TREE_AVAILABLE On)
|
||||
endif()
|
||||
|
||||
if (LLVM_TREE_AVAILABLE)
|
||||
# Compute the Clang version from the LLVM version.
|
||||
# FIXME: We should be able to reuse CLANG_VERSION variable calculated
|
||||
# in Clang cmake files, instead of copying the rules here.
|
||||
string(REGEX MATCH "[0-9]+\\.[0-9]+(\\.[0-9]+)?" CLANG_VERSION
|
||||
${PACKAGE_VERSION})
|
||||
# Setup the paths where compiler-rt runtimes and headers should be stored.
|
||||
set(COMPILER_RT_OUTPUT_DIR ${LLVM_LIBRARY_OUTPUT_INTDIR}/clang/${CLANG_VERSION})
|
||||
set(COMPILER_RT_EXEC_OUTPUT_DIR ${LLVM_RUNTIME_OUTPUT_INTDIR})
|
||||
set(COMPILER_RT_INSTALL_PATH lib${LLVM_LIBDIR_SUFFIX}/clang/${CLANG_VERSION})
|
||||
option(COMPILER_RT_INCLUDE_TESTS "Generate and build compiler-rt unit tests."
|
||||
${LLVM_INCLUDE_TESTS})
|
||||
option(COMPILER_RT_ENABLE_WERROR "Fail and stop if warning is triggered"
|
||||
${LLVM_ENABLE_WERROR})
|
||||
# Use just-built Clang to compile/link tests on all platforms, except for
|
||||
# Windows where we need to use clang-cl instead.
|
||||
if(NOT MSVC)
|
||||
set(COMPILER_RT_TEST_COMPILER ${LLVM_RUNTIME_OUTPUT_INTDIR}/clang)
|
||||
set(COMPILER_RT_TEST_CXX_COMPILER ${LLVM_RUNTIME_OUTPUT_INTDIR}/clang++)
|
||||
else()
|
||||
set(COMPILER_RT_TEST_COMPILER ${LLVM_RUNTIME_OUTPUT_INTDIR}/clang.exe)
|
||||
set(COMPILER_RT_TEST_CXX_COMPILER ${LLVM_RUNTIME_OUTPUT_INTDIR}/clang++.exe)
|
||||
endif()
|
||||
else()
|
||||
# Take output dir and install path from the user.
|
||||
set(COMPILER_RT_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR} CACHE PATH
|
||||
"Path where built compiler-rt libraries should be stored.")
|
||||
set(COMPILER_RT_EXEC_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/bin CACHE PATH
|
||||
"Path where built compiler-rt executables should be stored.")
|
||||
set(COMPILER_RT_INSTALL_PATH ${CMAKE_INSTALL_PREFIX} CACHE PATH
|
||||
"Path where built compiler-rt libraries should be installed.")
|
||||
option(COMPILER_RT_INCLUDE_TESTS "Generate and build compiler-rt unit tests." OFF)
|
||||
option(COMPILER_RT_ENABLE_WERROR "Fail and stop if warning is triggered" OFF)
|
||||
# Use a host compiler to compile/link tests.
|
||||
set(COMPILER_RT_TEST_COMPILER ${CMAKE_C_COMPILER} CACHE PATH "Compiler to use for testing")
|
||||
set(COMPILER_RT_TEST_CXX_COMPILER ${CMAKE_CXX_COMPILER} CACHE PATH "C++ Compiler to use for testing")
|
||||
endif()
|
||||
|
||||
if("${COMPILER_RT_TEST_COMPILER}" MATCHES "clang[+]*$")
|
||||
set(COMPILER_RT_TEST_COMPILER_ID Clang)
|
||||
elseif("${COMPILER_RT_TEST_COMPILER}" MATCHES "clang.*.exe$")
|
||||
set(COMPILER_RT_TEST_COMPILER_ID Clang)
|
||||
else()
|
||||
set(COMPILER_RT_TEST_COMPILER_ID GNU)
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED COMPILER_RT_OS_DIR)
|
||||
string(TOLOWER ${CMAKE_SYSTEM_NAME} COMPILER_RT_OS_DIR)
|
||||
endif()
|
||||
if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND NOT APPLE)
|
||||
set(COMPILER_RT_LIBRARY_OUTPUT_DIR
|
||||
${COMPILER_RT_OUTPUT_DIR})
|
||||
set(COMPILER_RT_LIBRARY_INSTALL_DIR
|
||||
${COMPILER_RT_INSTALL_PATH})
|
||||
else(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR)
|
||||
set(COMPILER_RT_LIBRARY_OUTPUT_DIR
|
||||
${COMPILER_RT_OUTPUT_DIR}/lib/${COMPILER_RT_OS_DIR})
|
||||
set(COMPILER_RT_LIBRARY_INSTALL_DIR
|
||||
${COMPILER_RT_INSTALL_PATH}/lib/${COMPILER_RT_OS_DIR})
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
# On Darwin if /usr/include doesn't exist, the user probably has Xcode but not
|
||||
# the command line tools. If this is the case, we need to find the OS X
|
||||
# sysroot to pass to clang.
|
||||
if(NOT EXISTS /usr/include)
|
||||
execute_process(COMMAND xcodebuild -version -sdk macosx Path
|
||||
OUTPUT_VARIABLE OSX_SYSROOT
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
set(OSX_SYSROOT_FLAG "-isysroot${OSX_SYSROOT}")
|
||||
endif()
|
||||
|
||||
option(COMPILER_RT_ENABLE_IOS "Enable building for iOS" 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()
|
||||
|
||||
if(WIN32 AND NOT MINGW AND NOT CYGWIN)
|
||||
set(CMAKE_SHARED_LIBRARY_PREFIX_C "")
|
||||
set(CMAKE_SHARED_LIBRARY_PREFIX_CXX "")
|
||||
set(CMAKE_STATIC_LIBRARY_PREFIX_C "")
|
||||
set(CMAKE_STATIC_LIBRARY_PREFIX_CXX "")
|
||||
set(CMAKE_STATIC_LIBRARY_SUFFIX_C ".lib")
|
||||
set(CMAKE_STATIC_LIBRARY_SUFFIX_CXX ".lib")
|
||||
endif()
|
||||
|
||||
macro(test_targets)
|
||||
# Find and run MSVC (not clang-cl) and get its version. This will tell clang-cl
|
||||
# what version of MSVC to pretend to be so that the STL works.
|
||||
set(MSVC_VERSION_FLAG "")
|
||||
if (MSVC)
|
||||
execute_process(COMMAND "$ENV{VSINSTALLDIR}/VC/bin/cl.exe"
|
||||
OUTPUT_QUIET
|
||||
ERROR_VARIABLE MSVC_COMPAT_VERSION
|
||||
)
|
||||
string(REGEX REPLACE "^.*Compiler Version ([0-9.]+) for .*$" "\\1"
|
||||
MSVC_COMPAT_VERSION "${MSVC_COMPAT_VERSION}")
|
||||
if (MSVC_COMPAT_VERSION MATCHES "^[0-9].+$")
|
||||
set(MSVC_VERSION_FLAG "-fms-compatibility-version=${MSVC_COMPAT_VERSION}")
|
||||
# Add this flag into the host build if this is clang-cl.
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
append("${MSVC_VERSION_FLAG}" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
|
||||
elseif (COMPILER_RT_TEST_COMPILER_ID MATCHES "Clang")
|
||||
# Add this flag to test compiles to suppress clang's auto-detection
|
||||
# logic.
|
||||
append("${MSVC_VERSION_FLAG}" COMPILER_RT_TEST_COMPILER_CFLAGS)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Generate the COMPILER_RT_SUPPORTED_ARCH list.
|
||||
if(ANDROID)
|
||||
# Examine compiler output to determine target architecture.
|
||||
detect_target_arch()
|
||||
set(COMPILER_RT_OS_SUFFIX "-android")
|
||||
elseif(NOT APPLE) # Supported archs for Apple platforms are generated later
|
||||
if(COMPILER_RT_DEFAULT_TARGET_ONLY)
|
||||
add_default_target_arch(${COMPILER_RT_DEFAULT_TARGET_ARCH})
|
||||
elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "i[2-6]86|x86|amd64")
|
||||
if(NOT MSVC)
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "OpenBSD")
|
||||
if (CMAKE_SIZEOF_VOID_P EQUAL 4)
|
||||
test_target_arch(i386 __i386__ "-m32")
|
||||
else()
|
||||
test_target_arch(x86_64 "" "-m64")
|
||||
endif()
|
||||
else()
|
||||
test_target_arch(x86_64 "" "-m64")
|
||||
test_target_arch(i386 __i386__ "-m32")
|
||||
endif()
|
||||
else()
|
||||
if (CMAKE_SIZEOF_VOID_P EQUAL 4)
|
||||
test_target_arch(i386 "" "")
|
||||
else()
|
||||
test_target_arch(x86_64 "" "")
|
||||
endif()
|
||||
endif()
|
||||
elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "powerpc")
|
||||
# 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()
|
||||
test_target_arch(powerpc64le "" "-m64")
|
||||
endif()
|
||||
elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "s390x")
|
||||
test_target_arch(s390x "" "")
|
||||
elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "mipsel|mips64el")
|
||||
# Gcc doesn't accept -m32/-m64 so we do the next best thing and use
|
||||
# -mips32r2/-mips64r2. We don't use -mips1/-mips3 because we want to match
|
||||
# clang's default CPU's. In the 64-bit case, we must also specify the ABI
|
||||
# since the default ABI differs between gcc and clang.
|
||||
# FIXME: Ideally, we would build the N32 library too.
|
||||
test_target_arch(mipsel "" "-mips32r2" "-mabi=32")
|
||||
test_target_arch(mips64el "" "-mips64r2" "-mabi=64")
|
||||
elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "mips")
|
||||
test_target_arch(mips "" "-mips32r2" "-mabi=32")
|
||||
test_target_arch(mips64 "" "-mips64r2" "-mabi=64")
|
||||
elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "arm")
|
||||
if(WIN32)
|
||||
test_target_arch(arm "" "" "")
|
||||
else()
|
||||
test_target_arch(arm "" "-march=armv7-a" "-mfloat-abi=soft")
|
||||
test_target_arch(armhf "" "-march=armv7-a" "-mfloat-abi=hard")
|
||||
test_target_arch(armv6m "" "-march=armv6m" "-mfloat-abi=soft")
|
||||
endif()
|
||||
elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "aarch32")
|
||||
test_target_arch(aarch32 "" "-march=armv8-a")
|
||||
elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "aarch64")
|
||||
test_target_arch(aarch64 "" "-march=armv8-a")
|
||||
elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "riscv32")
|
||||
test_target_arch(riscv32 "" "")
|
||||
elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "riscv64")
|
||||
test_target_arch(riscv64 "" "")
|
||||
elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "wasm32")
|
||||
test_target_arch(wasm32 "" "--target=wasm32-unknown-unknown")
|
||||
elseif("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "wasm64")
|
||||
test_target_arch(wasm64 "" "--target=wasm64-unknown-unknown")
|
||||
endif()
|
||||
set(COMPILER_RT_OS_SUFFIX "")
|
||||
endif()
|
||||
endmacro()
|
@ -1,167 +0,0 @@
|
||||
include(BuiltinTests)
|
||||
include(CheckCSourceCompiles)
|
||||
|
||||
# Make all the tests only check the compiler
|
||||
set(TEST_COMPILE_ONLY On)
|
||||
|
||||
# Check host compiler support for certain flags
|
||||
builtin_check_c_compiler_flag(-fPIC COMPILER_RT_HAS_FPIC_FLAG)
|
||||
builtin_check_c_compiler_flag(-fPIE COMPILER_RT_HAS_FPIE_FLAG)
|
||||
builtin_check_c_compiler_flag(-fno-builtin COMPILER_RT_HAS_FNO_BUILTIN_FLAG)
|
||||
builtin_check_c_compiler_flag(-std=c11 COMPILER_RT_HAS_STD_C11_FLAG)
|
||||
builtin_check_c_compiler_flag(-fvisibility=hidden COMPILER_RT_HAS_VISIBILITY_HIDDEN_FLAG)
|
||||
builtin_check_c_compiler_flag(-fomit-frame-pointer COMPILER_RT_HAS_OMIT_FRAME_POINTER_FLAG)
|
||||
builtin_check_c_compiler_flag(-ffreestanding COMPILER_RT_HAS_FREESTANDING_FLAG)
|
||||
builtin_check_c_compiler_flag(-fxray-instrument COMPILER_RT_HAS_XRAY_COMPILER_FLAG)
|
||||
|
||||
builtin_check_c_compiler_source(COMPILER_RT_HAS_ATOMIC_KEYWORD
|
||||
"
|
||||
int foo(int x, int y) {
|
||||
_Atomic int result = x * y;
|
||||
return result;
|
||||
}
|
||||
")
|
||||
|
||||
|
||||
set(ARM64 aarch64)
|
||||
set(ARM32 arm armhf armv6m armv7m armv7em armv7 armv7s armv7k)
|
||||
set(HEXAGON hexagon)
|
||||
set(X86 i386)
|
||||
set(X86_64 x86_64)
|
||||
set(MIPS32 mips mipsel)
|
||||
set(MIPS64 mips64 mips64el)
|
||||
set(PPC64 powerpc64 powerpc64le)
|
||||
set(RISCV32 riscv32)
|
||||
set(RISCV64 riscv64)
|
||||
set(WASM32 wasm32)
|
||||
set(WASM64 wasm64)
|
||||
|
||||
if(APPLE)
|
||||
set(ARM64 arm64)
|
||||
set(ARM32 armv7 armv7k armv7s)
|
||||
set(X86_64 x86_64 x86_64h)
|
||||
endif()
|
||||
|
||||
set(ALL_BUILTIN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64}
|
||||
${HEXAGON} ${MIPS32} ${MIPS64} ${PPC64} ${RISCV32} ${RISCV64} ${WASM32} ${WASM64})
|
||||
|
||||
include(CompilerRTUtils)
|
||||
include(CompilerRTDarwinUtils)
|
||||
|
||||
if(APPLE)
|
||||
|
||||
find_darwin_sdk_dir(DARWIN_osx_SYSROOT macosx)
|
||||
find_darwin_sdk_dir(DARWIN_iossim_SYSROOT iphonesimulator)
|
||||
find_darwin_sdk_dir(DARWIN_ios_SYSROOT iphoneos)
|
||||
find_darwin_sdk_dir(DARWIN_watchossim_SYSROOT watchsimulator)
|
||||
find_darwin_sdk_dir(DARWIN_watchos_SYSROOT watchos)
|
||||
find_darwin_sdk_dir(DARWIN_tvossim_SYSROOT appletvsimulator)
|
||||
find_darwin_sdk_dir(DARWIN_tvos_SYSROOT appletvos)
|
||||
|
||||
set(DARWIN_EMBEDDED_PLATFORMS)
|
||||
set(DARWIN_osx_BUILTIN_MIN_VER 10.5)
|
||||
set(DARWIN_osx_BUILTIN_MIN_VER_FLAG
|
||||
-mmacosx-version-min=${DARWIN_osx_BUILTIN_MIN_VER})
|
||||
|
||||
if(COMPILER_RT_ENABLE_IOS)
|
||||
list(APPEND DARWIN_EMBEDDED_PLATFORMS ios)
|
||||
set(DARWIN_ios_MIN_VER_FLAG -miphoneos-version-min)
|
||||
set(DARWIN_ios_BUILTIN_MIN_VER 6.0)
|
||||
set(DARWIN_ios_BUILTIN_MIN_VER_FLAG
|
||||
${DARWIN_ios_MIN_VER_FLAG}=${DARWIN_ios_BUILTIN_MIN_VER})
|
||||
endif()
|
||||
if(COMPILER_RT_ENABLE_WATCHOS)
|
||||
list(APPEND DARWIN_EMBEDDED_PLATFORMS watchos)
|
||||
set(DARWIN_watchos_MIN_VER_FLAG -mwatchos-version-min)
|
||||
set(DARWIN_watchos_BUILTIN_MIN_VER 2.0)
|
||||
set(DARWIN_watchos_BUILTIN_MIN_VER_FLAG
|
||||
${DARWIN_watchos_MIN_VER_FLAG}=${DARWIN_watchos_BUILTIN_MIN_VER})
|
||||
endif()
|
||||
if(COMPILER_RT_ENABLE_TVOS)
|
||||
list(APPEND DARWIN_EMBEDDED_PLATFORMS tvos)
|
||||
set(DARWIN_tvos_MIN_VER_FLAG -mtvos-version-min)
|
||||
set(DARWIN_tvos_BUILTIN_MIN_VER 9.0)
|
||||
set(DARWIN_tvos_BUILTIN_MIN_VER_FLAG
|
||||
${DARWIN_tvos_MIN_VER_FLAG}=${DARWIN_tvos_BUILTIN_MIN_VER})
|
||||
endif()
|
||||
|
||||
set(BUILTIN_SUPPORTED_OS osx)
|
||||
|
||||
# We're setting the flag manually for each target OS
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "")
|
||||
|
||||
if(NOT DARWIN_osx_ARCHS)
|
||||
set(DARWIN_osx_ARCHS i386 x86_64 x86_64h)
|
||||
endif()
|
||||
|
||||
set(DARWIN_sim_ARCHS i386 x86_64)
|
||||
set(DARWIN_device_ARCHS armv7 armv7s armv7k arm64)
|
||||
|
||||
message(STATUS "OSX supported arches: ${DARWIN_osx_ARCHS}")
|
||||
foreach(arch ${DARWIN_osx_ARCHS})
|
||||
list(APPEND COMPILER_RT_SUPPORTED_ARCH ${arch})
|
||||
set(CAN_TARGET_${arch} 1)
|
||||
endforeach()
|
||||
|
||||
foreach(platform ${DARWIN_EMBEDDED_PLATFORMS})
|
||||
if(DARWIN_${platform}sim_SYSROOT)
|
||||
set(DARWIN_${platform}sim_BUILTIN_MIN_VER
|
||||
${DARWIN_${platform}_BUILTIN_MIN_VER})
|
||||
set(DARWIN_${platform}sim_BUILTIN_MIN_VER_FLAG
|
||||
${DARWIN_${platform}_BUILTIN_MIN_VER_FLAG})
|
||||
|
||||
set(DARWIN_${platform}sim_SKIP_CC_KEXT On)
|
||||
|
||||
set(test_arches ${DARWIN_sim_ARCHS})
|
||||
if(DARWIN_${platform}sim_ARCHS)
|
||||
set(test_arches DARWIN_${platform}sim_ARCHS)
|
||||
endif()
|
||||
|
||||
darwin_test_archs(${platform}sim
|
||||
DARWIN_${platform}sim_ARCHS
|
||||
${test_arches})
|
||||
message(STATUS "${platform} Simulator supported builtin arches: ${DARWIN_${platform}sim_ARCHS}")
|
||||
if(DARWIN_${platform}sim_ARCHS)
|
||||
list(APPEND BUILTIN_SUPPORTED_OS ${platform}sim)
|
||||
endif()
|
||||
foreach(arch ${DARWIN_${platform}sim_ARCHS})
|
||||
list(APPEND COMPILER_RT_SUPPORTED_ARCH ${arch})
|
||||
set(CAN_TARGET_${arch} 1)
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if(DARWIN_${platform}_SYSROOT)
|
||||
set(test_arches ${DARWIN_device_ARCHS})
|
||||
if(DARWIN_${platform}_ARCHS)
|
||||
set(test_arches DARWIN_${platform}_ARCHS)
|
||||
endif()
|
||||
|
||||
darwin_test_archs(${platform}
|
||||
DARWIN_${platform}_ARCHS
|
||||
${test_arches})
|
||||
message(STATUS "${platform} supported builtin arches: ${DARWIN_${platform}_ARCHS}")
|
||||
if(DARWIN_${platform}_ARCHS)
|
||||
list(APPEND BUILTIN_SUPPORTED_OS ${platform})
|
||||
endif()
|
||||
foreach(arch ${DARWIN_${platform}_ARCHS})
|
||||
list(APPEND COMPILER_RT_SUPPORTED_ARCH ${arch})
|
||||
set(CAN_TARGET_${arch} 1)
|
||||
endforeach()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
list_intersect(BUILTIN_SUPPORTED_ARCH ALL_BUILTIN_SUPPORTED_ARCH COMPILER_RT_SUPPORTED_ARCH)
|
||||
|
||||
else()
|
||||
# If we're not building the builtins standalone, just rely on the tests in
|
||||
# config-ix.cmake to tell us what to build. Otherwise we need to do some leg
|
||||
# work here...
|
||||
if(COMPILER_RT_BUILTINS_STANDALONE_BUILD)
|
||||
test_targets()
|
||||
endif()
|
||||
# Architectures supported by compiler-rt libraries.
|
||||
filter_available_targets(BUILTIN_SUPPORTED_ARCH
|
||||
${ALL_BUILTIN_SUPPORTED_ARCH})
|
||||
endif()
|
||||
|
||||
message(STATUS "Builtin supported architectures: ${BUILTIN_SUPPORTED_ARCH}")
|
@ -1,15 +0,0 @@
|
||||
# This file sets up a CMakeCache for Apple-style builds of compiler-rt.
|
||||
# This configuration matches Apple uses when shipping Xcode releases.
|
||||
|
||||
set(COMPILER_RT_INCLUDE_TESTS OFF CACHE BOOL "")
|
||||
set(COMPILER_RT_HAS_SAFESTACK OFF CACHE BOOL "")
|
||||
set(COMPILER_RT_EXTERNALIZE_DEBUGINFO ON CACHE BOOL "")
|
||||
set(CMAKE_MACOSX_RPATH ON CACHE BOOL "")
|
||||
|
||||
set(CMAKE_C_FLAGS_RELEASE "-O3" CACHE STRING "")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-O3" CACHE STRING "")
|
||||
set(CMAKE_ASM_FLAGS_RELEASE "-O3" CACHE STRING "")
|
||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O3 -gline-tables-only -DNDEBUG" CACHE STRING "")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O3 -gline-tables-only -DNDEBUG" CACHE STRING "")
|
||||
set(CMAKE_ASM_FLAGS_RELWITHDEBINFO "-O3 -gline-tables-only -DNDEBUG" CACHE STRING "")
|
||||
set(CMAKE_BUILD_TYPE RELEASE CACHE STRING "")
|
@ -1,665 +0,0 @@
|
||||
include(CMakePushCheckState)
|
||||
include(CheckCCompilerFlag)
|
||||
include(CheckCXXCompilerFlag)
|
||||
include(CheckLibraryExists)
|
||||
include(CheckSymbolExists)
|
||||
include(TestBigEndian)
|
||||
|
||||
function(check_linker_flag flag out_var)
|
||||
cmake_push_check_state()
|
||||
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${flag}")
|
||||
check_cxx_compiler_flag("" ${out_var})
|
||||
cmake_pop_check_state()
|
||||
endfunction()
|
||||
|
||||
check_library_exists(c fopen "" COMPILER_RT_HAS_LIBC)
|
||||
if (COMPILER_RT_USE_BUILTINS_LIBRARY)
|
||||
include(HandleCompilerRT)
|
||||
find_compiler_rt_library(builtins COMPILER_RT_BUILTINS_LIBRARY)
|
||||
else()
|
||||
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 (COMPILER_RT_USE_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 ()
|
||||
if (MINGW)
|
||||
# Mingw64 requires quite a few "C" runtime libraries in order for basic
|
||||
# programs to link successfully with -nodefaultlibs.
|
||||
if (COMPILER_RT_USE_BUILTINS_LIBRARY)
|
||||
set(MINGW_RUNTIME ${COMPILER_RT_BUILTINS_LIBRARY})
|
||||
else ()
|
||||
set(MINGW_RUNTIME gcc_s gcc)
|
||||
endif()
|
||||
set(MINGW_LIBRARIES mingw32 ${MINGW_RUNTIME} moldname mingwex msvcrt advapi32
|
||||
shell32 user32 kernel32 mingw32 ${MINGW_RUNTIME}
|
||||
moldname mingwex msvcrt)
|
||||
list(APPEND CMAKE_REQUIRED_LIBRARIES ${MINGW_LIBRARIES})
|
||||
endif()
|
||||
endif ()
|
||||
|
||||
# CodeGen options.
|
||||
check_c_compiler_flag(-ffreestanding COMPILER_RT_HAS_FFREESTANDING_FLAG)
|
||||
check_cxx_compiler_flag(-fPIC COMPILER_RT_HAS_FPIC_FLAG)
|
||||
check_cxx_compiler_flag(-fPIE COMPILER_RT_HAS_FPIE_FLAG)
|
||||
check_cxx_compiler_flag(-fno-builtin COMPILER_RT_HAS_FNO_BUILTIN_FLAG)
|
||||
check_cxx_compiler_flag(-fno-exceptions COMPILER_RT_HAS_FNO_EXCEPTIONS_FLAG)
|
||||
check_cxx_compiler_flag(-fomit-frame-pointer COMPILER_RT_HAS_FOMIT_FRAME_POINTER_FLAG)
|
||||
check_cxx_compiler_flag(-funwind-tables COMPILER_RT_HAS_FUNWIND_TABLES_FLAG)
|
||||
check_cxx_compiler_flag(-fno-stack-protector COMPILER_RT_HAS_FNO_STACK_PROTECTOR_FLAG)
|
||||
check_cxx_compiler_flag(-fno-sanitize=safe-stack COMPILER_RT_HAS_FNO_SANITIZE_SAFE_STACK_FLAG)
|
||||
check_cxx_compiler_flag(-fvisibility=hidden COMPILER_RT_HAS_FVISIBILITY_HIDDEN_FLAG)
|
||||
check_cxx_compiler_flag(-frtti COMPILER_RT_HAS_FRTTI_FLAG)
|
||||
check_cxx_compiler_flag(-fno-rtti COMPILER_RT_HAS_FNO_RTTI_FLAG)
|
||||
check_cxx_compiler_flag("-Werror -fno-function-sections" COMPILER_RT_HAS_FNO_FUNCTION_SECTIONS_FLAG)
|
||||
check_cxx_compiler_flag(-std=c++11 COMPILER_RT_HAS_STD_CXX11_FLAG)
|
||||
check_cxx_compiler_flag(-ftls-model=initial-exec COMPILER_RT_HAS_FTLS_MODEL_INITIAL_EXEC)
|
||||
check_cxx_compiler_flag(-fno-lto COMPILER_RT_HAS_FNO_LTO_FLAG)
|
||||
check_cxx_compiler_flag("-Werror -msse3" COMPILER_RT_HAS_MSSE3_FLAG)
|
||||
check_cxx_compiler_flag("-Werror -msse4.2" COMPILER_RT_HAS_MSSE4_2_FLAG)
|
||||
check_cxx_compiler_flag(--sysroot=. COMPILER_RT_HAS_SYSROOT_FLAG)
|
||||
check_cxx_compiler_flag("-Werror -mcrc" COMPILER_RT_HAS_MCRC_FLAG)
|
||||
|
||||
if(NOT WIN32 AND NOT CYGWIN)
|
||||
# MinGW warns if -fvisibility-inlines-hidden is used.
|
||||
check_cxx_compiler_flag("-fvisibility-inlines-hidden" COMPILER_RT_HAS_FVISIBILITY_INLINES_HIDDEN_FLAG)
|
||||
endif()
|
||||
|
||||
check_cxx_compiler_flag(/GR COMPILER_RT_HAS_GR_FLAG)
|
||||
check_cxx_compiler_flag(/GS COMPILER_RT_HAS_GS_FLAG)
|
||||
check_cxx_compiler_flag(/MT COMPILER_RT_HAS_MT_FLAG)
|
||||
check_cxx_compiler_flag(/Oy COMPILER_RT_HAS_Oy_FLAG)
|
||||
|
||||
# Debug info flags.
|
||||
check_cxx_compiler_flag(-gline-tables-only COMPILER_RT_HAS_GLINE_TABLES_ONLY_FLAG)
|
||||
check_cxx_compiler_flag(-g COMPILER_RT_HAS_G_FLAG)
|
||||
check_cxx_compiler_flag(/Zi COMPILER_RT_HAS_Zi_FLAG)
|
||||
|
||||
# Warnings.
|
||||
check_cxx_compiler_flag(-Wall COMPILER_RT_HAS_WALL_FLAG)
|
||||
check_cxx_compiler_flag(-Werror COMPILER_RT_HAS_WERROR_FLAG)
|
||||
check_cxx_compiler_flag("-Werror -Wframe-larger-than=512" COMPILER_RT_HAS_WFRAME_LARGER_THAN_FLAG)
|
||||
check_cxx_compiler_flag("-Werror -Wglobal-constructors" COMPILER_RT_HAS_WGLOBAL_CONSTRUCTORS_FLAG)
|
||||
check_cxx_compiler_flag("-Werror -Wc99-extensions" COMPILER_RT_HAS_WC99_EXTENSIONS_FLAG)
|
||||
check_cxx_compiler_flag("-Werror -Wgnu" COMPILER_RT_HAS_WGNU_FLAG)
|
||||
check_cxx_compiler_flag("-Werror -Wnon-virtual-dtor" COMPILER_RT_HAS_WNON_VIRTUAL_DTOR_FLAG)
|
||||
check_cxx_compiler_flag("-Werror -Wvariadic-macros" COMPILER_RT_HAS_WVARIADIC_MACROS_FLAG)
|
||||
check_cxx_compiler_flag("-Werror -Wunused-parameter" COMPILER_RT_HAS_WUNUSED_PARAMETER_FLAG)
|
||||
check_cxx_compiler_flag("-Werror -Wcovered-switch-default" COMPILER_RT_HAS_WCOVERED_SWITCH_DEFAULT_FLAG)
|
||||
|
||||
check_cxx_compiler_flag(/W4 COMPILER_RT_HAS_W4_FLAG)
|
||||
check_cxx_compiler_flag(/WX COMPILER_RT_HAS_WX_FLAG)
|
||||
check_cxx_compiler_flag(/wd4146 COMPILER_RT_HAS_WD4146_FLAG)
|
||||
check_cxx_compiler_flag(/wd4291 COMPILER_RT_HAS_WD4291_FLAG)
|
||||
check_cxx_compiler_flag(/wd4221 COMPILER_RT_HAS_WD4221_FLAG)
|
||||
check_cxx_compiler_flag(/wd4391 COMPILER_RT_HAS_WD4391_FLAG)
|
||||
check_cxx_compiler_flag(/wd4722 COMPILER_RT_HAS_WD4722_FLAG)
|
||||
check_cxx_compiler_flag(/wd4800 COMPILER_RT_HAS_WD4800_FLAG)
|
||||
|
||||
# Symbols.
|
||||
check_symbol_exists(__func__ "" COMPILER_RT_HAS_FUNC_SYMBOL)
|
||||
|
||||
# Libraries.
|
||||
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)
|
||||
|
||||
# Look for terminfo library, used in unittests that depend on LLVMSupport.
|
||||
if(LLVM_ENABLE_TERMINFO)
|
||||
foreach(library terminfo tinfo curses ncurses ncursesw)
|
||||
string(TOUPPER ${library} library_suffix)
|
||||
check_library_exists(
|
||||
${library} setupterm "" COMPILER_RT_HAS_TERMINFO_${library_suffix})
|
||||
if(COMPILER_RT_HAS_TERMINFO_${library_suffix})
|
||||
set(COMPILER_RT_HAS_TERMINFO TRUE)
|
||||
set(COMPILER_RT_TERMINFO_LIB "${library}")
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
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(c++ __cxa_throw "" COMPILER_RT_HAS_LIBCXX)
|
||||
check_library_exists(stdc++ __cxa_throw "" COMPILER_RT_HAS_LIBSTDCXX)
|
||||
|
||||
# Linker flags.
|
||||
if(ANDROID)
|
||||
check_linker_flag("-Wl,-z,global" COMPILER_RT_HAS_Z_GLOBAL)
|
||||
check_library_exists(log __android_log_write "" COMPILER_RT_HAS_LIBLOG)
|
||||
endif()
|
||||
|
||||
# Architectures.
|
||||
|
||||
# List of all architectures we can target.
|
||||
set(COMPILER_RT_SUPPORTED_ARCH)
|
||||
|
||||
# Try to compile a very simple source file to ensure we can target the given
|
||||
# platform. We use the results of these tests to build only the various target
|
||||
# runtime libraries supported by our current compilers cross-compiling
|
||||
# abilities.
|
||||
set(SIMPLE_SOURCE ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/simple.cc)
|
||||
file(WRITE ${SIMPLE_SOURCE} "#include <stdlib.h>\n#include <stdio.h>\nint main() { printf(\"hello, world\"); }\n")
|
||||
|
||||
# Detect whether the current target platform is 32-bit or 64-bit, and setup
|
||||
# the correct commandline flags needed to attempt to target 32-bit and 64-bit.
|
||||
if (NOT CMAKE_SIZEOF_VOID_P EQUAL 4 AND
|
||||
NOT CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
message(FATAL_ERROR "Please use architecture with 4 or 8 byte pointers.")
|
||||
endif()
|
||||
|
||||
test_targets()
|
||||
|
||||
# Returns a list of architecture specific target cflags in @out_var list.
|
||||
function(get_target_flags_for_arch arch out_var)
|
||||
list(FIND COMPILER_RT_SUPPORTED_ARCH ${arch} ARCH_INDEX)
|
||||
if(ARCH_INDEX EQUAL -1)
|
||||
message(FATAL_ERROR "Unsupported architecture: ${arch}")
|
||||
else()
|
||||
if (NOT APPLE)
|
||||
set(${out_var} ${TARGET_${arch}_CFLAGS} PARENT_SCOPE)
|
||||
else()
|
||||
# This is only called in constructing cflags for tests executing on the
|
||||
# host. This will need to all be cleaned up to support building tests
|
||||
# for cross-targeted hardware (i.e. iOS).
|
||||
set(${out_var} -arch ${arch} PARENT_SCOPE)
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Returns a compiler and CFLAGS that should be used to run tests for the
|
||||
# specific architecture. When cross-compiling, this is controled via
|
||||
# COMPILER_RT_TEST_COMPILER and COMPILER_RT_TEST_COMPILER_CFLAGS.
|
||||
macro(get_test_cc_for_arch arch cc_out cflags_out)
|
||||
if(ANDROID OR ${arch} MATCHES "arm|aarch64")
|
||||
# This is only true if we are cross-compiling.
|
||||
# Build all tests with host compiler and use host tools.
|
||||
set(${cc_out} ${COMPILER_RT_TEST_COMPILER})
|
||||
set(${cflags_out} ${COMPILER_RT_TEST_COMPILER_CFLAGS})
|
||||
else()
|
||||
get_target_flags_for_arch(${arch} ${cflags_out})
|
||||
if(APPLE)
|
||||
list(APPEND ${cflags_out} ${DARWIN_osx_CFLAGS})
|
||||
endif()
|
||||
string(REPLACE ";" " " ${cflags_out} "${${cflags_out}}")
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
set(ARM64 aarch64)
|
||||
set(ARM32 arm armhf)
|
||||
set(HEXAGON hexagon)
|
||||
set(X86 i386)
|
||||
set(X86_64 x86_64)
|
||||
set(MIPS32 mips mipsel)
|
||||
set(MIPS64 mips64 mips64el)
|
||||
set(PPC64 powerpc64 powerpc64le)
|
||||
set(RISCV32 riscv32)
|
||||
set(RISCV64 riscv64)
|
||||
set(S390X s390x)
|
||||
set(WASM32 wasm32)
|
||||
set(WASM64 wasm64)
|
||||
|
||||
if(APPLE)
|
||||
set(ARM64 arm64)
|
||||
set(ARM32 armv7 armv7s armv7k)
|
||||
set(X86_64 x86_64 x86_64h)
|
||||
endif()
|
||||
|
||||
set(ALL_SANITIZER_COMMON_SUPPORTED_ARCH ${X86} ${X86_64} ${PPC64}
|
||||
${ARM32} ${ARM64} ${MIPS32} ${MIPS64} ${S390X})
|
||||
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} ${ARM64})
|
||||
|
||||
if(APPLE)
|
||||
set(ALL_LSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${MIPS64} ${ARM64})
|
||||
else()
|
||||
set(ALL_LSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${MIPS64} ${ARM64} ${ARM32} ${PPC64})
|
||||
endif()
|
||||
set(ALL_MSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64} ${PPC64})
|
||||
set(ALL_HWASAN_SUPPORTED_ARCH ${X86_64} ${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} ${ARM32} ${ARM64} ${MIPS64})
|
||||
set(ALL_ESAN_SUPPORTED_ARCH ${X86_64} ${MIPS64})
|
||||
set(ALL_SCUDO_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${MIPS32} ${MIPS64} ${PPC64})
|
||||
if(APPLE)
|
||||
set(ALL_XRAY_SUPPORTED_ARCH ${X86_64})
|
||||
else()
|
||||
set(ALL_XRAY_SUPPORTED_ARCH ${X86_64} ${ARM32} ${ARM64} ${MIPS32} ${MIPS64} powerpc64le)
|
||||
endif()
|
||||
set(ALL_SHADOWCALLSTACK_SUPPORTED_ARCH ${X86_64} ${ARM64})
|
||||
|
||||
if(APPLE)
|
||||
include(CompilerRTDarwinUtils)
|
||||
|
||||
find_darwin_sdk_dir(DARWIN_osx_SYSROOT macosx)
|
||||
find_darwin_sdk_dir(DARWIN_iossim_SYSROOT iphonesimulator)
|
||||
find_darwin_sdk_dir(DARWIN_ios_SYSROOT iphoneos)
|
||||
find_darwin_sdk_dir(DARWIN_watchossim_SYSROOT watchsimulator)
|
||||
find_darwin_sdk_dir(DARWIN_watchos_SYSROOT watchos)
|
||||
find_darwin_sdk_dir(DARWIN_tvossim_SYSROOT appletvsimulator)
|
||||
find_darwin_sdk_dir(DARWIN_tvos_SYSROOT appletvos)
|
||||
|
||||
if(NOT DARWIN_osx_SYSROOT)
|
||||
if(EXISTS /usr/include)
|
||||
set(DARWIN_osx_SYSROOT /)
|
||||
else()
|
||||
message(ERROR "Could not detect OS X Sysroot. Either install Xcode or the Apple Command Line Tools")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(COMPILER_RT_ENABLE_IOS)
|
||||
list(APPEND DARWIN_EMBEDDED_PLATFORMS ios)
|
||||
set(DARWIN_ios_MIN_VER_FLAG -miphoneos-version-min)
|
||||
set(DARWIN_ios_SANITIZER_MIN_VER_FLAG
|
||||
${DARWIN_ios_MIN_VER_FLAG}=8.0)
|
||||
endif()
|
||||
if(COMPILER_RT_ENABLE_WATCHOS)
|
||||
list(APPEND DARWIN_EMBEDDED_PLATFORMS watchos)
|
||||
set(DARWIN_watchos_MIN_VER_FLAG -mwatchos-version-min)
|
||||
set(DARWIN_watchos_SANITIZER_MIN_VER_FLAG
|
||||
${DARWIN_watchos_MIN_VER_FLAG}=2.0)
|
||||
endif()
|
||||
if(COMPILER_RT_ENABLE_TVOS)
|
||||
list(APPEND DARWIN_EMBEDDED_PLATFORMS tvos)
|
||||
set(DARWIN_tvos_MIN_VER_FLAG -mtvos-version-min)
|
||||
set(DARWIN_tvos_SANITIZER_MIN_VER_FLAG
|
||||
${DARWIN_tvos_MIN_VER_FLAG}=9.0)
|
||||
endif()
|
||||
|
||||
# Note: In order to target x86_64h on OS X the minimum deployment target must
|
||||
# be 10.8 or higher.
|
||||
set(SANITIZER_COMMON_SUPPORTED_OS osx)
|
||||
set(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}")
|
||||
if(MACOSX_VERSION_MIN_FLAG)
|
||||
set(SANITIZER_MIN_OSX_VERSION "${CMAKE_MATCH_1}")
|
||||
elseif(CMAKE_OSX_DEPLOYMENT_TARGET)
|
||||
set(SANITIZER_MIN_OSX_VERSION ${CMAKE_OSX_DEPLOYMENT_TARGET})
|
||||
else()
|
||||
set(SANITIZER_MIN_OSX_VERSION 10.9)
|
||||
endif()
|
||||
if(SANITIZER_MIN_OSX_VERSION VERSION_LESS "10.7")
|
||||
message(FATAL_ERROR "macOS deployment target '${SANITIZER_MIN_OSX_VERSION}' is too old.")
|
||||
endif()
|
||||
if(SANITIZER_MIN_OSX_VERSION VERSION_GREATER "10.9")
|
||||
message(WARNING "macOS deployment target '${SANITIZER_MIN_OSX_VERSION}' is too new, setting to '10.9' instead.")
|
||||
set(SANITIZER_MIN_OSX_VERSION 10.9)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# We're setting the flag manually for each target OS
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "")
|
||||
|
||||
set(DARWIN_COMMON_CFLAGS -stdlib=libc++)
|
||||
set(DARWIN_COMMON_LINK_FLAGS
|
||||
-stdlib=libc++
|
||||
-lc++
|
||||
-lc++abi)
|
||||
|
||||
check_linker_flag("-fapplication-extension" COMPILER_RT_HAS_APP_EXTENSION)
|
||||
if(COMPILER_RT_HAS_APP_EXTENSION)
|
||||
list(APPEND DARWIN_COMMON_LINK_FLAGS "-fapplication-extension")
|
||||
endif()
|
||||
|
||||
set(DARWIN_osx_CFLAGS
|
||||
${DARWIN_COMMON_CFLAGS}
|
||||
-mmacosx-version-min=${SANITIZER_MIN_OSX_VERSION})
|
||||
set(DARWIN_osx_LINK_FLAGS
|
||||
${DARWIN_COMMON_LINK_FLAGS}
|
||||
-mmacosx-version-min=${SANITIZER_MIN_OSX_VERSION})
|
||||
|
||||
if(DARWIN_osx_SYSROOT)
|
||||
list(APPEND DARWIN_osx_CFLAGS -isysroot ${DARWIN_osx_SYSROOT})
|
||||
list(APPEND DARWIN_osx_LINK_FLAGS -isysroot ${DARWIN_osx_SYSROOT})
|
||||
endif()
|
||||
|
||||
# Figure out which arches to use for each OS
|
||||
darwin_get_toolchain_supported_archs(toolchain_arches)
|
||||
message(STATUS "Toolchain supported arches: ${toolchain_arches}")
|
||||
|
||||
if(NOT MACOSX_VERSION_MIN_FLAG)
|
||||
darwin_test_archs(osx
|
||||
DARWIN_osx_ARCHS
|
||||
${toolchain_arches})
|
||||
message(STATUS "OSX supported arches: ${DARWIN_osx_ARCHS}")
|
||||
foreach(arch ${DARWIN_osx_ARCHS})
|
||||
list(APPEND COMPILER_RT_SUPPORTED_ARCH ${arch})
|
||||
set(CAN_TARGET_${arch} 1)
|
||||
endforeach()
|
||||
|
||||
foreach(platform ${DARWIN_EMBEDDED_PLATFORMS})
|
||||
if(DARWIN_${platform}sim_SYSROOT)
|
||||
set(DARWIN_${platform}sim_CFLAGS
|
||||
${DARWIN_COMMON_CFLAGS}
|
||||
${DARWIN_${platform}_SANITIZER_MIN_VER_FLAG}
|
||||
-isysroot ${DARWIN_${platform}sim_SYSROOT})
|
||||
set(DARWIN_${platform}sim_LINK_FLAGS
|
||||
${DARWIN_COMMON_LINK_FLAGS}
|
||||
${DARWIN_${platform}_SANITIZER_MIN_VER_FLAG}
|
||||
-isysroot ${DARWIN_${platform}sim_SYSROOT})
|
||||
|
||||
set(DARWIN_${platform}sim_SKIP_CC_KEXT On)
|
||||
darwin_test_archs(${platform}sim
|
||||
DARWIN_${platform}sim_ARCHS
|
||||
${toolchain_arches})
|
||||
message(STATUS "${platform} Simulator supported arches: ${DARWIN_${platform}sim_ARCHS}")
|
||||
if(DARWIN_${platform}sim_ARCHS)
|
||||
list(APPEND SANITIZER_COMMON_SUPPORTED_OS ${platform}sim)
|
||||
list(APPEND PROFILE_SUPPORTED_OS ${platform}sim)
|
||||
list(APPEND TSAN_SUPPORTED_OS ${platform}sim)
|
||||
endif()
|
||||
foreach(arch ${DARWIN_${platform}sim_ARCHS})
|
||||
list(APPEND COMPILER_RT_SUPPORTED_ARCH ${arch})
|
||||
set(CAN_TARGET_${arch} 1)
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if(DARWIN_${platform}_SYSROOT)
|
||||
set(DARWIN_${platform}_CFLAGS
|
||||
${DARWIN_COMMON_CFLAGS}
|
||||
${DARWIN_${platform}_SANITIZER_MIN_VER_FLAG}
|
||||
-isysroot ${DARWIN_${platform}_SYSROOT})
|
||||
set(DARWIN_${platform}_LINK_FLAGS
|
||||
${DARWIN_COMMON_LINK_FLAGS}
|
||||
${DARWIN_${platform}_SANITIZER_MIN_VER_FLAG}
|
||||
-isysroot ${DARWIN_${platform}_SYSROOT})
|
||||
|
||||
darwin_test_archs(${platform}
|
||||
DARWIN_${platform}_ARCHS
|
||||
${toolchain_arches})
|
||||
message(STATUS "${platform} supported arches: ${DARWIN_${platform}_ARCHS}")
|
||||
if(DARWIN_${platform}_ARCHS)
|
||||
list(APPEND SANITIZER_COMMON_SUPPORTED_OS ${platform})
|
||||
list(APPEND PROFILE_SUPPORTED_OS ${platform})
|
||||
|
||||
list_intersect(DARWIN_${platform}_TSAN_ARCHS DARWIN_${platform}_ARCHS ALL_TSAN_SUPPORTED_ARCH)
|
||||
if(DARWIN_${platform}_TSAN_ARCHS)
|
||||
list(APPEND TSAN_SUPPORTED_OS ${platform})
|
||||
endif()
|
||||
endif()
|
||||
foreach(arch ${DARWIN_${platform}_ARCHS})
|
||||
list(APPEND COMPILER_RT_SUPPORTED_ARCH ${arch})
|
||||
set(CAN_TARGET_${arch} 1)
|
||||
endforeach()
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
# for list_intersect
|
||||
include(CompilerRTUtils)
|
||||
|
||||
list_intersect(SANITIZER_COMMON_SUPPORTED_ARCH
|
||||
ALL_SANITIZER_COMMON_SUPPORTED_ARCH
|
||||
COMPILER_RT_SUPPORTED_ARCH
|
||||
)
|
||||
set(LSAN_COMMON_SUPPORTED_ARCH ${SANITIZER_COMMON_SUPPORTED_ARCH})
|
||||
set(UBSAN_COMMON_SUPPORTED_ARCH ${SANITIZER_COMMON_SUPPORTED_ARCH})
|
||||
list_intersect(ASAN_SUPPORTED_ARCH
|
||||
ALL_ASAN_SUPPORTED_ARCH
|
||||
SANITIZER_COMMON_SUPPORTED_ARCH)
|
||||
list_intersect(DFSAN_SUPPORTED_ARCH
|
||||
ALL_DFSAN_SUPPORTED_ARCH
|
||||
SANITIZER_COMMON_SUPPORTED_ARCH)
|
||||
list_intersect(LSAN_SUPPORTED_ARCH
|
||||
ALL_LSAN_SUPPORTED_ARCH
|
||||
SANITIZER_COMMON_SUPPORTED_ARCH)
|
||||
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)
|
||||
list_intersect(TSAN_SUPPORTED_ARCH
|
||||
ALL_TSAN_SUPPORTED_ARCH
|
||||
SANITIZER_COMMON_SUPPORTED_ARCH)
|
||||
list_intersect(UBSAN_SUPPORTED_ARCH
|
||||
ALL_UBSAN_SUPPORTED_ARCH
|
||||
SANITIZER_COMMON_SUPPORTED_ARCH)
|
||||
list_intersect(SAFESTACK_SUPPORTED_ARCH
|
||||
ALL_SAFESTACK_SUPPORTED_ARCH
|
||||
SANITIZER_COMMON_SUPPORTED_ARCH)
|
||||
list_intersect(CFI_SUPPORTED_ARCH
|
||||
ALL_CFI_SUPPORTED_ARCH
|
||||
SANITIZER_COMMON_SUPPORTED_ARCH)
|
||||
list_intersect(ESAN_SUPPORTED_ARCH
|
||||
ALL_ESAN_SUPPORTED_ARCH
|
||||
SANITIZER_COMMON_SUPPORTED_ARCH)
|
||||
list_intersect(SCUDO_SUPPORTED_ARCH
|
||||
ALL_SCUDO_SUPPORTED_ARCH
|
||||
SANITIZER_COMMON_SUPPORTED_ARCH)
|
||||
list_intersect(FUZZER_SUPPORTED_ARCH
|
||||
ALL_FUZZER_SUPPORTED_ARCH
|
||||
SANITIZER_COMMON_SUPPORTED_ARCH)
|
||||
list_intersect(XRAY_SUPPORTED_ARCH
|
||||
ALL_XRAY_SUPPORTED_ARCH
|
||||
SANITIZER_COMMON_SUPPORTED_ARCH)
|
||||
list_intersect(SHADOWCALLSTACK_SUPPORTED_ARCH
|
||||
ALL_SHADOWCALLSTACK_SUPPORTED_ARCH
|
||||
SANITIZER_COMMON_SUPPORTED_ARCH)
|
||||
|
||||
else()
|
||||
# Architectures supported by compiler-rt libraries.
|
||||
filter_available_targets(SANITIZER_COMMON_SUPPORTED_ARCH
|
||||
${ALL_SANITIZER_COMMON_SUPPORTED_ARCH})
|
||||
# LSan and UBSan common files should be available on all architectures
|
||||
# supported by other sanitizers (even if they build into dummy object files).
|
||||
filter_available_targets(LSAN_COMMON_SUPPORTED_ARCH
|
||||
${SANITIZER_COMMON_SUPPORTED_ARCH})
|
||||
filter_available_targets(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})
|
||||
filter_available_targets(SAFESTACK_SUPPORTED_ARCH
|
||||
${ALL_SAFESTACK_SUPPORTED_ARCH})
|
||||
filter_available_targets(CFI_SUPPORTED_ARCH ${ALL_CFI_SUPPORTED_ARCH})
|
||||
filter_available_targets(ESAN_SUPPORTED_ARCH ${ALL_ESAN_SUPPORTED_ARCH})
|
||||
filter_available_targets(SCUDO_SUPPORTED_ARCH ${ALL_SCUDO_SUPPORTED_ARCH})
|
||||
filter_available_targets(XRAY_SUPPORTED_ARCH ${ALL_XRAY_SUPPORTED_ARCH})
|
||||
filter_available_targets(SHADOWCALLSTACK_SUPPORTED_ARCH
|
||||
${ALL_SHADOWCALLSTACK_SUPPORTED_ARCH})
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
# See if the DIA SDK is available and usable.
|
||||
set(MSVC_DIA_SDK_DIR "$ENV{VSINSTALLDIR}DIA SDK")
|
||||
if (IS_DIRECTORY ${MSVC_DIA_SDK_DIR})
|
||||
set(CAN_SYMBOLIZE 1)
|
||||
else()
|
||||
set(CAN_SYMBOLIZE 0)
|
||||
endif()
|
||||
else()
|
||||
set(CAN_SYMBOLIZE 1)
|
||||
endif()
|
||||
|
||||
find_program(GOLD_EXECUTABLE NAMES ${LLVM_DEFAULT_TARGET_TRIPLE}-ld.gold ld.gold ${LLVM_DEFAULT_TARGET_TRIPLE}-ld ld DOC "The gold linker")
|
||||
|
||||
if(COMPILER_RT_SUPPORTED_ARCH)
|
||||
list(REMOVE_DUPLICATES COMPILER_RT_SUPPORTED_ARCH)
|
||||
endif()
|
||||
message(STATUS "Compiler-RT supported architectures: ${COMPILER_RT_SUPPORTED_ARCH}")
|
||||
|
||||
if(ANDROID)
|
||||
set(OS_NAME "Android")
|
||||
else()
|
||||
set(OS_NAME "${CMAKE_SYSTEM_NAME}")
|
||||
endif()
|
||||
|
||||
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|NetBSD|OpenBSD|Fuchsia|SunOS" OR
|
||||
(OS_NAME MATCHES "Windows" AND NOT CYGWIN AND
|
||||
(NOT MINGW OR CMAKE_CXX_COMPILER_ID MATCHES "Clang"))))
|
||||
set(COMPILER_RT_HAS_SANITIZER_COMMON TRUE)
|
||||
else()
|
||||
set(COMPILER_RT_HAS_SANITIZER_COMMON FALSE)
|
||||
endif()
|
||||
|
||||
if (COMPILER_RT_HAS_SANITIZER_COMMON)
|
||||
set(COMPILER_RT_HAS_INTERCEPTION TRUE)
|
||||
else()
|
||||
set(COMPILER_RT_HAS_INTERCEPTION FALSE)
|
||||
endif()
|
||||
|
||||
if (COMPILER_RT_HAS_SANITIZER_COMMON AND ASAN_SUPPORTED_ARCH AND
|
||||
NOT OS_NAME MATCHES "OpenBSD")
|
||||
set(COMPILER_RT_HAS_ASAN TRUE)
|
||||
else()
|
||||
set(COMPILER_RT_HAS_ASAN FALSE)
|
||||
endif()
|
||||
|
||||
if (OS_NAME MATCHES "Linux|FreeBSD|Windows|NetBSD|SunOS")
|
||||
set(COMPILER_RT_ASAN_HAS_STATIC_RUNTIME TRUE)
|
||||
else()
|
||||
set(COMPILER_RT_ASAN_HAS_STATIC_RUNTIME FALSE)
|
||||
endif()
|
||||
|
||||
# TODO: Add builtins support.
|
||||
|
||||
if (COMPILER_RT_HAS_SANITIZER_COMMON AND DFSAN_SUPPORTED_ARCH AND
|
||||
OS_NAME MATCHES "Linux")
|
||||
set(COMPILER_RT_HAS_DFSAN TRUE)
|
||||
else()
|
||||
set(COMPILER_RT_HAS_DFSAN FALSE)
|
||||
endif()
|
||||
|
||||
if (COMPILER_RT_HAS_SANITIZER_COMMON AND LSAN_SUPPORTED_ARCH AND
|
||||
OS_NAME MATCHES "Darwin|Linux|FreeBSD|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|FreeBSD|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|Fuchsia|SunOS|NetBSD")
|
||||
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|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|NetBSD|OpenBSD|Windows|Android|Fuchsia|SunOS")
|
||||
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|OpenBSD|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|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)
|
||||
set(COMPILER_RT_HAS_CFI TRUE)
|
||||
else()
|
||||
set(COMPILER_RT_HAS_CFI FALSE)
|
||||
endif()
|
||||
|
||||
if (COMPILER_RT_HAS_SANITIZER_COMMON AND ESAN_SUPPORTED_ARCH AND
|
||||
OS_NAME MATCHES "Linux|FreeBSD")
|
||||
set(COMPILER_RT_HAS_ESAN TRUE)
|
||||
else()
|
||||
set(COMPILER_RT_HAS_ESAN FALSE)
|
||||
endif()
|
||||
|
||||
if (COMPILER_RT_HAS_SANITIZER_COMMON AND SCUDO_SUPPORTED_ARCH AND
|
||||
OS_NAME MATCHES "Linux|Android|Fuchsia")
|
||||
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 "Darwin|Linux|FreeBSD|NetBSD|OpenBSD|Fuchsia")
|
||||
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|FreeBSD|OpenBSD|Fuchsia|Windows" AND
|
||||
# TODO: Support builds with MSVC.
|
||||
NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC" AND
|
||||
NOT "${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC")
|
||||
set(COMPILER_RT_HAS_FUZZER TRUE)
|
||||
else()
|
||||
set(COMPILER_RT_HAS_FUZZER FALSE)
|
||||
endif()
|
||||
|
||||
if (COMPILER_RT_HAS_SANITIZER_COMMON AND SHADOWCALLSTACK_SUPPORTED_ARCH AND
|
||||
OS_NAME MATCHES "Linux|Android")
|
||||
set(COMPILER_RT_HAS_SHADOWCALLSTACK TRUE)
|
||||
else()
|
||||
set(COMPILER_RT_HAS_SHADOWCALLSTACK FALSE)
|
||||
endif()
|
@ -1,66 +0,0 @@
|
||||
========================================
|
||||
Compiler-rt Testing Infrastructure Guide
|
||||
========================================
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
|
||||
Overview
|
||||
========
|
||||
|
||||
This document is the reference manual for the compiler-rt modifications to the
|
||||
testing infrastructure. Documentation for the infrastructure itself can be found at
|
||||
:ref:`llvm_testing_guide`.
|
||||
|
||||
LLVM testing infrastructure organization
|
||||
========================================
|
||||
|
||||
The compiler-rt testing infrastructure contains regression tests which are run
|
||||
as part of the usual ``make check-all`` and are expected to always pass -- they
|
||||
should be run before every commit.
|
||||
|
||||
Quick start
|
||||
===========
|
||||
|
||||
The regressions tests are in the "compiler-rt" module and are normally checked
|
||||
out in the directory ``llvm/projects/compiler-rt/test``. Use ``make check-all``
|
||||
to run the regression tests after building compiler-rt.
|
||||
|
||||
REQUIRES, XFAIL, etc.
|
||||
---------------------
|
||||
|
||||
Sometimes it is necessary to restrict a test to a specific target or mark it as
|
||||
an "expected fail" or XFAIL. This is normally achieved using ``REQUIRES:`` or
|
||||
``XFAIL:`` with a substring of LLVM's default target triple. Unfortunately, the
|
||||
behaviour of this is somewhat quirky in compiler-rt. There are two main
|
||||
pitfalls to avoid.
|
||||
|
||||
The first pitfall is that these directives perform a substring match on the
|
||||
triple and as such ``XFAIL: mips`` affects more triples than expected. For
|
||||
example, ``mips-linux-gnu``, ``mipsel-linux-gnu``, ``mips64-linux-gnu``, and
|
||||
``mips64el-linux-gnu`` will all match a ``XFAIL: mips`` directive. Including a
|
||||
trailing ``-`` such as in ``XFAIL: mips-`` can help to mitigate this quirk but
|
||||
even that has issues as described below.
|
||||
|
||||
The second pitfall is that the default target triple is often inappropriate for
|
||||
compiler-rt tests since compiler-rt tests may be compiled for multiple targets.
|
||||
For example, a typical build on an ``x86_64-linux-gnu`` host will often run the
|
||||
tests for both x86_64 and i386. In this situation ``XFAIL: x86_64`` will mark
|
||||
both the x86_64 and i386 tests as an expected failure while ``XFAIL: i386``
|
||||
will have no effect at all.
|
||||
|
||||
To remedy both pitfalls, compiler-rt tests provide a feature string which can
|
||||
be used to specify a single target. This string is of the form
|
||||
``target-is-${arch}`` where ``${arch}}`` is one of the values from the
|
||||
following lines of the CMake output::
|
||||
|
||||
-- Compiler-RT supported architectures: x86_64;i386
|
||||
-- Builtin supported architectures: i386;x86_64
|
||||
|
||||
So for example ``XFAIL: target-is-x86_64`` will mark a test as expected to fail
|
||||
on x86_64 without also affecting the i386 test and ``XFAIL: target-is-i386``
|
||||
will mark a test as expected to fail on i386 even if the default target triple
|
||||
is ``x86_64-linux-gnu``. Directives that use these ``target-is-${arch}`` string
|
||||
require exact matches so ``XFAIL: target-is-mips``,
|
||||
``XFAIL: target-is-mipsel``, ``XFAIL: target-is-mips64``, and
|
||||
``XFAIL: target-is-mips64el`` all refer to different MIPS targets.
|
@ -1,72 +0,0 @@
|
||||
if (COMPILER_RT_BUILD_SANITIZERS)
|
||||
set(SANITIZER_HEADERS
|
||||
sanitizer/allocator_interface.h
|
||||
sanitizer/asan_interface.h
|
||||
sanitizer/common_interface_defs.h
|
||||
sanitizer/coverage_interface.h
|
||||
sanitizer/dfsan_interface.h
|
||||
sanitizer/esan_interface.h
|
||||
sanitizer/hwasan_interface.h
|
||||
sanitizer/linux_syscall_hooks.h
|
||||
sanitizer/lsan_interface.h
|
||||
sanitizer/msan_interface.h
|
||||
sanitizer/netbsd_syscall_hooks.h
|
||||
sanitizer/scudo_interface.h
|
||||
sanitizer/tsan_interface.h
|
||||
sanitizer/tsan_interface_atomic.h)
|
||||
endif(COMPILER_RT_BUILD_SANITIZERS)
|
||||
|
||||
if (COMPILER_RT_BUILD_XRAY)
|
||||
set(XRAY_HEADERS
|
||||
xray/xray_interface.h
|
||||
xray/xray_log_interface.h)
|
||||
endif(COMPILER_RT_BUILD_XRAY)
|
||||
|
||||
set(COMPILER_RT_HEADERS
|
||||
${SANITIZER_HEADERS}
|
||||
${XRAY_HEADERS})
|
||||
|
||||
set(output_dir ${COMPILER_RT_OUTPUT_DIR}/include)
|
||||
|
||||
# Copy compiler-rt headers to the build tree.
|
||||
set(out_files)
|
||||
foreach( f ${COMPILER_RT_HEADERS} )
|
||||
set( src ${CMAKE_CURRENT_SOURCE_DIR}/${f} )
|
||||
set( dst ${output_dir}/${f} )
|
||||
add_custom_command(OUTPUT ${dst}
|
||||
DEPENDS ${src}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${src} ${dst}
|
||||
COMMENT "Copying compiler-rt's ${f}...")
|
||||
list(APPEND out_files ${dst})
|
||||
endforeach( f )
|
||||
|
||||
add_custom_target(compiler-rt-headers ALL DEPENDS ${out_files})
|
||||
add_dependencies(compiler-rt compiler-rt-headers)
|
||||
set_target_properties(compiler-rt-headers PROPERTIES FOLDER "Compiler-RT Misc")
|
||||
|
||||
# Install sanitizer headers.
|
||||
install(FILES ${SANITIZER_HEADERS}
|
||||
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()
|
@ -1,54 +0,0 @@
|
||||
# First, add the subdirectories which contain feature-based runtime libraries
|
||||
# and several convenience helper libraries.
|
||||
|
||||
include(AddCompilerRT)
|
||||
include(SanitizerUtils)
|
||||
|
||||
# Hoist the building of sanitizer_common on whether we're building either the
|
||||
# sanitizers or xray (or both).
|
||||
#
|
||||
#TODO: Refactor sanitizer_common into smaller pieces (e.g. flag parsing, utils).
|
||||
if (COMPILER_RT_HAS_SANITIZER_COMMON AND
|
||||
(COMPILER_RT_BUILD_SANITIZERS OR COMPILER_RT_BUILD_XRAY))
|
||||
add_subdirectory(sanitizer_common)
|
||||
endif()
|
||||
|
||||
if(COMPILER_RT_BUILD_BUILTINS)
|
||||
add_subdirectory(builtins)
|
||||
endif()
|
||||
|
||||
function(compiler_rt_build_runtime runtime)
|
||||
string(TOUPPER ${runtime} runtime_uppercase)
|
||||
if(COMPILER_RT_HAS_${runtime_uppercase})
|
||||
add_subdirectory(${runtime})
|
||||
if(${runtime} STREQUAL tsan)
|
||||
add_subdirectory(tsan/dd)
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
if(COMPILER_RT_BUILD_SANITIZERS)
|
||||
compiler_rt_build_runtime(interception)
|
||||
|
||||
if(COMPILER_RT_HAS_SANITIZER_COMMON)
|
||||
add_subdirectory(stats)
|
||||
add_subdirectory(lsan)
|
||||
add_subdirectory(ubsan)
|
||||
endif()
|
||||
|
||||
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()
|
@ -1,2 +0,0 @@
|
||||
BasedOnStyle: Google
|
||||
AllowShortIfStatementsOnASingleLine: false
|
@ -1,338 +0,0 @@
|
||||
# Build for the AddressSanitizer runtime support library.
|
||||
|
||||
set(ASAN_SOURCES
|
||||
asan_allocator.cc
|
||||
asan_activation.cc
|
||||
asan_debugging.cc
|
||||
asan_descriptions.cc
|
||||
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
|
||||
asan_malloc_mac.cc
|
||||
asan_malloc_win.cc
|
||||
asan_memory_profile.cc
|
||||
asan_poisoning.cc
|
||||
asan_posix.cc
|
||||
asan_premap_shadow.cc
|
||||
asan_report.cc
|
||||
asan_rtems.cc
|
||||
asan_rtl.cc
|
||||
asan_shadow_setup.cc
|
||||
asan_stack.cc
|
||||
asan_stats.cc
|
||||
asan_suppressions.cc
|
||||
asan_thread.cc
|
||||
asan_win.cc)
|
||||
|
||||
set(ASAN_CXX_SOURCES
|
||||
asan_new_delete.cc)
|
||||
|
||||
set(ASAN_PREINIT_SOURCES
|
||||
asan_preinit.cc)
|
||||
|
||||
SET(ASAN_HEADERS
|
||||
asan_activation.h
|
||||
asan_activation_flags.inc
|
||||
asan_allocator.h
|
||||
asan_descriptions.h
|
||||
asan_errors.h
|
||||
asan_fake_stack.h
|
||||
asan_flags.h
|
||||
asan_flags.inc
|
||||
asan_init_version.h
|
||||
asan_interceptors.h
|
||||
asan_interceptors_memintrinsics.h
|
||||
asan_interface.inc
|
||||
asan_interface_internal.h
|
||||
asan_internal.h
|
||||
asan_lock.h
|
||||
asan_malloc_local.h
|
||||
asan_mapping.h
|
||||
asan_mapping_myriad.h
|
||||
asan_poisoning.h
|
||||
asan_premap_shadow.h
|
||||
asan_report.h
|
||||
asan_scariness_score.h
|
||||
asan_stack.h
|
||||
asan_stats.h
|
||||
asan_suppressions.h
|
||||
asan_thread.h)
|
||||
|
||||
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 ${SANITIZER_COMMON_LINK_FLAGS})
|
||||
|
||||
if(ANDROID)
|
||||
# Put most Sanitizer shared libraries in the global group. For more details, see
|
||||
# android-changes-for-ndk-developers.md#changes-to-library-search-order
|
||||
if (COMPILER_RT_HAS_Z_GLOBAL)
|
||||
list(APPEND ASAN_DYNAMIC_LINK_FLAGS -Wl,-z,global)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(ASAN_DYNAMIC_DEFINITIONS
|
||||
${ASAN_COMMON_DEFINITIONS} ASAN_DYNAMIC=1)
|
||||
append_list_if(WIN32 INTERCEPTION_DYNAMIC_CRT ASAN_DYNAMIC_DEFINITIONS)
|
||||
|
||||
set(ASAN_DYNAMIC_CFLAGS ${ASAN_CFLAGS})
|
||||
append_list_if(COMPILER_RT_HAS_FTLS_MODEL_INITIAL_EXEC
|
||||
-ftls-model=initial-exec ASAN_DYNAMIC_CFLAGS)
|
||||
append_list_if(MSVC /DEBUG ASAN_DYNAMIC_LINK_FLAGS)
|
||||
|
||||
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_LIBLOG log ASAN_DYNAMIC_LIBS)
|
||||
append_list_if(MINGW "${MINGW_LIBRARIES}" ASAN_DYNAMIC_LIBS)
|
||||
|
||||
if (TARGET cxx-headers OR HAVE_LIBCXX)
|
||||
set(ASAN_DEPS cxx-headers)
|
||||
endif()
|
||||
|
||||
# Compile ASan sources into an object library.
|
||||
|
||||
add_compiler_rt_object_libraries(RTAsan_dynamic
|
||||
OS ${SANITIZER_COMMON_SUPPORTED_OS}
|
||||
ARCHS ${ASAN_SUPPORTED_ARCH}
|
||||
SOURCES ${ASAN_SOURCES} ${ASAN_CXX_SOURCES}
|
||||
ADDITIONAL_HEADERS ${ASAN_HEADERS}
|
||||
CFLAGS ${ASAN_DYNAMIC_CFLAGS}
|
||||
DEFS ${ASAN_DYNAMIC_DEFINITIONS}
|
||||
DEPS ${ASAN_DEPS})
|
||||
|
||||
if(NOT APPLE)
|
||||
add_compiler_rt_object_libraries(RTAsan
|
||||
ARCHS ${ASAN_SUPPORTED_ARCH}
|
||||
SOURCES ${ASAN_SOURCES}
|
||||
ADDITIONAL_HEADERS ${ASAN_HEADERS}
|
||||
CFLAGS ${ASAN_CFLAGS}
|
||||
DEFS ${ASAN_COMMON_DEFINITIONS}
|
||||
DEPS ${ASAN_DEPS})
|
||||
add_compiler_rt_object_libraries(RTAsan_cxx
|
||||
ARCHS ${ASAN_SUPPORTED_ARCH}
|
||||
SOURCES ${ASAN_CXX_SOURCES}
|
||||
ADDITIONAL_HEADERS ${ASAN_HEADERS}
|
||||
CFLAGS ${ASAN_CFLAGS}
|
||||
DEFS ${ASAN_COMMON_DEFINITIONS}
|
||||
DEPS ${ASAN_DEPS})
|
||||
add_compiler_rt_object_libraries(RTAsan_preinit
|
||||
ARCHS ${ASAN_SUPPORTED_ARCH}
|
||||
SOURCES ${ASAN_PREINIT_SOURCES}
|
||||
ADDITIONAL_HEADERS ${ASAN_HEADERS}
|
||||
CFLAGS ${ASAN_CFLAGS}
|
||||
DEFS ${ASAN_COMMON_DEFINITIONS}
|
||||
DEPS ${ASAN_DEPS})
|
||||
|
||||
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/dummy.cc "")
|
||||
add_compiler_rt_object_libraries(RTAsan_dynamic_version_script_dummy
|
||||
ARCHS ${ASAN_SUPPORTED_ARCH}
|
||||
SOURCES ${CMAKE_CURRENT_BINARY_DIR}/dummy.cc
|
||||
CFLAGS ${ASAN_DYNAMIC_CFLAGS}
|
||||
DEFS ${ASAN_DYNAMIC_DEFINITIONS}
|
||||
DEPS ${ASAN_DEPS})
|
||||
endif()
|
||||
|
||||
# Build ASan runtimes shipped with Clang.
|
||||
add_compiler_rt_component(asan)
|
||||
|
||||
if(APPLE)
|
||||
add_weak_symbols("asan" WEAK_SYMBOL_LINK_FLAGS)
|
||||
add_weak_symbols("lsan" WEAK_SYMBOL_LINK_FLAGS)
|
||||
add_weak_symbols("ubsan" WEAK_SYMBOL_LINK_FLAGS)
|
||||
add_weak_symbols("sanitizer_common" WEAK_SYMBOL_LINK_FLAGS)
|
||||
add_weak_symbols("xray" WEAK_SYMBOL_LINK_FLAGS)
|
||||
|
||||
add_compiler_rt_runtime(clang_rt.asan
|
||||
SHARED
|
||||
OS ${SANITIZER_COMMON_SUPPORTED_OS}
|
||||
ARCHS ${ASAN_SUPPORTED_ARCH}
|
||||
OBJECT_LIBS RTAsan_dynamic
|
||||
RTInterception
|
||||
RTSanitizerCommon
|
||||
RTSanitizerCommonLibc
|
||||
RTSanitizerCommonCoverage
|
||||
RTSanitizerCommonSymbolizer
|
||||
RTLSanCommon
|
||||
RTUbsan
|
||||
CFLAGS ${ASAN_DYNAMIC_CFLAGS}
|
||||
LINK_FLAGS ${WEAK_SYMBOL_LINK_FLAGS}
|
||||
DEFS ${ASAN_DYNAMIC_DEFINITIONS}
|
||||
PARENT_TARGET asan)
|
||||
else()
|
||||
# Build separate libraries for each target.
|
||||
|
||||
set(ASAN_COMMON_RUNTIME_OBJECT_LIBS
|
||||
RTInterception
|
||||
RTSanitizerCommon
|
||||
RTSanitizerCommonLibc
|
||||
RTSanitizerCommonCoverage
|
||||
RTSanitizerCommonSymbolizer
|
||||
RTLSanCommon
|
||||
RTUbsan)
|
||||
|
||||
add_compiler_rt_runtime(clang_rt.asan
|
||||
STATIC
|
||||
ARCHS ${ASAN_SUPPORTED_ARCH}
|
||||
OBJECT_LIBS RTAsan_preinit
|
||||
RTAsan
|
||||
${ASAN_COMMON_RUNTIME_OBJECT_LIBS}
|
||||
CFLAGS ${ASAN_CFLAGS}
|
||||
DEFS ${ASAN_COMMON_DEFINITIONS}
|
||||
PARENT_TARGET asan)
|
||||
|
||||
add_compiler_rt_runtime(clang_rt.asan_cxx
|
||||
STATIC
|
||||
ARCHS ${ASAN_SUPPORTED_ARCH}
|
||||
OBJECT_LIBS RTAsan_cxx
|
||||
RTUbsan_cxx
|
||||
CFLAGS ${ASAN_CFLAGS}
|
||||
DEFS ${ASAN_COMMON_DEFINITIONS}
|
||||
PARENT_TARGET asan)
|
||||
|
||||
add_compiler_rt_runtime(clang_rt.asan-preinit
|
||||
STATIC
|
||||
ARCHS ${ASAN_SUPPORTED_ARCH}
|
||||
OBJECT_LIBS RTAsan_preinit
|
||||
CFLAGS ${ASAN_CFLAGS}
|
||||
DEFS ${ASAN_COMMON_DEFINITIONS}
|
||||
PARENT_TARGET asan)
|
||||
|
||||
foreach(arch ${ASAN_SUPPORTED_ARCH})
|
||||
if (UNIX)
|
||||
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)
|
||||
# The Solaris 11.4 linker supports a subset of GNU ld version scripts,
|
||||
# but requires a special option to enable it.
|
||||
if (OS_NAME MATCHES "SunOS")
|
||||
list(APPEND VERSION_SCRIPT_FLAG -Wl,-z,gnu-version-script-compat)
|
||||
endif()
|
||||
set_property(SOURCE
|
||||
${CMAKE_CURRENT_BINARY_DIR}/dummy.cc
|
||||
APPEND PROPERTY
|
||||
OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/clang_rt.asan-dynamic-${arch}.vers)
|
||||
else()
|
||||
set(VERSION_SCRIPT_FLAG)
|
||||
endif()
|
||||
|
||||
set(ASAN_DYNAMIC_WEAK_INTERCEPTION)
|
||||
if (WIN32)
|
||||
add_compiler_rt_object_libraries(AsanWeakInterception
|
||||
${SANITIZER_COMMON_SUPPORTED_OS}
|
||||
ARCHS ${arch}
|
||||
SOURCES asan_win_weak_interception.cc
|
||||
CFLAGS ${ASAN_CFLAGS} -DSANITIZER_DYNAMIC
|
||||
DEFS ${ASAN_COMMON_DEFINITIONS}
|
||||
DEPS ${ASAN_DEPS})
|
||||
set(ASAN_DYNAMIC_WEAK_INTERCEPTION
|
||||
AsanWeakInterception
|
||||
UbsanWeakInterception
|
||||
SancovWeakInterception
|
||||
SanitizerCommonWeakInterception)
|
||||
endif()
|
||||
|
||||
add_compiler_rt_runtime(clang_rt.asan
|
||||
SHARED
|
||||
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.
|
||||
# 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}
|
||||
CFLAGS ${ASAN_DYNAMIC_CFLAGS}
|
||||
LINK_FLAGS ${ASAN_DYNAMIC_LINK_FLAGS}
|
||||
${VERSION_SCRIPT_FLAG}
|
||||
LINK_LIBS ${ASAN_DYNAMIC_LIBS}
|
||||
DEFS ${ASAN_DYNAMIC_DEFINITIONS}
|
||||
PARENT_TARGET asan)
|
||||
|
||||
if (SANITIZER_USE_SYMBOLS AND NOT ${arch} STREQUAL "i386")
|
||||
add_sanitizer_rt_symbols(clang_rt.asan_cxx
|
||||
ARCHS ${arch})
|
||||
add_dependencies(asan clang_rt.asan_cxx-${arch}-symbols)
|
||||
add_sanitizer_rt_symbols(clang_rt.asan
|
||||
ARCHS ${arch}
|
||||
EXTRA asan.syms.extra)
|
||||
add_dependencies(asan clang_rt.asan-${arch}-symbols)
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
add_compiler_rt_object_libraries(AsanDllThunk
|
||||
${SANITIZER_COMMON_SUPPORTED_OS}
|
||||
ARCHS ${arch}
|
||||
SOURCES asan_globals_win.cc
|
||||
asan_win_dll_thunk.cc
|
||||
CFLAGS ${ASAN_CFLAGS} -DSANITIZER_DLL_THUNK
|
||||
DEFS ${ASAN_COMMON_DEFINITIONS}
|
||||
DEPS ${ASAN_DEPS})
|
||||
|
||||
add_compiler_rt_runtime(clang_rt.asan_dll_thunk
|
||||
STATIC
|
||||
ARCHS ${arch}
|
||||
OBJECT_LIBS AsanDllThunk
|
||||
UbsanDllThunk
|
||||
SancovDllThunk
|
||||
SanitizerCommonDllThunk
|
||||
SOURCES $<TARGET_OBJECTS:RTInterception.${arch}>
|
||||
PARENT_TARGET asan)
|
||||
|
||||
set(DYNAMIC_RUNTIME_THUNK_CFLAGS "-DSANITIZER_DYNAMIC_RUNTIME_THUNK")
|
||||
if(MSVC)
|
||||
list(APPEND DYNAMIC_RUNTIME_THUNK_CFLAGS "-Zl")
|
||||
elseif(CMAKE_C_COMPILER_ID MATCHES Clang)
|
||||
list(APPEND DYNAMIC_RUNTIME_THUNK_CFLAGS "-nodefaultlibs")
|
||||
endif()
|
||||
|
||||
add_compiler_rt_object_libraries(AsanDynamicRuntimeThunk
|
||||
${SANITIZER_COMMON_SUPPORTED_OS}
|
||||
ARCHS ${arch}
|
||||
SOURCES asan_globals_win.cc
|
||||
asan_win_dynamic_runtime_thunk.cc
|
||||
CFLAGS ${ASAN_CFLAGS} ${DYNAMIC_RUNTIME_THUNK_CFLAGS}
|
||||
DEFS ${ASAN_COMMON_DEFINITIONS}
|
||||
DEPS ${ASAN_DEPS})
|
||||
|
||||
add_compiler_rt_runtime(clang_rt.asan_dynamic_runtime_thunk
|
||||
STATIC
|
||||
ARCHS ${arch}
|
||||
OBJECT_LIBS AsanDynamicRuntimeThunk
|
||||
UbsanDynamicRuntimeThunk
|
||||
SancovDynamicRuntimeThunk
|
||||
SanitizerCommonDynamicRuntimeThunk
|
||||
CFLAGS ${ASAN_CFLAGS} ${DYNAMIC_RUNTIME_THUNK_CFLAGS}
|
||||
DEFS ${ASAN_COMMON_DEFINITIONS}
|
||||
PARENT_TARGET asan)
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
add_compiler_rt_resource_file(asan_blacklist asan_blacklist.txt asan)
|
||||
|
||||
add_subdirectory(scripts)
|
||||
|
||||
if(COMPILER_RT_INCLUDE_TESTS)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
@ -1,4 +0,0 @@
|
||||
if(ANDROID)
|
||||
add_compiler_rt_script(asan_device_setup)
|
||||
add_dependencies(asan asan_device_setup)
|
||||
endif()
|
@ -1,467 +0,0 @@
|
||||
#!/bin/bash
|
||||
#===- lib/asan/scripts/asan_device_setup -----------------------------------===#
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
# Prepare Android device to run ASan applications.
|
||||
#
|
||||
#===------------------------------------------------------------------------===#
|
||||
|
||||
set -e
|
||||
|
||||
HERE="$(cd "$(dirname "$0")" && pwd)"
|
||||
|
||||
revert=no
|
||||
extra_options=
|
||||
device=
|
||||
lib=
|
||||
use_su=0
|
||||
|
||||
function usage {
|
||||
echo "usage: $0 [--revert] [--device device-id] [--lib path] [--extra-options options]"
|
||||
echo " --revert: Uninstall ASan from the device."
|
||||
echo " --lib: Path to ASan runtime library."
|
||||
echo " --extra-options: Extra ASAN_OPTIONS."
|
||||
echo " --device: Install to the given device. Use 'adb devices' to find"
|
||||
echo " device-id."
|
||||
echo " --use-su: Use 'su -c' prefix for every adb command instead of using"
|
||||
echo " 'adb root' once."
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
function adb_push {
|
||||
if [ $use_su -eq 0 ]; then
|
||||
$ADB push "$1" "$2"
|
||||
else
|
||||
local FILENAME=$(basename $1)
|
||||
$ADB push "$1" "/data/local/tmp/$FILENAME"
|
||||
$ADB shell su -c "rm \\\"$2/$FILENAME\\\"" >&/dev/null
|
||||
$ADB shell su -c "cat \\\"/data/local/tmp/$FILENAME\\\" > \\\"$2/$FILENAME\\\""
|
||||
$ADB shell su -c "rm \\\"/data/local/tmp/$FILENAME\\\""
|
||||
fi
|
||||
}
|
||||
|
||||
function adb_remount {
|
||||
if [ $use_su -eq 0 ]; then
|
||||
$ADB remount
|
||||
else
|
||||
local STORAGE=`$ADB shell mount | grep /system | cut -d ' ' -f1`
|
||||
if [ "$STORAGE" != "" ]; then
|
||||
echo Remounting $STORAGE at /system
|
||||
$ADB shell su -c "mount -o rw,remount $STORAGE /system"
|
||||
else
|
||||
echo Failed to get storage device name for "/system" mount point
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
function adb_shell {
|
||||
if [ $use_su -eq 0 ]; then
|
||||
$ADB shell $@
|
||||
else
|
||||
$ADB shell su -c "$*"
|
||||
fi
|
||||
}
|
||||
|
||||
function adb_root {
|
||||
if [ $use_su -eq 0 ]; then
|
||||
$ADB root
|
||||
fi
|
||||
}
|
||||
|
||||
function adb_wait_for_device {
|
||||
$ADB wait-for-device
|
||||
}
|
||||
|
||||
function adb_pull {
|
||||
if [ $use_su -eq 0 ]; then
|
||||
$ADB pull "$1" "$2"
|
||||
else
|
||||
local FILENAME=$(basename $1)
|
||||
$ADB shell rm "/data/local/tmp/$FILENAME" >&/dev/null
|
||||
$ADB shell su -c "[ -f \\\"$1\\\" ] && cat \\\"$1\\\" > \\\"/data/local/tmp/$FILENAME\\\" && chown root.shell \\\"/data/local/tmp/$FILENAME\\\" && chmod 755 \\\"/data/local/tmp/$FILENAME\\\"" &&
|
||||
$ADB pull "/data/local/tmp/$FILENAME" "$2" >&/dev/null && $ADB shell "rm \"/data/local/tmp/$FILENAME\""
|
||||
fi
|
||||
}
|
||||
|
||||
function get_device_arch { # OUT OUT64
|
||||
local _outvar=$1
|
||||
local _outvar64=$2
|
||||
local _ABI=$(adb_shell getprop ro.product.cpu.abi)
|
||||
local _ARCH=
|
||||
local _ARCH64=
|
||||
if [[ $_ABI == x86* ]]; then
|
||||
_ARCH=i386
|
||||
elif [[ $_ABI == armeabi* ]]; then
|
||||
_ARCH=arm
|
||||
elif [[ $_ABI == arm64-v8a* ]]; then
|
||||
_ARCH=arm
|
||||
_ARCH64=aarch64
|
||||
else
|
||||
echo "Unrecognized device ABI: $_ABI"
|
||||
exit 1
|
||||
fi
|
||||
eval $_outvar=\$_ARCH
|
||||
eval $_outvar64=\$_ARCH64
|
||||
}
|
||||
|
||||
while [[ $# > 0 ]]; do
|
||||
case $1 in
|
||||
--revert)
|
||||
revert=yes
|
||||
;;
|
||||
--extra-options)
|
||||
shift
|
||||
if [[ $# == 0 ]]; then
|
||||
echo "--extra-options requires an argument."
|
||||
exit 1
|
||||
fi
|
||||
extra_options="$1"
|
||||
;;
|
||||
--lib)
|
||||
shift
|
||||
if [[ $# == 0 ]]; then
|
||||
echo "--lib requires an argument."
|
||||
exit 1
|
||||
fi
|
||||
lib="$1"
|
||||
;;
|
||||
--device)
|
||||
shift
|
||||
if [[ $# == 0 ]]; then
|
||||
echo "--device requires an argument."
|
||||
exit 1
|
||||
fi
|
||||
device="$1"
|
||||
;;
|
||||
--use-su)
|
||||
use_su=1
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
ADB=${ADB:-adb}
|
||||
if [[ x$device != x ]]; then
|
||||
ADB="$ADB -s $device"
|
||||
fi
|
||||
|
||||
if [ $use_su -eq 1 ]; then
|
||||
# Test if 'su' is present on the device
|
||||
SU_TEST_OUT=`$ADB shell su -c "echo foo" 2>&1 | sed 's/\r$//'`
|
||||
if [ $? != 0 -o "$SU_TEST_OUT" != "foo" ]; then
|
||||
echo "ERROR: Cannot use 'su -c':"
|
||||
echo "$ adb shell su -c \"echo foo\""
|
||||
echo $SU_TEST_OUT
|
||||
echo "Check that 'su' binary is correctly installed on the device or omit"
|
||||
echo " --use-su flag"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo '>> Remounting /system rw'
|
||||
adb_wait_for_device
|
||||
adb_root
|
||||
adb_wait_for_device
|
||||
adb_remount
|
||||
adb_wait_for_device
|
||||
|
||||
get_device_arch ARCH ARCH64
|
||||
echo "Target architecture: $ARCH"
|
||||
ASAN_RT="libclang_rt.asan-$ARCH-android.so"
|
||||
if [[ -n $ARCH64 ]]; then
|
||||
echo "Target architecture: $ARCH64"
|
||||
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'
|
||||
|
||||
if ! adb_shell ls -l /system/bin/app_process | grep -o '\->.*app_process' >&/dev/null; then
|
||||
echo '>> Pre-L device detected.'
|
||||
adb_shell mv /system/bin/app_process.real /system/bin/app_process
|
||||
adb_shell rm /system/bin/asanwrapper
|
||||
elif ! adb_shell ls -l /system/bin/app_process64.real | grep -o 'No such file or directory' >&/dev/null; then
|
||||
# 64-bit installation.
|
||||
adb_shell mv /system/bin/app_process32.real /system/bin/app_process32
|
||||
adb_shell mv /system/bin/app_process64.real /system/bin/app_process64
|
||||
adb_shell rm /system/bin/asanwrapper
|
||||
adb_shell rm /system/bin/asanwrapper64
|
||||
else
|
||||
# 32-bit installation.
|
||||
adb_shell rm /system/bin/app_process.wrap
|
||||
adb_shell rm /system/bin/asanwrapper
|
||||
adb_shell rm /system/bin/app_process
|
||||
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
|
||||
|
||||
# Remove the library on the last step to give a chance to the 'su' binary to
|
||||
# be executed without problem.
|
||||
adb_shell rm /system/lib/$ASAN_RT
|
||||
|
||||
echo '>> Done'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ -d "$lib" ]]; then
|
||||
ASAN_RT_PATH="$lib"
|
||||
elif [[ -f "$lib" && "$lib" == *"$ASAN_RT" ]]; then
|
||||
ASAN_RT_PATH=$(dirname "$lib")
|
||||
elif [[ -f "$HERE/$ASAN_RT" ]]; then
|
||||
ASAN_RT_PATH="$HERE"
|
||||
elif [[ $(basename "$HERE") == "bin" ]]; then
|
||||
# We could be in the toolchain's base directory.
|
||||
# Consider ../lib, ../lib/asan, ../lib/linux,
|
||||
# ../lib/clang/$VERSION/lib/linux, and ../lib64/clang/$VERSION/lib/linux.
|
||||
P=$(ls "$HERE"/../lib/"$ASAN_RT" \
|
||||
"$HERE"/../lib/asan/"$ASAN_RT" \
|
||||
"$HERE"/../lib/linux/"$ASAN_RT" \
|
||||
"$HERE"/../lib/clang/*/lib/linux/"$ASAN_RT" \
|
||||
"$HERE"/../lib64/clang/*/lib/linux/"$ASAN_RT" 2>/dev/null | sort | tail -1)
|
||||
if [[ -n "$P" ]]; then
|
||||
ASAN_RT_PATH="$(dirname "$P")"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -z "$ASAN_RT_PATH" || ! -f "$ASAN_RT_PATH/$ASAN_RT" ]]; then
|
||||
echo ">> ASan runtime library not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -n "$ASAN_RT64" ]]; then
|
||||
if [[ -z "$ASAN_RT_PATH" || ! -f "$ASAN_RT_PATH/$ASAN_RT64" ]]; then
|
||||
echo ">> ASan runtime library not found"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
TMPDIRBASE=$(mktemp -d)
|
||||
TMPDIROLD="$TMPDIRBASE/old"
|
||||
TMPDIR="$TMPDIRBASE/new"
|
||||
mkdir "$TMPDIROLD"
|
||||
|
||||
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
|
||||
echo '>> Old-style ASan installation detected. Reverting.'
|
||||
adb_shell mv /system/bin/app_process.real /system/bin/app_process
|
||||
fi
|
||||
|
||||
echo '>> Pre-L device detected. Setting up app_process symlink.'
|
||||
adb_shell mv /system/bin/app_process /system/bin/app_process32
|
||||
adb_shell ln -s /system/bin/app_process32 /system/bin/app_process
|
||||
fi
|
||||
|
||||
echo '>> Copying files from the device'
|
||||
if [[ -n "$ASAN_RT64" ]]; then
|
||||
adb_pull /system/lib/"$ASAN_RT" "$TMPDIROLD" || true
|
||||
adb_pull /system/lib64/"$ASAN_RT64" "$TMPDIROLD" || true
|
||||
adb_pull /system/bin/app_process32 "$TMPDIROLD" || true
|
||||
adb_pull /system/bin/app_process32.real "$TMPDIROLD" || true
|
||||
adb_pull /system/bin/app_process64 "$TMPDIROLD" || true
|
||||
adb_pull /system/bin/app_process64.real "$TMPDIROLD" || true
|
||||
adb_pull /system/bin/asanwrapper "$TMPDIROLD" || true
|
||||
adb_pull /system/bin/asanwrapper64 "$TMPDIROLD" || true
|
||||
else
|
||||
adb_pull /system/lib/"$ASAN_RT" "$TMPDIROLD" || true
|
||||
adb_pull /system/bin/app_process32 "$TMPDIROLD" || true
|
||||
adb_pull /system/bin/app_process.wrap "$TMPDIROLD" || true
|
||||
adb_pull /system/bin/asanwrapper "$TMPDIROLD" || true
|
||||
fi
|
||||
cp -r "$TMPDIROLD" "$TMPDIR"
|
||||
|
||||
if [[ -f "$TMPDIR/app_process.wrap" || -f "$TMPDIR/app_process64.real" ]]; then
|
||||
echo ">> Previous installation detected"
|
||||
else
|
||||
echo ">> New installation"
|
||||
fi
|
||||
|
||||
echo '>> Generating wrappers'
|
||||
|
||||
cp "$ASAN_RT_PATH/$ASAN_RT" "$TMPDIR/"
|
||||
if [[ -n "$ASAN_RT64" ]]; then
|
||||
cp "$ASAN_RT_PATH/$ASAN_RT64" "$TMPDIR/"
|
||||
fi
|
||||
|
||||
ASAN_OPTIONS=start_deactivated=1
|
||||
|
||||
# The name of a symlink to libclang_rt.asan-$ARCH-android.so used in LD_PRELOAD.
|
||||
# The idea is to have the same name in lib and lib64 to keep it from falling
|
||||
# apart when a 64-bit process spawns a 32-bit one, inheriting the environment.
|
||||
ASAN_RT_SYMLINK=symlink-to-libclang_rt.asan
|
||||
|
||||
function generate_zygote_wrapper { # from, to
|
||||
local _from=$1
|
||||
local _to=$2
|
||||
if [[ PRE_L -eq 0 ]]; then
|
||||
# LD_PRELOAD parsing is broken in N if it starts with ":". Luckily, it is
|
||||
# unset in the system environment since L.
|
||||
local _ld_preload=$ASAN_RT_SYMLINK
|
||||
else
|
||||
local _ld_preload=\$LD_PRELOAD:$ASAN_RT_SYMLINK
|
||||
fi
|
||||
cat <<EOF >"$TMPDIR/$_from"
|
||||
#!/system/bin/sh-from-zygote
|
||||
ASAN_OPTIONS=$ASAN_OPTIONS \\
|
||||
ASAN_ACTIVATION_OPTIONS=include_if_exists=/data/local/tmp/asan.options.%b \\
|
||||
LD_PRELOAD=$_ld_preload \\
|
||||
exec $_to \$@
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
# On Android-L not allowing user segv handler breaks some applications.
|
||||
# Since ~May 2017 this is the default setting; included for compatibility with
|
||||
# older library versions.
|
||||
if [[ PRE_L -eq 0 ]]; then
|
||||
ASAN_OPTIONS="$ASAN_OPTIONS,allow_user_segv_handler=1"
|
||||
fi
|
||||
|
||||
if [[ x$extra_options != x ]] ; then
|
||||
ASAN_OPTIONS="$ASAN_OPTIONS,$extra_options"
|
||||
fi
|
||||
|
||||
# Zygote wrapper.
|
||||
if [[ -f "$TMPDIR/app_process64" ]]; then
|
||||
# A 64-bit device.
|
||||
if [[ ! -f "$TMPDIR/app_process64.real" ]]; then
|
||||
# New installation.
|
||||
mv "$TMPDIR/app_process32" "$TMPDIR/app_process32.real"
|
||||
mv "$TMPDIR/app_process64" "$TMPDIR/app_process64.real"
|
||||
fi
|
||||
generate_zygote_wrapper "app_process32" "/system/bin/app_process32.real"
|
||||
generate_zygote_wrapper "app_process64" "/system/bin/app_process64.real"
|
||||
else
|
||||
# A 32-bit device.
|
||||
generate_zygote_wrapper "app_process.wrap" "/system/bin/app_process32"
|
||||
fi
|
||||
|
||||
# General command-line tool wrapper (use for anything that's not started as
|
||||
# zygote).
|
||||
cat <<EOF >"$TMPDIR/asanwrapper"
|
||||
#!/system/bin/sh
|
||||
LD_PRELOAD=$ASAN_RT_SYMLINK \\
|
||||
exec \$@
|
||||
|
||||
EOF
|
||||
|
||||
if [[ -n "$ASAN_RT64" ]]; then
|
||||
cat <<EOF >"$TMPDIR/asanwrapper64"
|
||||
#!/system/bin/sh
|
||||
LD_PRELOAD=$ASAN_RT_SYMLINK \\
|
||||
exec \$@
|
||||
|
||||
EOF
|
||||
fi
|
||||
|
||||
function install { # from, to, chmod, chcon
|
||||
local _from=$1
|
||||
local _to=$2
|
||||
local _mode=$3
|
||||
local _context=$4
|
||||
local _basename="$(basename "$_from")"
|
||||
echo "Installing $_to/$_basename $_mode $_context"
|
||||
adb_push "$_from" "$_to/$_basename"
|
||||
adb_shell chown root.shell "$_to/$_basename"
|
||||
if [[ -n "$_mode" ]]; then
|
||||
adb_shell chmod "$_mode" "$_to/$_basename"
|
||||
fi
|
||||
if [[ -n "$_context" ]]; then
|
||||
adb_shell chcon "$_context" "$_to/$_basename"
|
||||
fi
|
||||
}
|
||||
|
||||
if ! ( cd "$TMPDIRBASE" && diff -qr old/ new/ ) ; then
|
||||
# Make SELinux happy by keeping app_process wrapper and the shell
|
||||
# it runs on in zygote domain.
|
||||
ENFORCING=0
|
||||
if adb_shell getenforce | grep Enforcing >/dev/null; then
|
||||
# Sometimes shell is not allowed to change file contexts.
|
||||
# Temporarily switch to permissive.
|
||||
ENFORCING=1
|
||||
adb_shell setenforce 0
|
||||
fi
|
||||
|
||||
if [[ PRE_L -eq 1 ]]; then
|
||||
CTX=u:object_r:system_file:s0
|
||||
else
|
||||
CTX=u:object_r:zygote_exec:s0
|
||||
fi
|
||||
|
||||
echo '>> Pushing files to the device'
|
||||
|
||||
if [[ -n "$ASAN_RT64" ]]; then
|
||||
install "$TMPDIR/$ASAN_RT" /system/lib 644
|
||||
install "$TMPDIR/$ASAN_RT64" /system/lib64 644
|
||||
install "$TMPDIR/app_process32" /system/bin 755 $CTX
|
||||
install "$TMPDIR/app_process32.real" /system/bin 755 $CTX
|
||||
install "$TMPDIR/app_process64" /system/bin 755 $CTX
|
||||
install "$TMPDIR/app_process64.real" /system/bin 755 $CTX
|
||||
install "$TMPDIR/asanwrapper" /system/bin 755
|
||||
install "$TMPDIR/asanwrapper64" /system/bin 755
|
||||
|
||||
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 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
|
||||
fi
|
||||
|
||||
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
|
||||
|
||||
echo '>> Restarting shell (asynchronous)'
|
||||
adb_shell stop
|
||||
adb_shell start
|
||||
|
||||
echo '>> Please wait until the device restarts'
|
||||
else
|
||||
echo '>> Device is up to date'
|
||||
fi
|
||||
|
||||
rm -r "$TMPDIRBASE"
|
@ -1,523 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
#===- lib/asan/scripts/asan_symbolize.py -----------------------------------===#
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
#===------------------------------------------------------------------------===#
|
||||
import argparse
|
||||
import bisect
|
||||
import getopt
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
symbolizers = {}
|
||||
DEBUG = False
|
||||
demangle = False
|
||||
binutils_prefix = None
|
||||
sysroot_path = None
|
||||
binary_name_filter = None
|
||||
fix_filename_patterns = None
|
||||
logfile = sys.stdin
|
||||
allow_system_symbolizer = True
|
||||
force_system_symbolizer = False
|
||||
|
||||
# FIXME: merge the code that calls fix_filename().
|
||||
def fix_filename(file_name):
|
||||
if fix_filename_patterns:
|
||||
for path_to_cut in fix_filename_patterns:
|
||||
file_name = re.sub('.*' + path_to_cut, '', file_name)
|
||||
file_name = re.sub('.*asan_[a-z_]*.cc:[0-9]*', '_asan_rtl_', file_name)
|
||||
file_name = re.sub('.*crtstuff.c:0', '???:0', file_name)
|
||||
return file_name
|
||||
|
||||
def sysroot_path_filter(binary_name):
|
||||
return sysroot_path + binary_name
|
||||
|
||||
def is_valid_arch(s):
|
||||
return s in ["i386", "x86_64", "x86_64h", "arm", "armv6", "armv7", "armv7s",
|
||||
"armv7k", "arm64", "powerpc64", "powerpc64le", "s390x", "s390"]
|
||||
|
||||
def guess_arch(addr):
|
||||
# Guess which arch we're running. 10 = len('0x') + 8 hex digits.
|
||||
if len(addr) > 10:
|
||||
return 'x86_64'
|
||||
else:
|
||||
return 'i386'
|
||||
|
||||
class Symbolizer(object):
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def symbolize(self, addr, binary, offset):
|
||||
"""Symbolize the given address (pair of binary and offset).
|
||||
|
||||
Overriden in subclasses.
|
||||
Args:
|
||||
addr: virtual address of an instruction.
|
||||
binary: path to executable/shared object containing this instruction.
|
||||
offset: instruction offset in the @binary.
|
||||
Returns:
|
||||
list of strings (one string for each inlined frame) describing
|
||||
the code locations for this instruction (that is, function name, file
|
||||
name, line and column numbers).
|
||||
"""
|
||||
return None
|
||||
|
||||
|
||||
class LLVMSymbolizer(Symbolizer):
|
||||
def __init__(self, symbolizer_path, default_arch, system, dsym_hints=[]):
|
||||
super(LLVMSymbolizer, self).__init__()
|
||||
self.symbolizer_path = symbolizer_path
|
||||
self.default_arch = default_arch
|
||||
self.system = system
|
||||
self.dsym_hints = dsym_hints
|
||||
self.pipe = self.open_llvm_symbolizer()
|
||||
|
||||
def open_llvm_symbolizer(self):
|
||||
cmd = [self.symbolizer_path,
|
||||
'--use-symbol-table=true',
|
||||
'--demangle=%s' % demangle,
|
||||
'--functions=linkage',
|
||||
'--inlining=true',
|
||||
'--default-arch=%s' % self.default_arch]
|
||||
if self.system == 'Darwin':
|
||||
for hint in self.dsym_hints:
|
||||
cmd.append('--dsym-hint=%s' % hint)
|
||||
if DEBUG:
|
||||
print(' '.join(cmd))
|
||||
try:
|
||||
result = subprocess.Popen(cmd, stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
bufsize=0,
|
||||
universal_newlines=True)
|
||||
except OSError:
|
||||
result = None
|
||||
return result
|
||||
|
||||
def symbolize(self, addr, binary, offset):
|
||||
"""Overrides Symbolizer.symbolize."""
|
||||
if not self.pipe:
|
||||
return None
|
||||
result = []
|
||||
try:
|
||||
symbolizer_input = '"%s" %s' % (binary, offset)
|
||||
if DEBUG:
|
||||
print(symbolizer_input)
|
||||
self.pipe.stdin.write("%s\n" % symbolizer_input)
|
||||
while True:
|
||||
function_name = self.pipe.stdout.readline().rstrip()
|
||||
if not function_name:
|
||||
break
|
||||
file_name = self.pipe.stdout.readline().rstrip()
|
||||
file_name = fix_filename(file_name)
|
||||
if (not function_name.startswith('??') or
|
||||
not file_name.startswith('??')):
|
||||
# Append only non-trivial frames.
|
||||
result.append('%s in %s %s' % (addr, function_name,
|
||||
file_name))
|
||||
except Exception:
|
||||
result = []
|
||||
if not result:
|
||||
result = None
|
||||
return result
|
||||
|
||||
|
||||
def LLVMSymbolizerFactory(system, default_arch, dsym_hints=[]):
|
||||
symbolizer_path = os.getenv('LLVM_SYMBOLIZER_PATH')
|
||||
if not symbolizer_path:
|
||||
symbolizer_path = os.getenv('ASAN_SYMBOLIZER_PATH')
|
||||
if not symbolizer_path:
|
||||
# Assume llvm-symbolizer is in PATH.
|
||||
symbolizer_path = 'llvm-symbolizer'
|
||||
return LLVMSymbolizer(symbolizer_path, default_arch, system, dsym_hints)
|
||||
|
||||
|
||||
class Addr2LineSymbolizer(Symbolizer):
|
||||
def __init__(self, binary):
|
||||
super(Addr2LineSymbolizer, self).__init__()
|
||||
self.binary = binary
|
||||
self.pipe = self.open_addr2line()
|
||||
self.output_terminator = -1
|
||||
|
||||
def open_addr2line(self):
|
||||
addr2line_tool = 'addr2line'
|
||||
if binutils_prefix:
|
||||
addr2line_tool = binutils_prefix + addr2line_tool
|
||||
cmd = [addr2line_tool, '-fi']
|
||||
if demangle:
|
||||
cmd += ['--demangle']
|
||||
cmd += ['-e', self.binary]
|
||||
if DEBUG:
|
||||
print(' '.join(cmd))
|
||||
return subprocess.Popen(cmd,
|
||||
stdin=subprocess.PIPE, stdout=subprocess.PIPE,
|
||||
bufsize=0,
|
||||
universal_newlines=True)
|
||||
|
||||
def symbolize(self, addr, binary, offset):
|
||||
"""Overrides Symbolizer.symbolize."""
|
||||
if self.binary != binary:
|
||||
return None
|
||||
lines = []
|
||||
try:
|
||||
self.pipe.stdin.write("%s\n" % offset)
|
||||
self.pipe.stdin.write("%s\n" % self.output_terminator)
|
||||
is_first_frame = True
|
||||
while True:
|
||||
function_name = self.pipe.stdout.readline().rstrip()
|
||||
file_name = self.pipe.stdout.readline().rstrip()
|
||||
if is_first_frame:
|
||||
is_first_frame = False
|
||||
elif function_name in ['', '??']:
|
||||
assert file_name == function_name
|
||||
break
|
||||
lines.append((function_name, file_name));
|
||||
except Exception:
|
||||
lines.append(('??', '??:0'))
|
||||
return ['%s in %s %s' % (addr, function, fix_filename(file)) for (function, file) in lines]
|
||||
|
||||
class UnbufferedLineConverter(object):
|
||||
"""
|
||||
Wrap a child process that responds to each line of input with one line of
|
||||
output. Uses pty to trick the child into providing unbuffered output.
|
||||
"""
|
||||
def __init__(self, args, close_stderr=False):
|
||||
# Local imports so that the script can start on Windows.
|
||||
import pty
|
||||
import termios
|
||||
pid, fd = pty.fork()
|
||||
if pid == 0:
|
||||
# We're the child. Transfer control to command.
|
||||
if close_stderr:
|
||||
dev_null = os.open('/dev/null', 0)
|
||||
os.dup2(dev_null, 2)
|
||||
os.execvp(args[0], args)
|
||||
else:
|
||||
# Disable echoing.
|
||||
attr = termios.tcgetattr(fd)
|
||||
attr[3] = attr[3] & ~termios.ECHO
|
||||
termios.tcsetattr(fd, termios.TCSANOW, attr)
|
||||
# Set up a file()-like interface to the child process
|
||||
self.r = os.fdopen(fd, "r", 1)
|
||||
self.w = os.fdopen(os.dup(fd), "w", 1)
|
||||
|
||||
def convert(self, line):
|
||||
self.w.write(line + "\n")
|
||||
return self.readline()
|
||||
|
||||
def readline(self):
|
||||
return self.r.readline().rstrip()
|
||||
|
||||
|
||||
class DarwinSymbolizer(Symbolizer):
|
||||
def __init__(self, addr, binary, arch):
|
||||
super(DarwinSymbolizer, self).__init__()
|
||||
self.binary = binary
|
||||
self.arch = arch
|
||||
self.open_atos()
|
||||
|
||||
def open_atos(self):
|
||||
if DEBUG:
|
||||
print('atos -o %s -arch %s' % (self.binary, self.arch))
|
||||
cmdline = ['atos', '-o', self.binary, '-arch', self.arch]
|
||||
self.atos = UnbufferedLineConverter(cmdline, close_stderr=True)
|
||||
|
||||
def symbolize(self, addr, binary, offset):
|
||||
"""Overrides Symbolizer.symbolize."""
|
||||
if self.binary != binary:
|
||||
return None
|
||||
if not os.path.exists(binary):
|
||||
# If the binary doesn't exist atos will exit which will lead to IOError
|
||||
# exceptions being raised later on so just don't try to symbolize.
|
||||
return ['{} ({}:{}+{})'.format(addr, binary, self.arch, offset)]
|
||||
atos_line = self.atos.convert('0x%x' % int(offset, 16))
|
||||
while "got symbolicator for" in atos_line:
|
||||
atos_line = self.atos.readline()
|
||||
# A well-formed atos response looks like this:
|
||||
# foo(type1, type2) (in object.name) (filename.cc:80)
|
||||
match = re.match('^(.*) \(in (.*)\) \((.*:\d*)\)$', atos_line)
|
||||
if DEBUG:
|
||||
print('atos_line: ', atos_line)
|
||||
if match:
|
||||
function_name = match.group(1)
|
||||
function_name = re.sub('\(.*?\)', '', function_name)
|
||||
file_name = fix_filename(match.group(3))
|
||||
return ['%s in %s %s' % (addr, function_name, file_name)]
|
||||
else:
|
||||
return ['%s in %s' % (addr, atos_line)]
|
||||
|
||||
|
||||
# Chain several symbolizers so that if one symbolizer fails, we fall back
|
||||
# to the next symbolizer in chain.
|
||||
class ChainSymbolizer(Symbolizer):
|
||||
def __init__(self, symbolizer_list):
|
||||
super(ChainSymbolizer, self).__init__()
|
||||
self.symbolizer_list = symbolizer_list
|
||||
|
||||
def symbolize(self, addr, binary, offset):
|
||||
"""Overrides Symbolizer.symbolize."""
|
||||
for symbolizer in self.symbolizer_list:
|
||||
if symbolizer:
|
||||
result = symbolizer.symbolize(addr, binary, offset)
|
||||
if result:
|
||||
return result
|
||||
return None
|
||||
|
||||
def append_symbolizer(self, symbolizer):
|
||||
self.symbolizer_list.append(symbolizer)
|
||||
|
||||
|
||||
def BreakpadSymbolizerFactory(binary):
|
||||
suffix = os.getenv('BREAKPAD_SUFFIX')
|
||||
if suffix:
|
||||
filename = binary + suffix
|
||||
if os.access(filename, os.F_OK):
|
||||
return BreakpadSymbolizer(filename)
|
||||
return None
|
||||
|
||||
|
||||
def SystemSymbolizerFactory(system, addr, binary, arch):
|
||||
if system == 'Darwin':
|
||||
return DarwinSymbolizer(addr, binary, arch)
|
||||
elif system in ['Linux', 'FreeBSD', 'NetBSD', 'SunOS']:
|
||||
return Addr2LineSymbolizer(binary)
|
||||
|
||||
|
||||
class BreakpadSymbolizer(Symbolizer):
|
||||
def __init__(self, filename):
|
||||
super(BreakpadSymbolizer, self).__init__()
|
||||
self.filename = filename
|
||||
lines = file(filename).readlines()
|
||||
self.files = []
|
||||
self.symbols = {}
|
||||
self.address_list = []
|
||||
self.addresses = {}
|
||||
# MODULE mac x86_64 A7001116478B33F18FF9BEDE9F615F190 t
|
||||
fragments = lines[0].rstrip().split()
|
||||
self.arch = fragments[2]
|
||||
self.debug_id = fragments[3]
|
||||
self.binary = ' '.join(fragments[4:])
|
||||
self.parse_lines(lines[1:])
|
||||
|
||||
def parse_lines(self, lines):
|
||||
cur_function_addr = ''
|
||||
for line in lines:
|
||||
fragments = line.split()
|
||||
if fragments[0] == 'FILE':
|
||||
assert int(fragments[1]) == len(self.files)
|
||||
self.files.append(' '.join(fragments[2:]))
|
||||
elif fragments[0] == 'PUBLIC':
|
||||
self.symbols[int(fragments[1], 16)] = ' '.join(fragments[3:])
|
||||
elif fragments[0] in ['CFI', 'STACK']:
|
||||
pass
|
||||
elif fragments[0] == 'FUNC':
|
||||
cur_function_addr = int(fragments[1], 16)
|
||||
if not cur_function_addr in self.symbols.keys():
|
||||
self.symbols[cur_function_addr] = ' '.join(fragments[4:])
|
||||
else:
|
||||
# Line starting with an address.
|
||||
addr = int(fragments[0], 16)
|
||||
self.address_list.append(addr)
|
||||
# Tuple of symbol address, size, line, file number.
|
||||
self.addresses[addr] = (cur_function_addr,
|
||||
int(fragments[1], 16),
|
||||
int(fragments[2]),
|
||||
int(fragments[3]))
|
||||
self.address_list.sort()
|
||||
|
||||
def get_sym_file_line(self, addr):
|
||||
key = None
|
||||
if addr in self.addresses.keys():
|
||||
key = addr
|
||||
else:
|
||||
index = bisect.bisect_left(self.address_list, addr)
|
||||
if index == 0:
|
||||
return None
|
||||
else:
|
||||
key = self.address_list[index - 1]
|
||||
sym_id, size, line_no, file_no = self.addresses[key]
|
||||
symbol = self.symbols[sym_id]
|
||||
filename = self.files[file_no]
|
||||
if addr < key + size:
|
||||
return symbol, filename, line_no
|
||||
else:
|
||||
return None
|
||||
|
||||
def symbolize(self, addr, binary, offset):
|
||||
if self.binary != binary:
|
||||
return None
|
||||
res = self.get_sym_file_line(int(offset, 16))
|
||||
if res:
|
||||
function_name, file_name, line_no = res
|
||||
result = ['%s in %s %s:%d' % (
|
||||
addr, function_name, file_name, line_no)]
|
||||
print(result)
|
||||
return result
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
class SymbolizationLoop(object):
|
||||
def __init__(self, binary_name_filter=None, dsym_hint_producer=None):
|
||||
if sys.platform == 'win32':
|
||||
# ASan on Windows uses dbghelp.dll to symbolize in-process, which works
|
||||
# even in sandboxed processes. Nothing needs to be done here.
|
||||
self.process_line = self.process_line_echo
|
||||
else:
|
||||
# Used by clients who may want to supply a different binary name.
|
||||
# E.g. in Chrome several binaries may share a single .dSYM.
|
||||
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', 'NetBSD','SunOS']:
|
||||
raise Exception('Unknown system')
|
||||
self.llvm_symbolizers = {}
|
||||
self.last_llvm_symbolizer = None
|
||||
self.dsym_hints = set([])
|
||||
self.frame_no = 0
|
||||
self.process_line = self.process_line_posix
|
||||
|
||||
def symbolize_address(self, addr, binary, offset, arch):
|
||||
# On non-Darwin (i.e. on platforms without .dSYM debug info) always use
|
||||
# a single symbolizer binary.
|
||||
# On Darwin, if the dsym hint producer is present:
|
||||
# 1. check whether we've seen this binary already; if so,
|
||||
# use |llvm_symbolizers[binary]|, which has already loaded the debug
|
||||
# info for this binary (might not be the case for
|
||||
# |last_llvm_symbolizer|);
|
||||
# 2. otherwise check if we've seen all the hints for this binary already;
|
||||
# if so, reuse |last_llvm_symbolizer| which has the full set of hints;
|
||||
# 3. otherwise create a new symbolizer and pass all currently known
|
||||
# .dSYM hints to it.
|
||||
result = None
|
||||
if not force_system_symbolizer:
|
||||
if not binary in self.llvm_symbolizers:
|
||||
use_new_symbolizer = True
|
||||
if self.system == 'Darwin' and self.dsym_hint_producer:
|
||||
dsym_hints_for_binary = set(self.dsym_hint_producer(binary))
|
||||
use_new_symbolizer = bool(dsym_hints_for_binary - self.dsym_hints)
|
||||
self.dsym_hints |= dsym_hints_for_binary
|
||||
if self.last_llvm_symbolizer and not use_new_symbolizer:
|
||||
self.llvm_symbolizers[binary] = self.last_llvm_symbolizer
|
||||
else:
|
||||
self.last_llvm_symbolizer = LLVMSymbolizerFactory(
|
||||
self.system, arch, self.dsym_hints)
|
||||
self.llvm_symbolizers[binary] = self.last_llvm_symbolizer
|
||||
# Use the chain of symbolizers:
|
||||
# Breakpad symbolizer -> LLVM symbolizer -> addr2line/atos
|
||||
# (fall back to next symbolizer if the previous one fails).
|
||||
if not binary in symbolizers:
|
||||
symbolizers[binary] = ChainSymbolizer(
|
||||
[BreakpadSymbolizerFactory(binary), self.llvm_symbolizers[binary]])
|
||||
result = symbolizers[binary].symbolize(addr, binary, offset)
|
||||
else:
|
||||
symbolizers[binary] = ChainSymbolizer([])
|
||||
if result is None:
|
||||
if not allow_system_symbolizer:
|
||||
raise Exception('Failed to launch or use llvm-symbolizer.')
|
||||
# Initialize system symbolizer only if other symbolizers failed.
|
||||
symbolizers[binary].append_symbolizer(
|
||||
SystemSymbolizerFactory(self.system, addr, binary, arch))
|
||||
result = symbolizers[binary].symbolize(addr, binary, offset)
|
||||
# The system symbolizer must produce some result.
|
||||
assert result
|
||||
return result
|
||||
|
||||
def get_symbolized_lines(self, symbolized_lines):
|
||||
if not symbolized_lines:
|
||||
return [self.current_line]
|
||||
else:
|
||||
result = []
|
||||
for symbolized_frame in symbolized_lines:
|
||||
result.append(' #%s %s' % (str(self.frame_no), symbolized_frame.rstrip()))
|
||||
self.frame_no += 1
|
||||
return result
|
||||
|
||||
def process_logfile(self):
|
||||
self.frame_no = 0
|
||||
for line in logfile:
|
||||
processed = self.process_line(line)
|
||||
print('\n'.join(processed))
|
||||
|
||||
def process_line_echo(self, line):
|
||||
return [line.rstrip()]
|
||||
|
||||
def process_line_posix(self, line):
|
||||
self.current_line = line.rstrip()
|
||||
#0 0x7f6e35cf2e45 (/blah/foo.so+0x11fe45)
|
||||
stack_trace_line_format = (
|
||||
'^( *#([0-9]+) *)(0x[0-9a-f]+) *\((.*)\+(0x[0-9a-f]+)\)')
|
||||
match = re.match(stack_trace_line_format, line)
|
||||
if not match:
|
||||
return [self.current_line]
|
||||
if DEBUG:
|
||||
print(line)
|
||||
_, frameno_str, addr, binary, offset = match.groups()
|
||||
arch = ""
|
||||
# Arch can be embedded in the filename, e.g.: "libabc.dylib:x86_64h"
|
||||
colon_pos = binary.rfind(":")
|
||||
if colon_pos != -1:
|
||||
maybe_arch = binary[colon_pos+1:]
|
||||
if is_valid_arch(maybe_arch):
|
||||
arch = maybe_arch
|
||||
binary = binary[0:colon_pos]
|
||||
if arch == "":
|
||||
arch = guess_arch(addr)
|
||||
if frameno_str == '0':
|
||||
# Assume that frame #0 is the first frame of new stack trace.
|
||||
self.frame_no = 0
|
||||
original_binary = binary
|
||||
if self.binary_name_filter:
|
||||
binary = self.binary_name_filter(binary)
|
||||
symbolized_line = self.symbolize_address(addr, binary, offset, arch)
|
||||
if not symbolized_line:
|
||||
if original_binary != binary:
|
||||
symbolized_line = self.symbolize_address(addr, original_binary, offset, arch)
|
||||
return self.get_symbolized_lines(symbolized_line)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
description='ASan symbolization script',
|
||||
epilog='Example of use:\n'
|
||||
'asan_symbolize.py -c "$HOME/opt/cross/bin/arm-linux-gnueabi-" '
|
||||
'-s "$HOME/SymbolFiles" < asan.log')
|
||||
parser.add_argument('path_to_cut', nargs='*',
|
||||
help='pattern to be cut from the result file path ')
|
||||
parser.add_argument('-d','--demangle', action='store_true',
|
||||
help='demangle function names')
|
||||
parser.add_argument('-s', metavar='SYSROOT',
|
||||
help='set path to sysroot for sanitized binaries')
|
||||
parser.add_argument('-c', metavar='CROSS_COMPILE',
|
||||
help='set prefix for binutils')
|
||||
parser.add_argument('-l','--logfile', default=sys.stdin,
|
||||
type=argparse.FileType('r'),
|
||||
help='set log file name to parse, default is stdin')
|
||||
parser.add_argument('--force-system-symbolizer', action='store_true',
|
||||
help='don\'t use llvm-symbolizer')
|
||||
args = parser.parse_args()
|
||||
if args.path_to_cut:
|
||||
fix_filename_patterns = args.path_to_cut
|
||||
if args.demangle:
|
||||
demangle = True
|
||||
if args.s:
|
||||
binary_name_filter = sysroot_path_filter
|
||||
sysroot_path = args.s
|
||||
if args.c:
|
||||
binutils_prefix = args.c
|
||||
if args.logfile:
|
||||
logfile = args.logfile
|
||||
else:
|
||||
logfile = sys.stdin
|
||||
if args.force_system_symbolizer:
|
||||
force_system_symbolizer = True
|
||||
if force_system_symbolizer:
|
||||
assert(allow_system_symbolizer)
|
||||
loop = SymbolizationLoop(binary_name_filter)
|
||||
loop.process_logfile()
|
@ -1,309 +0,0 @@
|
||||
# Testing rules for AddressSanitizer.
|
||||
#
|
||||
# These are broken into two buckets. One set of tests directly interacts with
|
||||
# the runtime library and checks its functionality. These are the
|
||||
# no-instrumentation tests.
|
||||
#
|
||||
# Another group of tests relies upon the ability to compile the test with
|
||||
# address sanitizer instrumentation pass. These tests form "integration" tests
|
||||
# and have some elements of version skew -- they test the *host* compiler's
|
||||
# instrumentation against the just-built runtime library.
|
||||
|
||||
include(CheckCXXCompilerFlag)
|
||||
include(CompilerRTCompile)
|
||||
|
||||
include_directories(..)
|
||||
include_directories(../..)
|
||||
|
||||
set(ASAN_UNITTEST_HEADERS
|
||||
asan_mac_test.h
|
||||
asan_test_config.h
|
||||
asan_test_utils.h)
|
||||
|
||||
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
|
||||
-I${COMPILER_RT_SOURCE_DIR}/lib/sanitizer_common/tests
|
||||
-fno-rtti
|
||||
-O2
|
||||
-Wno-format
|
||||
-Werror=sign-compare
|
||||
-Wno-non-virtual-dtor)
|
||||
append_list_if(COMPILER_RT_HAS_WVARIADIC_MACROS_FLAG -Wno-variadic-macros ASAN_UNITTEST_COMMON_CFLAGS)
|
||||
|
||||
# This will ensure the target linker is used
|
||||
# during cross compilation
|
||||
set(ASAN_UNITTEST_COMMON_LINK_FLAGS
|
||||
${COMPILER_RT_UNITTEST_LINK_FLAGS})
|
||||
|
||||
# -gline-tables-only must be enough for ASan, so use it if possible.
|
||||
if(COMPILER_RT_TEST_COMPILER_ID MATCHES "Clang")
|
||||
list(APPEND ASAN_UNITTEST_COMMON_CFLAGS -gline-tables-only)
|
||||
else()
|
||||
list(APPEND ASAN_UNITTEST_COMMON_CFLAGS -g)
|
||||
endif()
|
||||
if(MSVC)
|
||||
list(APPEND ASAN_UNITTEST_COMMON_CFLAGS -gcodeview)
|
||||
endif()
|
||||
list(APPEND ASAN_UNITTEST_COMMON_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)
|
||||
|
||||
if(APPLE)
|
||||
list(APPEND ASAN_UNITTEST_COMMON_CFLAGS ${DARWIN_osx_CFLAGS})
|
||||
list(APPEND ASAN_UNITTEST_COMMON_LINK_FLAGS ${DARWIN_osx_LINK_FLAGS})
|
||||
|
||||
add_weak_symbols("asan" WEAK_SYMBOL_LINK_FLAGS)
|
||||
add_weak_symbols("ubsan" WEAK_SYMBOL_LINK_FLAGS)
|
||||
add_weak_symbols("sanitizer_common" WEAK_SYMBOL_LINK_FLAGS)
|
||||
list(APPEND ASAN_UNITTEST_COMMON_LINK_FLAGS ${WEAK_SYMBOL_LINK_FLAGS})
|
||||
endif()
|
||||
|
||||
set(ASAN_BLACKLIST_FILE "${CMAKE_CURRENT_SOURCE_DIR}/asan_test.ignore")
|
||||
set(ASAN_UNITTEST_INSTRUMENTED_CFLAGS
|
||||
${ASAN_UNITTEST_COMMON_CFLAGS}
|
||||
-fsanitize=address
|
||||
"-fsanitize-blacklist=${ASAN_BLACKLIST_FILE}"
|
||||
)
|
||||
if(CAN_TARGET_x86_64 OR CAN_TARGET_i386)
|
||||
list(APPEND ASAN_UNITTEST_INSTRUMENTED_CFLAGS -mllvm -asan-instrument-assembly)
|
||||
endif()
|
||||
|
||||
if(NOT MSVC)
|
||||
list(APPEND ASAN_UNITTEST_COMMON_LINK_FLAGS --driver-mode=g++)
|
||||
endif()
|
||||
|
||||
# x86_64 FreeBSD 9.2 additionally requires libc++ to build the tests.
|
||||
if(CMAKE_SYSTEM MATCHES "FreeBSD-9.2-RELEASE")
|
||||
list(APPEND ASAN_UNITTEST_COMMON_LINK_FLAGS "-lc++")
|
||||
endif()
|
||||
|
||||
# Unit tests on Mac depend on Foundation.
|
||||
if(APPLE)
|
||||
list(APPEND ASAN_UNITTEST_COMMON_LINK_FLAGS -framework Foundation)
|
||||
endif()
|
||||
if(ANDROID)
|
||||
list(APPEND ASAN_UNITTEST_COMMON_LINK_FLAGS -pie)
|
||||
endif()
|
||||
|
||||
set(ASAN_UNITTEST_INSTRUMENTED_LINK_FLAGS
|
||||
${ASAN_UNITTEST_COMMON_LINK_FLAGS})
|
||||
list(APPEND ASAN_UNITTEST_INSTRUMENTED_LINK_FLAGS -fsanitize=address)
|
||||
|
||||
set(ASAN_DYNAMIC_UNITTEST_INSTRUMENTED_LINK_FLAGS
|
||||
${ASAN_UNITTEST_INSTRUMENTED_LINK_FLAGS}
|
||||
-shared-libasan)
|
||||
|
||||
set(ASAN_UNITTEST_INSTRUMENTED_LIBS)
|
||||
# NDK r10 requires -latomic almost always.
|
||||
append_list_if(ANDROID atomic ASAN_UNITTEST_INSTRUMENTED_LIBS)
|
||||
|
||||
set(ASAN_UNITTEST_NOINST_LINK_FLAGS ${ASAN_UNITTEST_COMMON_LINK_FLAGS})
|
||||
if(NOT APPLE)
|
||||
append_list_if(COMPILER_RT_HAS_LIBM -lm ASAN_UNITTEST_NOINST_LINK_FLAGS)
|
||||
append_list_if(COMPILER_RT_HAS_LIBDL -ldl ASAN_UNITTEST_NOINST_LINK_FLAGS)
|
||||
append_list_if(COMPILER_RT_HAS_LIBRT -lrt ASAN_UNITTEST_NOINST_LINK_FLAGS)
|
||||
append_list_if(COMPILER_RT_HAS_LIBPTHREAD -pthread ASAN_UNITTEST_NOINST_LINK_FLAGS)
|
||||
append_list_if(COMPILER_RT_HAS_LIBPTHREAD -pthread ASAN_DYNAMIC_UNITTEST_INSTRUMENTED_LINK_FLAGS)
|
||||
endif()
|
||||
|
||||
# TODO(eugenis): move all -l flags above to _LIBS?
|
||||
set(ASAN_UNITTEST_NOINST_LIBS)
|
||||
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)
|
||||
|
||||
# Main AddressSanitizer unit tests.
|
||||
add_custom_target(AsanUnitTests)
|
||||
set_target_properties(AsanUnitTests PROPERTIES FOLDER "Compiler-RT Tests")
|
||||
|
||||
# AddressSanitizer unit tests with dynamic runtime (on platforms where it's
|
||||
# not the default).
|
||||
add_custom_target(AsanDynamicUnitTests)
|
||||
set_target_properties(AsanDynamicUnitTests PROPERTIES FOLDER "Compiler-RT Tests")
|
||||
# ASan benchmarks (not actively used now).
|
||||
add_custom_target(AsanBenchmarks)
|
||||
set_target_properties(AsanBenchmarks PROPERTIES FOLDER "Compiler-RT Tests")
|
||||
|
||||
set(ASAN_NOINST_TEST_SOURCES
|
||||
${COMPILER_RT_GTEST_SOURCE}
|
||||
asan_fake_stack_test.cc
|
||||
asan_noinst_test.cc
|
||||
asan_test_main.cc)
|
||||
|
||||
set(ASAN_INST_TEST_SOURCES
|
||||
${COMPILER_RT_GTEST_SOURCE}
|
||||
asan_asm_test.cc
|
||||
asan_globals_test.cc
|
||||
asan_interface_test.cc
|
||||
asan_internal_interface_test.cc
|
||||
asan_test.cc
|
||||
asan_oob_test.cc
|
||||
asan_mem_test.cc
|
||||
asan_str_test.cc
|
||||
asan_test_main.cc)
|
||||
if(APPLE)
|
||||
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)
|
||||
|
||||
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_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()
|
||||
|
||||
# Otherwise, reuse ASAN_INST_TEST_OBJECTS.
|
||||
add_compiler_rt_test(AsanDynamicUnitTests "${dynamic_test_name}" "${arch}"
|
||||
SUBDIR "dynamic"
|
||||
OBJECTS ${ASAN_INST_TEST_OBJECTS}
|
||||
DEPS asan ${ASAN_INST_TEST_OBJECTS}
|
||||
LINK_FLAGS ${ASAN_DYNAMIC_UNITTEST_INSTRUMENTED_LINK_FLAGS}
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# 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()
|
||||
if(OS_NAME MATCHES "SunOS")
|
||||
list(REMOVE_ITEM ASAN_TEST_ARCH x86_64)
|
||||
endif()
|
||||
|
||||
foreach(arch ${ASAN_TEST_ARCH})
|
||||
|
||||
# Add static ASan runtime that will be linked with uninstrumented tests.
|
||||
set(ASAN_TEST_RUNTIME RTAsanTest.${arch})
|
||||
if(APPLE)
|
||||
set(ASAN_TEST_RUNTIME_OBJECTS
|
||||
$<TARGET_OBJECTS:RTAsan_dynamic.osx>
|
||||
$<TARGET_OBJECTS:RTInterception.osx>
|
||||
$<TARGET_OBJECTS:RTSanitizerCommon.osx>
|
||||
$<TARGET_OBJECTS:RTSanitizerCommonLibc.osx>
|
||||
$<TARGET_OBJECTS:RTSanitizerCommonCoverage.osx>
|
||||
$<TARGET_OBJECTS:RTSanitizerCommonSymbolizer.osx>
|
||||
$<TARGET_OBJECTS:RTLSanCommon.osx>
|
||||
$<TARGET_OBJECTS:RTUbsan.osx>)
|
||||
else()
|
||||
set(ASAN_TEST_RUNTIME_OBJECTS
|
||||
$<TARGET_OBJECTS:RTAsan.${arch}>
|
||||
$<TARGET_OBJECTS:RTAsan_cxx.${arch}>
|
||||
$<TARGET_OBJECTS:RTInterception.${arch}>
|
||||
$<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
|
||||
$<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
|
||||
$<TARGET_OBJECTS:RTSanitizerCommonCoverage.${arch}>
|
||||
$<TARGET_OBJECTS:RTSanitizerCommonSymbolizer.${arch}>
|
||||
$<TARGET_OBJECTS:RTLSanCommon.${arch}>
|
||||
$<TARGET_OBJECTS:RTUbsan.${arch}>
|
||||
$<TARGET_OBJECTS:RTUbsan_cxx.${arch}>)
|
||||
endif()
|
||||
add_library(${ASAN_TEST_RUNTIME} STATIC ${ASAN_TEST_RUNTIME_OBJECTS})
|
||||
set_target_properties(${ASAN_TEST_RUNTIME} PROPERTIES
|
||||
ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
FOLDER "Compiler-RT Runtime tests")
|
||||
|
||||
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()
|
||||
|
||||
if(ANDROID)
|
||||
foreach(arch ${ASAN_SUPPORTED_ARCH})
|
||||
# Test w/o ASan instrumentation. Link it with ASan statically.
|
||||
add_executable(AsanNoinstTest # FIXME: .arch?
|
||||
$<TARGET_OBJECTS:RTAsan.${arch}>
|
||||
$<TARGET_OBJECTS:RTInterception.${arch}>
|
||||
$<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
|
||||
$<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
|
||||
$<TARGET_OBJECTS:RTSanitizerCommonCoverage.${arch}>
|
||||
$<TARGET_OBJECTS:RTSanitizerCommonSymbolizer.${arch}>
|
||||
$<TARGET_OBJECTS:RTUbsan.${arch}>
|
||||
$<TARGET_OBJECTS:RTUbsan_cxx.${arch}>
|
||||
${COMPILER_RT_GTEST_SOURCE}
|
||||
${ASAN_NOINST_TEST_SOURCES})
|
||||
set_target_compile_flags(AsanNoinstTest ${ASAN_UNITTEST_COMMON_CFLAGS})
|
||||
set_target_link_flags(AsanNoinstTest ${ASAN_UNITTEST_NOINST_LINK_FLAGS})
|
||||
target_link_libraries(AsanNoinstTest ${ASAN_UNITTEST_NOINST_LIBS})
|
||||
|
||||
# Test with ASan instrumentation. Link with ASan dynamic runtime.
|
||||
add_executable(AsanTest
|
||||
${COMPILER_RT_GTEST_SOURCE}
|
||||
${ASAN_INST_TEST_SOURCES})
|
||||
set_target_compile_flags(AsanTest ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS})
|
||||
set_target_link_flags(AsanTest ${ASAN_UNITTEST_INSTRUMENTED_LINK_FLAGS})
|
||||
target_link_libraries(AsanTest ${ASAN_UNITTEST_INSTRUMENTED_LIBS})
|
||||
|
||||
# Setup correct output directory and link flags.
|
||||
set_target_properties(AsanNoinstTest AsanTest PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
# Add unit tests to the test suite.
|
||||
add_dependencies(AsanUnitTests AsanNoinstTest AsanTest)
|
||||
endforeach()
|
||||
endif()
|
@ -1,274 +0,0 @@
|
||||
//===-- asan_asm_test.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.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "asan_test_utils.h"
|
||||
|
||||
#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
|
||||
#if defined(__x86_64__) || \
|
||||
(defined(__i386__) && defined(__SSE2__) && !defined(__ANDROID__))
|
||||
|
||||
#include <emmintrin.h>
|
||||
|
||||
namespace {
|
||||
|
||||
template<typename T> void asm_write(T *ptr, T val);
|
||||
template<typename T> T asm_read(T *ptr);
|
||||
template<typename T> void asm_rep_movs(T *dst, T *src, size_t n);
|
||||
|
||||
} // End of anonymous namespace
|
||||
|
||||
#endif // defined(__x86_64__) || (defined(__i386__) && defined(__SSE2__))
|
||||
|
||||
#if defined(__x86_64__)
|
||||
|
||||
namespace {
|
||||
|
||||
#define DECLARE_ASM_WRITE(Type, Size, Mov, Reg) \
|
||||
template<> void asm_write<Type>(Type *ptr, Type val) { \
|
||||
__asm__( \
|
||||
Mov " %[val], (%[ptr]) \n\t" \
|
||||
: \
|
||||
: [ptr] "r" (ptr), [val] Reg (val) \
|
||||
: "memory" \
|
||||
); \
|
||||
}
|
||||
|
||||
#define DECLARE_ASM_READ(Type, Size, Mov, Reg) \
|
||||
template<> Type asm_read<Type>(Type *ptr) { \
|
||||
Type res; \
|
||||
__asm__( \
|
||||
Mov " (%[ptr]), %[res] \n\t" \
|
||||
: [res] Reg (res) \
|
||||
: [ptr] "r" (ptr) \
|
||||
: "memory" \
|
||||
); \
|
||||
return res; \
|
||||
}
|
||||
|
||||
#define DECLARE_ASM_REP_MOVS(Type, Movs) \
|
||||
template <> \
|
||||
void asm_rep_movs<Type>(Type * dst, Type * src, size_t size) { \
|
||||
__asm__("rep " Movs " \n\t" \
|
||||
: "+D"(dst), "+S"(src), "+c"(size) \
|
||||
: \
|
||||
: "memory"); \
|
||||
}
|
||||
|
||||
DECLARE_ASM_WRITE(U8, "8", "movq", "r");
|
||||
DECLARE_ASM_READ(U8, "8", "movq", "=r");
|
||||
DECLARE_ASM_REP_MOVS(U8, "movsq");
|
||||
|
||||
} // End of anonymous namespace
|
||||
|
||||
#endif // defined(__x86_64__)
|
||||
|
||||
#if defined(__i386__) && defined(__SSE2__) && !defined(__ANDROID__)
|
||||
|
||||
namespace {
|
||||
|
||||
#define DECLARE_ASM_WRITE(Type, Size, Mov, Reg) \
|
||||
template<> void asm_write<Type>(Type *ptr, Type val) { \
|
||||
__asm__( \
|
||||
Mov " %[val], (%[ptr]) \n\t" \
|
||||
: \
|
||||
: [ptr] "r" (ptr), [val] Reg (val) \
|
||||
: "memory" \
|
||||
); \
|
||||
}
|
||||
|
||||
#define DECLARE_ASM_READ(Type, Size, Mov, Reg) \
|
||||
template<> Type asm_read<Type>(Type *ptr) { \
|
||||
Type res; \
|
||||
__asm__( \
|
||||
Mov " (%[ptr]), %[res] \n\t" \
|
||||
: [res] Reg (res) \
|
||||
: [ptr] "r" (ptr) \
|
||||
: "memory" \
|
||||
); \
|
||||
return res; \
|
||||
}
|
||||
|
||||
#define DECLARE_ASM_REP_MOVS(Type, Movs) \
|
||||
template <> \
|
||||
void asm_rep_movs<Type>(Type * dst, Type * src, size_t size) { \
|
||||
__asm__("rep " Movs " \n\t" \
|
||||
: "+D"(dst), "+S"(src), "+c"(size) \
|
||||
: \
|
||||
: "memory"); \
|
||||
}
|
||||
|
||||
} // End of anonymous namespace
|
||||
|
||||
#endif // defined(__i386__) && defined(__SSE2__)
|
||||
|
||||
#if defined(__x86_64__) || \
|
||||
(defined(__i386__) && defined(__SSE2__) && !defined(__ANDROID__))
|
||||
|
||||
namespace {
|
||||
|
||||
DECLARE_ASM_WRITE(U1, "1", "movb", "r");
|
||||
DECLARE_ASM_WRITE(U2, "2", "movw", "r");
|
||||
DECLARE_ASM_WRITE(U4, "4", "movl", "r");
|
||||
DECLARE_ASM_WRITE(__m128i, "16", "movaps", "x");
|
||||
|
||||
DECLARE_ASM_READ(U1, "1", "movb", "=r");
|
||||
DECLARE_ASM_READ(U2, "2", "movw", "=r");
|
||||
DECLARE_ASM_READ(U4, "4", "movl", "=r");
|
||||
DECLARE_ASM_READ(__m128i, "16", "movaps", "=x");
|
||||
|
||||
DECLARE_ASM_REP_MOVS(U1, "movsb");
|
||||
DECLARE_ASM_REP_MOVS(U2, "movsw");
|
||||
DECLARE_ASM_REP_MOVS(U4, "movsl");
|
||||
|
||||
template<typename T> void TestAsmWrite(const char *DeathPattern) {
|
||||
T *buf = new T;
|
||||
EXPECT_DEATH(asm_write(&buf[1], static_cast<T>(0)), DeathPattern);
|
||||
T var = 0x12;
|
||||
asm_write(&var, static_cast<T>(0x21));
|
||||
ASSERT_EQ(static_cast<T>(0x21), var);
|
||||
delete buf;
|
||||
}
|
||||
|
||||
template<> void TestAsmWrite<__m128i>(const char *DeathPattern) {
|
||||
char *buf = new char[16];
|
||||
char *p = buf + 16;
|
||||
if (((uintptr_t) p % 16) != 0)
|
||||
p = buf + 8;
|
||||
assert(((uintptr_t) p % 16) == 0);
|
||||
__m128i val = _mm_set1_epi16(0x1234);
|
||||
EXPECT_DEATH(asm_write<__m128i>((__m128i*) p, val), DeathPattern);
|
||||
__m128i var = _mm_set1_epi16(0x4321);
|
||||
asm_write(&var, val);
|
||||
ASSERT_EQ(0x1234, _mm_extract_epi16(var, 0));
|
||||
delete [] buf;
|
||||
}
|
||||
|
||||
template<typename T> void TestAsmRead(const char *DeathPattern) {
|
||||
T *buf = new T;
|
||||
EXPECT_DEATH(asm_read(&buf[1]), DeathPattern);
|
||||
T var = 0x12;
|
||||
ASSERT_EQ(static_cast<T>(0x12), asm_read(&var));
|
||||
delete buf;
|
||||
}
|
||||
|
||||
template<> void TestAsmRead<__m128i>(const char *DeathPattern) {
|
||||
char *buf = new char[16];
|
||||
char *p = buf + 16;
|
||||
if (((uintptr_t) p % 16) != 0)
|
||||
p = buf + 8;
|
||||
assert(((uintptr_t) p % 16) == 0);
|
||||
EXPECT_DEATH(asm_read<__m128i>((__m128i*) p), DeathPattern);
|
||||
__m128i val = _mm_set1_epi16(0x1234);
|
||||
ASSERT_EQ(0x1234, _mm_extract_epi16(asm_read(&val), 0));
|
||||
delete [] buf;
|
||||
}
|
||||
|
||||
U4 AsmLoad(U4 *a) {
|
||||
U4 r;
|
||||
__asm__("movl (%[a]), %[r] \n\t" : [r] "=r" (r) : [a] "r" (a) : "memory");
|
||||
return r;
|
||||
}
|
||||
|
||||
void AsmStore(U4 r, U4 *a) {
|
||||
__asm__("movl %[r], (%[a]) \n\t" : : [a] "r" (a), [r] "r" (r) : "memory");
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void TestAsmRepMovs(const char *DeathPatternRead,
|
||||
const char *DeathPatternWrite) {
|
||||
T src_good[4] = { 0x0, 0x1, 0x2, 0x3 };
|
||||
T dst_good[4] = {};
|
||||
asm_rep_movs(dst_good, src_good, 4);
|
||||
ASSERT_EQ(static_cast<T>(0x0), dst_good[0]);
|
||||
ASSERT_EQ(static_cast<T>(0x1), dst_good[1]);
|
||||
ASSERT_EQ(static_cast<T>(0x2), dst_good[2]);
|
||||
ASSERT_EQ(static_cast<T>(0x3), dst_good[3]);
|
||||
|
||||
T dst_bad[3];
|
||||
EXPECT_DEATH(asm_rep_movs(dst_bad, src_good, 4), DeathPatternWrite);
|
||||
|
||||
T src_bad[3] = { 0x0, 0x1, 0x2 };
|
||||
EXPECT_DEATH(asm_rep_movs(dst_good, src_bad, 4), DeathPatternRead);
|
||||
|
||||
T* dp = dst_bad + 4;
|
||||
T* sp = src_bad + 4;
|
||||
asm_rep_movs(dp, sp, 0);
|
||||
}
|
||||
|
||||
} // End of anonymous namespace
|
||||
|
||||
TEST(AddressSanitizer, asm_load_store) {
|
||||
U4* buf = new U4[2];
|
||||
EXPECT_DEATH(AsmLoad(&buf[3]), "READ of size 4");
|
||||
EXPECT_DEATH(AsmStore(0x1234, &buf[3]), "WRITE of size 4");
|
||||
delete [] buf;
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, asm_rw) {
|
||||
TestAsmWrite<U1>("WRITE of size 1");
|
||||
TestAsmWrite<U2>("WRITE of size 2");
|
||||
TestAsmWrite<U4>("WRITE of size 4");
|
||||
#if defined(__x86_64__)
|
||||
TestAsmWrite<U8>("WRITE of size 8");
|
||||
#endif // defined(__x86_64__)
|
||||
TestAsmWrite<__m128i>("WRITE of size 16");
|
||||
|
||||
TestAsmRead<U1>("READ of size 1");
|
||||
TestAsmRead<U2>("READ of size 2");
|
||||
TestAsmRead<U4>("READ of size 4");
|
||||
#if defined(__x86_64__)
|
||||
TestAsmRead<U8>("READ of size 8");
|
||||
#endif // defined(__x86_64__)
|
||||
TestAsmRead<__m128i>("READ of size 16");
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, asm_flags) {
|
||||
long magic = 0x1234;
|
||||
long r = 0x0;
|
||||
|
||||
#if defined(__x86_64__) && !defined(__ILP32__)
|
||||
__asm__("xorq %%rax, %%rax \n\t"
|
||||
"movq (%[p]), %%rax \n\t"
|
||||
"sete %%al \n\t"
|
||||
"movzbq %%al, %[r] \n\t"
|
||||
: [r] "=r"(r)
|
||||
: [p] "r"(&magic)
|
||||
: "rax", "memory");
|
||||
#else
|
||||
__asm__("xorl %%eax, %%eax \n\t"
|
||||
"movl (%[p]), %%eax \n\t"
|
||||
"sete %%al \n\t"
|
||||
"movzbl %%al, %[r] \n\t"
|
||||
: [r] "=r"(r)
|
||||
: [p] "r"(&magic)
|
||||
: "eax", "memory");
|
||||
#endif // defined(__x86_64__) && !defined(__ILP32__)
|
||||
|
||||
ASSERT_EQ(0x1, r);
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, asm_rep_movs) {
|
||||
TestAsmRepMovs<U1>("READ of size 1", "WRITE of size 1");
|
||||
TestAsmRepMovs<U2>("READ of size 2", "WRITE of size 2");
|
||||
TestAsmRepMovs<U4>("READ of size 4", "WRITE of size 4");
|
||||
#if defined(__x86_64__)
|
||||
TestAsmRepMovs<U8>("READ of size 8", "WRITE of size 8");
|
||||
#endif // defined(__x86_64__)
|
||||
}
|
||||
|
||||
#endif // defined(__x86_64__) || (defined(__i386__) && defined(__SSE2__))
|
||||
|
||||
#endif // defined(__linux__)
|
@ -1,85 +0,0 @@
|
||||
//===-- asan_benchmarks_test.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.
|
||||
//
|
||||
// Some benchmarks for the instrumented code.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "asan_test_utils.h"
|
||||
|
||||
template<class T>
|
||||
__attribute__((noinline))
|
||||
static void ManyAccessFunc(T *x, size_t n_elements, size_t n_iter) {
|
||||
for (size_t iter = 0; iter < n_iter; iter++) {
|
||||
break_optimization(0);
|
||||
// hand unroll the loop to stress the reg alloc.
|
||||
for (size_t i = 0; i <= n_elements - 16; i += 16) {
|
||||
x[i + 0] = i;
|
||||
x[i + 1] = i;
|
||||
x[i + 2] = i;
|
||||
x[i + 3] = i;
|
||||
x[i + 4] = i;
|
||||
x[i + 5] = i;
|
||||
x[i + 6] = i;
|
||||
x[i + 7] = i;
|
||||
x[i + 8] = i;
|
||||
x[i + 9] = i;
|
||||
x[i + 10] = i;
|
||||
x[i + 11] = i;
|
||||
x[i + 12] = i;
|
||||
x[i + 13] = i;
|
||||
x[i + 14] = i;
|
||||
x[i + 15] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, ManyAccessBenchmark) {
|
||||
size_t kLen = 1024;
|
||||
int *int_array = new int[kLen];
|
||||
ManyAccessFunc(int_array, kLen, 1 << 24);
|
||||
delete [] int_array;
|
||||
}
|
||||
|
||||
// access 7 char elements in a 7 byte array (i.e. on the border).
|
||||
__attribute__((noinline))
|
||||
static void BorderAccessFunc(char *x, size_t n_iter) {
|
||||
for (size_t iter = 0; iter < n_iter; iter++) {
|
||||
break_optimization(x);
|
||||
x[0] = 0;
|
||||
x[1] = 0;
|
||||
x[2] = 0;
|
||||
x[3] = 0;
|
||||
x[4] = 0;
|
||||
x[5] = 0;
|
||||
x[6] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, BorderAccessBenchmark) {
|
||||
char *char_7_array = new char[7];
|
||||
BorderAccessFunc(char_7_array, 1 << 30);
|
||||
delete [] char_7_array;
|
||||
}
|
||||
|
||||
static void FunctionWithLargeStack() {
|
||||
int stack[1000];
|
||||
Ident(stack);
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, FakeStackBenchmark) {
|
||||
for (int i = 0; i < 10000000; i++)
|
||||
Ident(&FunctionWithLargeStack)();
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
// See http://llvm.org/bugs/show_bug.cgi?id=11468
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
|
||||
class Action {
|
||||
public:
|
||||
Action() {}
|
||||
void PrintString(const std::string& msg) const {
|
||||
fprintf(stderr, "%s\n", msg.c_str());
|
||||
}
|
||||
void Throw(const char& arg) const {
|
||||
PrintString("PrintString called!"); // this line is important
|
||||
throw arg;
|
||||
}
|
||||
};
|
||||
|
||||
int main() {
|
||||
const Action a;
|
||||
fprintf(stderr, "&a before = %p\n", &a);
|
||||
try {
|
||||
a.Throw('c');
|
||||
} catch(const char&) {
|
||||
fprintf(stderr, "&a in catch = %p\n", &a);
|
||||
}
|
||||
fprintf(stderr, "&a final = %p\n", &a);
|
||||
return 0;
|
||||
}
|
@ -1,152 +0,0 @@
|
||||
//===-- asan_fake_stack_test.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.
|
||||
//
|
||||
// Tests for FakeStack.
|
||||
// This test file should be compiled w/o asan instrumentation.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "asan_fake_stack.h"
|
||||
#include "asan_test_utils.h"
|
||||
#include "sanitizer_common/sanitizer_common.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace __asan {
|
||||
|
||||
TEST(FakeStack, FlagsSize) {
|
||||
EXPECT_EQ(FakeStack::SizeRequiredForFlags(10), 1U << 5);
|
||||
EXPECT_EQ(FakeStack::SizeRequiredForFlags(11), 1U << 6);
|
||||
EXPECT_EQ(FakeStack::SizeRequiredForFlags(20), 1U << 15);
|
||||
}
|
||||
|
||||
TEST(FakeStack, RequiredSize) {
|
||||
// for (int i = 15; i < 20; i++) {
|
||||
// uptr alloc_size = FakeStack::RequiredSize(i);
|
||||
// printf("%zdK ==> %zd\n", 1 << (i - 10), alloc_size);
|
||||
// }
|
||||
EXPECT_EQ(FakeStack::RequiredSize(15), 365568U);
|
||||
EXPECT_EQ(FakeStack::RequiredSize(16), 727040U);
|
||||
EXPECT_EQ(FakeStack::RequiredSize(17), 1449984U);
|
||||
EXPECT_EQ(FakeStack::RequiredSize(18), 2895872U);
|
||||
EXPECT_EQ(FakeStack::RequiredSize(19), 5787648U);
|
||||
}
|
||||
|
||||
TEST(FakeStack, FlagsOffset) {
|
||||
for (uptr stack_size_log = 15; stack_size_log <= 20; stack_size_log++) {
|
||||
uptr stack_size = 1UL << stack_size_log;
|
||||
uptr offset = 0;
|
||||
for (uptr class_id = 0; class_id < FakeStack::kNumberOfSizeClasses;
|
||||
class_id++) {
|
||||
uptr frame_size = FakeStack::BytesInSizeClass(class_id);
|
||||
uptr num_flags = stack_size / frame_size;
|
||||
EXPECT_EQ(offset, FakeStack::FlagsOffset(stack_size_log, class_id));
|
||||
// printf("%zd: %zd => %zd %zd\n", stack_size_log, class_id, offset,
|
||||
// FakeStack::FlagsOffset(stack_size_log, class_id));
|
||||
offset += num_flags;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(_WIN32) // FIXME: Fails due to OOM on Windows.
|
||||
TEST(FakeStack, CreateDestroy) {
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
for (uptr stack_size_log = 20; stack_size_log <= 22; stack_size_log++) {
|
||||
FakeStack *fake_stack = FakeStack::Create(stack_size_log);
|
||||
fake_stack->Destroy(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(FakeStack, ModuloNumberOfFrames) {
|
||||
EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, 0), 0U);
|
||||
EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, (1<<15)), 0U);
|
||||
EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, (1<<10)), 0U);
|
||||
EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, (1<<9)), 0U);
|
||||
EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, (1<<8)), 1U<<8);
|
||||
EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, (1<<15) + 1), 1U);
|
||||
|
||||
EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 1, 0), 0U);
|
||||
EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 1, 1<<9), 0U);
|
||||
EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 1, 1<<8), 0U);
|
||||
EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 1, 1<<7), 1U<<7);
|
||||
|
||||
EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 5, 0), 0U);
|
||||
EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 5, 1), 1U);
|
||||
EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 5, 15), 15U);
|
||||
EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 5, 16), 0U);
|
||||
EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 5, 17), 1U);
|
||||
}
|
||||
|
||||
TEST(FakeStack, GetFrame) {
|
||||
const uptr stack_size_log = 20;
|
||||
const uptr stack_size = 1 << stack_size_log;
|
||||
FakeStack *fs = FakeStack::Create(stack_size_log);
|
||||
u8 *base = fs->GetFrame(stack_size_log, 0, 0);
|
||||
EXPECT_EQ(base, reinterpret_cast<u8 *>(fs) +
|
||||
fs->SizeRequiredForFlags(stack_size_log) + 4096);
|
||||
EXPECT_EQ(base + 0*stack_size + 64 * 7, fs->GetFrame(stack_size_log, 0, 7U));
|
||||
EXPECT_EQ(base + 1*stack_size + 128 * 3, fs->GetFrame(stack_size_log, 1, 3U));
|
||||
EXPECT_EQ(base + 2*stack_size + 256 * 5, fs->GetFrame(stack_size_log, 2, 5U));
|
||||
fs->Destroy(0);
|
||||
}
|
||||
|
||||
TEST(FakeStack, Allocate) {
|
||||
const uptr stack_size_log = 19;
|
||||
FakeStack *fs = FakeStack::Create(stack_size_log);
|
||||
std::map<FakeFrame *, uptr> s;
|
||||
for (int iter = 0; iter < 2; iter++) {
|
||||
s.clear();
|
||||
for (uptr cid = 0; cid < FakeStack::kNumberOfSizeClasses; cid++) {
|
||||
uptr n = FakeStack::NumberOfFrames(stack_size_log, cid);
|
||||
uptr bytes_in_class = FakeStack::BytesInSizeClass(cid);
|
||||
for (uptr j = 0; j < n; j++) {
|
||||
FakeFrame *ff = fs->Allocate(stack_size_log, cid, 0);
|
||||
uptr x = reinterpret_cast<uptr>(ff);
|
||||
EXPECT_TRUE(s.insert(std::make_pair(ff, cid)).second);
|
||||
EXPECT_EQ(x, fs->AddrIsInFakeStack(x));
|
||||
EXPECT_EQ(x, fs->AddrIsInFakeStack(x + 1));
|
||||
EXPECT_EQ(x, fs->AddrIsInFakeStack(x + bytes_in_class - 1));
|
||||
EXPECT_NE(x, fs->AddrIsInFakeStack(x + bytes_in_class));
|
||||
}
|
||||
// We are out of fake stack, so Allocate should return 0.
|
||||
EXPECT_EQ(0UL, fs->Allocate(stack_size_log, cid, 0));
|
||||
}
|
||||
for (std::map<FakeFrame *, uptr>::iterator it = s.begin(); it != s.end();
|
||||
++it) {
|
||||
fs->Deallocate(reinterpret_cast<uptr>(it->first), it->second);
|
||||
}
|
||||
}
|
||||
fs->Destroy(0);
|
||||
}
|
||||
|
||||
static void RecursiveFunction(FakeStack *fs, int depth) {
|
||||
uptr class_id = depth / 3;
|
||||
FakeFrame *ff = fs->Allocate(fs->stack_size_log(), class_id, 0);
|
||||
if (depth) {
|
||||
RecursiveFunction(fs, depth - 1);
|
||||
RecursiveFunction(fs, depth - 1);
|
||||
}
|
||||
fs->Deallocate(reinterpret_cast<uptr>(ff), class_id);
|
||||
}
|
||||
|
||||
TEST(FakeStack, RecursiveStressTest) {
|
||||
const uptr stack_size_log = 16;
|
||||
FakeStack *fs = FakeStack::Create(stack_size_log);
|
||||
RecursiveFunction(fs, 22); // with 26 runs for 2-3 seconds.
|
||||
fs->Destroy(0);
|
||||
}
|
||||
|
||||
} // namespace __asan
|
@ -1,45 +0,0 @@
|
||||
//===-- asan_globals_test.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.
|
||||
//
|
||||
// Some globals in a separate file.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "asan_test_utils.h"
|
||||
|
||||
char glob1[1];
|
||||
char glob2[2];
|
||||
char glob3[3];
|
||||
char glob4[4];
|
||||
char glob5[5];
|
||||
char glob6[6];
|
||||
char glob7[7];
|
||||
char glob8[8];
|
||||
char glob9[9];
|
||||
char glob10[10];
|
||||
char glob11[11];
|
||||
char glob12[12];
|
||||
char glob13[13];
|
||||
char glob14[14];
|
||||
char glob15[15];
|
||||
char glob16[16];
|
||||
char glob17[17];
|
||||
char glob1000[1000];
|
||||
char glob10000[10000];
|
||||
char glob100000[100000];
|
||||
|
||||
static char static10[10];
|
||||
|
||||
int GlobalsTest(int zero) {
|
||||
static char func_static15[15];
|
||||
glob5[zero] = 0;
|
||||
static10[zero] = 0;
|
||||
func_static15[zero] = 0;
|
||||
return glob5[1] + func_static15[2];
|
||||
}
|
@ -1,422 +0,0 @@
|
||||
//===-- asan_interface_test.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.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "asan_test_utils.h"
|
||||
#include "sanitizer_common/sanitizer_internal_defs.h"
|
||||
#include <sanitizer/allocator_interface.h>
|
||||
#include <sanitizer/asan_interface.h>
|
||||
#include <vector>
|
||||
|
||||
TEST(AddressSanitizerInterface, GetEstimatedAllocatedSize) {
|
||||
EXPECT_EQ(0U, __sanitizer_get_estimated_allocated_size(0));
|
||||
const size_t sizes[] = { 1, 30, 1<<30 };
|
||||
for (size_t i = 0; i < 3; i++) {
|
||||
EXPECT_EQ(sizes[i], __sanitizer_get_estimated_allocated_size(sizes[i]));
|
||||
}
|
||||
}
|
||||
|
||||
static const char* kGetAllocatedSizeErrorMsg =
|
||||
"attempting to call __sanitizer_get_allocated_size";
|
||||
|
||||
TEST(AddressSanitizerInterface, GetAllocatedSizeAndOwnershipTest) {
|
||||
const size_t kArraySize = 100;
|
||||
char *array = Ident((char*)malloc(kArraySize));
|
||||
int *int_ptr = Ident(new int);
|
||||
|
||||
// Allocated memory is owned by allocator. Allocated size should be
|
||||
// equal to requested size.
|
||||
EXPECT_EQ(true, __sanitizer_get_ownership(array));
|
||||
EXPECT_EQ(kArraySize, __sanitizer_get_allocated_size(array));
|
||||
EXPECT_EQ(true, __sanitizer_get_ownership(int_ptr));
|
||||
EXPECT_EQ(sizeof(int), __sanitizer_get_allocated_size(int_ptr));
|
||||
|
||||
// We cannot call GetAllocatedSize from the memory we didn't map,
|
||||
// and from the interior pointers (not returned by previous malloc).
|
||||
void *wild_addr = (void*)0x1;
|
||||
EXPECT_FALSE(__sanitizer_get_ownership(wild_addr));
|
||||
EXPECT_DEATH(__sanitizer_get_allocated_size(wild_addr),
|
||||
kGetAllocatedSizeErrorMsg);
|
||||
EXPECT_FALSE(__sanitizer_get_ownership(array + kArraySize / 2));
|
||||
EXPECT_DEATH(__sanitizer_get_allocated_size(array + kArraySize / 2),
|
||||
kGetAllocatedSizeErrorMsg);
|
||||
|
||||
// NULL is not owned, but is a valid argument for
|
||||
// __sanitizer_get_allocated_size().
|
||||
EXPECT_FALSE(__sanitizer_get_ownership(NULL));
|
||||
EXPECT_EQ(0U, __sanitizer_get_allocated_size(NULL));
|
||||
|
||||
// When memory is freed, it's not owned, and call to GetAllocatedSize
|
||||
// is forbidden.
|
||||
free(array);
|
||||
EXPECT_FALSE(__sanitizer_get_ownership(array));
|
||||
EXPECT_DEATH(__sanitizer_get_allocated_size(array),
|
||||
kGetAllocatedSizeErrorMsg);
|
||||
delete int_ptr;
|
||||
|
||||
void *zero_alloc = Ident(malloc(0));
|
||||
if (zero_alloc != 0) {
|
||||
// If malloc(0) is not null, this pointer is owned and should have valid
|
||||
// allocated size.
|
||||
EXPECT_TRUE(__sanitizer_get_ownership(zero_alloc));
|
||||
// Allocated size is 0 or 1 depending on the allocator used.
|
||||
EXPECT_LT(__sanitizer_get_allocated_size(zero_alloc), 2U);
|
||||
}
|
||||
free(zero_alloc);
|
||||
}
|
||||
|
||||
TEST(AddressSanitizerInterface, GetCurrentAllocatedBytesTest) {
|
||||
size_t before_malloc, after_malloc, after_free;
|
||||
char *array;
|
||||
const size_t kMallocSize = 100;
|
||||
before_malloc = __sanitizer_get_current_allocated_bytes();
|
||||
|
||||
array = Ident((char*)malloc(kMallocSize));
|
||||
after_malloc = __sanitizer_get_current_allocated_bytes();
|
||||
EXPECT_EQ(before_malloc + kMallocSize, after_malloc);
|
||||
|
||||
free(array);
|
||||
after_free = __sanitizer_get_current_allocated_bytes();
|
||||
EXPECT_EQ(before_malloc, after_free);
|
||||
}
|
||||
|
||||
TEST(AddressSanitizerInterface, GetHeapSizeTest) {
|
||||
// ASan allocator does not keep huge chunks in free list, but unmaps them.
|
||||
// The chunk should be greater than the quarantine size,
|
||||
// otherwise it will be stuck in quarantine instead of being unmaped.
|
||||
static const size_t kLargeMallocSize = (1 << 28) + 1; // 256M
|
||||
free(Ident(malloc(kLargeMallocSize))); // Drain quarantine.
|
||||
size_t old_heap_size = __sanitizer_get_heap_size();
|
||||
for (int i = 0; i < 3; i++) {
|
||||
// fprintf(stderr, "allocating %zu bytes:\n", kLargeMallocSize);
|
||||
free(Ident(malloc(kLargeMallocSize)));
|
||||
EXPECT_EQ(old_heap_size, __sanitizer_get_heap_size());
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(__NetBSD__)
|
||||
static const size_t kManyThreadsMallocSizes[] = {5, 1UL<<10, 1UL<<14, 357};
|
||||
static const size_t kManyThreadsIterations = 250;
|
||||
static const size_t kManyThreadsNumThreads =
|
||||
(SANITIZER_WORDSIZE == 32) ? 40 : 200;
|
||||
|
||||
static void *ManyThreadsWithStatsWorker(void *arg) {
|
||||
(void)arg;
|
||||
for (size_t iter = 0; iter < kManyThreadsIterations; iter++) {
|
||||
for (size_t size_index = 0; size_index < 4; size_index++) {
|
||||
free(Ident(malloc(kManyThreadsMallocSizes[size_index])));
|
||||
}
|
||||
}
|
||||
// Just one large allocation.
|
||||
free(Ident(malloc(1 << 20)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
TEST(AddressSanitizerInterface, ManyThreadsWithStatsStressTest) {
|
||||
size_t before_test, after_test, i;
|
||||
pthread_t threads[kManyThreadsNumThreads];
|
||||
before_test = __sanitizer_get_current_allocated_bytes();
|
||||
for (i = 0; i < kManyThreadsNumThreads; i++) {
|
||||
PTHREAD_CREATE(&threads[i], 0,
|
||||
(void* (*)(void *x))ManyThreadsWithStatsWorker, (void*)i);
|
||||
}
|
||||
for (i = 0; i < kManyThreadsNumThreads; i++) {
|
||||
PTHREAD_JOIN(threads[i], 0);
|
||||
}
|
||||
after_test = __sanitizer_get_current_allocated_bytes();
|
||||
// ASan stats also reflect memory usage of internal ASan RTL structs,
|
||||
// so we can't check for equality here.
|
||||
EXPECT_LT(after_test, before_test + (1UL<<20));
|
||||
}
|
||||
#endif
|
||||
|
||||
static void DoDoubleFree() {
|
||||
int *x = Ident(new int);
|
||||
delete Ident(x);
|
||||
delete Ident(x);
|
||||
}
|
||||
|
||||
static void MyDeathCallback() {
|
||||
fprintf(stderr, "MyDeathCallback\n");
|
||||
fflush(0); // On Windows, stderr doesn't flush on crash.
|
||||
}
|
||||
|
||||
TEST(AddressSanitizerInterface, DeathCallbackTest) {
|
||||
__asan_set_death_callback(MyDeathCallback);
|
||||
EXPECT_DEATH(DoDoubleFree(), "MyDeathCallback");
|
||||
__asan_set_death_callback(NULL);
|
||||
}
|
||||
|
||||
#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)
|
||||
__asan_poison_memory_region(array + 40, 40);
|
||||
GOOD_ACCESS(array, 39);
|
||||
GOOD_ACCESS(array, 80);
|
||||
BAD_ACCESS(array, 40);
|
||||
BAD_ACCESS(array, 60);
|
||||
BAD_ACCESS(array, 79);
|
||||
char value;
|
||||
EXPECT_DEATH(value = Ident(array[40]), kUseAfterPoisonErrorMessage);
|
||||
__asan_unpoison_memory_region(array + 40, 40);
|
||||
// access previously poisoned memory.
|
||||
GOOD_ACCESS(array, 40);
|
||||
GOOD_ACCESS(array, 79);
|
||||
free(array);
|
||||
}
|
||||
|
||||
TEST(AddressSanitizerInterface, OverlappingPoisonMemoryRegionTest) {
|
||||
char *array = Ident((char*)malloc(120));
|
||||
// Poison [0..40) and [80..120)
|
||||
__asan_poison_memory_region(array, 40);
|
||||
__asan_poison_memory_region(array + 80, 40);
|
||||
BAD_ACCESS(array, 20);
|
||||
GOOD_ACCESS(array, 60);
|
||||
BAD_ACCESS(array, 100);
|
||||
// Poison whole array - [0..120)
|
||||
__asan_poison_memory_region(array, 120);
|
||||
BAD_ACCESS(array, 60);
|
||||
// Unpoison [24..96)
|
||||
__asan_unpoison_memory_region(array + 24, 72);
|
||||
BAD_ACCESS(array, 23);
|
||||
GOOD_ACCESS(array, 24);
|
||||
GOOD_ACCESS(array, 60);
|
||||
GOOD_ACCESS(array, 95);
|
||||
BAD_ACCESS(array, 96);
|
||||
free(array);
|
||||
}
|
||||
#endif // !defined(ASAN_SHADOW_SCALE) || ASAN_SHADOW_SCALE == 3
|
||||
|
||||
TEST(AddressSanitizerInterface, PushAndPopWithPoisoningTest) {
|
||||
// Vector of capacity 20
|
||||
char *vec = Ident((char*)malloc(20));
|
||||
__asan_poison_memory_region(vec, 20);
|
||||
for (size_t i = 0; i < 7; i++) {
|
||||
// Simulate push_back.
|
||||
__asan_unpoison_memory_region(vec + i, 1);
|
||||
GOOD_ACCESS(vec, i);
|
||||
BAD_ACCESS(vec, i + 1);
|
||||
}
|
||||
for (size_t i = 7; i > 0; i--) {
|
||||
// Simulate pop_back.
|
||||
__asan_poison_memory_region(vec + i - 1, 1);
|
||||
BAD_ACCESS(vec, i - 1);
|
||||
if (i > 1) GOOD_ACCESS(vec, i - 2);
|
||||
}
|
||||
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) {
|
||||
bool can_be_poisoned = true;
|
||||
for (int i = length - 1; i >= 0; i--) {
|
||||
if (!shadow[i])
|
||||
can_be_poisoned = false;
|
||||
if (!can_be_poisoned)
|
||||
shadow[i] = false;
|
||||
if (i % (1 << granularity) == 0) {
|
||||
can_be_poisoned = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AddressSanitizerInterface, PoisoningStressTest) {
|
||||
const size_t kSize = 24;
|
||||
bool expected[kSize];
|
||||
char *arr = Ident((char*)malloc(kSize));
|
||||
for (size_t l1 = 0; l1 < kSize; l1++) {
|
||||
for (size_t s1 = 1; l1 + s1 <= kSize; s1++) {
|
||||
for (size_t l2 = 0; l2 < kSize; l2++) {
|
||||
for (size_t s2 = 1; l2 + s2 <= kSize; s2++) {
|
||||
// Poison [l1, l1+s1), [l2, l2+s2) and check result.
|
||||
__asan_unpoison_memory_region(arr, kSize);
|
||||
__asan_poison_memory_region(arr + l1, s1);
|
||||
__asan_poison_memory_region(arr + l2, s2);
|
||||
memset(expected, false, kSize);
|
||||
memset(expected + l1, true, s1);
|
||||
MakeShadowValid(expected, kSize, /*granularity*/ 3);
|
||||
memset(expected + l2, true, s2);
|
||||
MakeShadowValid(expected, kSize, /*granularity*/ 3);
|
||||
for (size_t i = 0; i < kSize; i++) {
|
||||
ASSERT_EQ(expected[i], __asan_address_is_poisoned(arr + i));
|
||||
}
|
||||
// Unpoison [l1, l1+s1) and [l2, l2+s2) and check result.
|
||||
__asan_poison_memory_region(arr, kSize);
|
||||
__asan_unpoison_memory_region(arr + l1, s1);
|
||||
__asan_unpoison_memory_region(arr + l2, s2);
|
||||
memset(expected, true, kSize);
|
||||
memset(expected + l1, false, s1);
|
||||
MakeShadowValid(expected, kSize, /*granularity*/ 3);
|
||||
memset(expected + l2, false, s2);
|
||||
MakeShadowValid(expected, kSize, /*granularity*/ 3);
|
||||
for (size_t i = 0; i < kSize; i++) {
|
||||
ASSERT_EQ(expected[i], __asan_address_is_poisoned(arr + i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
free(arr);
|
||||
}
|
||||
#endif // !defined(ASAN_SHADOW_SCALE) || ASAN_SHADOW_SCALE == 3
|
||||
|
||||
TEST(AddressSanitizerInterface, GlobalRedzones) {
|
||||
GOOD_ACCESS(glob1, 1 - 1);
|
||||
GOOD_ACCESS(glob2, 2 - 1);
|
||||
GOOD_ACCESS(glob3, 3 - 1);
|
||||
GOOD_ACCESS(glob4, 4 - 1);
|
||||
GOOD_ACCESS(glob5, 5 - 1);
|
||||
GOOD_ACCESS(glob6, 6 - 1);
|
||||
GOOD_ACCESS(glob7, 7 - 1);
|
||||
GOOD_ACCESS(glob8, 8 - 1);
|
||||
GOOD_ACCESS(glob9, 9 - 1);
|
||||
GOOD_ACCESS(glob10, 10 - 1);
|
||||
GOOD_ACCESS(glob11, 11 - 1);
|
||||
GOOD_ACCESS(glob12, 12 - 1);
|
||||
GOOD_ACCESS(glob13, 13 - 1);
|
||||
GOOD_ACCESS(glob14, 14 - 1);
|
||||
GOOD_ACCESS(glob15, 15 - 1);
|
||||
GOOD_ACCESS(glob16, 16 - 1);
|
||||
GOOD_ACCESS(glob17, 17 - 1);
|
||||
GOOD_ACCESS(glob1000, 1000 - 1);
|
||||
GOOD_ACCESS(glob10000, 10000 - 1);
|
||||
GOOD_ACCESS(glob100000, 100000 - 1);
|
||||
|
||||
BAD_ACCESS(glob1, 1);
|
||||
BAD_ACCESS(glob2, 2);
|
||||
BAD_ACCESS(glob3, 3);
|
||||
BAD_ACCESS(glob4, 4);
|
||||
BAD_ACCESS(glob5, 5);
|
||||
BAD_ACCESS(glob6, 6);
|
||||
BAD_ACCESS(glob7, 7);
|
||||
BAD_ACCESS(glob8, 8);
|
||||
BAD_ACCESS(glob9, 9);
|
||||
BAD_ACCESS(glob10, 10);
|
||||
BAD_ACCESS(glob11, 11);
|
||||
BAD_ACCESS(glob12, 12);
|
||||
BAD_ACCESS(glob13, 13);
|
||||
BAD_ACCESS(glob14, 14);
|
||||
BAD_ACCESS(glob15, 15);
|
||||
BAD_ACCESS(glob16, 16);
|
||||
BAD_ACCESS(glob17, 17);
|
||||
BAD_ACCESS(glob1000, 1000);
|
||||
BAD_ACCESS(glob1000, 1100); // Redzone is at least 101 bytes.
|
||||
BAD_ACCESS(glob10000, 10000);
|
||||
BAD_ACCESS(glob10000, 11000); // Redzone is at least 1001 bytes.
|
||||
BAD_ACCESS(glob100000, 100000);
|
||||
BAD_ACCESS(glob100000, 110000); // Redzone is at least 10001 bytes.
|
||||
}
|
||||
|
||||
TEST(AddressSanitizerInterface, PoisonedRegion) {
|
||||
size_t rz = 16;
|
||||
for (size_t size = 1; size <= 64; size++) {
|
||||
char *p = new char[size];
|
||||
for (size_t beg = 0; beg < size + rz; beg++) {
|
||||
for (size_t end = beg; end < size + rz; end++) {
|
||||
void *first_poisoned = __asan_region_is_poisoned(p + beg, end - beg);
|
||||
if (beg == end) {
|
||||
EXPECT_FALSE(first_poisoned);
|
||||
} else if (beg < size && end <= size) {
|
||||
EXPECT_FALSE(first_poisoned);
|
||||
} else if (beg >= size) {
|
||||
EXPECT_EQ(p + beg, first_poisoned);
|
||||
} else {
|
||||
EXPECT_GT(end, size);
|
||||
EXPECT_EQ(p + size, first_poisoned);
|
||||
}
|
||||
}
|
||||
}
|
||||
delete [] p;
|
||||
}
|
||||
}
|
||||
|
||||
// This is a performance benchmark for manual runs.
|
||||
// asan's memset interceptor calls mem_is_zero for the entire shadow region.
|
||||
// the profile should look like this:
|
||||
// 89.10% [.] __memset_sse2
|
||||
// 10.50% [.] __sanitizer::mem_is_zero
|
||||
// I.e. mem_is_zero should consume ~ SHADOW_GRANULARITY less CPU cycles
|
||||
// than memset itself.
|
||||
TEST(AddressSanitizerInterface, DISABLED_StressLargeMemset) {
|
||||
size_t size = 1 << 20;
|
||||
char *x = new char[size];
|
||||
for (int i = 0; i < 100000; i++)
|
||||
Ident(memset)(x, 0, size);
|
||||
delete [] x;
|
||||
}
|
||||
|
||||
// Same here, but we run memset with small sizes.
|
||||
TEST(AddressSanitizerInterface, DISABLED_StressSmallMemset) {
|
||||
size_t size = 32;
|
||||
char *x = new char[size];
|
||||
for (int i = 0; i < 100000000; i++)
|
||||
Ident(memset)(x, 0, size);
|
||||
delete [] x;
|
||||
}
|
||||
static const char *kInvalidPoisonMessage = "invalid-poison-memory-range";
|
||||
static const char *kInvalidUnpoisonMessage = "invalid-unpoison-memory-range";
|
||||
|
||||
TEST(AddressSanitizerInterface, DISABLED_InvalidPoisonAndUnpoisonCallsTest) {
|
||||
char *array = Ident((char*)malloc(120));
|
||||
__asan_unpoison_memory_region(array, 120);
|
||||
// Try to unpoison not owned memory
|
||||
EXPECT_DEATH(__asan_unpoison_memory_region(array, 121),
|
||||
kInvalidUnpoisonMessage);
|
||||
EXPECT_DEATH(__asan_unpoison_memory_region(array - 1, 120),
|
||||
kInvalidUnpoisonMessage);
|
||||
|
||||
__asan_poison_memory_region(array, 120);
|
||||
// Try to poison not owned memory.
|
||||
EXPECT_DEATH(__asan_poison_memory_region(array, 121), kInvalidPoisonMessage);
|
||||
EXPECT_DEATH(__asan_poison_memory_region(array - 1, 120),
|
||||
kInvalidPoisonMessage);
|
||||
free(array);
|
||||
}
|
||||
|
||||
TEST(AddressSanitizerInterface, GetOwnershipStressTest) {
|
||||
std::vector<char *> pointers;
|
||||
std::vector<size_t> sizes;
|
||||
const size_t kNumMallocs = 1 << 9;
|
||||
for (size_t i = 0; i < kNumMallocs; i++) {
|
||||
size_t size = i * 100 + 1;
|
||||
pointers.push_back((char*)malloc(size));
|
||||
sizes.push_back(size);
|
||||
}
|
||||
for (size_t i = 0; i < 4000000; i++) {
|
||||
EXPECT_FALSE(__sanitizer_get_ownership(&pointers));
|
||||
EXPECT_FALSE(__sanitizer_get_ownership((void*)0x1234));
|
||||
size_t idx = i % kNumMallocs;
|
||||
EXPECT_TRUE(__sanitizer_get_ownership(pointers[idx]));
|
||||
EXPECT_EQ(sizes[idx], __sanitizer_get_allocated_size(pointers[idx]));
|
||||
}
|
||||
for (size_t i = 0, n = pointers.size(); i < n; i++)
|
||||
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);
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
//===-- asan_internal_interface_test.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.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "asan_interface_internal.h"
|
||||
#include "asan_test_utils.h"
|
||||
#include <vector>
|
||||
|
||||
TEST(AddressSanitizerInternalInterface, SetShadow) {
|
||||
std::vector<char> buffer(17, 0xff);
|
||||
|
||||
__asan_set_shadow_00((uptr)buffer.data(), buffer.size());
|
||||
EXPECT_EQ(std::vector<char>(buffer.size(), 0x00), buffer);
|
||||
|
||||
__asan_set_shadow_f1((uptr)buffer.data(), buffer.size());
|
||||
EXPECT_EQ(std::vector<char>(buffer.size(), 0xf1), buffer);
|
||||
|
||||
__asan_set_shadow_f2((uptr)buffer.data(), buffer.size());
|
||||
EXPECT_EQ(std::vector<char>(buffer.size(), 0xf2), buffer);
|
||||
|
||||
__asan_set_shadow_f3((uptr)buffer.data(), buffer.size());
|
||||
EXPECT_EQ(std::vector<char>(buffer.size(), 0xf3), buffer);
|
||||
|
||||
__asan_set_shadow_f5((uptr)buffer.data(), buffer.size());
|
||||
EXPECT_EQ(std::vector<char>(buffer.size(), 0xf5), buffer);
|
||||
|
||||
__asan_set_shadow_f8((uptr)buffer.data(), buffer.size());
|
||||
EXPECT_EQ(std::vector<char>(buffer.size(), 0xf8), buffer);
|
||||
}
|
@ -1,236 +0,0 @@
|
||||
//===-- asan_test_mac.cc --------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "asan_test_utils.h"
|
||||
|
||||
#include "asan_mac_test.h"
|
||||
|
||||
#include <malloc/malloc.h>
|
||||
#include <AvailabilityMacros.h> // For MAC_OS_X_VERSION_*
|
||||
#include <CoreFoundation/CFString.h>
|
||||
|
||||
TEST(AddressSanitizerMac, CFAllocatorDefaultDoubleFree) {
|
||||
EXPECT_DEATH(
|
||||
CFAllocatorDefaultDoubleFree(NULL),
|
||||
"attempting double-free");
|
||||
}
|
||||
|
||||
void CFAllocator_DoubleFreeOnPthread() {
|
||||
pthread_t child;
|
||||
PTHREAD_CREATE(&child, NULL, CFAllocatorDefaultDoubleFree, NULL);
|
||||
PTHREAD_JOIN(child, NULL); // Shouldn't be reached.
|
||||
}
|
||||
|
||||
TEST(AddressSanitizerMac, CFAllocatorDefaultDoubleFree_ChildPhread) {
|
||||
EXPECT_DEATH(CFAllocator_DoubleFreeOnPthread(), "attempting double-free");
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
void *GLOB;
|
||||
|
||||
void *CFAllocatorAllocateToGlob(void *unused) {
|
||||
GLOB = CFAllocatorAllocate(NULL, 100, /*hint*/0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *CFAllocatorDeallocateFromGlob(void *unused) {
|
||||
char *p = (char*)GLOB;
|
||||
p[100] = 'A'; // ASan should report an error here.
|
||||
CFAllocatorDeallocate(NULL, GLOB);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void CFAllocator_PassMemoryToAnotherThread() {
|
||||
pthread_t th1, th2;
|
||||
PTHREAD_CREATE(&th1, NULL, CFAllocatorAllocateToGlob, NULL);
|
||||
PTHREAD_JOIN(th1, NULL);
|
||||
PTHREAD_CREATE(&th2, NULL, CFAllocatorDeallocateFromGlob, NULL);
|
||||
PTHREAD_JOIN(th2, NULL);
|
||||
}
|
||||
|
||||
TEST(AddressSanitizerMac, CFAllocator_PassMemoryToAnotherThread) {
|
||||
EXPECT_DEATH(CFAllocator_PassMemoryToAnotherThread(),
|
||||
"heap-buffer-overflow");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// TODO(glider): figure out whether we still need these tests. Is it correct
|
||||
// to intercept the non-default CFAllocators?
|
||||
TEST(AddressSanitizerMac, DISABLED_CFAllocatorSystemDefaultDoubleFree) {
|
||||
EXPECT_DEATH(
|
||||
CFAllocatorSystemDefaultDoubleFree(),
|
||||
"attempting double-free");
|
||||
}
|
||||
|
||||
// We're intercepting malloc, so kCFAllocatorMalloc is routed to ASan.
|
||||
TEST(AddressSanitizerMac, CFAllocatorMallocDoubleFree) {
|
||||
EXPECT_DEATH(CFAllocatorMallocDoubleFree(), "attempting double-free");
|
||||
}
|
||||
|
||||
TEST(AddressSanitizerMac, DISABLED_CFAllocatorMallocZoneDoubleFree) {
|
||||
EXPECT_DEATH(CFAllocatorMallocZoneDoubleFree(), "attempting double-free");
|
||||
}
|
||||
|
||||
// For libdispatch tests below we check that ASan got to the shadow byte
|
||||
// legend, i.e. managed to print the thread stacks (this almost certainly
|
||||
// means that the libdispatch task creation has been intercepted correctly).
|
||||
TEST(AddressSanitizerMac, GCDDispatchAsync) {
|
||||
// Make sure the whole ASan report is printed, i.e. that we don't die
|
||||
// on a CHECK.
|
||||
EXPECT_DEATH(TestGCDDispatchAsync(), "Shadow byte legend");
|
||||
}
|
||||
|
||||
TEST(AddressSanitizerMac, GCDDispatchSync) {
|
||||
// Make sure the whole ASan report is printed, i.e. that we don't die
|
||||
// on a CHECK.
|
||||
EXPECT_DEATH(TestGCDDispatchSync(), "Shadow byte legend");
|
||||
}
|
||||
|
||||
|
||||
TEST(AddressSanitizerMac, GCDReuseWqthreadsAsync) {
|
||||
// Make sure the whole ASan report is printed, i.e. that we don't die
|
||||
// on a CHECK.
|
||||
EXPECT_DEATH(TestGCDReuseWqthreadsAsync(), "Shadow byte legend");
|
||||
}
|
||||
|
||||
TEST(AddressSanitizerMac, GCDReuseWqthreadsSync) {
|
||||
// Make sure the whole ASan report is printed, i.e. that we don't die
|
||||
// on a CHECK.
|
||||
EXPECT_DEATH(TestGCDReuseWqthreadsSync(), "Shadow byte legend");
|
||||
}
|
||||
|
||||
TEST(AddressSanitizerMac, GCDDispatchAfter) {
|
||||
// Make sure the whole ASan report is printed, i.e. that we don't die
|
||||
// on a CHECK.
|
||||
EXPECT_DEATH(TestGCDDispatchAfter(), "Shadow byte legend");
|
||||
}
|
||||
|
||||
TEST(AddressSanitizerMac, GCDSourceEvent) {
|
||||
// Make sure the whole ASan report is printed, i.e. that we don't die
|
||||
// on a CHECK.
|
||||
EXPECT_DEATH(TestGCDSourceEvent(), "Shadow byte legend");
|
||||
}
|
||||
|
||||
TEST(AddressSanitizerMac, GCDSourceCancel) {
|
||||
// Make sure the whole ASan report is printed, i.e. that we don't die
|
||||
// on a CHECK.
|
||||
EXPECT_DEATH(TestGCDSourceCancel(), "Shadow byte legend");
|
||||
}
|
||||
|
||||
TEST(AddressSanitizerMac, GCDGroupAsync) {
|
||||
// Make sure the whole ASan report is printed, i.e. that we don't die
|
||||
// on a CHECK.
|
||||
EXPECT_DEATH(TestGCDGroupAsync(), "Shadow byte legend");
|
||||
}
|
||||
|
||||
void *MallocIntrospectionLockWorker(void *_) {
|
||||
const int kNumPointers = 100;
|
||||
int i;
|
||||
void *pointers[kNumPointers];
|
||||
for (i = 0; i < kNumPointers; i++) {
|
||||
pointers[i] = malloc(i + 1);
|
||||
}
|
||||
for (i = 0; i < kNumPointers; i++) {
|
||||
free(pointers[i]);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *MallocIntrospectionLockForker(void *_) {
|
||||
pid_t result = fork();
|
||||
if (result == -1) {
|
||||
perror("fork");
|
||||
}
|
||||
assert(result != -1);
|
||||
if (result == 0) {
|
||||
// Call malloc in the child process to make sure we won't deadlock.
|
||||
void *ptr = malloc(42);
|
||||
free(ptr);
|
||||
exit(0);
|
||||
} else {
|
||||
// Return in the parent process.
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AddressSanitizerMac, MallocIntrospectionLock) {
|
||||
// Incorrect implementation of force_lock and force_unlock in our malloc zone
|
||||
// will cause forked processes to deadlock.
|
||||
// TODO(glider): need to detect that none of the child processes deadlocked.
|
||||
const int kNumWorkers = 5, kNumIterations = 100;
|
||||
int i, iter;
|
||||
for (iter = 0; iter < kNumIterations; iter++) {
|
||||
pthread_t workers[kNumWorkers], forker;
|
||||
for (i = 0; i < kNumWorkers; i++) {
|
||||
PTHREAD_CREATE(&workers[i], 0, MallocIntrospectionLockWorker, 0);
|
||||
}
|
||||
PTHREAD_CREATE(&forker, 0, MallocIntrospectionLockForker, 0);
|
||||
for (i = 0; i < kNumWorkers; i++) {
|
||||
PTHREAD_JOIN(workers[i], 0);
|
||||
}
|
||||
PTHREAD_JOIN(forker, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void *TSDAllocWorker(void *test_key) {
|
||||
if (test_key) {
|
||||
void *mem = malloc(10);
|
||||
pthread_setspecific(*(pthread_key_t*)test_key, mem);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TEST(AddressSanitizerMac, DISABLED_TSDWorkqueueTest) {
|
||||
pthread_t th;
|
||||
pthread_key_t test_key;
|
||||
pthread_key_create(&test_key, CallFreeOnWorkqueue);
|
||||
PTHREAD_CREATE(&th, NULL, TSDAllocWorker, &test_key);
|
||||
PTHREAD_JOIN(th, NULL);
|
||||
pthread_key_delete(test_key);
|
||||
}
|
||||
|
||||
// Test that CFStringCreateCopy does not copy constant strings.
|
||||
TEST(AddressSanitizerMac, CFStringCreateCopy) {
|
||||
CFStringRef str = CFSTR("Hello world!\n");
|
||||
CFStringRef str2 = CFStringCreateCopy(0, str);
|
||||
EXPECT_EQ(str, str2);
|
||||
}
|
||||
|
||||
TEST(AddressSanitizerMac, NSObjectOOB) {
|
||||
// Make sure that our allocators are used for NSObjects.
|
||||
EXPECT_DEATH(TestOOBNSObjects(), "heap-buffer-overflow");
|
||||
}
|
||||
|
||||
// Make sure that correct pointer is passed to free() when deallocating a
|
||||
// NSURL object.
|
||||
// See https://github.com/google/sanitizers/issues/70.
|
||||
TEST(AddressSanitizerMac, NSURLDeallocation) {
|
||||
TestNSURLDeallocation();
|
||||
}
|
||||
|
||||
// See https://github.com/google/sanitizers/issues/109.
|
||||
TEST(AddressSanitizerMac, Mstats) {
|
||||
malloc_statistics_t stats1, stats2;
|
||||
malloc_zone_statistics(/*all zones*/NULL, &stats1);
|
||||
const size_t kMallocSize = 100000;
|
||||
void *alloc = Ident(malloc(kMallocSize));
|
||||
malloc_zone_statistics(/*all zones*/NULL, &stats2);
|
||||
EXPECT_GT(stats2.blocks_in_use, stats1.blocks_in_use);
|
||||
EXPECT_GE(stats2.size_in_use - stats1.size_in_use, kMallocSize);
|
||||
free(alloc);
|
||||
// Even the default OSX allocator may not change the stats after free().
|
||||
}
|
||||
|
@ -1,19 +0,0 @@
|
||||
extern "C" {
|
||||
void *CFAllocatorDefaultDoubleFree(void *unused);
|
||||
void CFAllocatorSystemDefaultDoubleFree();
|
||||
void CFAllocatorMallocDoubleFree();
|
||||
void CFAllocatorMallocZoneDoubleFree();
|
||||
void CallFreeOnWorkqueue(void *mem);
|
||||
void TestGCDDispatchAsync();
|
||||
void TestGCDDispatchSync();
|
||||
void TestGCDReuseWqthreadsAsync();
|
||||
void TestGCDReuseWqthreadsSync();
|
||||
void TestGCDDispatchAfter();
|
||||
void TestGCDInTSDDestructor();
|
||||
void TestGCDSourceEvent();
|
||||
void TestGCDSourceCancel();
|
||||
void TestGCDGroupAsync();
|
||||
void TestOOBNSObjects();
|
||||
void TestNSURLDeallocation();
|
||||
void TestPassCFMemoryToAnotherThread();
|
||||
}
|
@ -1,241 +0,0 @@
|
||||
// Mac OS X 10.6 or higher only.
|
||||
#include <dispatch/dispatch.h>
|
||||
#include <pthread.h> // for pthread_yield_np()
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#import <CoreFoundation/CFBase.h>
|
||||
#import <Foundation/NSObject.h>
|
||||
#import <Foundation/NSURL.h>
|
||||
|
||||
// This is a (void*)(void*) function so it can be passed to pthread_create.
|
||||
void *CFAllocatorDefaultDoubleFree(void *unused) {
|
||||
void *mem = CFAllocatorAllocate(kCFAllocatorDefault, 5, 0);
|
||||
CFAllocatorDeallocate(kCFAllocatorDefault, mem);
|
||||
CFAllocatorDeallocate(kCFAllocatorDefault, mem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CFAllocatorSystemDefaultDoubleFree() {
|
||||
void *mem = CFAllocatorAllocate(kCFAllocatorSystemDefault, 5, 0);
|
||||
CFAllocatorDeallocate(kCFAllocatorSystemDefault, mem);
|
||||
CFAllocatorDeallocate(kCFAllocatorSystemDefault, mem);
|
||||
}
|
||||
|
||||
void CFAllocatorMallocDoubleFree() {
|
||||
void *mem = CFAllocatorAllocate(kCFAllocatorMalloc, 5, 0);
|
||||
CFAllocatorDeallocate(kCFAllocatorMalloc, mem);
|
||||
CFAllocatorDeallocate(kCFAllocatorMalloc, mem);
|
||||
}
|
||||
|
||||
void CFAllocatorMallocZoneDoubleFree() {
|
||||
void *mem = CFAllocatorAllocate(kCFAllocatorMallocZone, 5, 0);
|
||||
CFAllocatorDeallocate(kCFAllocatorMallocZone, mem);
|
||||
CFAllocatorDeallocate(kCFAllocatorMallocZone, mem);
|
||||
}
|
||||
|
||||
__attribute__((noinline))
|
||||
void access_memory(char *a) {
|
||||
*a = 0;
|
||||
}
|
||||
|
||||
// Test the +load instrumentation.
|
||||
// Because the +load methods are invoked before anything else is initialized,
|
||||
// it makes little sense to wrap the code below into a gTest test case.
|
||||
// If AddressSanitizer doesn't instrument the +load method below correctly,
|
||||
// everything will just crash.
|
||||
|
||||
char kStartupStr[] =
|
||||
"If your test didn't crash, AddressSanitizer is instrumenting "
|
||||
"the +load methods correctly.";
|
||||
|
||||
@interface LoadSomething : NSObject {
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation LoadSomething
|
||||
|
||||
+(void) load {
|
||||
for (size_t i = 0; i < strlen(kStartupStr); i++) {
|
||||
access_memory(&kStartupStr[i]); // make sure no optimizations occur.
|
||||
}
|
||||
// Don't print anything here not to interfere with the death tests.
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
void worker_do_alloc(int size) {
|
||||
char * volatile mem = (char * volatile)malloc(size);
|
||||
mem[0] = 0; // Ok
|
||||
free(mem);
|
||||
}
|
||||
|
||||
void worker_do_crash(int size) {
|
||||
char * volatile mem = (char * volatile)malloc(size);
|
||||
access_memory(&mem[size]); // BOOM
|
||||
free(mem);
|
||||
}
|
||||
|
||||
// Used by the GCD tests to avoid a race between the worker thread reporting a
|
||||
// memory error and the main thread which may exit with exit code 0 before
|
||||
// that.
|
||||
void wait_forever() {
|
||||
volatile bool infinite = true;
|
||||
while (infinite) pthread_yield_np();
|
||||
}
|
||||
|
||||
// Tests for the Grand Central Dispatch. See
|
||||
// http://developer.apple.com/library/mac/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html
|
||||
// for the reference.
|
||||
void TestGCDDispatchAsync() {
|
||||
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
|
||||
dispatch_block_t block = ^{ worker_do_crash(1024); };
|
||||
// dispatch_async() runs the task on a worker thread that does not go through
|
||||
// pthread_create(). We need to verify that AddressSanitizer notices that the
|
||||
// thread has started.
|
||||
dispatch_async(queue, block);
|
||||
wait_forever();
|
||||
}
|
||||
|
||||
void TestGCDDispatchSync() {
|
||||
dispatch_queue_t queue = dispatch_get_global_queue(2, 0);
|
||||
dispatch_block_t block = ^{ worker_do_crash(1024); };
|
||||
// dispatch_sync() runs the task on a worker thread that does not go through
|
||||
// pthread_create(). We need to verify that AddressSanitizer notices that the
|
||||
// thread has started.
|
||||
dispatch_sync(queue, block);
|
||||
wait_forever();
|
||||
}
|
||||
|
||||
// libdispatch spawns a rather small number of threads and reuses them. We need
|
||||
// to make sure AddressSanitizer handles the reusing correctly.
|
||||
void TestGCDReuseWqthreadsAsync() {
|
||||
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
|
||||
dispatch_block_t block_alloc = ^{ worker_do_alloc(1024); };
|
||||
dispatch_block_t block_crash = ^{ worker_do_crash(1024); };
|
||||
for (int i = 0; i < 100; i++) {
|
||||
dispatch_async(queue, block_alloc);
|
||||
}
|
||||
dispatch_async(queue, block_crash);
|
||||
wait_forever();
|
||||
}
|
||||
|
||||
// Try to trigger abnormal behaviour of dispatch_sync() being unhandled by us.
|
||||
void TestGCDReuseWqthreadsSync() {
|
||||
dispatch_queue_t queue[4];
|
||||
queue[0] = dispatch_get_global_queue(2, 0);
|
||||
queue[1] = dispatch_get_global_queue(0, 0);
|
||||
queue[2] = dispatch_get_global_queue(-2, 0);
|
||||
queue[3] = dispatch_queue_create("my_queue", NULL);
|
||||
dispatch_block_t block_alloc = ^{ worker_do_alloc(1024); };
|
||||
dispatch_block_t block_crash = ^{ worker_do_crash(1024); };
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
dispatch_sync(queue[i % 4], block_alloc);
|
||||
}
|
||||
dispatch_sync(queue[3], block_crash);
|
||||
wait_forever();
|
||||
}
|
||||
|
||||
void TestGCDDispatchAfter() {
|
||||
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
|
||||
dispatch_block_t block_crash = ^{ worker_do_crash(1024); };
|
||||
// Schedule the event one second from the current time.
|
||||
dispatch_time_t milestone =
|
||||
dispatch_time(DISPATCH_TIME_NOW, 1LL * NSEC_PER_SEC);
|
||||
dispatch_after(milestone, queue, block_crash);
|
||||
wait_forever();
|
||||
}
|
||||
|
||||
void worker_do_deallocate(void *ptr) {
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void CallFreeOnWorkqueue(void *tsd) {
|
||||
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
|
||||
dispatch_block_t block_dealloc = ^{ worker_do_deallocate(tsd); };
|
||||
dispatch_async(queue, block_dealloc);
|
||||
// Do not wait for the worker to free the memory -- nobody is going to touch
|
||||
// it.
|
||||
}
|
||||
|
||||
void TestGCDSourceEvent() {
|
||||
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
|
||||
dispatch_source_t timer =
|
||||
dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
|
||||
// Schedule the timer one second from the current time.
|
||||
dispatch_time_t milestone =
|
||||
dispatch_time(DISPATCH_TIME_NOW, 1LL * NSEC_PER_SEC);
|
||||
|
||||
dispatch_source_set_timer(timer, milestone, DISPATCH_TIME_FOREVER, 0);
|
||||
char * volatile mem = (char * volatile)malloc(10);
|
||||
dispatch_source_set_event_handler(timer, ^{
|
||||
access_memory(&mem[10]);
|
||||
});
|
||||
dispatch_resume(timer);
|
||||
wait_forever();
|
||||
}
|
||||
|
||||
void TestGCDSourceCancel() {
|
||||
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
|
||||
dispatch_source_t timer =
|
||||
dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
|
||||
// Schedule the timer one second from the current time.
|
||||
dispatch_time_t milestone =
|
||||
dispatch_time(DISPATCH_TIME_NOW, 1LL * NSEC_PER_SEC);
|
||||
|
||||
dispatch_source_set_timer(timer, milestone, DISPATCH_TIME_FOREVER, 0);
|
||||
char * volatile mem = (char * volatile)malloc(10);
|
||||
// Both dispatch_source_set_cancel_handler() and
|
||||
// dispatch_source_set_event_handler() use dispatch_barrier_async_f().
|
||||
// It's tricky to test dispatch_source_set_cancel_handler() separately,
|
||||
// so we test both here.
|
||||
dispatch_source_set_event_handler(timer, ^{
|
||||
dispatch_source_cancel(timer);
|
||||
});
|
||||
dispatch_source_set_cancel_handler(timer, ^{
|
||||
access_memory(&mem[10]);
|
||||
});
|
||||
dispatch_resume(timer);
|
||||
wait_forever();
|
||||
}
|
||||
|
||||
void TestGCDGroupAsync() {
|
||||
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
|
||||
dispatch_group_t group = dispatch_group_create();
|
||||
char * volatile mem = (char * volatile)malloc(10);
|
||||
dispatch_group_async(group, queue, ^{
|
||||
access_memory(&mem[10]);
|
||||
});
|
||||
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
|
||||
wait_forever();
|
||||
}
|
||||
|
||||
@interface FixedArray : NSObject {
|
||||
int items[10];
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation FixedArray
|
||||
-(int) access: (int)index {
|
||||
return items[index];
|
||||
}
|
||||
@end
|
||||
|
||||
void TestOOBNSObjects() {
|
||||
id anObject = [FixedArray new];
|
||||
[anObject access:1];
|
||||
[anObject access:11];
|
||||
[anObject release];
|
||||
}
|
||||
|
||||
void TestNSURLDeallocation() {
|
||||
NSURL *base =
|
||||
[[NSURL alloc] initWithString:@"file://localhost/Users/glider/Library/"];
|
||||
volatile NSURL *u =
|
||||
[[NSURL alloc] initWithString:@"Saved Application State"
|
||||
relativeToURL:base];
|
||||
[u release];
|
||||
[base release];
|
||||
}
|
@ -1,242 +0,0 @@
|
||||
//===-- asan_mem_test.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.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "asan_test_utils.h"
|
||||
#include <vector>
|
||||
|
||||
template<typename T>
|
||||
void MemSetOOBTestTemplate(size_t length) {
|
||||
if (length == 0) return;
|
||||
size_t size = Ident(sizeof(T) * length);
|
||||
T *array = Ident((T*)malloc(size));
|
||||
int element = Ident(42);
|
||||
int zero = Ident(0);
|
||||
void *(*MEMSET)(void *s, int c, size_t n) = Ident(memset);
|
||||
// memset interval inside array
|
||||
MEMSET(array, element, size);
|
||||
MEMSET(array, element, size - 1);
|
||||
MEMSET(array + length - 1, element, sizeof(T));
|
||||
MEMSET(array, element, 1);
|
||||
|
||||
// memset 0 bytes
|
||||
MEMSET(array - 10, element, zero);
|
||||
MEMSET(array - 1, element, zero);
|
||||
MEMSET(array, element, zero);
|
||||
MEMSET(array + length, 0, zero);
|
||||
MEMSET(array + length + 1, 0, zero);
|
||||
|
||||
// try to memset bytes to the right of array
|
||||
EXPECT_DEATH(MEMSET(array, 0, size + 1),
|
||||
RightOOBWriteMessage(0));
|
||||
EXPECT_DEATH(MEMSET((char*)(array + length) - 1, element, 6),
|
||||
RightOOBWriteMessage(0));
|
||||
EXPECT_DEATH(MEMSET(array + 1, element, size + sizeof(T)),
|
||||
RightOOBWriteMessage(0));
|
||||
// whole interval is to the right
|
||||
EXPECT_DEATH(MEMSET(array + length + 1, 0, 10),
|
||||
RightOOBWriteMessage(sizeof(T)));
|
||||
|
||||
// try to memset bytes to the left of array
|
||||
EXPECT_DEATH(MEMSET((char*)array - 1, element, size),
|
||||
LeftOOBWriteMessage(1));
|
||||
EXPECT_DEATH(MEMSET((char*)array - 5, 0, 6),
|
||||
LeftOOBWriteMessage(5));
|
||||
if (length >= 100) {
|
||||
// Large OOB, we find it only if the redzone is large enough.
|
||||
EXPECT_DEATH(memset(array - 5, element, size + 5 * sizeof(T)),
|
||||
LeftOOBWriteMessage(5 * sizeof(T)));
|
||||
}
|
||||
// whole interval is to the left
|
||||
EXPECT_DEATH(MEMSET(array - 2, 0, sizeof(T)),
|
||||
LeftOOBWriteMessage(2 * sizeof(T)));
|
||||
|
||||
// try to memset bytes both to the left & to the right
|
||||
EXPECT_DEATH(MEMSET((char*)array - 2, element, size + 4),
|
||||
LeftOOBWriteMessage(2));
|
||||
|
||||
free(array);
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, MemSetOOBTest) {
|
||||
MemSetOOBTestTemplate<char>(100);
|
||||
MemSetOOBTestTemplate<int>(5);
|
||||
MemSetOOBTestTemplate<double>(256);
|
||||
// We can test arrays of structres/classes here, but what for?
|
||||
}
|
||||
|
||||
// Try to allocate two arrays of 'size' bytes that are near each other.
|
||||
// Strictly speaking we are not guaranteed to find such two pointers,
|
||||
// but given the structure of asan's allocator we will.
|
||||
static bool AllocateTwoAdjacentArrays(char **x1, char **x2, size_t size) {
|
||||
std::vector<uintptr_t> v;
|
||||
bool res = false;
|
||||
for (size_t i = 0; i < 1000U && !res; i++) {
|
||||
v.push_back(reinterpret_cast<uintptr_t>(new char[size]));
|
||||
if (i == 0) continue;
|
||||
sort(v.begin(), v.end());
|
||||
for (size_t j = 1; j < v.size(); j++) {
|
||||
assert(v[j] > v[j-1]);
|
||||
if ((size_t)(v[j] - v[j-1]) < size * 2) {
|
||||
*x2 = reinterpret_cast<char*>(v[j]);
|
||||
*x1 = reinterpret_cast<char*>(v[j-1]);
|
||||
res = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < v.size(); i++) {
|
||||
char *p = reinterpret_cast<char *>(v[i]);
|
||||
if (res && p == *x1) continue;
|
||||
if (res && p == *x2) continue;
|
||||
delete [] p;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, LargeOOBInMemset) {
|
||||
for (size_t size = 200; size < 100000; size += size / 2) {
|
||||
char *x1, *x2;
|
||||
if (!Ident(AllocateTwoAdjacentArrays)(&x1, &x2, size))
|
||||
continue;
|
||||
// fprintf(stderr, " large oob memset: %p %p %zd\n", x1, x2, size);
|
||||
// Do a memset on x1 with huge out-of-bound access that will end up in x2.
|
||||
EXPECT_DEATH(Ident(memset)(x1, 0, size * 2),
|
||||
"is located 0 bytes to the right");
|
||||
delete [] x1;
|
||||
delete [] x2;
|
||||
return;
|
||||
}
|
||||
assert(0 && "Did not find two adjacent malloc-ed pointers");
|
||||
}
|
||||
|
||||
// Same test for memcpy and memmove functions
|
||||
template <typename T, class M>
|
||||
void MemTransferOOBTestTemplate(size_t length) {
|
||||
if (length == 0) return;
|
||||
size_t size = Ident(sizeof(T) * length);
|
||||
T *src = Ident((T*)malloc(size));
|
||||
T *dest = Ident((T*)malloc(size));
|
||||
int zero = Ident(0);
|
||||
|
||||
// valid transfer of bytes between arrays
|
||||
M::transfer(dest, src, size);
|
||||
M::transfer(dest + 1, src, size - sizeof(T));
|
||||
M::transfer(dest, src + length - 1, sizeof(T));
|
||||
M::transfer(dest, src, 1);
|
||||
|
||||
// transfer zero bytes
|
||||
M::transfer(dest - 1, src, 0);
|
||||
M::transfer(dest + length, src, zero);
|
||||
M::transfer(dest, src - 1, zero);
|
||||
M::transfer(dest, src, zero);
|
||||
|
||||
// try to change mem to the right of dest
|
||||
EXPECT_DEATH(M::transfer(dest + 1, src, size),
|
||||
RightOOBWriteMessage(0));
|
||||
EXPECT_DEATH(M::transfer((char*)(dest + length) - 1, src, 5),
|
||||
RightOOBWriteMessage(0));
|
||||
|
||||
// try to change mem to the left of dest
|
||||
EXPECT_DEATH(M::transfer(dest - 2, src, size),
|
||||
LeftOOBWriteMessage(2 * sizeof(T)));
|
||||
EXPECT_DEATH(M::transfer((char*)dest - 3, src, 4),
|
||||
LeftOOBWriteMessage(3));
|
||||
|
||||
// try to access mem to the right of src
|
||||
EXPECT_DEATH(M::transfer(dest, src + 2, size),
|
||||
RightOOBReadMessage(0));
|
||||
EXPECT_DEATH(M::transfer(dest, (char*)(src + length) - 3, 6),
|
||||
RightOOBReadMessage(0));
|
||||
|
||||
// try to access mem to the left of src
|
||||
EXPECT_DEATH(M::transfer(dest, src - 1, size),
|
||||
LeftOOBReadMessage(sizeof(T)));
|
||||
EXPECT_DEATH(M::transfer(dest, (char*)src - 6, 7),
|
||||
LeftOOBReadMessage(6));
|
||||
|
||||
// Generally we don't need to test cases where both accessing src and writing
|
||||
// to dest address to poisoned memory.
|
||||
|
||||
T *big_src = Ident((T*)malloc(size * 2));
|
||||
T *big_dest = Ident((T*)malloc(size * 2));
|
||||
// try to change mem to both sides of dest
|
||||
EXPECT_DEATH(M::transfer(dest - 1, big_src, size * 2),
|
||||
LeftOOBWriteMessage(sizeof(T)));
|
||||
// try to access mem to both sides of src
|
||||
EXPECT_DEATH(M::transfer(big_dest, src - 2, size * 2),
|
||||
LeftOOBReadMessage(2 * sizeof(T)));
|
||||
|
||||
free(src);
|
||||
free(dest);
|
||||
free(big_src);
|
||||
free(big_dest);
|
||||
}
|
||||
|
||||
class MemCpyWrapper {
|
||||
public:
|
||||
static void* transfer(void *to, const void *from, size_t size) {
|
||||
return Ident(memcpy)(to, from, size);
|
||||
}
|
||||
};
|
||||
|
||||
TEST(AddressSanitizer, MemCpyOOBTest) {
|
||||
MemTransferOOBTestTemplate<char, MemCpyWrapper>(100);
|
||||
MemTransferOOBTestTemplate<int, MemCpyWrapper>(1024);
|
||||
}
|
||||
|
||||
class MemMoveWrapper {
|
||||
public:
|
||||
static void* transfer(void *to, const void *from, size_t size) {
|
||||
return Ident(memmove)(to, from, size);
|
||||
}
|
||||
};
|
||||
|
||||
TEST(AddressSanitizer, MemMoveOOBTest) {
|
||||
MemTransferOOBTestTemplate<char, MemMoveWrapper>(100);
|
||||
MemTransferOOBTestTemplate<int, MemMoveWrapper>(1024);
|
||||
}
|
||||
|
||||
|
||||
TEST(AddressSanitizer, MemCmpOOBTest) {
|
||||
size_t size = Ident(100);
|
||||
char *s1 = MallocAndMemsetString(size);
|
||||
char *s2 = MallocAndMemsetString(size);
|
||||
// Normal memcmp calls.
|
||||
Ident(memcmp(s1, s2, size));
|
||||
Ident(memcmp(s1 + size - 1, s2 + size - 1, 1));
|
||||
Ident(memcmp(s1 - 1, s2 - 1, 0));
|
||||
// One of arguments points to not allocated memory.
|
||||
EXPECT_DEATH(Ident(memcmp)(s1 - 1, s2, 1), LeftOOBReadMessage(1));
|
||||
EXPECT_DEATH(Ident(memcmp)(s1, s2 - 1, 1), LeftOOBReadMessage(1));
|
||||
EXPECT_DEATH(Ident(memcmp)(s1 + size, s2, 1), RightOOBReadMessage(0));
|
||||
EXPECT_DEATH(Ident(memcmp)(s1, s2 + size, 1), RightOOBReadMessage(0));
|
||||
// Hit unallocated memory and die.
|
||||
EXPECT_DEATH(Ident(memcmp)(s1 + 1, s2 + 1, size), RightOOBReadMessage(0));
|
||||
EXPECT_DEATH(Ident(memcmp)(s1 + size - 1, s2, 2), RightOOBReadMessage(0));
|
||||
// Zero bytes are not terminators and don't prevent from OOB.
|
||||
s1[size - 1] = '\0';
|
||||
s2[size - 1] = '\0';
|
||||
EXPECT_DEATH(Ident(memcmp)(s1, s2, size + 1), RightOOBReadMessage(0));
|
||||
|
||||
// Even if the buffers differ in the first byte, we still assume that
|
||||
// memcmp may access the whole buffer and thus reporting the overflow here:
|
||||
s1[0] = 1;
|
||||
s2[0] = 123;
|
||||
EXPECT_DEATH(Ident(memcmp)(s1, s2, size + 1), RightOOBReadMessage(0));
|
||||
|
||||
free(s1);
|
||||
free(s2);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,273 +0,0 @@
|
||||
//===-- asan_noinst_test.cc -----------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// This test file should be compiled w/o asan instrumentation.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "asan_allocator.h"
|
||||
#include "asan_internal.h"
|
||||
#include "asan_mapping.h"
|
||||
#include "asan_test_utils.h"
|
||||
#include <sanitizer/allocator_interface.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h> // for memset()
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include <limits>
|
||||
|
||||
using namespace __sanitizer;
|
||||
|
||||
// ATTENTION!
|
||||
// Please don't call intercepted functions (including malloc() and friends)
|
||||
// in this test. The static runtime library is linked explicitly (without
|
||||
// -fsanitize=address), thus the interceptors do not work correctly on OS X.
|
||||
|
||||
// Make sure __asan_init is called before any test case is run.
|
||||
struct AsanInitCaller {
|
||||
AsanInitCaller() {
|
||||
__asan_init();
|
||||
}
|
||||
};
|
||||
static AsanInitCaller asan_init_caller;
|
||||
|
||||
TEST(AddressSanitizer, InternalSimpleDeathTest) {
|
||||
EXPECT_DEATH(exit(1), "");
|
||||
}
|
||||
|
||||
static void MallocStress(size_t n) {
|
||||
u32 seed = my_rand();
|
||||
BufferedStackTrace stack1;
|
||||
stack1.trace_buffer[0] = 0xa123;
|
||||
stack1.trace_buffer[1] = 0xa456;
|
||||
stack1.size = 2;
|
||||
|
||||
BufferedStackTrace stack2;
|
||||
stack2.trace_buffer[0] = 0xb123;
|
||||
stack2.trace_buffer[1] = 0xb456;
|
||||
stack2.size = 2;
|
||||
|
||||
BufferedStackTrace stack3;
|
||||
stack3.trace_buffer[0] = 0xc123;
|
||||
stack3.trace_buffer[1] = 0xc456;
|
||||
stack3.size = 2;
|
||||
|
||||
std::vector<void *> vec;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
if ((i % 3) == 0) {
|
||||
if (vec.empty()) continue;
|
||||
size_t idx = my_rand_r(&seed) % vec.size();
|
||||
void *ptr = vec[idx];
|
||||
vec[idx] = vec.back();
|
||||
vec.pop_back();
|
||||
__asan::asan_free(ptr, &stack1, __asan::FROM_MALLOC);
|
||||
} else {
|
||||
size_t size = my_rand_r(&seed) % 1000 + 1;
|
||||
switch ((my_rand_r(&seed) % 128)) {
|
||||
case 0: size += 1024; break;
|
||||
case 1: size += 2048; break;
|
||||
case 2: size += 4096; break;
|
||||
}
|
||||
size_t alignment = 1 << (my_rand_r(&seed) % 10 + 1);
|
||||
char *ptr = (char*)__asan::asan_memalign(alignment, size,
|
||||
&stack2, __asan::FROM_MALLOC);
|
||||
EXPECT_EQ(size, __asan::asan_malloc_usable_size(ptr, 0, 0));
|
||||
vec.push_back(ptr);
|
||||
ptr[0] = 0;
|
||||
ptr[size-1] = 0;
|
||||
ptr[size/2] = 0;
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < vec.size(); i++)
|
||||
__asan::asan_free(vec[i], &stack3, __asan::FROM_MALLOC);
|
||||
}
|
||||
|
||||
|
||||
TEST(AddressSanitizer, NoInstMallocTest) {
|
||||
MallocStress(ASAN_LOW_MEMORY ? 300000 : 1000000);
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, ThreadedMallocStressTest) {
|
||||
const int kNumThreads = 4;
|
||||
const int kNumIterations = (ASAN_LOW_MEMORY) ? 10000 : 100000;
|
||||
pthread_t t[kNumThreads];
|
||||
for (int i = 0; i < kNumThreads; i++) {
|
||||
PTHREAD_CREATE(&t[i], 0, (void* (*)(void *x))MallocStress,
|
||||
(void*)kNumIterations);
|
||||
}
|
||||
for (int i = 0; i < kNumThreads; i++) {
|
||||
PTHREAD_JOIN(t[i], 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void PrintShadow(const char *tag, uptr ptr, size_t size) {
|
||||
fprintf(stderr, "%s shadow: %lx size % 3ld: ", tag, (long)ptr, (long)size);
|
||||
uptr prev_shadow = 0;
|
||||
for (sptr i = -32; i < (sptr)size + 32; i++) {
|
||||
uptr shadow = __asan::MemToShadow(ptr + i);
|
||||
if (i == 0 || i == (sptr)size)
|
||||
fprintf(stderr, ".");
|
||||
if (shadow != prev_shadow) {
|
||||
prev_shadow = shadow;
|
||||
fprintf(stderr, "%02x", (int)*(u8*)shadow);
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, DISABLED_InternalPrintShadow) {
|
||||
for (size_t size = 1; size <= 513; size++) {
|
||||
char *ptr = new char[size];
|
||||
PrintShadow("m", (uptr)ptr, size);
|
||||
delete [] ptr;
|
||||
PrintShadow("f", (uptr)ptr, size);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, QuarantineTest) {
|
||||
BufferedStackTrace stack;
|
||||
stack.trace_buffer[0] = 0x890;
|
||||
stack.size = 1;
|
||||
|
||||
const int size = 1024;
|
||||
void *p = __asan::asan_malloc(size, &stack);
|
||||
__asan::asan_free(p, &stack, __asan::FROM_MALLOC);
|
||||
size_t i;
|
||||
size_t max_i = 1 << 30;
|
||||
for (i = 0; i < max_i; i++) {
|
||||
void *p1 = __asan::asan_malloc(size, &stack);
|
||||
__asan::asan_free(p1, &stack, __asan::FROM_MALLOC);
|
||||
if (p1 == p) break;
|
||||
}
|
||||
EXPECT_GE(i, 10000U);
|
||||
EXPECT_LT(i, max_i);
|
||||
}
|
||||
|
||||
#if !defined(__NetBSD__)
|
||||
void *ThreadedQuarantineTestWorker(void *unused) {
|
||||
(void)unused;
|
||||
u32 seed = my_rand();
|
||||
BufferedStackTrace stack;
|
||||
stack.trace_buffer[0] = 0x890;
|
||||
stack.size = 1;
|
||||
|
||||
for (size_t i = 0; i < 1000; i++) {
|
||||
void *p = __asan::asan_malloc(1 + (my_rand_r(&seed) % 4000), &stack);
|
||||
__asan::asan_free(p, &stack, __asan::FROM_MALLOC);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Check that the thread local allocators are flushed when threads are
|
||||
// destroyed.
|
||||
TEST(AddressSanitizer, ThreadedQuarantineTest) {
|
||||
// Run the routine once to warm up ASAN internal structures to get more
|
||||
// predictable incremental memory changes.
|
||||
pthread_t t;
|
||||
PTHREAD_CREATE(&t, NULL, ThreadedQuarantineTestWorker, 0);
|
||||
PTHREAD_JOIN(t, 0);
|
||||
|
||||
const int n_threads = 3000;
|
||||
size_t mmaped1 = __sanitizer_get_heap_size();
|
||||
for (int i = 0; i < n_threads; i++) {
|
||||
pthread_t t;
|
||||
PTHREAD_CREATE(&t, NULL, ThreadedQuarantineTestWorker, 0);
|
||||
PTHREAD_JOIN(t, 0);
|
||||
size_t mmaped2 = __sanitizer_get_heap_size();
|
||||
// Figure out why this much memory is required.
|
||||
EXPECT_LT(mmaped2 - mmaped1, 320U * (1 << 20));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void *ThreadedOneSizeMallocStress(void *unused) {
|
||||
(void)unused;
|
||||
BufferedStackTrace stack;
|
||||
stack.trace_buffer[0] = 0x890;
|
||||
stack.size = 1;
|
||||
const size_t kNumMallocs = 1000;
|
||||
for (int iter = 0; iter < 1000; iter++) {
|
||||
void *p[kNumMallocs];
|
||||
for (size_t i = 0; i < kNumMallocs; i++) {
|
||||
p[i] = __asan::asan_malloc(32, &stack);
|
||||
}
|
||||
for (size_t i = 0; i < kNumMallocs; i++) {
|
||||
__asan::asan_free(p[i], &stack, __asan::FROM_MALLOC);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, ThreadedOneSizeMallocStressTest) {
|
||||
const int kNumThreads = 4;
|
||||
pthread_t t[kNumThreads];
|
||||
for (int i = 0; i < kNumThreads; i++) {
|
||||
PTHREAD_CREATE(&t[i], 0, ThreadedOneSizeMallocStress, 0);
|
||||
}
|
||||
for (int i = 0; i < kNumThreads; i++) {
|
||||
PTHREAD_JOIN(t[i], 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, ShadowRegionIsPoisonedTest) {
|
||||
using __asan::kHighMemEnd;
|
||||
// Check that __asan_region_is_poisoned works for shadow regions.
|
||||
uptr ptr = kLowShadowBeg + 200;
|
||||
EXPECT_EQ(ptr, __asan_region_is_poisoned(ptr, 100));
|
||||
ptr = kShadowGapBeg + 200;
|
||||
EXPECT_EQ(ptr, __asan_region_is_poisoned(ptr, 100));
|
||||
ptr = kHighShadowBeg + 200;
|
||||
EXPECT_EQ(ptr, __asan_region_is_poisoned(ptr, 100));
|
||||
}
|
||||
|
||||
// Test __asan_load1 & friends.
|
||||
TEST(AddressSanitizer, LoadStoreCallbacks) {
|
||||
typedef void (*CB)(uptr p);
|
||||
CB cb[2][5] = {
|
||||
{
|
||||
__asan_load1, __asan_load2, __asan_load4, __asan_load8, __asan_load16,
|
||||
}, {
|
||||
__asan_store1, __asan_store2, __asan_store4, __asan_store8,
|
||||
__asan_store16,
|
||||
}
|
||||
};
|
||||
|
||||
uptr buggy_ptr;
|
||||
|
||||
__asan_test_only_reported_buggy_pointer = &buggy_ptr;
|
||||
BufferedStackTrace stack;
|
||||
stack.trace_buffer[0] = 0x890;
|
||||
stack.size = 1;
|
||||
|
||||
for (uptr len = 16; len <= 32; len++) {
|
||||
char *ptr = (char*) __asan::asan_malloc(len, &stack);
|
||||
uptr p = reinterpret_cast<uptr>(ptr);
|
||||
for (uptr is_write = 0; is_write <= 1; is_write++) {
|
||||
for (uptr size_log = 0; size_log <= 4; size_log++) {
|
||||
uptr size = 1 << size_log;
|
||||
CB call = cb[is_write][size_log];
|
||||
// Iterate only size-aligned offsets.
|
||||
for (uptr offset = 0; offset <= len; offset += size) {
|
||||
buggy_ptr = 0;
|
||||
call(p + offset);
|
||||
if (offset + size <= len)
|
||||
EXPECT_EQ(buggy_ptr, 0U);
|
||||
else
|
||||
EXPECT_EQ(buggy_ptr, p + offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
__asan::asan_free(ptr, &stack, __asan::FROM_MALLOC);
|
||||
}
|
||||
__asan_test_only_reported_buggy_pointer = 0;
|
||||
}
|
@ -1,128 +0,0 @@
|
||||
//===-- asan_oob_test.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.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "asan_test_utils.h"
|
||||
|
||||
NOINLINE void asan_write_sized_aligned(uint8_t *p, size_t size) {
|
||||
EXPECT_EQ(0U, ((uintptr_t)p % size));
|
||||
if (size == 1) asan_write((uint8_t*)p);
|
||||
else if (size == 2) asan_write((uint16_t*)p);
|
||||
else if (size == 4) asan_write((uint32_t*)p);
|
||||
else if (size == 8) asan_write((uint64_t*)p);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
NOINLINE void oob_test(int size, int off) {
|
||||
char *p = (char*)malloc_aaa(size);
|
||||
// fprintf(stderr, "writing %d byte(s) into [%p,%p) with offset %d\n",
|
||||
// sizeof(T), p, p + size, off);
|
||||
asan_write((T*)(p + off));
|
||||
free_aaa(p);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void OOBTest() {
|
||||
char expected_str[100];
|
||||
for (int size = sizeof(T); size < 20; size += 5) {
|
||||
for (int i = -5; i < 0; i++) {
|
||||
const char *str =
|
||||
"is located.*%d byte.*to the left";
|
||||
sprintf(expected_str, str, abs(i));
|
||||
EXPECT_DEATH(oob_test<T>(size, i), expected_str);
|
||||
}
|
||||
|
||||
for (int i = 0; i < (int)(size - sizeof(T) + 1); i++)
|
||||
oob_test<T>(size, i);
|
||||
|
||||
for (int i = size - sizeof(T) + 1; i <= (int)(size + 2 * sizeof(T)); i++) {
|
||||
const char *str =
|
||||
"is located.*%d byte.*to the right";
|
||||
int off = i >= size ? (i - size) : 0;
|
||||
// we don't catch unaligned partially OOB accesses.
|
||||
if (i % sizeof(T)) continue;
|
||||
sprintf(expected_str, str, off);
|
||||
EXPECT_DEATH(oob_test<T>(size, i), expected_str);
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_DEATH(oob_test<T>(kLargeMalloc, -1),
|
||||
"is located.*1 byte.*to the left");
|
||||
EXPECT_DEATH(oob_test<T>(kLargeMalloc, kLargeMalloc),
|
||||
"is located.*0 byte.*to the right");
|
||||
}
|
||||
|
||||
// TODO(glider): the following tests are EXTREMELY slow on Darwin:
|
||||
// AddressSanitizer.OOB_char (125503 ms)
|
||||
// AddressSanitizer.OOB_int (126890 ms)
|
||||
// AddressSanitizer.OOBRightTest (315605 ms)
|
||||
// AddressSanitizer.SimpleStackTest (366559 ms)
|
||||
|
||||
TEST(AddressSanitizer, OOB_char) {
|
||||
OOBTest<U1>();
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, OOB_int) {
|
||||
OOBTest<U4>();
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, OOBRightTest) {
|
||||
size_t max_access_size = SANITIZER_WORDSIZE == 64 ? 8 : 4;
|
||||
for (size_t access_size = 1; access_size <= max_access_size;
|
||||
access_size *= 2) {
|
||||
for (size_t alloc_size = 1; alloc_size <= 8; alloc_size++) {
|
||||
for (size_t offset = 0; offset <= 8; offset += access_size) {
|
||||
void *p = malloc(alloc_size);
|
||||
// allocated: [p, p + alloc_size)
|
||||
// accessed: [p + offset, p + offset + access_size)
|
||||
uint8_t *addr = (uint8_t*)p + offset;
|
||||
if (offset + access_size <= alloc_size) {
|
||||
asan_write_sized_aligned(addr, access_size);
|
||||
} else {
|
||||
int outside_bytes = offset > alloc_size ? (offset - alloc_size) : 0;
|
||||
const char *str =
|
||||
"is located.%d *byte.*to the right";
|
||||
char expected_str[100];
|
||||
sprintf(expected_str, str, outside_bytes);
|
||||
EXPECT_DEATH(asan_write_sized_aligned(addr, access_size),
|
||||
expected_str);
|
||||
}
|
||||
free(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, LargeOOBRightTest) {
|
||||
size_t large_power_of_two = 1 << 19;
|
||||
for (size_t i = 16; i <= 256; i *= 2) {
|
||||
size_t size = large_power_of_two - i;
|
||||
char *p = Ident(new char[size]);
|
||||
EXPECT_DEATH(p[size] = 0, "is located 0 bytes to the right");
|
||||
delete [] p;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, DISABLED_DemoOOBLeftLow) {
|
||||
oob_test<U1>(10, -1);
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, DISABLED_DemoOOBLeftHigh) {
|
||||
oob_test<U1>(kLargeMalloc, -1);
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, DISABLED_DemoOOBRightLow) {
|
||||
oob_test<U1>(10, 10);
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, DISABLED_DemoOOBRightHigh) {
|
||||
oob_test<U1>(kLargeMalloc, kLargeMalloc);
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
const int N = 1000;
|
||||
void *x[N];
|
||||
|
||||
void *Thread1(void *unused) {
|
||||
for (int i = 0; i < N; i++) {
|
||||
fprintf(stderr, "%s %d\n", __func__, i);
|
||||
free(x[i]);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *Thread2(void *unused) {
|
||||
for (int i = 0; i < N; i++) {
|
||||
fprintf(stderr, "%s %d\n", __func__, i);
|
||||
free(x[i]);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main() {
|
||||
for (int i = 0; i < N; i++)
|
||||
x[i] = malloc(128);
|
||||
pthread_t t[2];
|
||||
pthread_create(&t[0], 0, Thread1, 0);
|
||||
pthread_create(&t[1], 0, Thread2, 0);
|
||||
pthread_join(t[0], 0);
|
||||
pthread_join(t[1], 0);
|
||||
}
|
@ -1,635 +0,0 @@
|
||||
//=-- asan_str_test.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.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "asan_test_utils.h"
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <AvailabilityMacros.h> // For MAC_OS_X_VERSION_*
|
||||
#endif
|
||||
|
||||
// Used for string functions tests
|
||||
static char global_string[] = "global";
|
||||
static size_t global_string_length = 6;
|
||||
|
||||
const char kStackReadUnderflow[] =
|
||||
#if !GTEST_USES_SIMPLE_RE
|
||||
ASAN_PCRE_DOTALL
|
||||
"READ.*"
|
||||
#endif
|
||||
"underflows this variable";
|
||||
const char kStackReadOverflow[] =
|
||||
#if !GTEST_USES_SIMPLE_RE
|
||||
ASAN_PCRE_DOTALL
|
||||
"READ.*"
|
||||
#endif
|
||||
"overflows this variable";
|
||||
|
||||
namespace {
|
||||
enum class OOBKind {
|
||||
Heap,
|
||||
Stack,
|
||||
Global,
|
||||
};
|
||||
|
||||
string LeftOOBReadMessage(OOBKind oob_kind, int oob_distance) {
|
||||
return oob_kind == OOBKind::Stack ? kStackReadUnderflow
|
||||
: ::LeftOOBReadMessage(oob_distance);
|
||||
}
|
||||
|
||||
string RightOOBReadMessage(OOBKind oob_kind, int oob_distance) {
|
||||
return oob_kind == OOBKind::Stack ? kStackReadOverflow
|
||||
: ::RightOOBReadMessage(oob_distance);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
// Input to a test is a zero-terminated string str with given length
|
||||
// Accesses to the bytes to the left and to the right of str
|
||||
// are presumed to produce OOB errors
|
||||
void StrLenOOBTestTemplate(char *str, size_t length, OOBKind oob_kind) {
|
||||
// Normal strlen calls
|
||||
EXPECT_EQ(strlen(str), length);
|
||||
if (length > 0) {
|
||||
EXPECT_EQ(length - 1, strlen(str + 1));
|
||||
EXPECT_EQ(0U, strlen(str + length));
|
||||
}
|
||||
// Arg of strlen is not malloced, OOB access
|
||||
if (oob_kind != OOBKind::Global) {
|
||||
// We don't insert RedZones to the left of global variables
|
||||
EXPECT_DEATH(Ident(strlen(str - 1)), LeftOOBReadMessage(oob_kind, 1));
|
||||
EXPECT_DEATH(Ident(strlen(str - 5)), LeftOOBReadMessage(oob_kind, 5));
|
||||
}
|
||||
EXPECT_DEATH(Ident(strlen(str + length + 1)),
|
||||
RightOOBReadMessage(oob_kind, 0));
|
||||
// Overwrite terminator
|
||||
str[length] = 'a';
|
||||
// String is not zero-terminated, strlen will lead to OOB access
|
||||
EXPECT_DEATH(Ident(strlen(str)), RightOOBReadMessage(oob_kind, 0));
|
||||
EXPECT_DEATH(Ident(strlen(str + length)), RightOOBReadMessage(oob_kind, 0));
|
||||
// Restore terminator
|
||||
str[length] = 0;
|
||||
}
|
||||
TEST(AddressSanitizer, StrLenOOBTest) {
|
||||
// Check heap-allocated string
|
||||
size_t length = Ident(10);
|
||||
char *heap_string = Ident((char*)malloc(length + 1));
|
||||
char stack_string[10 + 1];
|
||||
break_optimization(&stack_string);
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
heap_string[i] = 'a';
|
||||
stack_string[i] = 'b';
|
||||
}
|
||||
heap_string[length] = 0;
|
||||
stack_string[length] = 0;
|
||||
StrLenOOBTestTemplate(heap_string, length, OOBKind::Heap);
|
||||
StrLenOOBTestTemplate(stack_string, length, OOBKind::Stack);
|
||||
StrLenOOBTestTemplate(global_string, global_string_length, OOBKind::Global);
|
||||
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;
|
||||
size_t hello_size = (hello_len + 1) * sizeof(wchar_t);
|
||||
EXPECT_EQ(hello_len, wcslen(Ident(L"Hello, World!")));
|
||||
wchar_t *heap_string = Ident((wchar_t*)malloc(hello_size));
|
||||
memcpy(heap_string, L"Hello, World!", hello_size);
|
||||
EXPECT_EQ(hello_len, Ident(wcslen(heap_string)));
|
||||
EXPECT_DEATH(Ident(wcslen(heap_string + 14)), RightOOBReadMessage(0));
|
||||
free(heap_string);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SANITIZER_TEST_HAS_STRNLEN
|
||||
TEST(AddressSanitizer, StrNLenOOBTest) {
|
||||
size_t size = Ident(123);
|
||||
char *str = MallocAndMemsetString(size);
|
||||
// Normal strnlen calls.
|
||||
Ident(strnlen(str - 1, 0));
|
||||
Ident(strnlen(str, size));
|
||||
Ident(strnlen(str + size - 1, 1));
|
||||
str[size - 1] = '\0';
|
||||
Ident(strnlen(str, 2 * size));
|
||||
// Argument points to not allocated memory.
|
||||
EXPECT_DEATH(Ident(strnlen(str - 1, 1)), LeftOOBReadMessage(1));
|
||||
EXPECT_DEATH(Ident(strnlen(str + size, 1)), RightOOBReadMessage(0));
|
||||
// Overwrite the terminating '\0' and hit unallocated memory.
|
||||
str[size - 1] = 'z';
|
||||
EXPECT_DEATH(Ident(strnlen(str, size + 1)), RightOOBReadMessage(0));
|
||||
free(str);
|
||||
}
|
||||
#endif // SANITIZER_TEST_HAS_STRNLEN
|
||||
|
||||
// This test fails with the WinASan dynamic runtime because we fail to intercept
|
||||
// strdup.
|
||||
#if defined(_MSC_VER) && defined(_DLL)
|
||||
#define MAYBE_StrDupOOBTest DISABLED_StrDupOOBTest
|
||||
#else
|
||||
#define MAYBE_StrDupOOBTest StrDupOOBTest
|
||||
#endif
|
||||
|
||||
TEST(AddressSanitizer, MAYBE_StrDupOOBTest) {
|
||||
size_t size = Ident(42);
|
||||
char *str = MallocAndMemsetString(size);
|
||||
char *new_str;
|
||||
// Normal strdup calls.
|
||||
str[size - 1] = '\0';
|
||||
new_str = strdup(str);
|
||||
free(new_str);
|
||||
new_str = strdup(str + size - 1);
|
||||
free(new_str);
|
||||
// Argument points to not allocated memory.
|
||||
EXPECT_DEATH(Ident(strdup(str - 1)), LeftOOBReadMessage(1));
|
||||
EXPECT_DEATH(Ident(strdup(str + size)), RightOOBReadMessage(0));
|
||||
// Overwrite the terminating '\0' and hit unallocated memory.
|
||||
str[size - 1] = 'z';
|
||||
EXPECT_DEATH(Ident(strdup(str)), RightOOBReadMessage(0));
|
||||
free(str);
|
||||
}
|
||||
|
||||
#if SANITIZER_TEST_HAS_STRNDUP
|
||||
TEST(AddressSanitizer, MAYBE_StrNDupOOBTest) {
|
||||
size_t size = Ident(42);
|
||||
char *str = MallocAndMemsetString(size);
|
||||
char *new_str;
|
||||
// Normal strndup calls.
|
||||
str[size - 1] = '\0';
|
||||
new_str = strndup(str, size - 13);
|
||||
free(new_str);
|
||||
new_str = strndup(str + size - 1, 13);
|
||||
free(new_str);
|
||||
// Argument points to not allocated memory.
|
||||
EXPECT_DEATH(Ident(strndup(str - 1, 13)), LeftOOBReadMessage(1));
|
||||
EXPECT_DEATH(Ident(strndup(str + size, 13)), RightOOBReadMessage(0));
|
||||
// Overwrite the terminating '\0' and hit unallocated memory.
|
||||
str[size - 1] = 'z';
|
||||
EXPECT_DEATH(Ident(strndup(str, size + 13)), RightOOBReadMessage(0));
|
||||
// Check handling of non 0 terminated strings.
|
||||
Ident(new_str = strndup(str + size - 1, 0));
|
||||
free(new_str);
|
||||
Ident(new_str = strndup(str + size - 1, 1));
|
||||
free(new_str);
|
||||
EXPECT_DEATH(Ident(strndup(str + size - 1, 2)), RightOOBReadMessage(0));
|
||||
free(str);
|
||||
}
|
||||
#endif // SANITIZER_TEST_HAS_STRNDUP
|
||||
|
||||
TEST(AddressSanitizer, StrCpyOOBTest) {
|
||||
size_t to_size = Ident(30);
|
||||
size_t from_size = Ident(6); // less than to_size
|
||||
char *to = Ident((char*)malloc(to_size));
|
||||
char *from = Ident((char*)malloc(from_size));
|
||||
// Normal strcpy calls.
|
||||
strcpy(from, "hello");
|
||||
strcpy(to, from);
|
||||
strcpy(to + to_size - from_size, from);
|
||||
// Length of "from" is too small.
|
||||
EXPECT_DEATH(Ident(strcpy(from, "hello2")), RightOOBWriteMessage(0));
|
||||
// "to" or "from" points to not allocated memory.
|
||||
EXPECT_DEATH(Ident(strcpy(to - 1, from)), LeftOOBWriteMessage(1));
|
||||
EXPECT_DEATH(Ident(strcpy(to, from - 1)), LeftOOBReadMessage(1));
|
||||
EXPECT_DEATH(Ident(strcpy(to, from + from_size)), RightOOBReadMessage(0));
|
||||
EXPECT_DEATH(Ident(strcpy(to + to_size, from)), RightOOBWriteMessage(0));
|
||||
// Overwrite the terminating '\0' character and hit unallocated memory.
|
||||
from[from_size - 1] = '!';
|
||||
EXPECT_DEATH(Ident(strcpy(to, from)), RightOOBReadMessage(0));
|
||||
free(to);
|
||||
free(from);
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, StrNCpyOOBTest) {
|
||||
size_t to_size = Ident(20);
|
||||
size_t from_size = Ident(6); // less than to_size
|
||||
char *to = Ident((char*)malloc(to_size));
|
||||
// From is a zero-terminated string "hello\0" of length 6
|
||||
char *from = Ident((char*)malloc(from_size));
|
||||
strcpy(from, "hello");
|
||||
// copy 0 bytes
|
||||
strncpy(to, from, 0);
|
||||
strncpy(to - 1, from - 1, 0);
|
||||
// normal strncpy calls
|
||||
strncpy(to, from, from_size);
|
||||
strncpy(to, from, to_size);
|
||||
strncpy(to, from + from_size - 1, to_size);
|
||||
strncpy(to + to_size - 1, from, 1);
|
||||
// One of {to, from} points to not allocated memory
|
||||
EXPECT_DEATH(Ident(strncpy(to, from - 1, from_size)),
|
||||
LeftOOBReadMessage(1));
|
||||
EXPECT_DEATH(Ident(strncpy(to - 1, from, from_size)),
|
||||
LeftOOBWriteMessage(1));
|
||||
EXPECT_DEATH(Ident(strncpy(to, from + from_size, 1)),
|
||||
RightOOBReadMessage(0));
|
||||
EXPECT_DEATH(Ident(strncpy(to + to_size, from, 1)),
|
||||
RightOOBWriteMessage(0));
|
||||
// Length of "to" is too small
|
||||
EXPECT_DEATH(Ident(strncpy(to + to_size - from_size + 1, from, from_size)),
|
||||
RightOOBWriteMessage(0));
|
||||
EXPECT_DEATH(Ident(strncpy(to + 1, from, to_size)),
|
||||
RightOOBWriteMessage(0));
|
||||
// Overwrite terminator in from
|
||||
from[from_size - 1] = '!';
|
||||
// normal strncpy call
|
||||
strncpy(to, from, from_size);
|
||||
// Length of "from" is too small
|
||||
EXPECT_DEATH(Ident(strncpy(to, from, to_size)),
|
||||
RightOOBReadMessage(0));
|
||||
free(to);
|
||||
free(from);
|
||||
}
|
||||
|
||||
// Users may have different definitions of "strchr" and "index", so provide
|
||||
// function pointer typedefs and overload RunStrChrTest implementation.
|
||||
// We can't use macro for RunStrChrTest body here, as this macro would
|
||||
// confuse EXPECT_DEATH gtest macro.
|
||||
typedef char*(*PointerToStrChr1)(const char*, int);
|
||||
typedef char*(*PointerToStrChr2)(char*, int);
|
||||
|
||||
template<typename StrChrFn>
|
||||
static void RunStrChrTestImpl(StrChrFn *StrChr) {
|
||||
size_t size = Ident(100);
|
||||
char *str = MallocAndMemsetString(size);
|
||||
str[10] = 'q';
|
||||
str[11] = '\0';
|
||||
EXPECT_EQ(str, StrChr(str, 'z'));
|
||||
EXPECT_EQ(str + 10, StrChr(str, 'q'));
|
||||
EXPECT_EQ(NULL, StrChr(str, 'a'));
|
||||
// StrChr argument points to not allocated memory.
|
||||
EXPECT_DEATH(Ident(StrChr(str - 1, 'z')), LeftOOBReadMessage(1));
|
||||
EXPECT_DEATH(Ident(StrChr(str + size, 'z')), RightOOBReadMessage(0));
|
||||
// Overwrite the terminator and hit not allocated memory.
|
||||
str[11] = 'z';
|
||||
EXPECT_DEATH(Ident(StrChr(str, 'a')), RightOOBReadMessage(0));
|
||||
free(str);
|
||||
}
|
||||
|
||||
// Prefer to use the standard signature if both are available.
|
||||
UNUSED static void RunStrChrTest(PointerToStrChr1 StrChr, ...) {
|
||||
RunStrChrTestImpl(StrChr);
|
||||
}
|
||||
UNUSED static void RunStrChrTest(PointerToStrChr2 StrChr, int) {
|
||||
RunStrChrTestImpl(StrChr);
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, StrChrAndIndexOOBTest) {
|
||||
RunStrChrTest(&strchr, 0);
|
||||
// No index() on Windows and on Android L.
|
||||
#if !defined(_WIN32) && !defined(__ANDROID__)
|
||||
RunStrChrTest(&index, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, StrCmpAndFriendsLogicTest) {
|
||||
// strcmp
|
||||
EXPECT_EQ(0, strcmp("", ""));
|
||||
EXPECT_EQ(0, strcmp("abcd", "abcd"));
|
||||
EXPECT_GT(0, strcmp("ab", "ac"));
|
||||
EXPECT_GT(0, strcmp("abc", "abcd"));
|
||||
EXPECT_LT(0, strcmp("acc", "abc"));
|
||||
EXPECT_LT(0, strcmp("abcd", "abc"));
|
||||
|
||||
// strncmp
|
||||
EXPECT_EQ(0, strncmp("a", "b", 0));
|
||||
EXPECT_EQ(0, strncmp("abcd", "abcd", 10));
|
||||
EXPECT_EQ(0, strncmp("abcd", "abcef", 3));
|
||||
EXPECT_GT(0, strncmp("abcde", "abcfa", 4));
|
||||
EXPECT_GT(0, strncmp("a", "b", 5));
|
||||
EXPECT_GT(0, strncmp("bc", "bcde", 4));
|
||||
EXPECT_LT(0, strncmp("xyz", "xyy", 10));
|
||||
EXPECT_LT(0, strncmp("baa", "aaa", 1));
|
||||
EXPECT_LT(0, strncmp("zyx", "", 2));
|
||||
|
||||
#if !defined(_WIN32) // no str[n]casecmp on Windows.
|
||||
// strcasecmp
|
||||
EXPECT_EQ(0, strcasecmp("", ""));
|
||||
EXPECT_EQ(0, strcasecmp("zzz", "zzz"));
|
||||
EXPECT_EQ(0, strcasecmp("abCD", "ABcd"));
|
||||
EXPECT_GT(0, strcasecmp("aB", "Ac"));
|
||||
EXPECT_GT(0, strcasecmp("ABC", "ABCd"));
|
||||
EXPECT_LT(0, strcasecmp("acc", "abc"));
|
||||
EXPECT_LT(0, strcasecmp("ABCd", "abc"));
|
||||
|
||||
// strncasecmp
|
||||
EXPECT_EQ(0, strncasecmp("a", "b", 0));
|
||||
EXPECT_EQ(0, strncasecmp("abCD", "ABcd", 10));
|
||||
EXPECT_EQ(0, strncasecmp("abCd", "ABcef", 3));
|
||||
EXPECT_GT(0, strncasecmp("abcde", "ABCfa", 4));
|
||||
EXPECT_GT(0, strncasecmp("a", "B", 5));
|
||||
EXPECT_GT(0, strncasecmp("bc", "BCde", 4));
|
||||
EXPECT_LT(0, strncasecmp("xyz", "xyy", 10));
|
||||
EXPECT_LT(0, strncasecmp("Baa", "aaa", 1));
|
||||
EXPECT_LT(0, strncasecmp("zyx", "", 2));
|
||||
#endif
|
||||
|
||||
// memcmp
|
||||
EXPECT_EQ(0, memcmp("a", "b", 0));
|
||||
EXPECT_EQ(0, memcmp("ab\0c", "ab\0c", 4));
|
||||
EXPECT_GT(0, memcmp("\0ab", "\0ac", 3));
|
||||
EXPECT_GT(0, memcmp("abb\0", "abba", 4));
|
||||
EXPECT_LT(0, memcmp("ab\0cd", "ab\0c\0", 5));
|
||||
EXPECT_LT(0, memcmp("zza", "zyx", 3));
|
||||
}
|
||||
|
||||
typedef int(*PointerToStrCmp)(const char*, const char*);
|
||||
void RunStrCmpTest(PointerToStrCmp StrCmp) {
|
||||
size_t size = Ident(100);
|
||||
int fill = 'o';
|
||||
char *s1 = MallocAndMemsetString(size, fill);
|
||||
char *s2 = MallocAndMemsetString(size, fill);
|
||||
s1[size - 1] = '\0';
|
||||
s2[size - 1] = '\0';
|
||||
// Normal StrCmp calls
|
||||
Ident(StrCmp(s1, s2));
|
||||
Ident(StrCmp(s1, s2 + size - 1));
|
||||
Ident(StrCmp(s1 + size - 1, s2 + size - 1));
|
||||
// One of arguments points to not allocated memory.
|
||||
EXPECT_DEATH(Ident(StrCmp)(s1 - 1, s2), LeftOOBReadMessage(1));
|
||||
EXPECT_DEATH(Ident(StrCmp)(s1, s2 - 1), LeftOOBReadMessage(1));
|
||||
EXPECT_DEATH(Ident(StrCmp)(s1 + size, s2), RightOOBReadMessage(0));
|
||||
EXPECT_DEATH(Ident(StrCmp)(s1, s2 + size), RightOOBReadMessage(0));
|
||||
// Hit unallocated memory and die.
|
||||
s1[size - 1] = fill;
|
||||
EXPECT_DEATH(Ident(StrCmp)(s1, s1), RightOOBReadMessage(0));
|
||||
EXPECT_DEATH(Ident(StrCmp)(s1 + size - 1, s2), RightOOBReadMessage(0));
|
||||
free(s1);
|
||||
free(s2);
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, StrCmpOOBTest) {
|
||||
RunStrCmpTest(&strcmp);
|
||||
}
|
||||
|
||||
#if !defined(_WIN32) // no str[n]casecmp on Windows.
|
||||
TEST(AddressSanitizer, StrCaseCmpOOBTest) {
|
||||
RunStrCmpTest(&strcasecmp);
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef int(*PointerToStrNCmp)(const char*, const char*, size_t);
|
||||
void RunStrNCmpTest(PointerToStrNCmp StrNCmp) {
|
||||
size_t size = Ident(100);
|
||||
char *s1 = MallocAndMemsetString(size);
|
||||
char *s2 = MallocAndMemsetString(size);
|
||||
s1[size - 1] = '\0';
|
||||
s2[size - 1] = '\0';
|
||||
// Normal StrNCmp calls
|
||||
Ident(StrNCmp(s1, s2, size + 2));
|
||||
s1[size - 1] = 'z';
|
||||
s2[size - 1] = 'x';
|
||||
Ident(StrNCmp(s1 + size - 2, s2 + size - 2, size));
|
||||
s2[size - 1] = 'z';
|
||||
Ident(StrNCmp(s1 - 1, s2 - 1, 0));
|
||||
Ident(StrNCmp(s1 + size - 1, s2 + size - 1, 1));
|
||||
// One of arguments points to not allocated memory.
|
||||
EXPECT_DEATH(Ident(StrNCmp)(s1 - 1, s2, 1), LeftOOBReadMessage(1));
|
||||
EXPECT_DEATH(Ident(StrNCmp)(s1, s2 - 1, 1), LeftOOBReadMessage(1));
|
||||
EXPECT_DEATH(Ident(StrNCmp)(s1 + size, s2, 1), RightOOBReadMessage(0));
|
||||
EXPECT_DEATH(Ident(StrNCmp)(s1, s2 + size, 1), RightOOBReadMessage(0));
|
||||
// Hit unallocated memory and die.
|
||||
EXPECT_DEATH(Ident(StrNCmp)(s1 + 1, s2 + 1, size), RightOOBReadMessage(0));
|
||||
EXPECT_DEATH(Ident(StrNCmp)(s1 + size - 1, s2, 2), RightOOBReadMessage(0));
|
||||
free(s1);
|
||||
free(s2);
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, StrNCmpOOBTest) {
|
||||
RunStrNCmpTest(&strncmp);
|
||||
}
|
||||
|
||||
#if !defined(_WIN32) // no str[n]casecmp on Windows.
|
||||
TEST(AddressSanitizer, StrNCaseCmpOOBTest) {
|
||||
RunStrNCmpTest(&strncasecmp);
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(AddressSanitizer, StrCatOOBTest) {
|
||||
// strcat() reads strlen(to) bytes from |to| before concatenating.
|
||||
size_t to_size = Ident(100);
|
||||
char *to = MallocAndMemsetString(to_size);
|
||||
to[0] = '\0';
|
||||
size_t from_size = Ident(20);
|
||||
char *from = MallocAndMemsetString(from_size);
|
||||
from[from_size - 1] = '\0';
|
||||
// Normal strcat calls.
|
||||
strcat(to, from);
|
||||
strcat(to, from);
|
||||
strcat(to + from_size, from + from_size - 2);
|
||||
// Passing an invalid pointer is an error even when concatenating an empty
|
||||
// string.
|
||||
EXPECT_DEATH(strcat(to - 1, from + from_size - 1), LeftOOBAccessMessage(1));
|
||||
// One of arguments points to not allocated memory.
|
||||
EXPECT_DEATH(strcat(to - 1, from), LeftOOBAccessMessage(1));
|
||||
EXPECT_DEATH(strcat(to, from - 1), LeftOOBReadMessage(1));
|
||||
EXPECT_DEATH(strcat(to, from + from_size), RightOOBReadMessage(0));
|
||||
|
||||
// "from" is not zero-terminated.
|
||||
from[from_size - 1] = 'z';
|
||||
EXPECT_DEATH(strcat(to, from), RightOOBReadMessage(0));
|
||||
from[from_size - 1] = '\0';
|
||||
// "to" is too short to fit "from".
|
||||
memset(to, 'z', to_size);
|
||||
to[to_size - from_size + 1] = '\0';
|
||||
EXPECT_DEATH(strcat(to, from), RightOOBWriteMessage(0));
|
||||
// length of "to" is just enough.
|
||||
strcat(to, from + 1);
|
||||
|
||||
free(to);
|
||||
free(from);
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, StrNCatOOBTest) {
|
||||
// strncat() reads strlen(to) bytes from |to| before concatenating.
|
||||
size_t to_size = Ident(100);
|
||||
char *to = MallocAndMemsetString(to_size);
|
||||
to[0] = '\0';
|
||||
size_t from_size = Ident(20);
|
||||
char *from = MallocAndMemsetString(from_size);
|
||||
// Normal strncat calls.
|
||||
strncat(to, from, 0);
|
||||
strncat(to, from, from_size);
|
||||
from[from_size - 1] = '\0';
|
||||
strncat(to, from, 2 * from_size);
|
||||
// Catenating empty string with an invalid string is still an error.
|
||||
EXPECT_DEATH(strncat(to - 1, from, 0), LeftOOBAccessMessage(1));
|
||||
strncat(to, from + from_size - 1, 10);
|
||||
// One of arguments points to not allocated memory.
|
||||
EXPECT_DEATH(strncat(to - 1, from, 2), LeftOOBAccessMessage(1));
|
||||
EXPECT_DEATH(strncat(to, from - 1, 2), LeftOOBReadMessage(1));
|
||||
EXPECT_DEATH(strncat(to, from + from_size, 2), RightOOBReadMessage(0));
|
||||
|
||||
memset(from, 'z', from_size);
|
||||
memset(to, 'z', to_size);
|
||||
to[0] = '\0';
|
||||
// "from" is too short.
|
||||
EXPECT_DEATH(strncat(to, from, from_size + 1), RightOOBReadMessage(0));
|
||||
// "to" is too short to fit "from".
|
||||
to[0] = 'z';
|
||||
to[to_size - from_size + 1] = '\0';
|
||||
EXPECT_DEATH(strncat(to, from, from_size - 1), RightOOBWriteMessage(0));
|
||||
// "to" is just enough.
|
||||
strncat(to, from, from_size - 2);
|
||||
|
||||
free(to);
|
||||
free(from);
|
||||
}
|
||||
|
||||
static string OverlapErrorMessage(const string &func) {
|
||||
return func + "-param-overlap";
|
||||
}
|
||||
|
||||
TEST(AddressSanitizer, StrArgsOverlapTest) {
|
||||
size_t size = Ident(100);
|
||||
char *str = Ident((char*)malloc(size));
|
||||
|
||||
// Do not check memcpy() on OS X 10.7 and later, where it actually aliases
|
||||
// memmove().
|
||||
#if !defined(__APPLE__) || !defined(MAC_OS_X_VERSION_10_7) || \
|
||||
(MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7)
|
||||
// Check "memcpy". Use Ident() to avoid inlining.
|
||||
#if PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE
|
||||
memset(str, 'z', size);
|
||||
Ident(memcpy)(str + 1, str + 11, 10);
|
||||
Ident(memcpy)(str, str, 0);
|
||||
EXPECT_DEATH(Ident(memcpy)(str, str + 14, 15), OverlapErrorMessage("memcpy"));
|
||||
EXPECT_DEATH(Ident(memcpy)(str + 14, str, 15), OverlapErrorMessage("memcpy"));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// We do not treat memcpy with to==from as a bug.
|
||||
// See http://llvm.org/bugs/show_bug.cgi?id=11763.
|
||||
// EXPECT_DEATH(Ident(memcpy)(str + 20, str + 20, 1),
|
||||
// OverlapErrorMessage("memcpy"));
|
||||
|
||||
// Check "strcpy".
|
||||
memset(str, 'z', size);
|
||||
str[9] = '\0';
|
||||
strcpy(str + 10, str);
|
||||
EXPECT_DEATH(strcpy(str + 9, str), OverlapErrorMessage("strcpy"));
|
||||
EXPECT_DEATH(strcpy(str, str + 4), OverlapErrorMessage("strcpy"));
|
||||
strcpy(str, str + 5);
|
||||
|
||||
// Check "strncpy".
|
||||
memset(str, 'z', size);
|
||||
strncpy(str, str + 10, 10);
|
||||
EXPECT_DEATH(strncpy(str, str + 9, 10), OverlapErrorMessage("strncpy"));
|
||||
EXPECT_DEATH(strncpy(str + 9, str, 10), OverlapErrorMessage("strncpy"));
|
||||
str[10] = '\0';
|
||||
strncpy(str + 11, str, 20);
|
||||
EXPECT_DEATH(strncpy(str + 10, str, 20), OverlapErrorMessage("strncpy"));
|
||||
|
||||
// Check "strcat".
|
||||
memset(str, 'z', size);
|
||||
str[10] = '\0';
|
||||
str[20] = '\0';
|
||||
strcat(str, str + 10);
|
||||
EXPECT_DEATH(strcat(str, str + 11), OverlapErrorMessage("strcat"));
|
||||
str[10] = '\0';
|
||||
strcat(str + 11, str);
|
||||
EXPECT_DEATH(strcat(str, str + 9), OverlapErrorMessage("strcat"));
|
||||
EXPECT_DEATH(strcat(str + 9, str), OverlapErrorMessage("strcat"));
|
||||
EXPECT_DEATH(strcat(str + 10, str), OverlapErrorMessage("strcat"));
|
||||
|
||||
// Check "strncat".
|
||||
memset(str, 'z', size);
|
||||
str[10] = '\0';
|
||||
strncat(str, str + 10, 10); // from is empty
|
||||
EXPECT_DEATH(strncat(str, str + 11, 10), OverlapErrorMessage("strncat"));
|
||||
str[10] = '\0';
|
||||
str[20] = '\0';
|
||||
strncat(str + 5, str, 5);
|
||||
str[10] = '\0';
|
||||
EXPECT_DEATH(strncat(str + 5, str, 6), OverlapErrorMessage("strncat"));
|
||||
EXPECT_DEATH(strncat(str, str + 9, 10), OverlapErrorMessage("strncat"));
|
||||
|
||||
free(str);
|
||||
}
|
||||
|
||||
typedef void(*PointerToCallAtoi)(const char*);
|
||||
|
||||
void RunAtoiOOBTest(PointerToCallAtoi Atoi) {
|
||||
char *array = MallocAndMemsetString(10, '1');
|
||||
// Invalid pointer to the string.
|
||||
EXPECT_DEATH(Atoi(array + 11), RightOOBReadMessage(1));
|
||||
EXPECT_DEATH(Atoi(array - 1), LeftOOBReadMessage(1));
|
||||
// Die if a buffer doesn't have terminating NULL.
|
||||
EXPECT_DEATH(Atoi(array), RightOOBReadMessage(0));
|
||||
// Make last symbol a terminating NULL
|
||||
array[9] = '\0';
|
||||
Atoi(array);
|
||||
// Sometimes we need to detect overflow if no digits are found.
|
||||
memset(array, ' ', 10);
|
||||
EXPECT_DEATH(Atoi(array), RightOOBReadMessage(0));
|
||||
array[9] = '-';
|
||||
EXPECT_DEATH(Atoi(array), RightOOBReadMessage(0));
|
||||
EXPECT_DEATH(Atoi(array + 9), RightOOBReadMessage(0));
|
||||
free(array);
|
||||
}
|
||||
|
||||
#if !defined(_WIN32) // FIXME: Fix and enable on Windows.
|
||||
void CallAtoi(const char *nptr) {
|
||||
Ident(atoi(nptr));
|
||||
}
|
||||
void CallAtol(const char *nptr) {
|
||||
Ident(atol(nptr));
|
||||
}
|
||||
void CallAtoll(const char *nptr) {
|
||||
Ident(atoll(nptr));
|
||||
}
|
||||
TEST(AddressSanitizer, AtoiAndFriendsOOBTest) {
|
||||
RunAtoiOOBTest(&CallAtoi);
|
||||
RunAtoiOOBTest(&CallAtol);
|
||||
RunAtoiOOBTest(&CallAtoll);
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef void(*PointerToCallStrtol)(const char*, char**, int);
|
||||
|
||||
void RunStrtolOOBTest(PointerToCallStrtol Strtol) {
|
||||
char *array = MallocAndMemsetString(3);
|
||||
array[0] = '1';
|
||||
array[1] = '2';
|
||||
array[2] = '3';
|
||||
// Invalid pointer to the string.
|
||||
EXPECT_DEATH(Strtol(array + 3, NULL, 0), RightOOBReadMessage(0));
|
||||
EXPECT_DEATH(Strtol(array - 1, NULL, 0), LeftOOBReadMessage(1));
|
||||
// Buffer overflow if there is no terminating null (depends on base).
|
||||
EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBReadMessage(0));
|
||||
array[2] = 'z';
|
||||
EXPECT_DEATH(Strtol(array, NULL, 36), RightOOBReadMessage(0));
|
||||
// Add terminating zero to get rid of overflow.
|
||||
array[2] = '\0';
|
||||
Strtol(array, NULL, 36);
|
||||
// Sometimes we need to detect overflow if no digits are found.
|
||||
array[0] = array[1] = array[2] = ' ';
|
||||
EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBReadMessage(0));
|
||||
array[2] = '+';
|
||||
EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBReadMessage(0));
|
||||
array[2] = '-';
|
||||
EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBReadMessage(0));
|
||||
free(array);
|
||||
}
|
||||
|
||||
#if !defined(_WIN32) // FIXME: Fix and enable on Windows.
|
||||
void CallStrtol(const char *nptr, char **endptr, int base) {
|
||||
Ident(strtol(nptr, endptr, base));
|
||||
}
|
||||
void CallStrtoll(const char *nptr, char **endptr, int base) {
|
||||
Ident(strtoll(nptr, endptr, base));
|
||||
}
|
||||
TEST(AddressSanitizer, StrtollOOBTest) {
|
||||
RunStrtolOOBTest(&CallStrtoll);
|
||||
}
|
||||
TEST(AddressSanitizer, StrtolOOBTest) {
|
||||
RunStrtolOOBTest(&CallStrtol);
|
||||
}
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@ -1,3 +0,0 @@
|
||||
# blacklisted functions for instrumented ASan unit test
|
||||
fun:*IgnoreTest*
|
||||
fun:*SomeOtherFunc*
|
@ -1,50 +0,0 @@
|
||||
//===-- asan_test_config.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.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#if !defined(INCLUDED_FROM_ASAN_TEST_UTILS_H)
|
||||
# error "This file should be included into asan_test_utils.h only"
|
||||
#endif
|
||||
|
||||
#ifndef ASAN_TEST_CONFIG_H
|
||||
#define ASAN_TEST_CONFIG_H
|
||||
|
||||
#include <string>
|
||||
|
||||
using std::string;
|
||||
|
||||
#ifndef ASAN_UAR
|
||||
# error "please define ASAN_UAR"
|
||||
#endif
|
||||
|
||||
#ifndef ASAN_HAS_EXCEPTIONS
|
||||
# error "please define ASAN_HAS_EXCEPTIONS"
|
||||
#endif
|
||||
|
||||
#ifndef ASAN_HAS_BLACKLIST
|
||||
# error "please define ASAN_HAS_BLACKLIST"
|
||||
#endif
|
||||
|
||||
#ifndef ASAN_NEEDS_SEGV
|
||||
# if defined(_WIN32)
|
||||
# define ASAN_NEEDS_SEGV 0
|
||||
# else
|
||||
# define ASAN_NEEDS_SEGV 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef ASAN_AVOID_EXPENSIVE_TESTS
|
||||
# define ASAN_AVOID_EXPENSIVE_TESTS 0
|
||||
#endif
|
||||
|
||||
#define ASAN_PCRE_DOTALL ""
|
||||
|
||||
#endif // ASAN_TEST_CONFIG_H
|
@ -1,56 +0,0 @@
|
||||
//===-- asan_test_main.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.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "asan_test_utils.h"
|
||||
#include "sanitizer_common/sanitizer_platform.h"
|
||||
|
||||
// Default ASAN_OPTIONS for the unit tests.
|
||||
extern "C" const char* __asan_default_options() {
|
||||
#if SANITIZER_MAC
|
||||
// On Darwin, we default to `abort_on_error=1`, which would make tests run
|
||||
// much slower. Let's override this and run lit tests with 'abort_on_error=0'
|
||||
// and make sure we do not overwhelm the syslog while testing. Also, let's
|
||||
// turn symbolization off to speed up testing, especially when not running
|
||||
// with llvm-symbolizer but with atos.
|
||||
return "symbolize=false:abort_on_error=0:log_to_syslog=0";
|
||||
#elif SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT
|
||||
// On PowerPC and ARM Thumb, a couple tests involving pthread_exit fail due to
|
||||
// leaks detected by LSan. Symbolized leak report is required to apply a
|
||||
// suppression for this known problem.
|
||||
return "";
|
||||
#else
|
||||
// Let's turn symbolization off to speed up testing (more than 3 times speedup
|
||||
// observed).
|
||||
return "symbolize=false";
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace __sanitizer {
|
||||
bool ReexecDisabled() {
|
||||
#if __has_feature(address_sanitizer) && SANITIZER_MAC
|
||||
// Allow re-exec in instrumented unit tests on Darwin. Technically, we only
|
||||
// need this for 10.10 and below, where re-exec is required for the
|
||||
// interceptors to work, but to avoid duplicating the version detection logic,
|
||||
// let's just allow re-exec for all Darwin versions. On newer OS versions,
|
||||
// returning 'false' doesn't do anything anyway, because we don't re-exec.
|
||||
return false;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
} // namespace __sanitizer
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
testing::GTEST_FLAG(death_test_style) = "threadsafe";
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
@ -1,109 +0,0 @@
|
||||
//===-- asan_test_utils.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.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef ASAN_TEST_UTILS_H
|
||||
#define ASAN_TEST_UTILS_H
|
||||
|
||||
#if !defined(SANITIZER_EXTERNAL_TEST_CONFIG)
|
||||
# define INCLUDED_FROM_ASAN_TEST_UTILS_H
|
||||
# include "asan_test_config.h"
|
||||
# undef INCLUDED_FROM_ASAN_TEST_UTILS_H
|
||||
#endif
|
||||
|
||||
#include "sanitizer_test_utils.h"
|
||||
#include "sanitizer_pthread_wrappers.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <algorithm>
|
||||
#include <setjmp.h>
|
||||
|
||||
#if !defined(_WIN32)
|
||||
# include <strings.h>
|
||||
# include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
# include <sys/prctl.h>
|
||||
# include <sys/types.h>
|
||||
# include <sys/stat.h>
|
||||
# include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__NetBSD__)
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
#if ASAN_HAS_EXCEPTIONS
|
||||
# define ASAN_THROW(x) throw (x)
|
||||
#else
|
||||
# define ASAN_THROW(x)
|
||||
#endif
|
||||
|
||||
typedef uint8_t U1;
|
||||
typedef uint16_t U2;
|
||||
typedef uint32_t U4;
|
||||
typedef uint64_t U8;
|
||||
|
||||
static const int kPageSize = 4096;
|
||||
|
||||
// Big enough to be handled by secondary allocator and small enough to fit into
|
||||
// quarantine for all configurations.
|
||||
const size_t kLargeMalloc = 1 << 22;
|
||||
|
||||
extern void free_aaa(void *p);
|
||||
extern void *malloc_aaa(size_t size);
|
||||
|
||||
template<typename T>
|
||||
NOINLINE void asan_write(T *a) {
|
||||
*a = 0;
|
||||
}
|
||||
|
||||
string RightOOBErrorMessage(int oob_distance, bool is_write);
|
||||
string RightOOBWriteMessage(int oob_distance);
|
||||
string RightOOBReadMessage(int oob_distance);
|
||||
string LeftOOBErrorMessage(int oob_distance, bool is_write);
|
||||
string LeftOOBWriteMessage(int oob_distance);
|
||||
string LeftOOBReadMessage(int oob_distance);
|
||||
string LeftOOBAccessMessage(int oob_distance);
|
||||
char* MallocAndMemsetString(size_t size, char ch);
|
||||
char* MallocAndMemsetString(size_t size);
|
||||
|
||||
extern char glob1[1];
|
||||
extern char glob2[2];
|
||||
extern char glob3[3];
|
||||
extern char glob4[4];
|
||||
extern char glob5[5];
|
||||
extern char glob6[6];
|
||||
extern char glob7[7];
|
||||
extern char glob8[8];
|
||||
extern char glob9[9];
|
||||
extern char glob10[10];
|
||||
extern char glob11[11];
|
||||
extern char glob12[12];
|
||||
extern char glob13[13];
|
||||
extern char glob14[14];
|
||||
extern char glob15[15];
|
||||
extern char glob16[16];
|
||||
extern char glob17[17];
|
||||
extern char glob1000[1000];
|
||||
extern char glob10000[10000];
|
||||
extern char glob100000[100000];
|
||||
extern int GlobalsTest(int x);
|
||||
|
||||
#endif // ASAN_TEST_UTILS_H
|
@ -1,615 +0,0 @@
|
||||
# This directory contains a large amount of C code which provides
|
||||
# generic implementations of the core runtime library along with optimized
|
||||
# architecture-specific code in various subdirectories.
|
||||
|
||||
if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
|
||||
cmake_minimum_required(VERSION 3.4.3)
|
||||
|
||||
project(CompilerRTBuiltins C ASM)
|
||||
set(COMPILER_RT_STANDALONE_BUILD TRUE)
|
||||
set(COMPILER_RT_BUILTINS_STANDALONE_BUILD TRUE)
|
||||
list(INSERT CMAKE_MODULE_PATH 0
|
||||
"${CMAKE_SOURCE_DIR}/../../cmake"
|
||||
"${CMAKE_SOURCE_DIR}/../../cmake/Modules")
|
||||
include(base-config-ix)
|
||||
include(CompilerRTUtils)
|
||||
|
||||
load_llvm_config()
|
||||
construct_compiler_rt_default_triple()
|
||||
|
||||
if(APPLE)
|
||||
include(CompilerRTDarwinUtils)
|
||||
endif()
|
||||
include(AddCompilerRT)
|
||||
endif()
|
||||
|
||||
include(builtin-config-ix)
|
||||
|
||||
# TODO: Need to add a mechanism for logging errors when builtin source files are
|
||||
# added to a sub-directory and not this CMakeLists file.
|
||||
set(GENERIC_SOURCES
|
||||
absvdi2.c
|
||||
absvsi2.c
|
||||
absvti2.c
|
||||
adddf3.c
|
||||
addsf3.c
|
||||
addtf3.c
|
||||
addvdi3.c
|
||||
addvsi3.c
|
||||
addvti3.c
|
||||
apple_versioning.c
|
||||
ashldi3.c
|
||||
ashlti3.c
|
||||
ashrdi3.c
|
||||
ashrti3.c
|
||||
bswapdi2.c
|
||||
bswapsi2.c
|
||||
clzdi2.c
|
||||
clzsi2.c
|
||||
clzti2.c
|
||||
cmpdi2.c
|
||||
cmpti2.c
|
||||
comparedf2.c
|
||||
comparesf2.c
|
||||
ctzdi2.c
|
||||
ctzsi2.c
|
||||
ctzti2.c
|
||||
divdc3.c
|
||||
divdf3.c
|
||||
divdi3.c
|
||||
divmoddi4.c
|
||||
divmodsi4.c
|
||||
divsc3.c
|
||||
divsf3.c
|
||||
divsi3.c
|
||||
divtc3.c
|
||||
divti3.c
|
||||
divtf3.c
|
||||
extendsfdf2.c
|
||||
extendhfsf2.c
|
||||
ffsdi2.c
|
||||
ffssi2.c
|
||||
ffsti2.c
|
||||
fixdfdi.c
|
||||
fixdfsi.c
|
||||
fixdfti.c
|
||||
fixsfdi.c
|
||||
fixsfsi.c
|
||||
fixsfti.c
|
||||
fixunsdfdi.c
|
||||
fixunsdfsi.c
|
||||
fixunsdfti.c
|
||||
fixunssfdi.c
|
||||
fixunssfsi.c
|
||||
fixunssfti.c
|
||||
floatdidf.c
|
||||
floatdisf.c
|
||||
floatsidf.c
|
||||
floatsisf.c
|
||||
floattidf.c
|
||||
floattisf.c
|
||||
floatundidf.c
|
||||
floatundisf.c
|
||||
floatunsidf.c
|
||||
floatunsisf.c
|
||||
floatuntidf.c
|
||||
floatuntisf.c
|
||||
int_util.c
|
||||
lshrdi3.c
|
||||
lshrti3.c
|
||||
moddi3.c
|
||||
modsi3.c
|
||||
modti3.c
|
||||
muldc3.c
|
||||
muldf3.c
|
||||
muldi3.c
|
||||
mulodi4.c
|
||||
mulosi4.c
|
||||
muloti4.c
|
||||
mulsc3.c
|
||||
mulsf3.c
|
||||
multi3.c
|
||||
multf3.c
|
||||
mulvdi3.c
|
||||
mulvsi3.c
|
||||
mulvti3.c
|
||||
negdf2.c
|
||||
negdi2.c
|
||||
negsf2.c
|
||||
negti2.c
|
||||
negvdi2.c
|
||||
negvsi2.c
|
||||
negvti2.c
|
||||
os_version_check.c
|
||||
paritydi2.c
|
||||
paritysi2.c
|
||||
parityti2.c
|
||||
popcountdi2.c
|
||||
popcountsi2.c
|
||||
popcountti2.c
|
||||
powidf2.c
|
||||
powisf2.c
|
||||
powitf2.c
|
||||
subdf3.c
|
||||
subsf3.c
|
||||
subvdi3.c
|
||||
subvsi3.c
|
||||
subvti3.c
|
||||
subtf3.c
|
||||
trampoline_setup.c
|
||||
truncdfhf2.c
|
||||
truncdfsf2.c
|
||||
truncsfhf2.c
|
||||
ucmpdi2.c
|
||||
ucmpti2.c
|
||||
udivdi3.c
|
||||
udivmoddi4.c
|
||||
udivmodsi4.c
|
||||
udivmodti4.c
|
||||
udivsi3.c
|
||||
udivti3.c
|
||||
umoddi3.c
|
||||
umodsi3.c
|
||||
umodti3.c)
|
||||
|
||||
set(GENERIC_TF_SOURCES
|
||||
comparetf2.c
|
||||
extenddftf2.c
|
||||
extendsftf2.c
|
||||
fixtfdi.c
|
||||
fixtfsi.c
|
||||
fixtfti.c
|
||||
fixunstfdi.c
|
||||
fixunstfsi.c
|
||||
fixunstfti.c
|
||||
floatditf.c
|
||||
floatsitf.c
|
||||
floattitf.c
|
||||
floatunditf.c
|
||||
floatunsitf.c
|
||||
floatuntitf.c
|
||||
multc3.c
|
||||
trunctfdf2.c
|
||||
trunctfsf2.c)
|
||||
|
||||
option(COMPILER_RT_EXCLUDE_ATOMIC_BUILTIN
|
||||
"Skip the atomic builtin (these should normally be provided by a shared library)"
|
||||
On)
|
||||
|
||||
if(NOT FUCHSIA AND NOT COMPILER_RT_BAREMETAL_BUILD)
|
||||
set(GENERIC_SOURCES
|
||||
${GENERIC_SOURCES}
|
||||
emutls.c
|
||||
enable_execute_stack.c
|
||||
eprintf.c)
|
||||
endif()
|
||||
|
||||
if(COMPILER_RT_HAS_ATOMIC_KEYWORD AND NOT COMPILER_RT_EXCLUDE_ATOMIC_BUILTIN)
|
||||
set(GENERIC_SOURCES
|
||||
${GENERIC_SOURCES}
|
||||
atomic.c)
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
set(GENERIC_SOURCES
|
||||
${GENERIC_SOURCES}
|
||||
atomic_flag_clear.c
|
||||
atomic_flag_clear_explicit.c
|
||||
atomic_flag_test_and_set.c
|
||||
atomic_flag_test_and_set_explicit.c
|
||||
atomic_signal_fence.c
|
||||
atomic_thread_fence.c)
|
||||
endif()
|
||||
|
||||
if (HAVE_UNWIND_H)
|
||||
set(GENERIC_SOURCES
|
||||
${GENERIC_SOURCES}
|
||||
gcc_personality_v0.c)
|
||||
endif ()
|
||||
|
||||
if (NOT FUCHSIA)
|
||||
set(GENERIC_SOURCES
|
||||
${GENERIC_SOURCES}
|
||||
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/floatdidf.c
|
||||
x86_64/floatdisf.c
|
||||
x86_64/floatdixf.c
|
||||
x86_64/floatundidf.S
|
||||
x86_64/floatundisf.S
|
||||
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)
|
||||
set(x86_64_SOURCES
|
||||
${x86_64_SOURCES}
|
||||
x86_64/chkstk.S
|
||||
x86_64/chkstk2.S)
|
||||
endif()
|
||||
|
||||
set(i386_SOURCES
|
||||
i386/ashldi3.S
|
||||
i386/ashrdi3.S
|
||||
i386/divdi3.S
|
||||
i386/floatdidf.S
|
||||
i386/floatdisf.S
|
||||
i386/floatdixf.S
|
||||
i386/floatundidf.S
|
||||
i386/floatundisf.S
|
||||
i386/floatundixf.S
|
||||
i386/lshrdi3.S
|
||||
i386/moddi3.S
|
||||
i386/muldi3.S
|
||||
i386/udivdi3.S
|
||||
i386/umoddi3.S)
|
||||
filter_builtin_sources(i386_SOURCES EXCLUDE i386_SOURCES "${i386_SOURCES};${GENERIC_SOURCES}")
|
||||
|
||||
if (WIN32)
|
||||
set(i386_SOURCES
|
||||
${i386_SOURCES}
|
||||
i386/chkstk.S
|
||||
i386/chkstk2.S)
|
||||
endif()
|
||||
else () # MSVC
|
||||
# Use C versions of functions when building on MSVC
|
||||
# MSVC's assembler takes Intel syntax, not AT&T syntax.
|
||||
# Also use only MSVC compilable builtin implementations.
|
||||
set(x86_64_SOURCES
|
||||
x86_64/floatdidf.c
|
||||
x86_64/floatdisf.c
|
||||
x86_64/floatdixf.c
|
||||
${GENERIC_SOURCES})
|
||||
set(x86_64h_SOURCES ${x86_64_SOURCES})
|
||||
set(i386_SOURCES ${GENERIC_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
|
||||
arm/clzdi2.S
|
||||
arm/clzsi2.S
|
||||
arm/comparesf2.S
|
||||
arm/divmodsi4.S
|
||||
arm/divsi3.S
|
||||
arm/modsi3.S
|
||||
arm/sync_fetch_and_add_4.S
|
||||
arm/sync_fetch_and_add_8.S
|
||||
arm/sync_fetch_and_and_4.S
|
||||
arm/sync_fetch_and_and_8.S
|
||||
arm/sync_fetch_and_max_4.S
|
||||
arm/sync_fetch_and_max_8.S
|
||||
arm/sync_fetch_and_min_4.S
|
||||
arm/sync_fetch_and_min_8.S
|
||||
arm/sync_fetch_and_nand_4.S
|
||||
arm/sync_fetch_and_nand_8.S
|
||||
arm/sync_fetch_and_or_4.S
|
||||
arm/sync_fetch_and_or_8.S
|
||||
arm/sync_fetch_and_sub_4.S
|
||||
arm/sync_fetch_and_sub_8.S
|
||||
arm/sync_fetch_and_umax_4.S
|
||||
arm/sync_fetch_and_umax_8.S
|
||||
arm/sync_fetch_and_umin_4.S
|
||||
arm/sync_fetch_and_umin_8.S
|
||||
arm/sync_fetch_and_xor_4.S
|
||||
arm/sync_fetch_and_xor_8.S
|
||||
arm/udivmodsi4.S
|
||||
arm/udivsi3.S
|
||||
arm/umodsi3.S)
|
||||
filter_builtin_sources(arm_SOURCES EXCLUDE arm_SOURCES "${arm_SOURCES};${GENERIC_SOURCES}")
|
||||
|
||||
set(thumb1_SOURCES
|
||||
arm/divsi3.S
|
||||
arm/udivsi3.S
|
||||
arm/comparesf2.S
|
||||
arm/addsf3.S
|
||||
${GENERIC_SOURCES})
|
||||
|
||||
set(arm_EABI_SOURCES
|
||||
arm/aeabi_cdcmp.S
|
||||
arm/aeabi_cdcmpeq_check_nan.c
|
||||
arm/aeabi_cfcmp.S
|
||||
arm/aeabi_cfcmpeq_check_nan.c
|
||||
arm/aeabi_dcmp.S
|
||||
arm/aeabi_div0.c
|
||||
arm/aeabi_drsub.c
|
||||
arm/aeabi_fcmp.S
|
||||
arm/aeabi_frsub.c
|
||||
arm/aeabi_idivmod.S
|
||||
arm/aeabi_ldivmod.S
|
||||
arm/aeabi_memcmp.S
|
||||
arm/aeabi_memcpy.S
|
||||
arm/aeabi_memmove.S
|
||||
arm/aeabi_memset.S
|
||||
arm/aeabi_uidivmod.S
|
||||
arm/aeabi_uldivmod.S)
|
||||
|
||||
set(arm_Thumb1_JT_SOURCES
|
||||
arm/switch16.S
|
||||
arm/switch32.S
|
||||
arm/switch8.S
|
||||
arm/switchu8.S)
|
||||
set(arm_Thumb1_SjLj_EH_SOURCES
|
||||
arm/restore_vfp_d8_d15_regs.S
|
||||
arm/save_vfp_d8_d15_regs.S)
|
||||
set(arm_Thumb1_VFPv2_SOURCES
|
||||
arm/adddf3vfp.S
|
||||
arm/addsf3vfp.S
|
||||
arm/divdf3vfp.S
|
||||
arm/divsf3vfp.S
|
||||
arm/eqdf2vfp.S
|
||||
arm/eqsf2vfp.S
|
||||
arm/extendsfdf2vfp.S
|
||||
arm/fixdfsivfp.S
|
||||
arm/fixsfsivfp.S
|
||||
arm/fixunsdfsivfp.S
|
||||
arm/fixunssfsivfp.S
|
||||
arm/floatsidfvfp.S
|
||||
arm/floatsisfvfp.S
|
||||
arm/floatunssidfvfp.S
|
||||
arm/floatunssisfvfp.S
|
||||
arm/gedf2vfp.S
|
||||
arm/gesf2vfp.S
|
||||
arm/gtdf2vfp.S
|
||||
arm/gtsf2vfp.S
|
||||
arm/ledf2vfp.S
|
||||
arm/lesf2vfp.S
|
||||
arm/ltdf2vfp.S
|
||||
arm/ltsf2vfp.S
|
||||
arm/muldf3vfp.S
|
||||
arm/mulsf3vfp.S
|
||||
arm/nedf2vfp.S
|
||||
arm/negdf2vfp.S
|
||||
arm/negsf2vfp.S
|
||||
arm/nesf2vfp.S
|
||||
arm/subdf3vfp.S
|
||||
arm/subsf3vfp.S
|
||||
arm/truncdfsf2vfp.S
|
||||
arm/unorddf2vfp.S
|
||||
arm/unordsf2vfp.S)
|
||||
set(arm_Thumb1_icache_SOURCES
|
||||
arm/sync_synchronize.S)
|
||||
set(arm_Thumb1_SOURCES
|
||||
${arm_Thumb1_JT_SOURCES}
|
||||
${arm_Thumb1_SjLj_EH_SOURCES}
|
||||
${arm_Thumb1_VFPv2_SOURCES}
|
||||
${arm_Thumb1_icache_SOURCES})
|
||||
|
||||
if(MINGW)
|
||||
set(arm_SOURCES
|
||||
arm/aeabi_idivmod.S
|
||||
arm/aeabi_ldivmod.S
|
||||
arm/aeabi_uidivmod.S
|
||||
arm/aeabi_uldivmod.S
|
||||
arm/chkstk.S
|
||||
divmoddi4.c
|
||||
divmodsi4.c
|
||||
divdi3.c
|
||||
divsi3.c
|
||||
fixdfdi.c
|
||||
fixsfdi.c
|
||||
fixunsdfdi.c
|
||||
fixunssfdi.c
|
||||
floatdidf.c
|
||||
floatdisf.c
|
||||
floatundidf.c
|
||||
floatundisf.c
|
||||
mingw_fixfloat.c
|
||||
moddi3.c
|
||||
udivmoddi4.c
|
||||
udivmodsi4.c
|
||||
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
|
||||
${arm_SOURCES}
|
||||
${arm_EABI_SOURCES}
|
||||
${arm_Thumb1_SOURCES})
|
||||
|
||||
set(thumb1_SOURCES
|
||||
${thumb1_SOURCES}
|
||||
${arm_EABI_SOURCES})
|
||||
endif()
|
||||
|
||||
set(aarch64_SOURCES
|
||||
${GENERIC_TF_SOURCES}
|
||||
${GENERIC_SOURCES})
|
||||
|
||||
if (MINGW)
|
||||
set(aarch64_SOURCES
|
||||
${aarch64_SOURCES}
|
||||
aarch64/chkstk.S)
|
||||
endif()
|
||||
|
||||
set(armhf_SOURCES ${arm_SOURCES})
|
||||
set(armv7_SOURCES ${arm_SOURCES})
|
||||
set(armv7s_SOURCES ${arm_SOURCES})
|
||||
set(armv7k_SOURCES ${arm_SOURCES})
|
||||
set(arm64_SOURCES ${aarch64_SOURCES})
|
||||
|
||||
# macho_embedded archs
|
||||
set(armv6m_SOURCES ${thumb1_SOURCES})
|
||||
set(armv7m_SOURCES ${arm_SOURCES})
|
||||
set(armv7em_SOURCES ${arm_SOURCES})
|
||||
|
||||
# hexagon arch
|
||||
set(hexagon_SOURCES ${GENERIC_SOURCES} ${GENERIC_TF_SOURCES})
|
||||
set(hexagon_SOURCES
|
||||
hexagon/common_entry_exit_abi1.S
|
||||
hexagon/common_entry_exit_abi2.S
|
||||
hexagon/common_entry_exit_legacy.S
|
||||
hexagon/dfaddsub.S
|
||||
hexagon/dfdiv.S
|
||||
hexagon/dffma.S
|
||||
hexagon/dfminmax.S
|
||||
hexagon/dfmul.S
|
||||
hexagon/dfsqrt.S
|
||||
hexagon/divdi3.S
|
||||
hexagon/divsi3.S
|
||||
hexagon/fabs_opt.S
|
||||
hexagon/fastmath2_dlib_asm.S
|
||||
hexagon/fastmath2_ldlib_asm.S
|
||||
hexagon/fastmath_dlib_asm.S
|
||||
hexagon/fma_opt.S
|
||||
hexagon/fmax_opt.S
|
||||
hexagon/fmin_opt.S
|
||||
hexagon/memcpy_forward_vp4cp4n2.S
|
||||
hexagon/memcpy_likely_aligned.S
|
||||
hexagon/moddi3.S
|
||||
hexagon/modsi3.S
|
||||
hexagon/sfdiv_opt.S
|
||||
hexagon/sfsqrt_opt.S
|
||||
hexagon/udivdi3.S
|
||||
hexagon/udivmoddi4.S
|
||||
hexagon/udivmodsi4.S
|
||||
hexagon/udivsi3.S
|
||||
hexagon/umoddi3.S
|
||||
hexagon/umodsi3.S)
|
||||
|
||||
|
||||
set(mips_SOURCES ${GENERIC_SOURCES})
|
||||
set(mipsel_SOURCES ${mips_SOURCES})
|
||||
set(mips64_SOURCES ${GENERIC_TF_SOURCES}
|
||||
${mips_SOURCES})
|
||||
set(mips64el_SOURCES ${GENERIC_TF_SOURCES}
|
||||
${mips_SOURCES})
|
||||
|
||||
set(powerpc64_SOURCES
|
||||
ppc/divtc3.c
|
||||
ppc/fixtfdi.c
|
||||
ppc/fixunstfti.c
|
||||
ppc/fixunstfdi.c
|
||||
ppc/floattitf.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(riscv_SOURCES ${GENERIC_SOURCES} ${GENERIC_TF_SOURCES})
|
||||
set(riscv32_SOURCES
|
||||
riscv/mulsi3.S
|
||||
${riscv_SOURCES})
|
||||
set(riscv64_SOURCES ${riscv_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")
|
||||
|
||||
if (APPLE)
|
||||
add_subdirectory(Darwin-excludes)
|
||||
add_subdirectory(macho_embedded)
|
||||
darwin_add_builtin_libraries(${BUILTIN_SUPPORTED_OS})
|
||||
else ()
|
||||
set(BUILTIN_CFLAGS "")
|
||||
|
||||
append_list_if(COMPILER_RT_HAS_STD_C11_FLAG -std=c11 BUILTIN_CFLAGS)
|
||||
|
||||
# These flags would normally be added to CMAKE_C_FLAGS by the llvm
|
||||
# cmake step. Add them manually if this is a standalone build.
|
||||
if(COMPILER_RT_STANDALONE_BUILD)
|
||||
append_list_if(COMPILER_RT_HAS_FPIC_FLAG -fPIC BUILTIN_CFLAGS)
|
||||
append_list_if(COMPILER_RT_HAS_FNO_BUILTIN_FLAG -fno-builtin BUILTIN_CFLAGS)
|
||||
append_list_if(COMPILER_RT_HAS_VISIBILITY_HIDDEN_FLAG -fvisibility=hidden BUILTIN_CFLAGS)
|
||||
if(NOT COMPILER_RT_DEBUG)
|
||||
append_list_if(COMPILER_RT_HAS_OMIT_FRAME_POINTER_FLAG -fomit-frame-pointer BUILTIN_CFLAGS)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(BUILTIN_DEFS "")
|
||||
|
||||
append_list_if(COMPILER_RT_HAS_VISIBILITY_HIDDEN_FLAG VISIBILITY_HIDDEN BUILTIN_DEFS)
|
||||
|
||||
foreach (arch ${BUILTIN_SUPPORTED_ARCH})
|
||||
if (CAN_TARGET_${arch})
|
||||
# NOTE: some architectures (e.g. i386) have multiple names. Ensure that
|
||||
# we catch them all.
|
||||
set(_arch ${arch})
|
||||
if("${arch}" STREQUAL "armv6m")
|
||||
set(_arch "arm|armv6m")
|
||||
elseif("${arch}" MATCHES "^(armhf|armv7|armv7s|armv7k|armv7m|armv7em)$")
|
||||
set(_arch "arm")
|
||||
endif()
|
||||
|
||||
# For ARM archs, exclude any VFP builtins if VFP is not supported
|
||||
if (${arch} MATCHES "^(arm|armhf|armv7|armv7s|armv7k|armv7m|armv7em)$")
|
||||
string(REPLACE ";" " " _TARGET_${arch}_CFLAGS "${TARGET_${arch}_CFLAGS}")
|
||||
check_compile_definition(__VFP_FP__ "${CMAKE_C_FLAGS} ${_TARGET_${arch}_CFLAGS}" COMPILER_RT_HAS_${arch}_VFP)
|
||||
if(NOT COMPILER_RT_HAS_${arch}_VFP)
|
||||
list(REMOVE_ITEM ${arch}_SOURCES ${arm_Thumb1_VFPv2_SOURCES} ${arm_Thumb1_SjLj_EH_SOURCES})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# 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.
|
||||
foreach (_file ${${arch}_SOURCES})
|
||||
if (${_file} MATCHES ${_arch}/*)
|
||||
get_filename_component(_name ${_file} NAME)
|
||||
string(REPLACE ".S" ".c" _cname "${_name}")
|
||||
list(REMOVE_ITEM ${arch}_SOURCES ${_cname})
|
||||
endif ()
|
||||
endforeach ()
|
||||
|
||||
# Needed for clear_cache on debug mode, due to r7's usage in inline asm.
|
||||
# Release mode already sets it via -O2/3, Debug mode doesn't.
|
||||
if (${arch} STREQUAL "armhf")
|
||||
list(APPEND BUILTIN_CFLAGS -fomit-frame-pointer -DCOMPILER_RT_ARMHF_TARGET)
|
||||
endif()
|
||||
|
||||
# For RISCV32, we must force enable int128 for compiling long
|
||||
# double routines.
|
||||
if("${arch}" STREQUAL "riscv32")
|
||||
list(APPEND BUILTIN_CFLAGS -fforce-enable-int128)
|
||||
endif()
|
||||
|
||||
add_compiler_rt_runtime(clang_rt.builtins
|
||||
STATIC
|
||||
ARCHS ${arch}
|
||||
SOURCES ${${arch}_SOURCES}
|
||||
DEFS ${BUILTIN_DEFS}
|
||||
CFLAGS ${BUILTIN_CFLAGS}
|
||||
PARENT_TARGET builtins)
|
||||
endif ()
|
||||
endforeach ()
|
||||
endif ()
|
||||
|
||||
add_dependencies(compiler-rt builtins)
|
@ -1,4 +0,0 @@
|
||||
file(GLOB filter_files ${CMAKE_CURRENT_SOURCE_DIR}/*.txt)
|
||||
foreach(filter_file ${filter_files})
|
||||
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${filter_file})
|
||||
endforeach()
|
@ -1,11 +0,0 @@
|
||||
This folder contains list of symbols that should be excluded from the builtin
|
||||
libraries for Darwin. There are two reasons symbols are excluded:
|
||||
|
||||
(1) They aren't supported on Darwin
|
||||
(2) They are contained within the OS on the minimum supported target
|
||||
|
||||
The builtin libraries must contain all symbols not provided by the lowest
|
||||
supported target OS. Meaning if minimum deployment target is iOS 6, all builtins
|
||||
not included in the ios6-<arch>.txt files need to be included. The one catch is
|
||||
that this is per-architecture. Since iOS 6 doesn't support arm64, when supporting
|
||||
iOS 6, the minimum deployment target for arm64 binaries is iOS 7.
|
@ -1,57 +0,0 @@
|
||||
absvti2
|
||||
addtf3
|
||||
addvti3
|
||||
aeabi_cdcmp
|
||||
aeabi_cdcmpeq_check_nan
|
||||
aeabi_cfcmp
|
||||
aeabi_cfcmpeq_check_nan
|
||||
aeabi_dcmp
|
||||
aeabi_div0
|
||||
aeabi_drsub
|
||||
aeabi_fcmp
|
||||
aeabi_frsub
|
||||
aeabi_idivmod
|
||||
aeabi_ldivmod
|
||||
aeabi_memcmp
|
||||
aeabi_memcpy
|
||||
aeabi_memmove
|
||||
aeabi_memset
|
||||
aeabi_uidivmod
|
||||
aeabi_uldivmod
|
||||
ashlti3
|
||||
ashrti3
|
||||
clzti2
|
||||
cmpti2
|
||||
ctzti2
|
||||
divtf3
|
||||
divti3
|
||||
ffsti2
|
||||
fixdfti
|
||||
fixsfti
|
||||
fixunsdfti
|
||||
fixunssfti
|
||||
fixunsxfti
|
||||
fixxfti
|
||||
floattidf
|
||||
floattisf
|
||||
floattixf
|
||||
floatuntidf
|
||||
floatuntisf
|
||||
floatuntixf
|
||||
lshrti3
|
||||
modti3
|
||||
multf3
|
||||
multi3
|
||||
mulvti3
|
||||
negti2
|
||||
negvti2
|
||||
parityti2
|
||||
popcountti2
|
||||
powitf2
|
||||
subtf3
|
||||
subvti3
|
||||
trampoline_setup
|
||||
ucmpti2
|
||||
udivmodti4
|
||||
udivti3
|
||||
umodti3
|
@ -1,57 +0,0 @@
|
||||
absvti2
|
||||
addtf3
|
||||
addvti3
|
||||
aeabi_cdcmp
|
||||
aeabi_cdcmpeq_check_nan
|
||||
aeabi_cfcmp
|
||||
aeabi_cfcmpeq_check_nan
|
||||
aeabi_dcmp
|
||||
aeabi_div0
|
||||
aeabi_drsub
|
||||
aeabi_fcmp
|
||||
aeabi_frsub
|
||||
aeabi_idivmod
|
||||
aeabi_ldivmod
|
||||
aeabi_memcmp
|
||||
aeabi_memcpy
|
||||
aeabi_memmove
|
||||
aeabi_memset
|
||||
aeabi_uidivmod
|
||||
aeabi_uldivmod
|
||||
ashlti3
|
||||
ashrti3
|
||||
clzti2
|
||||
cmpti2
|
||||
ctzti2
|
||||
divtf3
|
||||
divti3
|
||||
ffsti2
|
||||
fixdfti
|
||||
fixsfti
|
||||
fixunsdfti
|
||||
fixunssfti
|
||||
fixunsxfti
|
||||
fixxfti
|
||||
floattidf
|
||||
floattisf
|
||||
floattixf
|
||||
floatuntidf
|
||||
floatuntisf
|
||||
floatuntixf
|
||||
lshrti3
|
||||
modti3
|
||||
multf
|
||||
multi3
|
||||
mulvti3
|
||||
negti2
|
||||
negvti2
|
||||
parityti2
|
||||
popcountti2
|
||||
powitf2
|
||||
subtf3
|
||||
subvti3
|
||||
trampoline_setup
|
||||
ucmpti2
|
||||
udivmodti4
|
||||
udivti3
|
||||
umodti3
|
@ -1 +0,0 @@
|
||||
apple_versioning
|
@ -1,120 +0,0 @@
|
||||
absvdi2
|
||||
absvsi2
|
||||
adddf3
|
||||
adddf3vfp
|
||||
addsf3
|
||||
addsf3vfp
|
||||
addvdi3
|
||||
addvsi3
|
||||
ashldi3
|
||||
ashrdi3
|
||||
bswapdi2
|
||||
bswapsi2
|
||||
clzdi2
|
||||
clzsi2
|
||||
cmpdi2
|
||||
ctzdi2
|
||||
ctzsi2
|
||||
divdc3
|
||||
divdf3
|
||||
divdf3vfp
|
||||
divdi3
|
||||
divmodsi4
|
||||
divsc3
|
||||
divsf3
|
||||
divsf3vfp
|
||||
divsi3
|
||||
eqdf2
|
||||
eqdf2vfp
|
||||
eqsf2
|
||||
eqsf2vfp
|
||||
extendsfdf2
|
||||
extendsfdf2vfp
|
||||
ffsdi2
|
||||
fixdfdi
|
||||
fixdfsi
|
||||
fixdfsivfp
|
||||
fixsfdi
|
||||
fixsfsi
|
||||
fixsfsivfp
|
||||
fixunsdfdi
|
||||
fixunsdfsi
|
||||
fixunsdfsivfp
|
||||
fixunssfdi
|
||||
fixunssfsi
|
||||
fixunssfsivfp
|
||||
floatdidf
|
||||
floatdisf
|
||||
floatsidf
|
||||
floatsidfvfp
|
||||
floatsisf
|
||||
floatsisfvfp
|
||||
floatundidf
|
||||
floatundisf
|
||||
floatunsidf
|
||||
floatunsisf
|
||||
floatunssidfvfp
|
||||
floatunssisfvfp
|
||||
gcc_personality_sj0
|
||||
gedf2
|
||||
gedf2vfp
|
||||
gesf2
|
||||
gesf2vfp
|
||||
gtdf2
|
||||
gtdf2vfp
|
||||
gtsf2
|
||||
gtsf2vfp
|
||||
ledf2
|
||||
ledf2vfp
|
||||
lesf2
|
||||
lesf2vfp
|
||||
lshrdi3
|
||||
ltdf2
|
||||
ltdf2vfp
|
||||
ltsf2
|
||||
ltsf2vfp
|
||||
moddi3
|
||||
modsi3
|
||||
muldc3
|
||||
muldf3
|
||||
muldf3vfp
|
||||
muldi3
|
||||
mulodi4
|
||||
mulosi4
|
||||
mulsc3
|
||||
mulsf3
|
||||
mulsf3vfp
|
||||
mulvdi3
|
||||
mulvsi3
|
||||
nedf2
|
||||
nedf2vfp
|
||||
negdi2
|
||||
negvdi2
|
||||
negvsi2
|
||||
nesf2
|
||||
nesf2vfp
|
||||
paritydi2
|
||||
paritysi2
|
||||
popcountdi2
|
||||
popcountsi2
|
||||
powidf2
|
||||
powisf2
|
||||
subdf3
|
||||
subdf3vfp
|
||||
subsf3
|
||||
subsf3vfp
|
||||
subvdi3
|
||||
subvsi3
|
||||
truncdfsf2
|
||||
truncdfsf2vfp
|
||||
ucmpdi2
|
||||
udivdi3
|
||||
udivmoddi4
|
||||
udivmodsi4
|
||||
udivsi3
|
||||
umoddi3
|
||||
umodsi3
|
||||
unorddf2
|
||||
unorddf2vfp
|
||||
unordsf2
|
||||
unordsf2vfp
|
@ -1,120 +0,0 @@
|
||||
absvdi2
|
||||
absvsi2
|
||||
adddf3
|
||||
adddf3vfp
|
||||
addsf3
|
||||
addsf3vfp
|
||||
addvdi3
|
||||
addvsi3
|
||||
ashldi3
|
||||
ashrdi3
|
||||
bswapdi2
|
||||
bswapsi2
|
||||
clzdi2
|
||||
clzsi2
|
||||
cmpdi2
|
||||
ctzdi2
|
||||
ctzsi2
|
||||
divdc3
|
||||
divdf3
|
||||
divdf3vfp
|
||||
divdi3
|
||||
divmodsi4
|
||||
divsc3
|
||||
divsf3
|
||||
divsf3vfp
|
||||
divsi3
|
||||
eqdf2
|
||||
eqdf2vfp
|
||||
eqsf2
|
||||
eqsf2vfp
|
||||
extendsfdf2
|
||||
extendsfdf2vfp
|
||||
ffsdi2
|
||||
fixdfdi
|
||||
fixdfsi
|
||||
fixdfsivfp
|
||||
fixsfdi
|
||||
fixsfsi
|
||||
fixsfsivfp
|
||||
fixunsdfdi
|
||||
fixunsdfsi
|
||||
fixunsdfsivfp
|
||||
fixunssfdi
|
||||
fixunssfsi
|
||||
fixunssfsivfp
|
||||
floatdidf
|
||||
floatdisf
|
||||
floatsidf
|
||||
floatsidfvfp
|
||||
floatsisf
|
||||
floatsisfvfp
|
||||
floatundidf
|
||||
floatundisf
|
||||
floatunsidf
|
||||
floatunsisf
|
||||
floatunssidfvfp
|
||||
floatunssisfvfp
|
||||
gcc_personality_sj0
|
||||
gedf2
|
||||
gedf2vfp
|
||||
gesf2
|
||||
gesf2vfp
|
||||
gtdf2
|
||||
gtdf2vfp
|
||||
gtsf2
|
||||
gtsf2vfp
|
||||
ledf2
|
||||
ledf2vfp
|
||||
lesf2
|
||||
lesf2vfp
|
||||
lshrdi3
|
||||
ltdf2
|
||||
ltdf2vfp
|
||||
ltsf2
|
||||
ltsf2vfp
|
||||
moddi3
|
||||
modsi3
|
||||
muldc3
|
||||
muldf3
|
||||
muldf3vfp
|
||||
muldi3
|
||||
mulodi4
|
||||
mulosi4
|
||||
mulsc3
|
||||
mulsf3
|
||||
mulsf3vfp
|
||||
mulvdi3
|
||||
mulvsi3
|
||||
nedf2
|
||||
nedf2vfp
|
||||
negdi2
|
||||
negvdi2
|
||||
negvsi2
|
||||
nesf2
|
||||
nesf2vfp
|
||||
paritydi2
|
||||
paritysi2
|
||||
popcountdi2
|
||||
popcountsi2
|
||||
powidf2
|
||||
powisf2
|
||||
subdf3
|
||||
subdf3vfp
|
||||
subsf3
|
||||
subsf3vfp
|
||||
subvdi3
|
||||
subvsi3
|
||||
truncdfsf2
|
||||
truncdfsf2vfp
|
||||
ucmpdi2
|
||||
udivdi3
|
||||
udivmoddi4
|
||||
udivmodsi4
|
||||
udivsi3
|
||||
umoddi3
|
||||
umodsi3
|
||||
unorddf2
|
||||
unorddf2vfp
|
||||
unordsf2
|
||||
unordsf2vfp
|
@ -1,16 +0,0 @@
|
||||
clzti2
|
||||
divti3
|
||||
fixdfti
|
||||
fixsfti
|
||||
fixunsdfti
|
||||
floattidf
|
||||
floattisf
|
||||
floatuntidf
|
||||
floatuntisf
|
||||
gcc_personality_v0
|
||||
modti3
|
||||
powidf2
|
||||
powisf2
|
||||
udivmodti4
|
||||
udivti3
|
||||
umodti3
|
@ -1,82 +0,0 @@
|
||||
absvti2
|
||||
addtf3
|
||||
addvti3
|
||||
ashlti3
|
||||
ashrti3
|
||||
clzti2
|
||||
cmpti2
|
||||
ctzti2
|
||||
divti3
|
||||
divtf3
|
||||
ffsti2
|
||||
fixdfti
|
||||
fixsfti
|
||||
fixunsdfti
|
||||
fixunssfti
|
||||
fixunsxfti
|
||||
fixxfti
|
||||
floattidf
|
||||
floattisf
|
||||
floattixf
|
||||
floatuntidf
|
||||
floatuntisf
|
||||
floatuntixf
|
||||
lshrti3
|
||||
modti3
|
||||
muloti4
|
||||
multi3
|
||||
multf3
|
||||
mulvti3
|
||||
negti2
|
||||
negvti2
|
||||
parityti2
|
||||
popcountti2
|
||||
powitf2
|
||||
subvti3
|
||||
subtf3
|
||||
trampoline_setup
|
||||
ucmpti2
|
||||
udivmodti4
|
||||
udivti3
|
||||
umodti3
|
||||
absvti2
|
||||
addtf3
|
||||
addvti3
|
||||
ashlti3
|
||||
ashrti3
|
||||
clzti2
|
||||
cmpti2
|
||||
ctzti2
|
||||
divti3
|
||||
divtf3
|
||||
ffsti2
|
||||
fixdfti
|
||||
fixsfti
|
||||
fixunsdfti
|
||||
fixunssfti
|
||||
fixunsxfti
|
||||
fixxfti
|
||||
floattidf
|
||||
floattisf
|
||||
floattixf
|
||||
floatuntidf
|
||||
floatuntisf
|
||||
floatuntixf
|
||||
lshrti3
|
||||
modti3
|
||||
muloti4
|
||||
multi3
|
||||
multf3
|
||||
mulvti3
|
||||
negti2
|
||||
negvti2
|
||||
parityti2
|
||||
popcountti2
|
||||
powitf2
|
||||
subvti3
|
||||
subtf3
|
||||
trampoline_setup
|
||||
ucmpti2
|
||||
udivmodti4
|
||||
udivti3
|
||||
umodti3
|
@ -1,12 +0,0 @@
|
||||
addtf3
|
||||
divtf3
|
||||
multf3
|
||||
powitf2
|
||||
subtf3
|
||||
trampoline_setup
|
||||
addtf3
|
||||
divtf3
|
||||
multf3
|
||||
powitf2
|
||||
subtf3
|
||||
trampoline_setup
|
@ -1 +0,0 @@
|
||||
apple_versioning
|
@ -1,35 +0,0 @@
|
||||
absvti2
|
||||
addvti3
|
||||
ashlti3
|
||||
ashrti3
|
||||
clzti2
|
||||
cmpti2
|
||||
ctzti2
|
||||
divti3
|
||||
ffsti2
|
||||
fixdfti
|
||||
fixsfti
|
||||
fixunsdfti
|
||||
fixunssfti
|
||||
fixunsxfti
|
||||
fixxfti
|
||||
floattidf
|
||||
floattisf
|
||||
floattixf
|
||||
floatuntidf
|
||||
floatuntisf
|
||||
floatuntixf
|
||||
lshrti3
|
||||
modti3
|
||||
muloti4
|
||||
multi3
|
||||
mulvti3
|
||||
negti2
|
||||
negvti2
|
||||
parityti2
|
||||
popcountti2
|
||||
subvti3
|
||||
ucmpti2
|
||||
udivmodti4
|
||||
udivti3
|
||||
umodti3
|
@ -1,7 +0,0 @@
|
||||
apple_versioning
|
||||
addtf3
|
||||
divtf3
|
||||
multf3
|
||||
powitf2
|
||||
subtf3
|
||||
trampoline_setup
|
@ -1,4 +0,0 @@
|
||||
file(GLOB filter_files ${CMAKE_CURRENT_SOURCE_DIR}/*.txt)
|
||||
foreach(filter_file ${filter_files})
|
||||
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${filter_file})
|
||||
endforeach()
|
@ -1,16 +0,0 @@
|
||||
aeabi_cdcmpeq
|
||||
aeabi_cdrcmple
|
||||
aeabi_cfcmpeq
|
||||
aeabi_cfrcmple
|
||||
aeabi_dcmpeq
|
||||
aeabi_dcmpge
|
||||
aeabi_dcmpgt
|
||||
aeabi_dcmple
|
||||
aeabi_dcmplt
|
||||
aeabi_drsub
|
||||
aeabi_fcmpeq
|
||||
aeabi_fcmpge
|
||||
aeabi_fcmpgt
|
||||
aeabi_fcmple
|
||||
aeabi_fcmplt
|
||||
aeabi_frsub
|
@ -1,92 +0,0 @@
|
||||
absvdi2
|
||||
absvsi2
|
||||
addvdi3
|
||||
addvsi3
|
||||
ashldi3
|
||||
ashrdi3
|
||||
clzdi2
|
||||
clzsi2
|
||||
cmpdi2
|
||||
ctzdi2
|
||||
ctzsi2
|
||||
divdc3
|
||||
divdi3
|
||||
divsc3
|
||||
divmodsi4
|
||||
udivmodsi4
|
||||
do_global_dtors
|
||||
ffsdi2
|
||||
fixdfdi
|
||||
fixsfdi
|
||||
fixunsdfdi
|
||||
fixunsdfsi
|
||||
fixunssfdi
|
||||
fixunssfsi
|
||||
floatdidf
|
||||
floatdisf
|
||||
floatundidf
|
||||
floatundisf
|
||||
gcc_bcmp
|
||||
lshrdi3
|
||||
moddi3
|
||||
muldc3
|
||||
muldi3
|
||||
mulsc3
|
||||
mulvdi3
|
||||
mulvsi3
|
||||
negdi2
|
||||
negvdi2
|
||||
negvsi2
|
||||
paritydi2
|
||||
paritysi2
|
||||
popcountdi2
|
||||
popcountsi2
|
||||
powidf2
|
||||
powisf2
|
||||
subvdi3
|
||||
subvsi3
|
||||
ucmpdi2
|
||||
udiv_w_sdiv
|
||||
udivdi3
|
||||
udivmoddi4
|
||||
umoddi3
|
||||
adddf3
|
||||
addsf3
|
||||
cmpdf2
|
||||
cmpsf2
|
||||
div0
|
||||
divdf3
|
||||
divsf3
|
||||
divsi3
|
||||
extendsfdf2
|
||||
extendhfsf2
|
||||
ffssi2
|
||||
fixdfsi
|
||||
fixsfsi
|
||||
floatsidf
|
||||
floatsisf
|
||||
floatunsidf
|
||||
floatunsisf
|
||||
comparedf2
|
||||
comparesf2
|
||||
modsi3
|
||||
muldf3
|
||||
mulsf3
|
||||
negdf2
|
||||
negsf2
|
||||
subdf3
|
||||
subsf3
|
||||
truncdfhf2
|
||||
truncdfsf2
|
||||
truncsfhf2
|
||||
udivsi3
|
||||
umodsi3
|
||||
unorddf2
|
||||
unordsf2
|
||||
atomic_flag_clear
|
||||
atomic_flag_clear_explicit
|
||||
atomic_flag_test_and_set
|
||||
atomic_flag_test_and_set_explicit
|
||||
atomic_signal_fence
|
||||
atomic_thread_fence
|
||||
int_util
|
@ -1,7 +0,0 @@
|
||||
i686.get_pc_thunk.eax
|
||||
i686.get_pc_thunk.ebp
|
||||
i686.get_pc_thunk.ebx
|
||||
i686.get_pc_thunk.ecx
|
||||
i686.get_pc_thunk.edi
|
||||
i686.get_pc_thunk.edx
|
||||
i686.get_pc_thunk.esi
|
@ -1,10 +0,0 @@
|
||||
sync_fetch_and_add_8
|
||||
sync_fetch_and_sub_8
|
||||
sync_fetch_and_and_8
|
||||
sync_fetch_and_or_8
|
||||
sync_fetch_and_xor_8
|
||||
sync_fetch_and_nand_8
|
||||
sync_fetch_and_max_8
|
||||
sync_fetch_and_umax_8
|
||||
sync_fetch_and_min_8
|
||||
sync_fetch_and_umin_8
|
@ -1,14 +0,0 @@
|
||||
switch16
|
||||
switch32
|
||||
switch8
|
||||
switchu8
|
||||
sync_fetch_and_add_4
|
||||
sync_fetch_and_sub_4
|
||||
sync_fetch_and_and_4
|
||||
sync_fetch_and_or_4
|
||||
sync_fetch_and_xor_4
|
||||
sync_fetch_and_nand_4
|
||||
sync_fetch_and_max_4
|
||||
sync_fetch_and_umax_4
|
||||
sync_fetch_and_min_4
|
||||
sync_fetch_and_umin_4
|
@ -1,41 +0,0 @@
|
||||
add_compiler_rt_component(cfi)
|
||||
|
||||
if(OS_NAME MATCHES "Linux" OR OS_NAME MATCHES "FreeBSD" OR OS_NAME MATCHES "NetBSD")
|
||||
set(CFI_SOURCES cfi.cc)
|
||||
|
||||
include_directories(..)
|
||||
|
||||
set(CFI_CFLAGS
|
||||
${SANITIZER_COMMON_CFLAGS}
|
||||
)
|
||||
|
||||
set(CFI_DIAG_CFLAGS
|
||||
-DCFI_ENABLE_DIAG=1
|
||||
)
|
||||
|
||||
foreach(arch ${CFI_SUPPORTED_ARCH})
|
||||
add_compiler_rt_runtime(clang_rt.cfi
|
||||
STATIC
|
||||
ARCHS ${arch}
|
||||
SOURCES ${CFI_SOURCES}
|
||||
OBJECT_LIBS RTInterception
|
||||
RTSanitizerCommon
|
||||
RTSanitizerCommonLibc
|
||||
CFLAGS ${CFI_CFLAGS}
|
||||
PARENT_TARGET cfi)
|
||||
add_compiler_rt_runtime(clang_rt.cfi_diag
|
||||
STATIC
|
||||
ARCHS ${arch}
|
||||
SOURCES ${CFI_SOURCES}
|
||||
OBJECT_LIBS RTInterception
|
||||
RTSanitizerCommon
|
||||
RTSanitizerCommonLibc
|
||||
RTSanitizerCommonCoverage
|
||||
RTSanitizerCommonSymbolizer
|
||||
RTUbsan
|
||||
CFLAGS ${CFI_CFLAGS} ${CFI_DIAG_CFLAGS}
|
||||
PARENT_TARGET cfi)
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
add_compiler_rt_resource_file(cfi_blacklist cfi_blacklist.txt cfi)
|
@ -1,2 +0,0 @@
|
||||
BasedOnStyle: Google
|
||||
AllowShortIfStatementsOnASingleLine: false
|
@ -1,57 +0,0 @@
|
||||
include_directories(..)
|
||||
|
||||
# Runtime library sources and build flags.
|
||||
set(DFSAN_RTL_SOURCES
|
||||
dfsan.cc
|
||||
dfsan_custom.cc
|
||||
dfsan_interceptors.cc)
|
||||
|
||||
set(DFSAN_RTL_HEADERS
|
||||
dfsan.h
|
||||
dfsan_flags.inc
|
||||
dfsan_platform.h)
|
||||
|
||||
set(DFSAN_COMMON_CFLAGS ${SANITIZER_COMMON_CFLAGS})
|
||||
append_rtti_flag(OFF DFSAN_COMMON_CFLAGS)
|
||||
# Prevent clang from generating libc calls.
|
||||
append_list_if(COMPILER_RT_HAS_FFREESTANDING_FLAG -ffreestanding DFSAN_COMMON_CFLAGS)
|
||||
|
||||
# Static runtime library.
|
||||
add_compiler_rt_component(dfsan)
|
||||
|
||||
foreach(arch ${DFSAN_SUPPORTED_ARCH})
|
||||
set(DFSAN_CFLAGS ${DFSAN_COMMON_CFLAGS})
|
||||
append_list_if(COMPILER_RT_HAS_FPIE_FLAG -fPIE DFSAN_CFLAGS)
|
||||
add_compiler_rt_runtime(clang_rt.dfsan
|
||||
STATIC
|
||||
ARCHS ${arch}
|
||||
SOURCES ${DFSAN_RTL_SOURCES}
|
||||
$<TARGET_OBJECTS:RTInterception.${arch}>
|
||||
$<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
|
||||
$<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
|
||||
ADDITIONAL_HEADERS ${DFSAN_RTL_HEADERS}
|
||||
CFLAGS ${DFSAN_CFLAGS}
|
||||
PARENT_TARGET dfsan)
|
||||
add_sanitizer_rt_symbols(clang_rt.dfsan
|
||||
ARCHS ${arch}
|
||||
EXTRA dfsan.syms.extra)
|
||||
add_dependencies(dfsan
|
||||
clang_rt.dfsan-${arch}-symbols)
|
||||
endforeach()
|
||||
|
||||
set(dfsan_abilist_dir ${COMPILER_RT_OUTPUT_DIR}/share)
|
||||
set(dfsan_abilist_filename ${dfsan_abilist_dir}/dfsan_abilist.txt)
|
||||
add_custom_target(dfsan_abilist ALL
|
||||
DEPENDS ${dfsan_abilist_filename})
|
||||
add_custom_command(OUTPUT ${dfsan_abilist_filename}
|
||||
VERBATIM
|
||||
COMMAND
|
||||
${CMAKE_COMMAND} -E make_directory ${dfsan_abilist_dir}
|
||||
COMMAND
|
||||
cat ${CMAKE_CURRENT_SOURCE_DIR}/done_abilist.txt
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/libc_ubuntu1404_abilist.txt
|
||||
> ${dfsan_abilist_filename}
|
||||
DEPENDS done_abilist.txt libc_ubuntu1404_abilist.txt)
|
||||
add_dependencies(dfsan dfsan_abilist)
|
||||
install(FILES ${dfsan_abilist_filename}
|
||||
DESTINATION ${COMPILER_RT_INSTALL_PATH}/share)
|
@ -1,96 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
#===- lib/dfsan/scripts/build-libc-list.py ---------------------------------===#
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
#===------------------------------------------------------------------------===#
|
||||
# The purpose of this script is to identify every function symbol in a set of
|
||||
# libraries (in this case, libc and libgcc) so that they can be marked as
|
||||
# uninstrumented, thus allowing the instrumentation pass to treat calls to those
|
||||
# functions correctly.
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
from optparse import OptionParser
|
||||
|
||||
def defined_function_list(object):
|
||||
functions = []
|
||||
readelf_proc = subprocess.Popen(['readelf', '-s', '-W', object],
|
||||
stdout=subprocess.PIPE)
|
||||
readelf = readelf_proc.communicate()[0].split('\n')
|
||||
if readelf_proc.returncode != 0:
|
||||
raise subprocess.CalledProcessError(readelf_proc.returncode, 'readelf')
|
||||
for line in readelf:
|
||||
if (line[31:35] == 'FUNC' or line[31:36] == 'IFUNC') and \
|
||||
line[39:44] != 'LOCAL' and \
|
||||
line[55:58] != 'UND':
|
||||
function_name = line[59:].split('@')[0]
|
||||
functions.append(function_name)
|
||||
return functions
|
||||
|
||||
p = OptionParser()
|
||||
|
||||
p.add_option('--libc-dso-path', metavar='PATH',
|
||||
help='path to libc DSO directory',
|
||||
default='/lib/x86_64-linux-gnu')
|
||||
p.add_option('--libc-archive-path', metavar='PATH',
|
||||
help='path to libc archive directory',
|
||||
default='/usr/lib/x86_64-linux-gnu')
|
||||
|
||||
p.add_option('--libgcc-dso-path', metavar='PATH',
|
||||
help='path to libgcc DSO directory',
|
||||
default='/lib/x86_64-linux-gnu')
|
||||
p.add_option('--libgcc-archive-path', metavar='PATH',
|
||||
help='path to libgcc archive directory',
|
||||
default='/usr/lib/gcc/x86_64-linux-gnu/4.6')
|
||||
|
||||
p.add_option('--with-libstdcxx', action='store_true',
|
||||
dest='with_libstdcxx',
|
||||
help='include libstdc++ in the list (inadvisable)')
|
||||
p.add_option('--libstdcxx-dso-path', metavar='PATH',
|
||||
help='path to libstdc++ DSO directory',
|
||||
default='/usr/lib/x86_64-linux-gnu')
|
||||
|
||||
(options, args) = p.parse_args()
|
||||
|
||||
libs = [os.path.join(options.libc_dso_path, name) for name in
|
||||
['ld-linux-x86-64.so.2',
|
||||
'libanl.so.1',
|
||||
'libBrokenLocale.so.1',
|
||||
'libcidn.so.1',
|
||||
'libcrypt.so.1',
|
||||
'libc.so.6',
|
||||
'libdl.so.2',
|
||||
'libm.so.6',
|
||||
'libnsl.so.1',
|
||||
'libpthread.so.0',
|
||||
'libresolv.so.2',
|
||||
'librt.so.1',
|
||||
'libthread_db.so.1',
|
||||
'libutil.so.1']]
|
||||
libs += [os.path.join(options.libc_archive_path, name) for name in
|
||||
['libc_nonshared.a',
|
||||
'libpthread_nonshared.a']]
|
||||
|
||||
libs.append(os.path.join(options.libgcc_dso_path, 'libgcc_s.so.1'))
|
||||
libs.append(os.path.join(options.libgcc_archive_path, 'libgcc.a'))
|
||||
|
||||
if options.with_libstdcxx:
|
||||
libs.append(os.path.join(options.libstdcxx_dso_path, 'libstdc++.so.6'))
|
||||
|
||||
functions = []
|
||||
for l in libs:
|
||||
if os.path.exists(l):
|
||||
functions += defined_function_list(l)
|
||||
else:
|
||||
print >> sys.stderr, 'warning: library %s not found' % l
|
||||
|
||||
functions = list(set(functions))
|
||||
functions.sort()
|
||||
|
||||
for f in functions:
|
||||
print 'fun:%s=uninstrumented' % f
|
@ -1,54 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
DFSAN_DIR=$(dirname "$0")/../
|
||||
DFSAN_CUSTOM_TESTS=${DFSAN_DIR}/../../test/dfsan/custom.cc
|
||||
DFSAN_CUSTOM_WRAPPERS=${DFSAN_DIR}/dfsan_custom.cc
|
||||
DFSAN_ABI_LIST=${DFSAN_DIR}/done_abilist.txt
|
||||
|
||||
DIFFOUT=$(mktemp -q /tmp/tmp.XXXXXXXXXX)
|
||||
ERRORLOG=$(mktemp -q /tmp/tmp.XXXXXXXXXX)
|
||||
DIFF_A=$(mktemp -q /tmp/tmp.XXXXXXXXXX)
|
||||
DIFF_B=$(mktemp -q /tmp/tmp.XXXXXXXXXX)
|
||||
|
||||
on_exit() {
|
||||
rm -f ${DIFFOUT} 2> /dev/null
|
||||
rm -f ${ERRORLOG} 2> /dev/null
|
||||
rm -f ${DIFF_A} 2> /dev/null
|
||||
rm -f ${DIFF_B} 2> /dev/null
|
||||
}
|
||||
|
||||
# Ignore __sanitizer_cov_trace* because they are implemented elsewhere.
|
||||
trap on_exit EXIT
|
||||
grep -E "^fun:.*=custom" ${DFSAN_ABI_LIST} \
|
||||
| grep -v "dfsan_get_label\|__sanitizer_cov_trace" \
|
||||
| sed "s/^fun:\(.*\)=custom.*/\1/" | sort > $DIFF_A
|
||||
grep -E "__dfsw.*\(" ${DFSAN_CUSTOM_WRAPPERS} \
|
||||
| grep -v "__sanitizer_cov_trace" \
|
||||
| sed "s/.*__dfsw_\(.*\)(.*/\1/" | sort > $DIFF_B
|
||||
diff -u $DIFF_A $DIFF_B > ${DIFFOUT}
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
echo -n "The following differences between the ABI list and ">> ${ERRORLOG}
|
||||
echo "the implemented custom wrappers have been found:" >> ${ERRORLOG}
|
||||
cat ${DIFFOUT} >> ${ERRORLOG}
|
||||
fi
|
||||
|
||||
grep -E __dfsw_ ${DFSAN_CUSTOM_WRAPPERS} \
|
||||
| grep -v "__sanitizer_cov_trace" \
|
||||
| sed "s/.*__dfsw_\([^(]*\).*/\1/" | sort > $DIFF_A
|
||||
grep -E "^[[:space:]]*test_.*\(\);" ${DFSAN_CUSTOM_TESTS} \
|
||||
| sed "s/.*test_\(.*\)();/\1/" | sort > $DIFF_B
|
||||
diff -u $DIFF_A $DIFF_B > ${DIFFOUT}
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
echo -n "The following differences between the implemented " >> ${ERRORLOG}
|
||||
echo "custom wrappers and the tests have been found:" >> ${ERRORLOG}
|
||||
cat ${DIFFOUT} >> ${ERRORLOG}
|
||||
fi
|
||||
|
||||
if [ -s ${ERRORLOG} ]
|
||||
then
|
||||
cat ${ERRORLOG}
|
||||
exit 1
|
||||
fi
|
||||
|
@ -1,55 +0,0 @@
|
||||
# Build for the EfficiencySanitizer runtime support library.
|
||||
|
||||
add_compiler_rt_component(esan)
|
||||
|
||||
set(ESAN_RTL_CFLAGS ${SANITIZER_COMMON_CFLAGS})
|
||||
append_rtti_flag(OFF ESAN_RTL_CFLAGS)
|
||||
|
||||
include_directories(..)
|
||||
|
||||
set(ESAN_SOURCES
|
||||
esan.cpp
|
||||
esan_flags.cpp
|
||||
esan_interface.cpp
|
||||
esan_interceptors.cpp
|
||||
esan_linux.cpp
|
||||
esan_sideline_linux.cpp
|
||||
esan_sideline_bsd.cpp
|
||||
cache_frag.cpp
|
||||
working_set.cpp
|
||||
working_set_posix.cpp)
|
||||
|
||||
set(ESAN_HEADERS
|
||||
cache_frag.h
|
||||
esan.h
|
||||
esan_circular_buffer.h
|
||||
esan_flags.h
|
||||
esan_flags.inc
|
||||
esan_hashtable.h
|
||||
esan_interface_internal.h
|
||||
esan_shadow.h
|
||||
esan_sideline.h
|
||||
working_set.h)
|
||||
|
||||
foreach (arch ${ESAN_SUPPORTED_ARCH})
|
||||
add_compiler_rt_runtime(clang_rt.esan
|
||||
STATIC
|
||||
ARCHS ${arch}
|
||||
SOURCES ${ESAN_SOURCES}
|
||||
$<TARGET_OBJECTS:RTInterception.${arch}>
|
||||
$<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
|
||||
$<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
|
||||
$<TARGET_OBJECTS:RTSanitizerCommonSymbolizer.${arch}>
|
||||
ADDITIONAL_HEADERS ${ESAN_HEADERS}
|
||||
CFLAGS ${ESAN_RTL_CFLAGS})
|
||||
add_sanitizer_rt_symbols(clang_rt.esan
|
||||
ARCHS ${arch}
|
||||
EXTRA esan.syms.extra)
|
||||
add_dependencies(esan
|
||||
clang_rt.esan-${arch}
|
||||
clang_rt.esan-${arch}-symbols)
|
||||
endforeach()
|
||||
|
||||
if (COMPILER_RT_INCLUDE_TESTS)
|
||||
# TODO(bruening): add tests via add_subdirectory(tests)
|
||||
endif()
|
@ -1,147 +0,0 @@
|
||||
set(LIBFUZZER_SOURCES
|
||||
FuzzerCrossOver.cpp
|
||||
FuzzerDataFlowTrace.cpp
|
||||
FuzzerDriver.cpp
|
||||
FuzzerExtFunctionsDlsym.cpp
|
||||
FuzzerExtFunctionsWeak.cpp
|
||||
FuzzerExtFunctionsWindows.cpp
|
||||
FuzzerExtraCounters.cpp
|
||||
FuzzerIO.cpp
|
||||
FuzzerIOPosix.cpp
|
||||
FuzzerIOWindows.cpp
|
||||
FuzzerLoop.cpp
|
||||
FuzzerMerge.cpp
|
||||
FuzzerMutate.cpp
|
||||
FuzzerSHA1.cpp
|
||||
FuzzerShmemFuchsia.cpp
|
||||
FuzzerShmemPosix.cpp
|
||||
FuzzerShmemWindows.cpp
|
||||
FuzzerTracePC.cpp
|
||||
FuzzerUtil.cpp
|
||||
FuzzerUtilDarwin.cpp
|
||||
FuzzerUtilFuchsia.cpp
|
||||
FuzzerUtilLinux.cpp
|
||||
FuzzerUtilPosix.cpp
|
||||
FuzzerUtilWindows.cpp)
|
||||
|
||||
set(LIBFUZZER_HEADERS
|
||||
FuzzerBuiltins.h
|
||||
FuzzerBuiltinsMsvc.h
|
||||
FuzzerCommand.h
|
||||
FuzzerCorpus.h
|
||||
FuzzerDataFlowTrace.h
|
||||
FuzzerDefs.h
|
||||
FuzzerDictionary.h
|
||||
FuzzerExtFunctions.def
|
||||
FuzzerExtFunctions.h
|
||||
FuzzerFlags.def
|
||||
FuzzerIO.h
|
||||
FuzzerInterface.h
|
||||
FuzzerInternal.h
|
||||
FuzzerMerge.h
|
||||
FuzzerMutate.h
|
||||
FuzzerOptions.h
|
||||
FuzzerRandom.h
|
||||
FuzzerSHA1.h
|
||||
FuzzerShmem.h
|
||||
FuzzerTracePC.h
|
||||
FuzzerUtil.h
|
||||
FuzzerValueBitMap.h)
|
||||
|
||||
CHECK_CXX_SOURCE_COMPILES("
|
||||
static thread_local int blah;
|
||||
int main() {
|
||||
return 0;
|
||||
}
|
||||
" HAS_THREAD_LOCAL)
|
||||
|
||||
set(LIBFUZZER_CFLAGS ${SANITIZER_COMMON_CFLAGS})
|
||||
|
||||
if(OS_NAME MATCHES "Linux|Fuchsia" AND COMPILER_RT_LIBCXX_PATH)
|
||||
list(APPEND LIBFUZZER_CFLAGS -nostdinc++ -D_LIBCPP_ABI_VERSION=Fuzzer)
|
||||
# Remove -stdlib= which is unused when passing -nostdinc++.
|
||||
string(REGEX REPLACE "-stdlib=[a-zA-Z+]*" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
|
||||
elseif(TARGET cxx-headers OR HAVE_LIBCXX)
|
||||
set(LIBFUZZER_DEPS cxx-headers)
|
||||
endif()
|
||||
|
||||
append_list_if(COMPILER_RT_HAS_OMIT_FRAME_POINTER_FLAG -fno-omit-frame-pointer LIBFUZZER_CFLAGS)
|
||||
|
||||
if (CMAKE_CXX_FLAGS MATCHES "fsanitize-coverage")
|
||||
list(APPEND LIBFUZZER_CFLAGS -fno-sanitize-coverage=trace-pc-guard,edge,trace-cmp,indirect-calls,8bit-counters)
|
||||
endif()
|
||||
|
||||
if(NOT HAS_THREAD_LOCAL)
|
||||
list(APPEND LIBFUZZER_CFLAGS -Dthread_local=__thread)
|
||||
endif()
|
||||
|
||||
set(FUZZER_SUPPORTED_OS ${SANITIZER_COMMON_SUPPORTED_OS})
|
||||
|
||||
add_compiler_rt_object_libraries(RTfuzzer
|
||||
OS ${FUZZER_SUPPORTED_OS}
|
||||
ARCHS ${FUZZER_SUPPORTED_ARCH}
|
||||
SOURCES ${LIBFUZZER_SOURCES}
|
||||
ADDITIONAL_HEADERS ${LIBFUZZER_HEADERS}
|
||||
CFLAGS ${LIBFUZZER_CFLAGS}
|
||||
DEPS ${LIBFUZZER_DEPS})
|
||||
|
||||
add_compiler_rt_object_libraries(RTfuzzer_main
|
||||
OS ${FUZZER_SUPPORTED_OS}
|
||||
ARCHS ${FUZZER_SUPPORTED_ARCH}
|
||||
SOURCES FuzzerMain.cpp
|
||||
CFLAGS ${LIBFUZZER_CFLAGS}
|
||||
DEPS ${LIBFUZZER_DEPS})
|
||||
|
||||
add_compiler_rt_runtime(clang_rt.fuzzer
|
||||
STATIC
|
||||
OS ${FUZZER_SUPPORTED_OS}
|
||||
ARCHS ${FUZZER_SUPPORTED_ARCH}
|
||||
OBJECT_LIBS RTfuzzer RTfuzzer_main
|
||||
CFLAGS ${LIBFUZZER_CFLAGS}
|
||||
PARENT_TARGET fuzzer)
|
||||
|
||||
add_compiler_rt_runtime(clang_rt.fuzzer_no_main
|
||||
STATIC
|
||||
OS ${FUZZER_SUPPORTED_OS}
|
||||
ARCHS ${FUZZER_SUPPORTED_ARCH}
|
||||
OBJECT_LIBS RTfuzzer
|
||||
CFLAGS ${LIBFUZZER_CFLAGS}
|
||||
PARENT_TARGET fuzzer)
|
||||
|
||||
if(OS_NAME MATCHES "Linux|Fuchsia" AND COMPILER_RT_LIBCXX_PATH)
|
||||
macro(partially_link_libcxx name dir arch)
|
||||
set(cxx_${arch}_merge_dir "${CMAKE_CURRENT_BINARY_DIR}/cxx_${arch}_merge.dir")
|
||||
file(MAKE_DIRECTORY ${cxx_${arch}_merge_dir})
|
||||
add_custom_command(TARGET clang_rt.${name}-${arch} POST_BUILD
|
||||
COMMAND ${CMAKE_LINKER} --whole-archive "$<TARGET_LINKER_FILE:clang_rt.${name}-${arch}>" --no-whole-archive ${dir}/lib/libc++.a -r -o ${name}.o
|
||||
COMMAND ${CMAKE_OBJCOPY} --localize-hidden ${name}.o
|
||||
COMMAND ${CMAKE_COMMAND} -E remove "$<TARGET_LINKER_FILE:clang_rt.${name}-${arch}>"
|
||||
COMMAND ${CMAKE_AR} qcs "$<TARGET_LINKER_FILE:clang_rt.${name}-${arch}>" ${name}.o
|
||||
WORKING_DIRECTORY ${cxx_${arch}_merge_dir}
|
||||
)
|
||||
endmacro()
|
||||
|
||||
foreach(arch ${FUZZER_SUPPORTED_ARCH})
|
||||
get_target_flags_for_arch(${arch} TARGET_CFLAGS)
|
||||
set(LIBCXX_${arch}_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/libcxx_fuzzer_${arch})
|
||||
add_custom_libcxx(libcxx_fuzzer_${arch} ${LIBCXX_${arch}_PREFIX}
|
||||
CFLAGS ${TARGET_CFLAGS}
|
||||
-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS=1
|
||||
-fvisibility=hidden
|
||||
CMAKE_ARGS -DCMAKE_CXX_COMPILER_WORKS=ON
|
||||
-DLIBCXX_ENABLE_EXCEPTIONS=OFF
|
||||
-DLIBCXX_ENABLE_SHARED=OFF
|
||||
-DLIBCXX_ABI_NAMESPACE=Fuzzer
|
||||
-DLIBCXX_CXX_ABI=none)
|
||||
target_compile_options(RTfuzzer.${arch} PRIVATE -isystem ${LIBCXX_${arch}_PREFIX}/include/c++/v1)
|
||||
add_dependencies(RTfuzzer.${arch} libcxx_fuzzer_${arch}-build)
|
||||
target_compile_options(RTfuzzer_main.${arch} PRIVATE -isystem ${LIBCXX_${arch}_PREFIX}/include/c++/v1)
|
||||
add_dependencies(RTfuzzer_main.${arch} libcxx_fuzzer_${arch}-build)
|
||||
partially_link_libcxx(fuzzer_no_main ${LIBCXX_${arch}_PREFIX} ${arch})
|
||||
partially_link_libcxx(fuzzer ${LIBCXX_${arch}_PREFIX} ${arch})
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if(COMPILER_RT_INCLUDE_TESTS)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
@ -1,378 +0,0 @@
|
||||
//===- afl_driver.cpp - a glue between AFL and libFuzzer --------*- C++ -* ===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/* This file allows to fuzz libFuzzer-style target functions
|
||||
(LLVMFuzzerTestOneInput) with AFL using AFL's persistent (in-process) mode.
|
||||
|
||||
Usage:
|
||||
################################################################################
|
||||
cat << EOF > test_fuzzer.cc
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||
if (size > 0 && data[0] == 'H')
|
||||
if (size > 1 && data[1] == 'I')
|
||||
if (size > 2 && data[2] == '!')
|
||||
__builtin_trap();
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
# Build your target with -fsanitize-coverage=trace-pc-guard using fresh clang.
|
||||
clang -g -fsanitize-coverage=trace-pc-guard test_fuzzer.cc -c
|
||||
# Build afl-llvm-rt.o.c from the AFL distribution.
|
||||
clang -c -w $AFL_HOME/llvm_mode/afl-llvm-rt.o.c
|
||||
# Build this file, link it with afl-llvm-rt.o.o and the target code.
|
||||
clang++ afl_driver.cpp test_fuzzer.o afl-llvm-rt.o.o
|
||||
# Run AFL:
|
||||
rm -rf IN OUT; mkdir IN OUT; echo z > IN/z;
|
||||
$AFL_HOME/afl-fuzz -i IN -o OUT ./a.out
|
||||
################################################################################
|
||||
Environment Variables:
|
||||
There are a few environment variables that can be set to use features that
|
||||
afl-fuzz doesn't have.
|
||||
|
||||
AFL_DRIVER_STDERR_DUPLICATE_FILENAME: Setting this *appends* stderr to the file
|
||||
specified. If the file does not exist, it is created. This is useful for getting
|
||||
stack traces (when using ASAN for example) or original error messages on hard to
|
||||
reproduce bugs.
|
||||
|
||||
AFL_DRIVER_EXTRA_STATS_FILENAME: Setting this causes afl_driver to write extra
|
||||
statistics to the file specified. Currently these are peak_rss_mb
|
||||
(the peak amount of virtual memory used in MB) and slowest_unit_time_secs. If
|
||||
the file does not exist it is created. If the file does exist then
|
||||
afl_driver assumes it was restarted by afl-fuzz and will try to read old
|
||||
statistics from the file. If that fails then the process will quit.
|
||||
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
// Platform detection. Copied from FuzzerInternal.h
|
||||
#ifdef __linux__
|
||||
#define LIBFUZZER_LINUX 1
|
||||
#define LIBFUZZER_APPLE 0
|
||||
#define LIBFUZZER_NETBSD 0
|
||||
#define LIBFUZZER_FREEBSD 0
|
||||
#define LIBFUZZER_OPENBSD 0
|
||||
#elif __APPLE__
|
||||
#define LIBFUZZER_LINUX 0
|
||||
#define LIBFUZZER_APPLE 1
|
||||
#define LIBFUZZER_NETBSD 0
|
||||
#define LIBFUZZER_FREEBSD 0
|
||||
#define LIBFUZZER_OPENBSD 0
|
||||
#elif __NetBSD__
|
||||
#define LIBFUZZER_LINUX 0
|
||||
#define LIBFUZZER_APPLE 0
|
||||
#define LIBFUZZER_NETBSD 1
|
||||
#define LIBFUZZER_FREEBSD 0
|
||||
#define LIBFUZZER_OPENBSD 0
|
||||
#elif __FreeBSD__
|
||||
#define LIBFUZZER_LINUX 0
|
||||
#define LIBFUZZER_APPLE 0
|
||||
#define LIBFUZZER_NETBSD 0
|
||||
#define LIBFUZZER_FREEBSD 1
|
||||
#define LIBFUZZER_OPENBSD 0
|
||||
#elif __OpenBSD__
|
||||
#define LIBFUZZER_LINUX 0
|
||||
#define LIBFUZZER_APPLE 0
|
||||
#define LIBFUZZER_NETBSD 0
|
||||
#define LIBFUZZER_FREEBSD 0
|
||||
#define LIBFUZZER_OPENBSD 1
|
||||
#else
|
||||
#error "Support for your platform has not been implemented"
|
||||
#endif
|
||||
|
||||
// Used to avoid repeating error checking boilerplate. If cond is false, a
|
||||
// fatal error has occurred in the program. In this event print error_message
|
||||
// to stderr and abort(). Otherwise do nothing. Note that setting
|
||||
// AFL_DRIVER_STDERR_DUPLICATE_FILENAME may cause error_message to be appended
|
||||
// to the file as well, if the error occurs after the duplication is performed.
|
||||
#define CHECK_ERROR(cond, error_message) \
|
||||
if (!(cond)) { \
|
||||
fprintf(stderr, "%s\n", (error_message)); \
|
||||
abort(); \
|
||||
}
|
||||
|
||||
// libFuzzer interface is thin, so we don't include any libFuzzer headers.
|
||||
extern "C" {
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
|
||||
__attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv);
|
||||
}
|
||||
|
||||
// Notify AFL about persistent mode.
|
||||
static volatile char AFL_PERSISTENT[] = "##SIG_AFL_PERSISTENT##";
|
||||
extern "C" int __afl_persistent_loop(unsigned int);
|
||||
static volatile char suppress_warning2 = AFL_PERSISTENT[0];
|
||||
|
||||
// Notify AFL about deferred forkserver.
|
||||
static volatile char AFL_DEFER_FORKSVR[] = "##SIG_AFL_DEFER_FORKSRV##";
|
||||
extern "C" void __afl_manual_init();
|
||||
static volatile char suppress_warning1 = AFL_DEFER_FORKSVR[0];
|
||||
|
||||
// Input buffer.
|
||||
static const size_t kMaxAflInputSize = 1 << 20;
|
||||
static uint8_t AflInputBuf[kMaxAflInputSize];
|
||||
|
||||
// Variables we need for writing to the extra stats file.
|
||||
static FILE *extra_stats_file = NULL;
|
||||
static uint32_t previous_peak_rss = 0;
|
||||
static time_t slowest_unit_time_secs = 0;
|
||||
static const int kNumExtraStats = 2;
|
||||
static const char *kExtraStatsFormatString = "peak_rss_mb : %u\n"
|
||||
"slowest_unit_time_sec : %u\n";
|
||||
|
||||
// Experimental feature to use afl_driver without AFL's deferred mode.
|
||||
// Needs to run before __afl_auto_init.
|
||||
__attribute__((constructor(0))) void __decide_deferred_forkserver(void) {
|
||||
if (getenv("AFL_DRIVER_DONT_DEFER")) {
|
||||
if (unsetenv("__AFL_DEFER_FORKSRV")) {
|
||||
perror("Failed to unset __AFL_DEFER_FORKSRV");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Copied from FuzzerUtil.cpp.
|
||||
size_t GetPeakRSSMb() {
|
||||
struct rusage usage;
|
||||
if (getrusage(RUSAGE_SELF, &usage))
|
||||
return 0;
|
||||
if (LIBFUZZER_LINUX || LIBFUZZER_NETBSD || LIBFUZZER_FREEBSD ||
|
||||
LIBFUZZER_OPENBSD) {
|
||||
// ru_maxrss is in KiB
|
||||
return usage.ru_maxrss >> 10;
|
||||
} else if (LIBFUZZER_APPLE) {
|
||||
// ru_maxrss is in bytes
|
||||
return usage.ru_maxrss >> 20;
|
||||
}
|
||||
assert(0 && "GetPeakRSSMb() is not implemented for your platform");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Based on SetSigaction in FuzzerUtil.cpp
|
||||
static void SetSigaction(int signum,
|
||||
void (*callback)(int, siginfo_t *, void *)) {
|
||||
struct sigaction sigact;
|
||||
memset(&sigact, 0, sizeof(sigact));
|
||||
sigact.sa_sigaction = callback;
|
||||
if (sigaction(signum, &sigact, 0)) {
|
||||
fprintf(stderr, "libFuzzer: sigaction failed with %d\n", errno);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Write extra stats to the file specified by the user. If none is specified
|
||||
// this function will never be called.
|
||||
static void write_extra_stats() {
|
||||
uint32_t peak_rss = GetPeakRSSMb();
|
||||
|
||||
if (peak_rss < previous_peak_rss)
|
||||
peak_rss = previous_peak_rss;
|
||||
|
||||
int chars_printed = fprintf(extra_stats_file, kExtraStatsFormatString,
|
||||
peak_rss, slowest_unit_time_secs);
|
||||
|
||||
CHECK_ERROR(chars_printed != 0, "Failed to write extra_stats_file");
|
||||
|
||||
CHECK_ERROR(fclose(extra_stats_file) == 0,
|
||||
"Failed to close extra_stats_file");
|
||||
}
|
||||
|
||||
// Call write_extra_stats before we exit.
|
||||
static void crash_handler(int, siginfo_t *, void *) {
|
||||
// Make sure we don't try calling write_extra_stats again if we crashed while
|
||||
// trying to call it.
|
||||
static bool first_crash = true;
|
||||
CHECK_ERROR(first_crash,
|
||||
"Crashed in crash signal handler. This is a bug in the fuzzer.");
|
||||
|
||||
first_crash = false;
|
||||
write_extra_stats();
|
||||
}
|
||||
|
||||
// If the user has specified an extra_stats_file through the environment
|
||||
// variable AFL_DRIVER_EXTRA_STATS_FILENAME, then perform necessary set up
|
||||
// to write stats to it on exit. If no file is specified, do nothing. Otherwise
|
||||
// install signal and exit handlers to write to the file when the process exits.
|
||||
// Then if the file doesn't exist create it and set extra stats to 0. But if it
|
||||
// does exist then read the initial values of the extra stats from the file
|
||||
// and check that the file is writable.
|
||||
static void maybe_initialize_extra_stats() {
|
||||
// If AFL_DRIVER_EXTRA_STATS_FILENAME isn't set then we have nothing to do.
|
||||
char *extra_stats_filename = getenv("AFL_DRIVER_EXTRA_STATS_FILENAME");
|
||||
if (!extra_stats_filename)
|
||||
return;
|
||||
|
||||
// Open the file and find the previous peak_rss_mb value.
|
||||
// This is necessary because the fuzzing process is restarted after N
|
||||
// iterations are completed. So we may need to get this value from a previous
|
||||
// process to be accurate.
|
||||
extra_stats_file = fopen(extra_stats_filename, "r");
|
||||
|
||||
// If extra_stats_file already exists: read old stats from it.
|
||||
if (extra_stats_file) {
|
||||
int matches = fscanf(extra_stats_file, kExtraStatsFormatString,
|
||||
&previous_peak_rss, &slowest_unit_time_secs);
|
||||
|
||||
// Make sure we have read a real extra stats file and that we have used it
|
||||
// to set slowest_unit_time_secs and previous_peak_rss.
|
||||
CHECK_ERROR(matches == kNumExtraStats, "Extra stats file is corrupt");
|
||||
|
||||
CHECK_ERROR(fclose(extra_stats_file) == 0, "Failed to close file");
|
||||
|
||||
// Now open the file for writing.
|
||||
extra_stats_file = fopen(extra_stats_filename, "w");
|
||||
CHECK_ERROR(extra_stats_file,
|
||||
"Failed to open extra stats file for writing");
|
||||
} else {
|
||||
// Looks like this is the first time in a fuzzing job this is being called.
|
||||
extra_stats_file = fopen(extra_stats_filename, "w+");
|
||||
CHECK_ERROR(extra_stats_file, "failed to create extra stats file");
|
||||
}
|
||||
|
||||
// Make sure that crash_handler gets called on any kind of fatal error.
|
||||
int crash_signals[] = {SIGSEGV, SIGBUS, SIGABRT, SIGILL, SIGFPE, SIGINT,
|
||||
SIGTERM};
|
||||
|
||||
const size_t num_signals = sizeof(crash_signals) / sizeof(crash_signals[0]);
|
||||
|
||||
for (size_t idx = 0; idx < num_signals; idx++)
|
||||
SetSigaction(crash_signals[idx], crash_handler);
|
||||
|
||||
// Make sure it gets called on other kinds of exits.
|
||||
atexit(write_extra_stats);
|
||||
}
|
||||
|
||||
// If the user asks us to duplicate stderr, then do it.
|
||||
static void maybe_duplicate_stderr() {
|
||||
char* stderr_duplicate_filename =
|
||||
getenv("AFL_DRIVER_STDERR_DUPLICATE_FILENAME");
|
||||
|
||||
if (!stderr_duplicate_filename)
|
||||
return;
|
||||
|
||||
FILE* stderr_duplicate_stream =
|
||||
freopen(stderr_duplicate_filename, "a+", stderr);
|
||||
|
||||
if (!stderr_duplicate_stream) {
|
||||
fprintf(
|
||||
stderr,
|
||||
"Failed to duplicate stderr to AFL_DRIVER_STDERR_DUPLICATE_FILENAME");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
// Define LLVMFuzzerMutate to avoid link failures for targets that use it
|
||||
// with libFuzzer's LLVMFuzzerCustomMutator.
|
||||
extern "C" size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) {
|
||||
assert(false && "LLVMFuzzerMutate should not be called from afl_driver");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Execute any files provided as parameters.
|
||||
int ExecuteFilesOnyByOne(int argc, char **argv) {
|
||||
for (int i = 1; i < argc; i++) {
|
||||
std::ifstream in(argv[i], std::ios::binary);
|
||||
in.seekg(0, in.end);
|
||||
size_t length = in.tellg();
|
||||
in.seekg (0, in.beg);
|
||||
std::cout << "Reading " << length << " bytes from " << argv[i] << std::endl;
|
||||
// Allocate exactly length bytes so that we reliably catch buffer overflows.
|
||||
std::vector<char> bytes(length);
|
||||
in.read(bytes.data(), bytes.size());
|
||||
assert(in);
|
||||
LLVMFuzzerTestOneInput(reinterpret_cast<const uint8_t *>(bytes.data()),
|
||||
bytes.size());
|
||||
std::cout << "Execution successful" << std::endl;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
fprintf(stderr,
|
||||
"======================= INFO =========================\n"
|
||||
"This binary is built for AFL-fuzz.\n"
|
||||
"To run the target function on individual input(s) execute this:\n"
|
||||
" %s < INPUT_FILE\n"
|
||||
"or\n"
|
||||
" %s INPUT_FILE1 [INPUT_FILE2 ... ]\n"
|
||||
"To fuzz with afl-fuzz execute this:\n"
|
||||
" afl-fuzz [afl-flags] %s [-N]\n"
|
||||
"afl-fuzz will run N iterations before "
|
||||
"re-spawning the process (default: 1000)\n"
|
||||
"======================================================\n",
|
||||
argv[0], argv[0], argv[0]);
|
||||
if (LLVMFuzzerInitialize)
|
||||
LLVMFuzzerInitialize(&argc, &argv);
|
||||
// Do any other expensive one-time initialization here.
|
||||
|
||||
maybe_duplicate_stderr();
|
||||
maybe_initialize_extra_stats();
|
||||
|
||||
if (!getenv("AFL_DRIVER_DONT_DEFER"))
|
||||
__afl_manual_init();
|
||||
|
||||
int N = 1000;
|
||||
if (argc == 2 && argv[1][0] == '-')
|
||||
N = atoi(argv[1] + 1);
|
||||
else if(argc == 2 && (N = atoi(argv[1])) > 0)
|
||||
fprintf(stderr, "WARNING: using the deprecated call style `%s %d`\n",
|
||||
argv[0], N);
|
||||
else if (argc > 1)
|
||||
return ExecuteFilesOnyByOne(argc, argv);
|
||||
|
||||
assert(N > 0);
|
||||
|
||||
// Call LLVMFuzzerTestOneInput here so that coverage caused by initialization
|
||||
// on the first execution of LLVMFuzzerTestOneInput is ignored.
|
||||
uint8_t dummy_input[1] = {0};
|
||||
LLVMFuzzerTestOneInput(dummy_input, 1);
|
||||
|
||||
time_t unit_time_secs;
|
||||
int num_runs = 0;
|
||||
while (__afl_persistent_loop(N)) {
|
||||
ssize_t n_read = read(0, AflInputBuf, kMaxAflInputSize);
|
||||
if (n_read > 0) {
|
||||
// Copy AflInputBuf into a separate buffer to let asan find buffer
|
||||
// overflows. Don't use unique_ptr/etc to avoid extra dependencies.
|
||||
uint8_t *copy = new uint8_t[n_read];
|
||||
memcpy(copy, AflInputBuf, n_read);
|
||||
|
||||
struct timeval unit_start_time;
|
||||
CHECK_ERROR(gettimeofday(&unit_start_time, NULL) == 0,
|
||||
"Calling gettimeofday failed");
|
||||
|
||||
num_runs++;
|
||||
LLVMFuzzerTestOneInput(copy, n_read);
|
||||
|
||||
struct timeval unit_stop_time;
|
||||
CHECK_ERROR(gettimeofday(&unit_stop_time, NULL) == 0,
|
||||
"Calling gettimeofday failed");
|
||||
|
||||
// Update slowest_unit_time_secs if we see a new max.
|
||||
unit_time_secs = unit_stop_time.tv_sec - unit_start_time.tv_sec;
|
||||
if (slowest_unit_time_secs < unit_time_secs)
|
||||
slowest_unit_time_secs = unit_time_secs;
|
||||
|
||||
delete[] copy;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "%s: successfully executed %d input(s)\n", argv[0], num_runs);
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
#!/bin/sh
|
||||
LIBFUZZER_SRC_DIR=$(dirname $0)
|
||||
CXX="${CXX:-clang}"
|
||||
for f in $LIBFUZZER_SRC_DIR/*.cpp; do
|
||||
$CXX -g -O2 -fno-omit-frame-pointer -std=c++11 $f -c &
|
||||
done
|
||||
wait
|
||||
rm -f libFuzzer.a
|
||||
ar ru libFuzzer.a Fuzzer*.o
|
||||
rm -f Fuzzer*.o
|
||||
|
@ -1,217 +0,0 @@
|
||||
/*===- DataFlow.cpp - a standalone DataFlow tracer -------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// An experimental data-flow tracer for fuzz targets.
|
||||
// It is based on DFSan and SanitizerCoverage.
|
||||
// https://clang.llvm.org/docs/DataFlowSanitizer.html
|
||||
// https://clang.llvm.org/docs/SanitizerCoverage.html#tracing-data-flow
|
||||
//
|
||||
// It executes the fuzz target on the given input while monitoring the
|
||||
// data flow for every instrumented comparison instruction.
|
||||
//
|
||||
// The output shows which functions depend on which bytes of the input.
|
||||
//
|
||||
// Build:
|
||||
// 1. Compile this file with -fsanitize=dataflow
|
||||
// 2. Build the fuzz target with -g -fsanitize=dataflow
|
||||
// -fsanitize-coverage=trace-pc-guard,pc-table,func,trace-cmp
|
||||
// 3. Link those together with -fsanitize=dataflow
|
||||
//
|
||||
// -fsanitize-coverage=trace-cmp inserts callbacks around every comparison
|
||||
// instruction, DFSan modifies the calls to pass the data flow labels.
|
||||
// The callbacks update the data flow label for the current function.
|
||||
// See e.g. __dfsw___sanitizer_cov_trace_cmp1 below.
|
||||
//
|
||||
// -fsanitize-coverage=trace-pc-guard,pc-table,func instruments function
|
||||
// entries so that the comparison callback knows that current function.
|
||||
//
|
||||
//
|
||||
// Run:
|
||||
// # Collect data flow for INPUT_FILE, write to OUTPUT_FILE (default: stdout)
|
||||
// ./a.out INPUT_FILE [OUTPUT_FILE]
|
||||
//
|
||||
// # Print all instrumented functions. llvm-symbolizer must be present in PATH
|
||||
// ./a.out
|
||||
//
|
||||
// Example output:
|
||||
// ===============
|
||||
// F0 11111111111111
|
||||
// F1 10000000000000
|
||||
// ===============
|
||||
// "FN xxxxxxxxxx": tells what bytes of the input does the function N depend on.
|
||||
// The byte string is LEN+1 bytes. The last byte is set if the function
|
||||
// depends on the input length.
|
||||
//===----------------------------------------------------------------------===*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <execinfo.h> // backtrace_symbols_fd
|
||||
|
||||
#include <sanitizer/dfsan_interface.h>
|
||||
|
||||
extern "C" {
|
||||
extern int LLVMFuzzerTestOneInput(const unsigned char *Data, size_t Size);
|
||||
__attribute__((weak)) extern int LLVMFuzzerInitialize(int *argc, char ***argv);
|
||||
} // extern "C"
|
||||
|
||||
static size_t InputLen;
|
||||
static size_t NumFuncs;
|
||||
static const uintptr_t *FuncsBeg;
|
||||
static __thread size_t CurrentFunc;
|
||||
static dfsan_label *FuncLabels; // Array of NumFuncs elements.
|
||||
static char *PrintableStringForLabel; // InputLen + 2 bytes.
|
||||
static bool LabelSeen[1 << 8 * sizeof(dfsan_label)];
|
||||
|
||||
// Prints all instrumented functions.
|
||||
static int PrintFunctions() {
|
||||
// We don't have the symbolizer integrated with dfsan yet.
|
||||
// So use backtrace_symbols_fd and pipe it through llvm-symbolizer.
|
||||
// TODO(kcc): this is pretty ugly and may break in lots of ways.
|
||||
// We'll need to make a proper in-process symbolizer work with DFSan.
|
||||
FILE *Pipe = popen("sed 's/(+/ /g; s/).*//g' "
|
||||
"| llvm-symbolizer "
|
||||
"| grep 'dfs\\$' "
|
||||
"| sed 's/dfs\\$//g'", "w");
|
||||
for (size_t I = 0; I < NumFuncs; I++) {
|
||||
uintptr_t PC = FuncsBeg[I * 2];
|
||||
void *const Buf[1] = {(void*)PC};
|
||||
backtrace_symbols_fd(Buf, 1, fileno(Pipe));
|
||||
}
|
||||
pclose(Pipe);
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
void SetBytesForLabel(dfsan_label L, char *Bytes) {
|
||||
if (LabelSeen[L])
|
||||
return;
|
||||
LabelSeen[L] = true;
|
||||
assert(L);
|
||||
if (L <= InputLen + 1) {
|
||||
Bytes[L - 1] = '1';
|
||||
} else {
|
||||
auto *DLI = dfsan_get_label_info(L);
|
||||
SetBytesForLabel(DLI->l1, Bytes);
|
||||
SetBytesForLabel(DLI->l2, Bytes);
|
||||
}
|
||||
}
|
||||
|
||||
static char *GetPrintableStringForLabel(dfsan_label L) {
|
||||
memset(PrintableStringForLabel, '0', InputLen + 1);
|
||||
PrintableStringForLabel[InputLen + 1] = 0;
|
||||
memset(LabelSeen, 0, sizeof(LabelSeen));
|
||||
SetBytesForLabel(L, PrintableStringForLabel);
|
||||
return PrintableStringForLabel;
|
||||
}
|
||||
|
||||
static void PrintDataFlow(FILE *Out) {
|
||||
for (size_t I = 0; I < NumFuncs; I++)
|
||||
if (FuncLabels[I])
|
||||
fprintf(Out, "F%zd %s\n", I, GetPrintableStringForLabel(FuncLabels[I]));
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (LLVMFuzzerInitialize)
|
||||
LLVMFuzzerInitialize(&argc, &argv);
|
||||
if (argc == 1)
|
||||
return PrintFunctions();
|
||||
assert(argc == 4 || argc == 5);
|
||||
size_t Beg = atoi(argv[1]);
|
||||
size_t End = atoi(argv[2]);
|
||||
assert(Beg < End);
|
||||
|
||||
const char *Input = argv[3];
|
||||
fprintf(stderr, "INFO: reading '%s'\n", Input);
|
||||
FILE *In = fopen(Input, "r");
|
||||
assert(In);
|
||||
fseek(In, 0, SEEK_END);
|
||||
InputLen = ftell(In);
|
||||
fseek(In, 0, SEEK_SET);
|
||||
unsigned char *Buf = (unsigned char*)malloc(InputLen);
|
||||
size_t NumBytesRead = fread(Buf, 1, InputLen, In);
|
||||
assert(NumBytesRead == InputLen);
|
||||
PrintableStringForLabel = (char*)malloc(InputLen + 2);
|
||||
fclose(In);
|
||||
|
||||
fprintf(stderr, "INFO: running '%s'\n", Input);
|
||||
for (size_t I = 1; I <= InputLen; I++) {
|
||||
dfsan_label L = dfsan_create_label("", nullptr);
|
||||
assert(L == I);
|
||||
size_t Idx = I - 1;
|
||||
if (Idx >= Beg && Idx < End)
|
||||
dfsan_set_label(L, Buf + Idx, 1);
|
||||
}
|
||||
dfsan_label SizeL = dfsan_create_label("", nullptr);
|
||||
assert(SizeL == InputLen + 1);
|
||||
dfsan_set_label(SizeL, &InputLen, sizeof(InputLen));
|
||||
|
||||
LLVMFuzzerTestOneInput(Buf, InputLen);
|
||||
free(Buf);
|
||||
|
||||
bool OutIsStdout = argc == 4;
|
||||
fprintf(stderr, "INFO: writing dataflow to %s\n",
|
||||
OutIsStdout ? "<stdout>" : argv[4]);
|
||||
FILE *Out = OutIsStdout ? stdout : fopen(argv[4], "w");
|
||||
PrintDataFlow(Out);
|
||||
if (!OutIsStdout) fclose(Out);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
void __sanitizer_cov_trace_pc_guard_init(uint32_t *start,
|
||||
uint32_t *stop) {
|
||||
assert(NumFuncs == 0 && "This tool does not support DSOs");
|
||||
assert(start < stop && "The code is not instrumented for coverage");
|
||||
if (start == stop || *start) return; // Initialize only once.
|
||||
for (uint32_t *x = start; x < stop; x++)
|
||||
*x = ++NumFuncs; // The first index is 1.
|
||||
FuncLabels = (dfsan_label*)calloc(NumFuncs, sizeof(dfsan_label));
|
||||
fprintf(stderr, "INFO: %zd instrumented function(s) observed\n", NumFuncs);
|
||||
}
|
||||
|
||||
void __sanitizer_cov_pcs_init(const uintptr_t *pcs_beg,
|
||||
const uintptr_t *pcs_end) {
|
||||
assert(NumFuncs == (pcs_end - pcs_beg) / 2);
|
||||
FuncsBeg = pcs_beg;
|
||||
}
|
||||
|
||||
void __sanitizer_cov_trace_pc_indir(uint64_t x){} // unused.
|
||||
|
||||
void __sanitizer_cov_trace_pc_guard(uint32_t *guard){
|
||||
uint32_t FuncNum = *guard - 1; // Guards start from 1.
|
||||
assert(FuncNum < NumFuncs);
|
||||
CurrentFunc = FuncNum;
|
||||
}
|
||||
|
||||
void __dfsw___sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases,
|
||||
dfsan_label L1, dfsan_label UnusedL) {
|
||||
assert(CurrentFunc < NumFuncs);
|
||||
FuncLabels[CurrentFunc] = dfsan_union(FuncLabels[CurrentFunc], L1);
|
||||
}
|
||||
|
||||
#define HOOK(Name, Type) \
|
||||
void Name(Type Arg1, Type Arg2, dfsan_label L1, dfsan_label L2) { \
|
||||
assert(CurrentFunc < NumFuncs); \
|
||||
FuncLabels[CurrentFunc] = \
|
||||
dfsan_union(FuncLabels[CurrentFunc], dfsan_union(L1, L2)); \
|
||||
}
|
||||
|
||||
HOOK(__dfsw___sanitizer_cov_trace_const_cmp1, uint8_t)
|
||||
HOOK(__dfsw___sanitizer_cov_trace_const_cmp2, uint16_t)
|
||||
HOOK(__dfsw___sanitizer_cov_trace_const_cmp4, uint32_t)
|
||||
HOOK(__dfsw___sanitizer_cov_trace_const_cmp8, uint64_t)
|
||||
HOOK(__dfsw___sanitizer_cov_trace_cmp1, uint8_t)
|
||||
HOOK(__dfsw___sanitizer_cov_trace_cmp2, uint16_t)
|
||||
HOOK(__dfsw___sanitizer_cov_trace_cmp4, uint32_t)
|
||||
HOOK(__dfsw___sanitizer_cov_trace_cmp8, uint64_t)
|
||||
|
||||
} // extern "C"
|
@ -1,79 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
#===- lib/fuzzer/scripts/collect_data_flow.py ------------------------------===#
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
#===------------------------------------------------------------------------===#
|
||||
# Runs the data-flow tracer several times on the same input in order to collect
|
||||
# the complete trace for all input bytes (running it on all bytes at once
|
||||
# may fail if DFSan runs out of labels).
|
||||
# Usage:
|
||||
#
|
||||
# # Collect dataflow for one input, store it in OUTPUT (default is stdout)
|
||||
# collect_data_flow.py BINARY INPUT [OUTPUT]
|
||||
#
|
||||
# # Collect dataflow for all inputs in CORPUS_DIR, store them in OUTPUT_DIR
|
||||
# collect_data_flow.py BINARY CORPUS_DIR OUTPUT_DIR
|
||||
#===------------------------------------------------------------------------===#
|
||||
import atexit
|
||||
import hashlib
|
||||
import sys
|
||||
import os
|
||||
import subprocess
|
||||
import tempfile
|
||||
import shutil
|
||||
|
||||
tmpdir = ""
|
||||
|
||||
def cleanup(d):
|
||||
print("removing: %s" % d)
|
||||
shutil.rmtree(d)
|
||||
|
||||
def collect_dataflow_for_corpus(self, exe, corpus_dir, output_dir):
|
||||
print("Collecting dataflow for corpus: %s output_dir: %s" % (corpus_dir,
|
||||
output_dir))
|
||||
assert not os.path.exists(output_dir)
|
||||
os.mkdir(output_dir)
|
||||
for root, dirs, files in os.walk(corpus_dir):
|
||||
for f in files:
|
||||
path = os.path.join(root, f)
|
||||
sha1 = hashlib.sha1(open(path).read()).hexdigest()
|
||||
output = os.path.join(output_dir, sha1)
|
||||
subprocess.call([self, exe, path, output])
|
||||
functions_txt = open(os.path.join(output_dir, "functions.txt"), "w")
|
||||
subprocess.call([exe], stdout=functions_txt)
|
||||
|
||||
|
||||
def main(argv):
|
||||
exe = argv[1]
|
||||
inp = argv[2]
|
||||
if os.path.isdir(inp):
|
||||
return collect_dataflow_for_corpus(argv[0], exe, inp, argv[3])
|
||||
size = os.path.getsize(inp)
|
||||
q = [[0, size]]
|
||||
tmpdir = tempfile.mkdtemp(prefix="libfuzzer-tmp-")
|
||||
atexit.register(cleanup, tmpdir)
|
||||
print "tmpdir: ", tmpdir
|
||||
outputs = []
|
||||
while len(q):
|
||||
r = q.pop()
|
||||
print "******* Trying: ", r
|
||||
tmpfile = os.path.join(tmpdir, str(r[0]) + "-" + str(r[1]))
|
||||
ret = subprocess.call([exe, str(r[0]), str(r[1]), inp, tmpfile])
|
||||
if ret and r[1] - r[0] >= 2:
|
||||
q.append([r[0], (r[1] + r[0]) / 2])
|
||||
q.append([(r[1] + r[0]) / 2, r[1]])
|
||||
else:
|
||||
outputs.append(tmpfile)
|
||||
print "******* Success: ", r
|
||||
f = sys.stdout
|
||||
if len(argv) >= 4:
|
||||
f = open(argv[3], "w")
|
||||
merge = os.path.join(os.path.dirname(argv[0]), "merge_data_flow.py")
|
||||
subprocess.call([merge] + outputs, stdout=f)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(sys.argv)
|
@ -1,36 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
#===- lib/fuzzer/scripts/merge_data_flow.py ------------------------------===#
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
#===------------------------------------------------------------------------===#
|
||||
# Merge several data flow traces into one.
|
||||
# Usage:
|
||||
# merge_data_flow.py trace1 trace2 ... > result
|
||||
#===------------------------------------------------------------------------===#
|
||||
import sys
|
||||
import fileinput
|
||||
from array import array
|
||||
|
||||
def Merge(a, b):
|
||||
res = array('b')
|
||||
for i in range(0, len(a)):
|
||||
res.append(ord('1' if a[i] == '1' or b[i] == '1' else '0'))
|
||||
return res.tostring()
|
||||
|
||||
def main(argv):
|
||||
D = {}
|
||||
for line in fileinput.input():
|
||||
[F,BV] = line.strip().split(' ')
|
||||
if F in D:
|
||||
D[F] = Merge(D[F], BV)
|
||||
else:
|
||||
D[F] = BV;
|
||||
for F in D.keys():
|
||||
print("%s %s" % (F, D[F]))
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(sys.argv)
|
@ -1,93 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
#===- lib/fuzzer/scripts/unbalanced_allocs.py ------------------------------===#
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
#===------------------------------------------------------------------------===#
|
||||
#
|
||||
# Post-process -trace_malloc=2 output and printout only allocations and frees
|
||||
# unbalanced inside of fuzzer runs.
|
||||
# Usage:
|
||||
# my_fuzzer -trace_malloc=2 -runs=10 2>&1 | unbalanced_allocs.py -skip=5
|
||||
#
|
||||
#===------------------------------------------------------------------------===#
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
_skip = 0
|
||||
|
||||
def PrintStack(line, stack):
|
||||
global _skip
|
||||
if _skip > 0:
|
||||
return
|
||||
print('Unbalanced ' + line.rstrip());
|
||||
for l in stack:
|
||||
print(l.rstrip())
|
||||
|
||||
def ProcessStack(line, f):
|
||||
stack = []
|
||||
while line and line.startswith(' #'):
|
||||
stack += [line]
|
||||
line = f.readline()
|
||||
return line, stack
|
||||
|
||||
def ProcessFree(line, f, allocs):
|
||||
if not line.startswith('FREE['):
|
||||
return f.readline()
|
||||
|
||||
addr = int(line.split()[1], 16)
|
||||
next_line, stack = ProcessStack(f.readline(), f)
|
||||
if addr in allocs:
|
||||
del allocs[addr]
|
||||
else:
|
||||
PrintStack(line, stack)
|
||||
return next_line
|
||||
|
||||
def ProcessMalloc(line, f, allocs):
|
||||
if not line.startswith('MALLOC['):
|
||||
return ProcessFree(line, f, allocs)
|
||||
|
||||
addr = int(line.split()[1], 16)
|
||||
assert not addr in allocs
|
||||
|
||||
next_line, stack = ProcessStack(f.readline(), f)
|
||||
allocs[addr] = (line, stack)
|
||||
return next_line
|
||||
|
||||
def ProcessRun(line, f):
|
||||
if not line.startswith('MallocFreeTracer: START'):
|
||||
return ProcessMalloc(line, f, {})
|
||||
|
||||
allocs = {}
|
||||
print(line.rstrip())
|
||||
line = f.readline()
|
||||
while line:
|
||||
if line.startswith('MallocFreeTracer: STOP'):
|
||||
global _skip
|
||||
_skip = _skip - 1
|
||||
for _, (l, s) in allocs.items():
|
||||
PrintStack(l, s)
|
||||
print(line.rstrip())
|
||||
return f.readline()
|
||||
line = ProcessMalloc(line, f, allocs)
|
||||
return line
|
||||
|
||||
def ProcessFile(f):
|
||||
line = f.readline()
|
||||
while line:
|
||||
line = ProcessRun(line, f);
|
||||
|
||||
def main(argv):
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--skip', default=0, help='number of runs to ignore')
|
||||
args = parser.parse_args()
|
||||
global _skip
|
||||
_skip = int(args.skip) + 1
|
||||
ProcessFile(sys.stdin)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(sys.argv)
|
@ -1,41 +0,0 @@
|
||||
/*===- StandaloneFuzzTargetMain.c - standalone main() for fuzz targets. ---===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// This main() function can be linked to a fuzz target (i.e. a library
|
||||
// that exports LLVMFuzzerTestOneInput() and possibly LLVMFuzzerInitialize())
|
||||
// instead of libFuzzer. This main() function will not perform any fuzzing
|
||||
// but will simply feed all input files one by one to the fuzz target.
|
||||
//
|
||||
// Use this file to provide reproducers for bugs when linking against libFuzzer
|
||||
// or other fuzzing engine is undesirable.
|
||||
//===----------------------------------------------------------------------===*/
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
extern int LLVMFuzzerTestOneInput(const unsigned char *data, size_t size);
|
||||
__attribute__((weak)) extern int LLVMFuzzerInitialize(int *argc, char ***argv);
|
||||
int main(int argc, char **argv) {
|
||||
fprintf(stderr, "StandaloneFuzzTargetMain: running %d inputs\n", argc - 1);
|
||||
if (LLVMFuzzerInitialize)
|
||||
LLVMFuzzerInitialize(&argc, &argv);
|
||||
for (int i = 1; i < argc; i++) {
|
||||
fprintf(stderr, "Running: %s\n", argv[i]);
|
||||
FILE *f = fopen(argv[i], "r");
|
||||
assert(f);
|
||||
fseek(f, 0, SEEK_END);
|
||||
size_t len = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
unsigned char *buf = (unsigned char*)malloc(len);
|
||||
size_t n_read = fread(buf, 1, len, f);
|
||||
assert(n_read == len);
|
||||
LLVMFuzzerTestOneInput(buf, len);
|
||||
free(buf);
|
||||
fprintf(stderr, "Done: %s: (%zd bytes)\n", argv[i], n_read);
|
||||
}
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
include(CompilerRTCompile)
|
||||
|
||||
set(LIBFUZZER_UNITTEST_CFLAGS
|
||||
${COMPILER_RT_UNITTEST_CFLAGS}
|
||||
${COMPILER_RT_GTEST_CFLAGS}
|
||||
-I${COMPILER_RT_SOURCE_DIR}/lib/fuzzer
|
||||
-fno-rtti
|
||||
-O2)
|
||||
|
||||
if (APPLE)
|
||||
set(FUZZER_SUPPORTED_OS osx)
|
||||
endif()
|
||||
|
||||
add_custom_target(FuzzerUnitTests)
|
||||
set_target_properties(FuzzerUnitTests PROPERTIES FOLDER "Compiler-RT Tests")
|
||||
|
||||
set(LIBFUZZER_UNITTEST_LINK_FLAGS ${COMPILER_RT_UNITTEST_LINK_FLAGS})
|
||||
list(APPEND LIBFUZZER_UNITTEST_LINK_FLAGS --driver-mode=g++)
|
||||
|
||||
if(APPLE OR CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
|
||||
list(APPEND LIBFUZZER_UNITTEST_LINK_FLAGS -lc++ -lpthread)
|
||||
elseif(NOT WIN32)
|
||||
list(APPEND LIBFUZZER_UNITTEST_LINK_FLAGS -lstdc++ -lpthread)
|
||||
endif()
|
||||
|
||||
if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux" AND COMPILER_RT_LIBCXX_PATH)
|
||||
list(APPEND LIBFUZZER_UNITTEST_CFLAGS -nostdinc++)
|
||||
endif()
|
||||
|
||||
if(COMPILER_RT_DEFAULT_TARGET_ARCH IN_LIST FUZZER_SUPPORTED_ARCH)
|
||||
# libFuzzer unit tests are only run on the host machine.
|
||||
set(arch ${COMPILER_RT_DEFAULT_TARGET_ARCH})
|
||||
|
||||
set(LIBFUZZER_TEST_RUNTIME RTFuzzerTest.${arch})
|
||||
if(APPLE)
|
||||
set(LIBFUZZER_TEST_RUNTIME_OBJECTS
|
||||
$<TARGET_OBJECTS:RTfuzzer.osx>)
|
||||
else()
|
||||
set(LIBFUZZER_TEST_RUNTIME_OBJECTS
|
||||
$<TARGET_OBJECTS:RTfuzzer.${arch}>)
|
||||
endif()
|
||||
add_library(${LIBFUZZER_TEST_RUNTIME} STATIC
|
||||
${LIBFUZZER_TEST_RUNTIME_OBJECTS})
|
||||
set_target_properties(${LIBFUZZER_TEST_RUNTIME} PROPERTIES
|
||||
ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
FOLDER "Compiler-RT Runtime tests")
|
||||
|
||||
if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux" AND COMPILER_RT_LIBCXX_PATH)
|
||||
set(LIBFUZZER_TEST_RUNTIME_DEPS libcxx_fuzzer_${arch}-build)
|
||||
set(LIBFUZZER_TEST_RUNTIME_CFLAGS -isystem ${LIBCXX_${arch}_PREFIX}/include/c++/v1)
|
||||
set(LIBFUZZER_TEST_RUNTIME_LINK_FLAGS ${LIBCXX_${arch}_PREFIX}/lib/libc++.a)
|
||||
endif()
|
||||
|
||||
set(FuzzerTestObjects)
|
||||
generate_compiler_rt_tests(FuzzerTestObjects
|
||||
FuzzerUnitTests "Fuzzer-${arch}-Test" ${arch}
|
||||
SOURCES FuzzerUnittest.cpp ${COMPILER_RT_GTEST_SOURCE}
|
||||
RUNTIME ${LIBFUZZER_TEST_RUNTIME}
|
||||
DEPS gtest ${LIBFUZZER_TEST_RUNTIME_DEPS}
|
||||
CFLAGS ${LIBFUZZER_UNITTEST_CFLAGS} ${LIBFUZZER_TEST_RUNTIME_CFLAGS}
|
||||
LINK_FLAGS ${LIBFUZZER_UNITTEST_LINK_FLAGS} ${LIBFUZZER_TEST_RUNTIME_LINK_FLAGS})
|
||||
set_target_properties(FuzzerUnitTests PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
endif()
|
@ -1,964 +0,0 @@
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
|
||||
// Avoid ODR violations (LibFuzzer is built without ASan and this test is built
|
||||
// with ASan) involving C++ standard library types when using libcxx.
|
||||
#define _LIBCPP_HAS_NO_ASAN
|
||||
|
||||
// Do not attempt to use LLVM ostream from gtest.
|
||||
#define GTEST_NO_LLVM_RAW_OSTREAM 1
|
||||
|
||||
#include "FuzzerCorpus.h"
|
||||
#include "FuzzerDictionary.h"
|
||||
#include "FuzzerInternal.h"
|
||||
#include "FuzzerMerge.h"
|
||||
#include "FuzzerMutate.h"
|
||||
#include "FuzzerRandom.h"
|
||||
#include "FuzzerTracePC.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
|
||||
using namespace fuzzer;
|
||||
|
||||
// For now, have LLVMFuzzerTestOneInput just to make it link.
|
||||
// Later we may want to make unittests that actually call LLVMFuzzerTestOneInput.
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
abort();
|
||||
}
|
||||
|
||||
TEST(Fuzzer, Basename) {
|
||||
EXPECT_EQ(Basename("foo/bar"), "bar");
|
||||
EXPECT_EQ(Basename("bar"), "bar");
|
||||
EXPECT_EQ(Basename("/bar"), "bar");
|
||||
EXPECT_EQ(Basename("foo/x"), "x");
|
||||
EXPECT_EQ(Basename("foo/"), "");
|
||||
#if LIBFUZZER_WINDOWS
|
||||
EXPECT_EQ(Basename("foo\\bar"), "bar");
|
||||
EXPECT_EQ(Basename("foo\\bar/baz"), "baz");
|
||||
EXPECT_EQ(Basename("\\bar"), "bar");
|
||||
EXPECT_EQ(Basename("foo\\x"), "x");
|
||||
EXPECT_EQ(Basename("foo\\"), "");
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(Fuzzer, CrossOver) {
|
||||
std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
|
||||
fuzzer::EF = t.get();
|
||||
Random Rand(0);
|
||||
std::unique_ptr<MutationDispatcher> MD(new MutationDispatcher(Rand, {}));
|
||||
Unit A({0, 1, 2}), B({5, 6, 7});
|
||||
Unit C;
|
||||
Unit Expected[] = {
|
||||
{ 0 },
|
||||
{ 0, 1 },
|
||||
{ 0, 5 },
|
||||
{ 0, 1, 2 },
|
||||
{ 0, 1, 5 },
|
||||
{ 0, 5, 1 },
|
||||
{ 0, 5, 6 },
|
||||
{ 0, 1, 2, 5 },
|
||||
{ 0, 1, 5, 2 },
|
||||
{ 0, 1, 5, 6 },
|
||||
{ 0, 5, 1, 2 },
|
||||
{ 0, 5, 1, 6 },
|
||||
{ 0, 5, 6, 1 },
|
||||
{ 0, 5, 6, 7 },
|
||||
{ 0, 1, 2, 5, 6 },
|
||||
{ 0, 1, 5, 2, 6 },
|
||||
{ 0, 1, 5, 6, 2 },
|
||||
{ 0, 1, 5, 6, 7 },
|
||||
{ 0, 5, 1, 2, 6 },
|
||||
{ 0, 5, 1, 6, 2 },
|
||||
{ 0, 5, 1, 6, 7 },
|
||||
{ 0, 5, 6, 1, 2 },
|
||||
{ 0, 5, 6, 1, 7 },
|
||||
{ 0, 5, 6, 7, 1 },
|
||||
{ 0, 1, 2, 5, 6, 7 },
|
||||
{ 0, 1, 5, 2, 6, 7 },
|
||||
{ 0, 1, 5, 6, 2, 7 },
|
||||
{ 0, 1, 5, 6, 7, 2 },
|
||||
{ 0, 5, 1, 2, 6, 7 },
|
||||
{ 0, 5, 1, 6, 2, 7 },
|
||||
{ 0, 5, 1, 6, 7, 2 },
|
||||
{ 0, 5, 6, 1, 2, 7 },
|
||||
{ 0, 5, 6, 1, 7, 2 },
|
||||
{ 0, 5, 6, 7, 1, 2 }
|
||||
};
|
||||
for (size_t Len = 1; Len < 8; Len++) {
|
||||
Set<Unit> FoundUnits, ExpectedUnitsWitThisLength;
|
||||
for (int Iter = 0; Iter < 3000; Iter++) {
|
||||
C.resize(Len);
|
||||
size_t NewSize = MD->CrossOver(A.data(), A.size(), B.data(), B.size(),
|
||||
C.data(), C.size());
|
||||
C.resize(NewSize);
|
||||
FoundUnits.insert(C);
|
||||
}
|
||||
for (const Unit &U : Expected)
|
||||
if (U.size() <= Len)
|
||||
ExpectedUnitsWitThisLength.insert(U);
|
||||
EXPECT_EQ(ExpectedUnitsWitThisLength, FoundUnits);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Fuzzer, Hash) {
|
||||
uint8_t A[] = {'a', 'b', 'c'};
|
||||
fuzzer::Unit U(A, A + sizeof(A));
|
||||
EXPECT_EQ("a9993e364706816aba3e25717850c26c9cd0d89d", fuzzer::Hash(U));
|
||||
U.push_back('d');
|
||||
EXPECT_EQ("81fe8bfe87576c3ecb22426f8e57847382917acf", fuzzer::Hash(U));
|
||||
}
|
||||
|
||||
typedef size_t (MutationDispatcher::*Mutator)(uint8_t *Data, size_t Size,
|
||||
size_t MaxSize);
|
||||
|
||||
void TestEraseBytes(Mutator M, int NumIter) {
|
||||
std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
|
||||
fuzzer::EF = t.get();
|
||||
uint8_t REM0[8] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
|
||||
uint8_t REM1[8] = {0x00, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
|
||||
uint8_t REM2[8] = {0x00, 0x11, 0x33, 0x44, 0x55, 0x66, 0x77};
|
||||
uint8_t REM3[8] = {0x00, 0x11, 0x22, 0x44, 0x55, 0x66, 0x77};
|
||||
uint8_t REM4[8] = {0x00, 0x11, 0x22, 0x33, 0x55, 0x66, 0x77};
|
||||
uint8_t REM5[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x66, 0x77};
|
||||
uint8_t REM6[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x77};
|
||||
uint8_t REM7[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
|
||||
|
||||
uint8_t REM8[6] = {0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
|
||||
uint8_t REM9[6] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55};
|
||||
uint8_t REM10[6] = {0x00, 0x11, 0x22, 0x55, 0x66, 0x77};
|
||||
|
||||
uint8_t REM11[5] = {0x33, 0x44, 0x55, 0x66, 0x77};
|
||||
uint8_t REM12[5] = {0x00, 0x11, 0x22, 0x33, 0x44};
|
||||
uint8_t REM13[5] = {0x00, 0x44, 0x55, 0x66, 0x77};
|
||||
|
||||
|
||||
Random Rand(0);
|
||||
std::unique_ptr<MutationDispatcher> MD(new MutationDispatcher(Rand, {}));
|
||||
int FoundMask = 0;
|
||||
for (int i = 0; i < NumIter; i++) {
|
||||
uint8_t T[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
|
||||
size_t NewSize = (*MD.*M)(T, sizeof(T), sizeof(T));
|
||||
if (NewSize == 7 && !memcmp(REM0, T, 7)) FoundMask |= 1 << 0;
|
||||
if (NewSize == 7 && !memcmp(REM1, T, 7)) FoundMask |= 1 << 1;
|
||||
if (NewSize == 7 && !memcmp(REM2, T, 7)) FoundMask |= 1 << 2;
|
||||
if (NewSize == 7 && !memcmp(REM3, T, 7)) FoundMask |= 1 << 3;
|
||||
if (NewSize == 7 && !memcmp(REM4, T, 7)) FoundMask |= 1 << 4;
|
||||
if (NewSize == 7 && !memcmp(REM5, T, 7)) FoundMask |= 1 << 5;
|
||||
if (NewSize == 7 && !memcmp(REM6, T, 7)) FoundMask |= 1 << 6;
|
||||
if (NewSize == 7 && !memcmp(REM7, T, 7)) FoundMask |= 1 << 7;
|
||||
|
||||
if (NewSize == 6 && !memcmp(REM8, T, 6)) FoundMask |= 1 << 8;
|
||||
if (NewSize == 6 && !memcmp(REM9, T, 6)) FoundMask |= 1 << 9;
|
||||
if (NewSize == 6 && !memcmp(REM10, T, 6)) FoundMask |= 1 << 10;
|
||||
|
||||
if (NewSize == 5 && !memcmp(REM11, T, 5)) FoundMask |= 1 << 11;
|
||||
if (NewSize == 5 && !memcmp(REM12, T, 5)) FoundMask |= 1 << 12;
|
||||
if (NewSize == 5 && !memcmp(REM13, T, 5)) FoundMask |= 1 << 13;
|
||||
}
|
||||
EXPECT_EQ(FoundMask, (1 << 14) - 1);
|
||||
}
|
||||
|
||||
TEST(FuzzerMutate, EraseBytes1) {
|
||||
TestEraseBytes(&MutationDispatcher::Mutate_EraseBytes, 200);
|
||||
}
|
||||
TEST(FuzzerMutate, EraseBytes2) {
|
||||
TestEraseBytes(&MutationDispatcher::Mutate, 2000);
|
||||
}
|
||||
|
||||
void TestInsertByte(Mutator M, int NumIter) {
|
||||
std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
|
||||
fuzzer::EF = t.get();
|
||||
Random Rand(0);
|
||||
std::unique_ptr<MutationDispatcher> MD(new MutationDispatcher(Rand, {}));
|
||||
int FoundMask = 0;
|
||||
uint8_t INS0[8] = {0xF1, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
|
||||
uint8_t INS1[8] = {0x00, 0xF2, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
|
||||
uint8_t INS2[8] = {0x00, 0x11, 0xF3, 0x22, 0x33, 0x44, 0x55, 0x66};
|
||||
uint8_t INS3[8] = {0x00, 0x11, 0x22, 0xF4, 0x33, 0x44, 0x55, 0x66};
|
||||
uint8_t INS4[8] = {0x00, 0x11, 0x22, 0x33, 0xF5, 0x44, 0x55, 0x66};
|
||||
uint8_t INS5[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0xF6, 0x55, 0x66};
|
||||
uint8_t INS6[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0xF7, 0x66};
|
||||
uint8_t INS7[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0xF8};
|
||||
for (int i = 0; i < NumIter; i++) {
|
||||
uint8_t T[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
|
||||
size_t NewSize = (*MD.*M)(T, 7, 8);
|
||||
if (NewSize == 8 && !memcmp(INS0, T, 8)) FoundMask |= 1 << 0;
|
||||
if (NewSize == 8 && !memcmp(INS1, T, 8)) FoundMask |= 1 << 1;
|
||||
if (NewSize == 8 && !memcmp(INS2, T, 8)) FoundMask |= 1 << 2;
|
||||
if (NewSize == 8 && !memcmp(INS3, T, 8)) FoundMask |= 1 << 3;
|
||||
if (NewSize == 8 && !memcmp(INS4, T, 8)) FoundMask |= 1 << 4;
|
||||
if (NewSize == 8 && !memcmp(INS5, T, 8)) FoundMask |= 1 << 5;
|
||||
if (NewSize == 8 && !memcmp(INS6, T, 8)) FoundMask |= 1 << 6;
|
||||
if (NewSize == 8 && !memcmp(INS7, T, 8)) FoundMask |= 1 << 7;
|
||||
}
|
||||
EXPECT_EQ(FoundMask, 255);
|
||||
}
|
||||
|
||||
TEST(FuzzerMutate, InsertByte1) {
|
||||
TestInsertByte(&MutationDispatcher::Mutate_InsertByte, 1 << 15);
|
||||
}
|
||||
TEST(FuzzerMutate, InsertByte2) {
|
||||
TestInsertByte(&MutationDispatcher::Mutate, 1 << 17);
|
||||
}
|
||||
|
||||
void TestInsertRepeatedBytes(Mutator M, int NumIter) {
|
||||
std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
|
||||
fuzzer::EF = t.get();
|
||||
Random Rand(0);
|
||||
std::unique_ptr<MutationDispatcher> MD(new MutationDispatcher(Rand, {}));
|
||||
int FoundMask = 0;
|
||||
uint8_t INS0[7] = {0x00, 0x11, 0x22, 0x33, 'a', 'a', 'a'};
|
||||
uint8_t INS1[7] = {0x00, 0x11, 0x22, 'a', 'a', 'a', 0x33};
|
||||
uint8_t INS2[7] = {0x00, 0x11, 'a', 'a', 'a', 0x22, 0x33};
|
||||
uint8_t INS3[7] = {0x00, 'a', 'a', 'a', 0x11, 0x22, 0x33};
|
||||
uint8_t INS4[7] = {'a', 'a', 'a', 0x00, 0x11, 0x22, 0x33};
|
||||
|
||||
uint8_t INS5[8] = {0x00, 0x11, 0x22, 0x33, 'b', 'b', 'b', 'b'};
|
||||
uint8_t INS6[8] = {0x00, 0x11, 0x22, 'b', 'b', 'b', 'b', 0x33};
|
||||
uint8_t INS7[8] = {0x00, 0x11, 'b', 'b', 'b', 'b', 0x22, 0x33};
|
||||
uint8_t INS8[8] = {0x00, 'b', 'b', 'b', 'b', 0x11, 0x22, 0x33};
|
||||
uint8_t INS9[8] = {'b', 'b', 'b', 'b', 0x00, 0x11, 0x22, 0x33};
|
||||
|
||||
for (int i = 0; i < NumIter; i++) {
|
||||
uint8_t T[8] = {0x00, 0x11, 0x22, 0x33};
|
||||
size_t NewSize = (*MD.*M)(T, 4, 8);
|
||||
if (NewSize == 7 && !memcmp(INS0, T, 7)) FoundMask |= 1 << 0;
|
||||
if (NewSize == 7 && !memcmp(INS1, T, 7)) FoundMask |= 1 << 1;
|
||||
if (NewSize == 7 && !memcmp(INS2, T, 7)) FoundMask |= 1 << 2;
|
||||
if (NewSize == 7 && !memcmp(INS3, T, 7)) FoundMask |= 1 << 3;
|
||||
if (NewSize == 7 && !memcmp(INS4, T, 7)) FoundMask |= 1 << 4;
|
||||
|
||||
if (NewSize == 8 && !memcmp(INS5, T, 8)) FoundMask |= 1 << 5;
|
||||
if (NewSize == 8 && !memcmp(INS6, T, 8)) FoundMask |= 1 << 6;
|
||||
if (NewSize == 8 && !memcmp(INS7, T, 8)) FoundMask |= 1 << 7;
|
||||
if (NewSize == 8 && !memcmp(INS8, T, 8)) FoundMask |= 1 << 8;
|
||||
if (NewSize == 8 && !memcmp(INS9, T, 8)) FoundMask |= 1 << 9;
|
||||
|
||||
}
|
||||
EXPECT_EQ(FoundMask, (1 << 10) - 1);
|
||||
}
|
||||
|
||||
TEST(FuzzerMutate, InsertRepeatedBytes1) {
|
||||
TestInsertRepeatedBytes(&MutationDispatcher::Mutate_InsertRepeatedBytes, 10000);
|
||||
}
|
||||
TEST(FuzzerMutate, InsertRepeatedBytes2) {
|
||||
TestInsertRepeatedBytes(&MutationDispatcher::Mutate, 300000);
|
||||
}
|
||||
|
||||
void TestChangeByte(Mutator M, int NumIter) {
|
||||
std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
|
||||
fuzzer::EF = t.get();
|
||||
Random Rand(0);
|
||||
std::unique_ptr<MutationDispatcher> MD(new MutationDispatcher(Rand, {}));
|
||||
int FoundMask = 0;
|
||||
uint8_t CH0[8] = {0xF0, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
|
||||
uint8_t CH1[8] = {0x00, 0xF1, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
|
||||
uint8_t CH2[8] = {0x00, 0x11, 0xF2, 0x33, 0x44, 0x55, 0x66, 0x77};
|
||||
uint8_t CH3[8] = {0x00, 0x11, 0x22, 0xF3, 0x44, 0x55, 0x66, 0x77};
|
||||
uint8_t CH4[8] = {0x00, 0x11, 0x22, 0x33, 0xF4, 0x55, 0x66, 0x77};
|
||||
uint8_t CH5[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0xF5, 0x66, 0x77};
|
||||
uint8_t CH6[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0xF5, 0x77};
|
||||
uint8_t CH7[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0xF7};
|
||||
for (int i = 0; i < NumIter; i++) {
|
||||
uint8_t T[9] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
|
||||
size_t NewSize = (*MD.*M)(T, 8, 9);
|
||||
if (NewSize == 8 && !memcmp(CH0, T, 8)) FoundMask |= 1 << 0;
|
||||
if (NewSize == 8 && !memcmp(CH1, T, 8)) FoundMask |= 1 << 1;
|
||||
if (NewSize == 8 && !memcmp(CH2, T, 8)) FoundMask |= 1 << 2;
|
||||
if (NewSize == 8 && !memcmp(CH3, T, 8)) FoundMask |= 1 << 3;
|
||||
if (NewSize == 8 && !memcmp(CH4, T, 8)) FoundMask |= 1 << 4;
|
||||
if (NewSize == 8 && !memcmp(CH5, T, 8)) FoundMask |= 1 << 5;
|
||||
if (NewSize == 8 && !memcmp(CH6, T, 8)) FoundMask |= 1 << 6;
|
||||
if (NewSize == 8 && !memcmp(CH7, T, 8)) FoundMask |= 1 << 7;
|
||||
}
|
||||
EXPECT_EQ(FoundMask, 255);
|
||||
}
|
||||
|
||||
TEST(FuzzerMutate, ChangeByte1) {
|
||||
TestChangeByte(&MutationDispatcher::Mutate_ChangeByte, 1 << 15);
|
||||
}
|
||||
TEST(FuzzerMutate, ChangeByte2) {
|
||||
TestChangeByte(&MutationDispatcher::Mutate, 1 << 17);
|
||||
}
|
||||
|
||||
void TestChangeBit(Mutator M, int NumIter) {
|
||||
std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
|
||||
fuzzer::EF = t.get();
|
||||
Random Rand(0);
|
||||
std::unique_ptr<MutationDispatcher> MD(new MutationDispatcher(Rand, {}));
|
||||
int FoundMask = 0;
|
||||
uint8_t CH0[8] = {0x01, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
|
||||
uint8_t CH1[8] = {0x00, 0x13, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
|
||||
uint8_t CH2[8] = {0x00, 0x11, 0x02, 0x33, 0x44, 0x55, 0x66, 0x77};
|
||||
uint8_t CH3[8] = {0x00, 0x11, 0x22, 0x37, 0x44, 0x55, 0x66, 0x77};
|
||||
uint8_t CH4[8] = {0x00, 0x11, 0x22, 0x33, 0x54, 0x55, 0x66, 0x77};
|
||||
uint8_t CH5[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x54, 0x66, 0x77};
|
||||
uint8_t CH6[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x76, 0x77};
|
||||
uint8_t CH7[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0xF7};
|
||||
for (int i = 0; i < NumIter; i++) {
|
||||
uint8_t T[9] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
|
||||
size_t NewSize = (*MD.*M)(T, 8, 9);
|
||||
if (NewSize == 8 && !memcmp(CH0, T, 8)) FoundMask |= 1 << 0;
|
||||
if (NewSize == 8 && !memcmp(CH1, T, 8)) FoundMask |= 1 << 1;
|
||||
if (NewSize == 8 && !memcmp(CH2, T, 8)) FoundMask |= 1 << 2;
|
||||
if (NewSize == 8 && !memcmp(CH3, T, 8)) FoundMask |= 1 << 3;
|
||||
if (NewSize == 8 && !memcmp(CH4, T, 8)) FoundMask |= 1 << 4;
|
||||
if (NewSize == 8 && !memcmp(CH5, T, 8)) FoundMask |= 1 << 5;
|
||||
if (NewSize == 8 && !memcmp(CH6, T, 8)) FoundMask |= 1 << 6;
|
||||
if (NewSize == 8 && !memcmp(CH7, T, 8)) FoundMask |= 1 << 7;
|
||||
}
|
||||
EXPECT_EQ(FoundMask, 255);
|
||||
}
|
||||
|
||||
TEST(FuzzerMutate, ChangeBit1) {
|
||||
TestChangeBit(&MutationDispatcher::Mutate_ChangeBit, 1 << 16);
|
||||
}
|
||||
TEST(FuzzerMutate, ChangeBit2) {
|
||||
TestChangeBit(&MutationDispatcher::Mutate, 1 << 18);
|
||||
}
|
||||
|
||||
void TestShuffleBytes(Mutator M, int NumIter) {
|
||||
std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
|
||||
fuzzer::EF = t.get();
|
||||
Random Rand(0);
|
||||
std::unique_ptr<MutationDispatcher> MD(new MutationDispatcher(Rand, {}));
|
||||
int FoundMask = 0;
|
||||
uint8_t CH0[7] = {0x00, 0x22, 0x11, 0x33, 0x44, 0x55, 0x66};
|
||||
uint8_t CH1[7] = {0x11, 0x00, 0x33, 0x22, 0x44, 0x55, 0x66};
|
||||
uint8_t CH2[7] = {0x00, 0x33, 0x11, 0x22, 0x44, 0x55, 0x66};
|
||||
uint8_t CH3[7] = {0x00, 0x11, 0x22, 0x44, 0x55, 0x66, 0x33};
|
||||
uint8_t CH4[7] = {0x00, 0x11, 0x22, 0x33, 0x55, 0x44, 0x66};
|
||||
for (int i = 0; i < NumIter; i++) {
|
||||
uint8_t T[7] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
|
||||
size_t NewSize = (*MD.*M)(T, 7, 7);
|
||||
if (NewSize == 7 && !memcmp(CH0, T, 7)) FoundMask |= 1 << 0;
|
||||
if (NewSize == 7 && !memcmp(CH1, T, 7)) FoundMask |= 1 << 1;
|
||||
if (NewSize == 7 && !memcmp(CH2, T, 7)) FoundMask |= 1 << 2;
|
||||
if (NewSize == 7 && !memcmp(CH3, T, 7)) FoundMask |= 1 << 3;
|
||||
if (NewSize == 7 && !memcmp(CH4, T, 7)) FoundMask |= 1 << 4;
|
||||
}
|
||||
EXPECT_EQ(FoundMask, 31);
|
||||
}
|
||||
|
||||
TEST(FuzzerMutate, ShuffleBytes1) {
|
||||
TestShuffleBytes(&MutationDispatcher::Mutate_ShuffleBytes, 1 << 17);
|
||||
}
|
||||
TEST(FuzzerMutate, ShuffleBytes2) {
|
||||
TestShuffleBytes(&MutationDispatcher::Mutate, 1 << 20);
|
||||
}
|
||||
|
||||
void TestCopyPart(Mutator M, int NumIter) {
|
||||
std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
|
||||
fuzzer::EF = t.get();
|
||||
Random Rand(0);
|
||||
std::unique_ptr<MutationDispatcher> MD(new MutationDispatcher(Rand, {}));
|
||||
int FoundMask = 0;
|
||||
uint8_t CH0[7] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x00, 0x11};
|
||||
uint8_t CH1[7] = {0x55, 0x66, 0x22, 0x33, 0x44, 0x55, 0x66};
|
||||
uint8_t CH2[7] = {0x00, 0x55, 0x66, 0x33, 0x44, 0x55, 0x66};
|
||||
uint8_t CH3[7] = {0x00, 0x11, 0x22, 0x00, 0x11, 0x22, 0x66};
|
||||
uint8_t CH4[7] = {0x00, 0x11, 0x11, 0x22, 0x33, 0x55, 0x66};
|
||||
|
||||
for (int i = 0; i < NumIter; i++) {
|
||||
uint8_t T[7] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
|
||||
size_t NewSize = (*MD.*M)(T, 7, 7);
|
||||
if (NewSize == 7 && !memcmp(CH0, T, 7)) FoundMask |= 1 << 0;
|
||||
if (NewSize == 7 && !memcmp(CH1, T, 7)) FoundMask |= 1 << 1;
|
||||
if (NewSize == 7 && !memcmp(CH2, T, 7)) FoundMask |= 1 << 2;
|
||||
if (NewSize == 7 && !memcmp(CH3, T, 7)) FoundMask |= 1 << 3;
|
||||
if (NewSize == 7 && !memcmp(CH4, T, 7)) FoundMask |= 1 << 4;
|
||||
}
|
||||
|
||||
uint8_t CH5[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x00, 0x11, 0x22};
|
||||
uint8_t CH6[8] = {0x22, 0x33, 0x44, 0x00, 0x11, 0x22, 0x33, 0x44};
|
||||
uint8_t CH7[8] = {0x00, 0x11, 0x22, 0x00, 0x11, 0x22, 0x33, 0x44};
|
||||
uint8_t CH8[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x22, 0x33, 0x44};
|
||||
uint8_t CH9[8] = {0x00, 0x11, 0x22, 0x22, 0x33, 0x44, 0x33, 0x44};
|
||||
|
||||
for (int i = 0; i < NumIter; i++) {
|
||||
uint8_t T[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
|
||||
size_t NewSize = (*MD.*M)(T, 5, 8);
|
||||
if (NewSize == 8 && !memcmp(CH5, T, 8)) FoundMask |= 1 << 5;
|
||||
if (NewSize == 8 && !memcmp(CH6, T, 8)) FoundMask |= 1 << 6;
|
||||
if (NewSize == 8 && !memcmp(CH7, T, 8)) FoundMask |= 1 << 7;
|
||||
if (NewSize == 8 && !memcmp(CH8, T, 8)) FoundMask |= 1 << 8;
|
||||
if (NewSize == 8 && !memcmp(CH9, T, 8)) FoundMask |= 1 << 9;
|
||||
}
|
||||
|
||||
EXPECT_EQ(FoundMask, 1023);
|
||||
}
|
||||
|
||||
TEST(FuzzerMutate, CopyPart1) {
|
||||
TestCopyPart(&MutationDispatcher::Mutate_CopyPart, 1 << 10);
|
||||
}
|
||||
TEST(FuzzerMutate, CopyPart2) {
|
||||
TestCopyPart(&MutationDispatcher::Mutate, 1 << 13);
|
||||
}
|
||||
TEST(FuzzerMutate, CopyPartNoInsertAtMaxSize) {
|
||||
// This (non exhaustively) tests if `Mutate_CopyPart` tries to perform an
|
||||
// insert on an input of size `MaxSize`. Performing an insert in this case
|
||||
// will lead to the mutation failing.
|
||||
std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
|
||||
fuzzer::EF = t.get();
|
||||
Random Rand(0);
|
||||
std::unique_ptr<MutationDispatcher> MD(new MutationDispatcher(Rand, {}));
|
||||
uint8_t Data[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x00, 0x11, 0x22};
|
||||
size_t MaxSize = sizeof(Data);
|
||||
for (int count = 0; count < (1 << 18); ++count) {
|
||||
size_t NewSize = MD->Mutate_CopyPart(Data, MaxSize, MaxSize);
|
||||
ASSERT_EQ(NewSize, MaxSize);
|
||||
}
|
||||
}
|
||||
|
||||
void TestAddWordFromDictionary(Mutator M, int NumIter) {
|
||||
std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
|
||||
fuzzer::EF = t.get();
|
||||
Random Rand(0);
|
||||
std::unique_ptr<MutationDispatcher> MD(new MutationDispatcher(Rand, {}));
|
||||
uint8_t Word1[4] = {0xAA, 0xBB, 0xCC, 0xDD};
|
||||
uint8_t Word2[3] = {0xFF, 0xEE, 0xEF};
|
||||
MD->AddWordToManualDictionary(Word(Word1, sizeof(Word1)));
|
||||
MD->AddWordToManualDictionary(Word(Word2, sizeof(Word2)));
|
||||
int FoundMask = 0;
|
||||
uint8_t CH0[7] = {0x00, 0x11, 0x22, 0xAA, 0xBB, 0xCC, 0xDD};
|
||||
uint8_t CH1[7] = {0x00, 0x11, 0xAA, 0xBB, 0xCC, 0xDD, 0x22};
|
||||
uint8_t CH2[7] = {0x00, 0xAA, 0xBB, 0xCC, 0xDD, 0x11, 0x22};
|
||||
uint8_t CH3[7] = {0xAA, 0xBB, 0xCC, 0xDD, 0x00, 0x11, 0x22};
|
||||
uint8_t CH4[6] = {0x00, 0x11, 0x22, 0xFF, 0xEE, 0xEF};
|
||||
uint8_t CH5[6] = {0x00, 0x11, 0xFF, 0xEE, 0xEF, 0x22};
|
||||
uint8_t CH6[6] = {0x00, 0xFF, 0xEE, 0xEF, 0x11, 0x22};
|
||||
uint8_t CH7[6] = {0xFF, 0xEE, 0xEF, 0x00, 0x11, 0x22};
|
||||
for (int i = 0; i < NumIter; i++) {
|
||||
uint8_t T[7] = {0x00, 0x11, 0x22};
|
||||
size_t NewSize = (*MD.*M)(T, 3, 7);
|
||||
if (NewSize == 7 && !memcmp(CH0, T, 7)) FoundMask |= 1 << 0;
|
||||
if (NewSize == 7 && !memcmp(CH1, T, 7)) FoundMask |= 1 << 1;
|
||||
if (NewSize == 7 && !memcmp(CH2, T, 7)) FoundMask |= 1 << 2;
|
||||
if (NewSize == 7 && !memcmp(CH3, T, 7)) FoundMask |= 1 << 3;
|
||||
if (NewSize == 6 && !memcmp(CH4, T, 6)) FoundMask |= 1 << 4;
|
||||
if (NewSize == 6 && !memcmp(CH5, T, 6)) FoundMask |= 1 << 5;
|
||||
if (NewSize == 6 && !memcmp(CH6, T, 6)) FoundMask |= 1 << 6;
|
||||
if (NewSize == 6 && !memcmp(CH7, T, 6)) FoundMask |= 1 << 7;
|
||||
}
|
||||
EXPECT_EQ(FoundMask, 255);
|
||||
}
|
||||
|
||||
TEST(FuzzerMutate, AddWordFromDictionary1) {
|
||||
TestAddWordFromDictionary(
|
||||
&MutationDispatcher::Mutate_AddWordFromManualDictionary, 1 << 15);
|
||||
}
|
||||
|
||||
TEST(FuzzerMutate, AddWordFromDictionary2) {
|
||||
TestAddWordFromDictionary(&MutationDispatcher::Mutate, 1 << 15);
|
||||
}
|
||||
|
||||
void TestChangeASCIIInteger(Mutator M, int NumIter) {
|
||||
std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
|
||||
fuzzer::EF = t.get();
|
||||
Random Rand(0);
|
||||
std::unique_ptr<MutationDispatcher> MD(new MutationDispatcher(Rand, {}));
|
||||
|
||||
uint8_t CH0[8] = {'1', '2', '3', '4', '5', '6', '7', '7'};
|
||||
uint8_t CH1[8] = {'1', '2', '3', '4', '5', '6', '7', '9'};
|
||||
uint8_t CH2[8] = {'2', '4', '6', '9', '1', '3', '5', '6'};
|
||||
uint8_t CH3[8] = {'0', '6', '1', '7', '2', '8', '3', '9'};
|
||||
int FoundMask = 0;
|
||||
for (int i = 0; i < NumIter; i++) {
|
||||
uint8_t T[8] = {'1', '2', '3', '4', '5', '6', '7', '8'};
|
||||
size_t NewSize = (*MD.*M)(T, 8, 8);
|
||||
/**/ if (NewSize == 8 && !memcmp(CH0, T, 8)) FoundMask |= 1 << 0;
|
||||
else if (NewSize == 8 && !memcmp(CH1, T, 8)) FoundMask |= 1 << 1;
|
||||
else if (NewSize == 8 && !memcmp(CH2, T, 8)) FoundMask |= 1 << 2;
|
||||
else if (NewSize == 8 && !memcmp(CH3, T, 8)) FoundMask |= 1 << 3;
|
||||
else if (NewSize == 8) FoundMask |= 1 << 4;
|
||||
}
|
||||
EXPECT_EQ(FoundMask, 31);
|
||||
}
|
||||
|
||||
TEST(FuzzerMutate, ChangeASCIIInteger1) {
|
||||
TestChangeASCIIInteger(&MutationDispatcher::Mutate_ChangeASCIIInteger,
|
||||
1 << 15);
|
||||
}
|
||||
|
||||
TEST(FuzzerMutate, ChangeASCIIInteger2) {
|
||||
TestChangeASCIIInteger(&MutationDispatcher::Mutate, 1 << 15);
|
||||
}
|
||||
|
||||
void TestChangeBinaryInteger(Mutator M, int NumIter) {
|
||||
std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
|
||||
fuzzer::EF = t.get();
|
||||
Random Rand(0);
|
||||
std::unique_ptr<MutationDispatcher> MD(new MutationDispatcher(Rand, {}));
|
||||
|
||||
uint8_t CH0[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x79};
|
||||
uint8_t CH1[8] = {0x00, 0x11, 0x22, 0x31, 0x44, 0x55, 0x66, 0x77};
|
||||
uint8_t CH2[8] = {0xff, 0x10, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
|
||||
uint8_t CH3[8] = {0x00, 0x11, 0x2a, 0x33, 0x44, 0x55, 0x66, 0x77};
|
||||
uint8_t CH4[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x4f, 0x66, 0x77};
|
||||
uint8_t CH5[8] = {0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88};
|
||||
uint8_t CH6[8] = {0x00, 0x11, 0x22, 0x00, 0x00, 0x00, 0x08, 0x77}; // Size
|
||||
uint8_t CH7[8] = {0x00, 0x08, 0x00, 0x33, 0x44, 0x55, 0x66, 0x77}; // Sw(Size)
|
||||
|
||||
int FoundMask = 0;
|
||||
for (int i = 0; i < NumIter; i++) {
|
||||
uint8_t T[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
|
||||
size_t NewSize = (*MD.*M)(T, 8, 8);
|
||||
/**/ if (NewSize == 8 && !memcmp(CH0, T, 8)) FoundMask |= 1 << 0;
|
||||
else if (NewSize == 8 && !memcmp(CH1, T, 8)) FoundMask |= 1 << 1;
|
||||
else if (NewSize == 8 && !memcmp(CH2, T, 8)) FoundMask |= 1 << 2;
|
||||
else if (NewSize == 8 && !memcmp(CH3, T, 8)) FoundMask |= 1 << 3;
|
||||
else if (NewSize == 8 && !memcmp(CH4, T, 8)) FoundMask |= 1 << 4;
|
||||
else if (NewSize == 8 && !memcmp(CH5, T, 8)) FoundMask |= 1 << 5;
|
||||
else if (NewSize == 8 && !memcmp(CH6, T, 8)) FoundMask |= 1 << 6;
|
||||
else if (NewSize == 8 && !memcmp(CH7, T, 8)) FoundMask |= 1 << 7;
|
||||
}
|
||||
EXPECT_EQ(FoundMask, 255);
|
||||
}
|
||||
|
||||
TEST(FuzzerMutate, ChangeBinaryInteger1) {
|
||||
TestChangeBinaryInteger(&MutationDispatcher::Mutate_ChangeBinaryInteger,
|
||||
1 << 12);
|
||||
}
|
||||
|
||||
TEST(FuzzerMutate, ChangeBinaryInteger2) {
|
||||
TestChangeBinaryInteger(&MutationDispatcher::Mutate, 1 << 15);
|
||||
}
|
||||
|
||||
|
||||
TEST(FuzzerDictionary, ParseOneDictionaryEntry) {
|
||||
Unit U;
|
||||
EXPECT_FALSE(ParseOneDictionaryEntry("", &U));
|
||||
EXPECT_FALSE(ParseOneDictionaryEntry(" ", &U));
|
||||
EXPECT_FALSE(ParseOneDictionaryEntry("\t ", &U));
|
||||
EXPECT_FALSE(ParseOneDictionaryEntry(" \" ", &U));
|
||||
EXPECT_FALSE(ParseOneDictionaryEntry(" zz\" ", &U));
|
||||
EXPECT_FALSE(ParseOneDictionaryEntry(" \"zz ", &U));
|
||||
EXPECT_FALSE(ParseOneDictionaryEntry(" \"\" ", &U));
|
||||
EXPECT_TRUE(ParseOneDictionaryEntry("\"a\"", &U));
|
||||
EXPECT_EQ(U, Unit({'a'}));
|
||||
EXPECT_TRUE(ParseOneDictionaryEntry("\"abc\"", &U));
|
||||
EXPECT_EQ(U, Unit({'a', 'b', 'c'}));
|
||||
EXPECT_TRUE(ParseOneDictionaryEntry("abc=\"abc\"", &U));
|
||||
EXPECT_EQ(U, Unit({'a', 'b', 'c'}));
|
||||
EXPECT_FALSE(ParseOneDictionaryEntry("\"\\\"", &U));
|
||||
EXPECT_TRUE(ParseOneDictionaryEntry("\"\\\\\"", &U));
|
||||
EXPECT_EQ(U, Unit({'\\'}));
|
||||
EXPECT_TRUE(ParseOneDictionaryEntry("\"\\xAB\"", &U));
|
||||
EXPECT_EQ(U, Unit({0xAB}));
|
||||
EXPECT_TRUE(ParseOneDictionaryEntry("\"\\xABz\\xDE\"", &U));
|
||||
EXPECT_EQ(U, Unit({0xAB, 'z', 0xDE}));
|
||||
EXPECT_TRUE(ParseOneDictionaryEntry("\"#\"", &U));
|
||||
EXPECT_EQ(U, Unit({'#'}));
|
||||
EXPECT_TRUE(ParseOneDictionaryEntry("\"\\\"\"", &U));
|
||||
EXPECT_EQ(U, Unit({'"'}));
|
||||
}
|
||||
|
||||
TEST(FuzzerDictionary, ParseDictionaryFile) {
|
||||
Vector<Unit> Units;
|
||||
EXPECT_FALSE(ParseDictionaryFile("zzz\n", &Units));
|
||||
EXPECT_FALSE(ParseDictionaryFile("", &Units));
|
||||
EXPECT_TRUE(ParseDictionaryFile("\n", &Units));
|
||||
EXPECT_EQ(Units.size(), 0U);
|
||||
EXPECT_TRUE(ParseDictionaryFile("#zzzz a b c d\n", &Units));
|
||||
EXPECT_EQ(Units.size(), 0U);
|
||||
EXPECT_TRUE(ParseDictionaryFile(" #zzzz\n", &Units));
|
||||
EXPECT_EQ(Units.size(), 0U);
|
||||
EXPECT_TRUE(ParseDictionaryFile(" #zzzz\n", &Units));
|
||||
EXPECT_EQ(Units.size(), 0U);
|
||||
EXPECT_TRUE(ParseDictionaryFile(" #zzzz\naaa=\"aa\"", &Units));
|
||||
EXPECT_EQ(Units, Vector<Unit>({Unit({'a', 'a'})}));
|
||||
EXPECT_TRUE(
|
||||
ParseDictionaryFile(" #zzzz\naaa=\"aa\"\n\nabc=\"abc\"", &Units));
|
||||
EXPECT_EQ(Units,
|
||||
Vector<Unit>({Unit({'a', 'a'}), Unit({'a', 'b', 'c'})}));
|
||||
}
|
||||
|
||||
TEST(FuzzerUtil, Base64) {
|
||||
EXPECT_EQ("", Base64({}));
|
||||
EXPECT_EQ("YQ==", Base64({'a'}));
|
||||
EXPECT_EQ("eA==", Base64({'x'}));
|
||||
EXPECT_EQ("YWI=", Base64({'a', 'b'}));
|
||||
EXPECT_EQ("eHk=", Base64({'x', 'y'}));
|
||||
EXPECT_EQ("YWJj", Base64({'a', 'b', 'c'}));
|
||||
EXPECT_EQ("eHl6", Base64({'x', 'y', 'z'}));
|
||||
EXPECT_EQ("YWJjeA==", Base64({'a', 'b', 'c', 'x'}));
|
||||
EXPECT_EQ("YWJjeHk=", Base64({'a', 'b', 'c', 'x', 'y'}));
|
||||
EXPECT_EQ("YWJjeHl6", Base64({'a', 'b', 'c', 'x', 'y', 'z'}));
|
||||
}
|
||||
|
||||
TEST(Corpus, Distribution) {
|
||||
DataFlowTrace DFT;
|
||||
Random Rand(0);
|
||||
std::unique_ptr<InputCorpus> C(new InputCorpus(""));
|
||||
size_t N = 10;
|
||||
size_t TriesPerUnit = 1<<16;
|
||||
for (size_t i = 0; i < N; i++)
|
||||
C->AddToCorpus(Unit{static_cast<uint8_t>(i)}, 1, false, false, {}, DFT,
|
||||
nullptr);
|
||||
|
||||
Vector<size_t> Hist(N);
|
||||
for (size_t i = 0; i < N * TriesPerUnit; i++) {
|
||||
Hist[C->ChooseUnitIdxToMutate(Rand)]++;
|
||||
}
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
// A weak sanity check that every unit gets invoked.
|
||||
EXPECT_GT(Hist[i], TriesPerUnit / N / 3);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Merge, Bad) {
|
||||
const char *kInvalidInputs[] = {
|
||||
"",
|
||||
"x",
|
||||
"3\nx",
|
||||
"2\n3",
|
||||
"2\n2",
|
||||
"2\n2\nA\n",
|
||||
"2\n2\nA\nB\nC\n",
|
||||
"0\n0\n",
|
||||
"1\n1\nA\nDONE 0",
|
||||
"1\n1\nA\nSTARTED 1",
|
||||
};
|
||||
Merger M;
|
||||
for (auto S : kInvalidInputs) {
|
||||
// fprintf(stderr, "TESTING:\n%s\n", S);
|
||||
EXPECT_FALSE(M.Parse(S, false));
|
||||
}
|
||||
}
|
||||
|
||||
void EQ(const Vector<uint32_t> &A, const Vector<uint32_t> &B) {
|
||||
EXPECT_EQ(A, B);
|
||||
}
|
||||
|
||||
void EQ(const Vector<std::string> &A, const Vector<std::string> &B) {
|
||||
Set<std::string> a(A.begin(), A.end());
|
||||
Set<std::string> b(B.begin(), B.end());
|
||||
EXPECT_EQ(a, b);
|
||||
}
|
||||
|
||||
static void Merge(const std::string &Input,
|
||||
const Vector<std::string> Result,
|
||||
size_t NumNewFeatures) {
|
||||
Merger M;
|
||||
Vector<std::string> NewFiles;
|
||||
EXPECT_TRUE(M.Parse(Input, true));
|
||||
std::stringstream SS;
|
||||
M.PrintSummary(SS);
|
||||
EXPECT_EQ(NumNewFeatures, M.Merge(&NewFiles));
|
||||
EXPECT_EQ(M.AllFeatures(), M.ParseSummary(SS));
|
||||
EQ(NewFiles, Result);
|
||||
}
|
||||
|
||||
TEST(Merge, Good) {
|
||||
Merger M;
|
||||
|
||||
EXPECT_TRUE(M.Parse("1\n0\nAA\n", false));
|
||||
EXPECT_EQ(M.Files.size(), 1U);
|
||||
EXPECT_EQ(M.NumFilesInFirstCorpus, 0U);
|
||||
EXPECT_EQ(M.Files[0].Name, "AA");
|
||||
EXPECT_TRUE(M.LastFailure.empty());
|
||||
EXPECT_EQ(M.FirstNotProcessedFile, 0U);
|
||||
|
||||
EXPECT_TRUE(M.Parse("2\n1\nAA\nBB\nSTARTED 0 42\n", false));
|
||||
EXPECT_EQ(M.Files.size(), 2U);
|
||||
EXPECT_EQ(M.NumFilesInFirstCorpus, 1U);
|
||||
EXPECT_EQ(M.Files[0].Name, "AA");
|
||||
EXPECT_EQ(M.Files[1].Name, "BB");
|
||||
EXPECT_EQ(M.LastFailure, "AA");
|
||||
EXPECT_EQ(M.FirstNotProcessedFile, 1U);
|
||||
|
||||
EXPECT_TRUE(M.Parse("3\n1\nAA\nBB\nC\n"
|
||||
"STARTED 0 1000\n"
|
||||
"DONE 0 1 2 3\n"
|
||||
"STARTED 1 1001\n"
|
||||
"DONE 1 4 5 6 \n"
|
||||
"STARTED 2 1002\n"
|
||||
"", true));
|
||||
EXPECT_EQ(M.Files.size(), 3U);
|
||||
EXPECT_EQ(M.NumFilesInFirstCorpus, 1U);
|
||||
EXPECT_EQ(M.Files[0].Name, "AA");
|
||||
EXPECT_EQ(M.Files[0].Size, 1000U);
|
||||
EXPECT_EQ(M.Files[1].Name, "BB");
|
||||
EXPECT_EQ(M.Files[1].Size, 1001U);
|
||||
EXPECT_EQ(M.Files[2].Name, "C");
|
||||
EXPECT_EQ(M.Files[2].Size, 1002U);
|
||||
EXPECT_EQ(M.LastFailure, "C");
|
||||
EXPECT_EQ(M.FirstNotProcessedFile, 3U);
|
||||
EQ(M.Files[0].Features, {1, 2, 3});
|
||||
EQ(M.Files[1].Features, {4, 5, 6});
|
||||
|
||||
|
||||
Vector<std::string> NewFiles;
|
||||
|
||||
EXPECT_TRUE(M.Parse("3\n2\nAA\nBB\nC\n"
|
||||
"STARTED 0 1000\nDONE 0 1 2 3\n"
|
||||
"STARTED 1 1001\nDONE 1 4 5 6 \n"
|
||||
"STARTED 2 1002\nDONE 2 6 1 3 \n"
|
||||
"", true));
|
||||
EXPECT_EQ(M.Files.size(), 3U);
|
||||
EXPECT_EQ(M.NumFilesInFirstCorpus, 2U);
|
||||
EXPECT_TRUE(M.LastFailure.empty());
|
||||
EXPECT_EQ(M.FirstNotProcessedFile, 3U);
|
||||
EQ(M.Files[0].Features, {1, 2, 3});
|
||||
EQ(M.Files[1].Features, {4, 5, 6});
|
||||
EQ(M.Files[2].Features, {1, 3, 6});
|
||||
EXPECT_EQ(0U, M.Merge(&NewFiles));
|
||||
EQ(NewFiles, {});
|
||||
|
||||
EXPECT_TRUE(M.Parse("3\n1\nA\nB\nC\n"
|
||||
"STARTED 0 1000\nDONE 0 1 2 3\n"
|
||||
"STARTED 1 1001\nDONE 1 4 5 6 \n"
|
||||
"STARTED 2 1002\nDONE 2 6 1 3\n"
|
||||
"", true));
|
||||
EQ(M.Files[0].Features, {1, 2, 3});
|
||||
EQ(M.Files[1].Features, {4, 5, 6});
|
||||
EQ(M.Files[2].Features, {1, 3, 6});
|
||||
EXPECT_EQ(3U, M.Merge(&NewFiles));
|
||||
EQ(NewFiles, {"B"});
|
||||
|
||||
// Same as the above, but with InitialFeatures.
|
||||
EXPECT_TRUE(M.Parse("2\n0\nB\nC\n"
|
||||
"STARTED 0 1001\nDONE 0 4 5 6 \n"
|
||||
"STARTED 1 1002\nDONE 1 6 1 3\n"
|
||||
"", true));
|
||||
EQ(M.Files[0].Features, {4, 5, 6});
|
||||
EQ(M.Files[1].Features, {1, 3, 6});
|
||||
Set<uint32_t> InitialFeatures;
|
||||
InitialFeatures.insert(1);
|
||||
InitialFeatures.insert(2);
|
||||
InitialFeatures.insert(3);
|
||||
EXPECT_EQ(3U, M.Merge(InitialFeatures, &NewFiles));
|
||||
EQ(NewFiles, {"B"});
|
||||
}
|
||||
|
||||
TEST(Merge, Merge) {
|
||||
|
||||
Merge("3\n1\nA\nB\nC\n"
|
||||
"STARTED 0 1000\nDONE 0 1 2 3\n"
|
||||
"STARTED 1 1001\nDONE 1 4 5 6 \n"
|
||||
"STARTED 2 1002\nDONE 2 6 1 3 \n",
|
||||
{"B"}, 3);
|
||||
|
||||
Merge("3\n0\nA\nB\nC\n"
|
||||
"STARTED 0 2000\nDONE 0 1 2 3\n"
|
||||
"STARTED 1 1001\nDONE 1 4 5 6 \n"
|
||||
"STARTED 2 1002\nDONE 2 6 1 3 \n",
|
||||
{"A", "B", "C"}, 6);
|
||||
|
||||
Merge("4\n0\nA\nB\nC\nD\n"
|
||||
"STARTED 0 2000\nDONE 0 1 2 3\n"
|
||||
"STARTED 1 1101\nDONE 1 4 5 6 \n"
|
||||
"STARTED 2 1102\nDONE 2 6 1 3 100 \n"
|
||||
"STARTED 3 1000\nDONE 3 1 \n",
|
||||
{"A", "B", "C", "D"}, 7);
|
||||
|
||||
Merge("4\n1\nA\nB\nC\nD\n"
|
||||
"STARTED 0 2000\nDONE 0 4 5 6 7 8\n"
|
||||
"STARTED 1 1100\nDONE 1 1 2 3 \n"
|
||||
"STARTED 2 1100\nDONE 2 2 3 \n"
|
||||
"STARTED 3 1000\nDONE 3 1 \n",
|
||||
{"B", "D"}, 3);
|
||||
}
|
||||
|
||||
TEST(Fuzzer, ForEachNonZeroByte) {
|
||||
const size_t N = 64;
|
||||
alignas(64) uint8_t Ar[N + 8] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 2, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 3, 0, 4, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 5, 0, 6, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 7, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 8,
|
||||
9, 9, 9, 9, 9, 9, 9, 9,
|
||||
};
|
||||
typedef Vector<std::pair<size_t, uint8_t> > Vec;
|
||||
Vec Res, Expected;
|
||||
auto CB = [&](size_t FirstFeature, size_t Idx, uint8_t V) {
|
||||
Res.push_back({FirstFeature + Idx, V});
|
||||
};
|
||||
ForEachNonZeroByte(Ar, Ar + N, 100, CB);
|
||||
Expected = {{108, 1}, {109, 2}, {118, 3}, {120, 4},
|
||||
{135, 5}, {137, 6}, {146, 7}, {163, 8}};
|
||||
EXPECT_EQ(Res, Expected);
|
||||
|
||||
Res.clear();
|
||||
ForEachNonZeroByte(Ar + 9, Ar + N, 109, CB);
|
||||
Expected = { {109, 2}, {118, 3}, {120, 4},
|
||||
{135, 5}, {137, 6}, {146, 7}, {163, 8}};
|
||||
EXPECT_EQ(Res, Expected);
|
||||
|
||||
Res.clear();
|
||||
ForEachNonZeroByte(Ar + 9, Ar + N - 9, 109, CB);
|
||||
Expected = { {109, 2}, {118, 3}, {120, 4},
|
||||
{135, 5}, {137, 6}, {146, 7}};
|
||||
EXPECT_EQ(Res, Expected);
|
||||
}
|
||||
|
||||
// FuzzerCommand unit tests. The arguments in the two helper methods below must
|
||||
// match.
|
||||
static void makeCommandArgs(Vector<std::string> *ArgsToAdd) {
|
||||
assert(ArgsToAdd);
|
||||
ArgsToAdd->clear();
|
||||
ArgsToAdd->push_back("foo");
|
||||
ArgsToAdd->push_back("-bar=baz");
|
||||
ArgsToAdd->push_back("qux");
|
||||
ArgsToAdd->push_back(Command::ignoreRemainingArgs());
|
||||
ArgsToAdd->push_back("quux");
|
||||
ArgsToAdd->push_back("-grault=garply");
|
||||
}
|
||||
|
||||
static std::string makeCmdLine(const char *separator, const char *suffix) {
|
||||
std::string CmdLine("foo -bar=baz qux ");
|
||||
if (strlen(separator) != 0) {
|
||||
CmdLine += separator;
|
||||
CmdLine += " ";
|
||||
}
|
||||
CmdLine += Command::ignoreRemainingArgs();
|
||||
CmdLine += " quux -grault=garply";
|
||||
if (strlen(suffix) != 0) {
|
||||
CmdLine += " ";
|
||||
CmdLine += suffix;
|
||||
}
|
||||
return CmdLine;
|
||||
}
|
||||
|
||||
TEST(FuzzerCommand, Create) {
|
||||
std::string CmdLine;
|
||||
|
||||
// Default constructor
|
||||
Command DefaultCmd;
|
||||
|
||||
CmdLine = DefaultCmd.toString();
|
||||
EXPECT_EQ(CmdLine, "");
|
||||
|
||||
// Explicit constructor
|
||||
Vector<std::string> ArgsToAdd;
|
||||
makeCommandArgs(&ArgsToAdd);
|
||||
Command InitializedCmd(ArgsToAdd);
|
||||
|
||||
CmdLine = InitializedCmd.toString();
|
||||
EXPECT_EQ(CmdLine, makeCmdLine("", ""));
|
||||
|
||||
// Compare each argument
|
||||
auto InitializedArgs = InitializedCmd.getArguments();
|
||||
auto i = ArgsToAdd.begin();
|
||||
auto j = InitializedArgs.begin();
|
||||
while (i != ArgsToAdd.end() && j != InitializedArgs.end()) {
|
||||
EXPECT_EQ(*i++, *j++);
|
||||
}
|
||||
EXPECT_EQ(i, ArgsToAdd.end());
|
||||
EXPECT_EQ(j, InitializedArgs.end());
|
||||
|
||||
// Copy constructor
|
||||
Command CopiedCmd(InitializedCmd);
|
||||
|
||||
CmdLine = CopiedCmd.toString();
|
||||
EXPECT_EQ(CmdLine, makeCmdLine("", ""));
|
||||
|
||||
// Assignment operator
|
||||
Command AssignedCmd;
|
||||
AssignedCmd = CopiedCmd;
|
||||
|
||||
CmdLine = AssignedCmd.toString();
|
||||
EXPECT_EQ(CmdLine, makeCmdLine("", ""));
|
||||
}
|
||||
|
||||
TEST(FuzzerCommand, ModifyArguments) {
|
||||
Vector<std::string> ArgsToAdd;
|
||||
makeCommandArgs(&ArgsToAdd);
|
||||
Command Cmd;
|
||||
std::string CmdLine;
|
||||
|
||||
Cmd.addArguments(ArgsToAdd);
|
||||
CmdLine = Cmd.toString();
|
||||
EXPECT_EQ(CmdLine, makeCmdLine("", ""));
|
||||
|
||||
Cmd.addArgument("waldo");
|
||||
EXPECT_TRUE(Cmd.hasArgument("waldo"));
|
||||
|
||||
CmdLine = Cmd.toString();
|
||||
EXPECT_EQ(CmdLine, makeCmdLine("waldo", ""));
|
||||
|
||||
Cmd.removeArgument("waldo");
|
||||
EXPECT_FALSE(Cmd.hasArgument("waldo"));
|
||||
|
||||
CmdLine = Cmd.toString();
|
||||
EXPECT_EQ(CmdLine, makeCmdLine("", ""));
|
||||
}
|
||||
|
||||
TEST(FuzzerCommand, ModifyFlags) {
|
||||
Vector<std::string> ArgsToAdd;
|
||||
makeCommandArgs(&ArgsToAdd);
|
||||
Command Cmd(ArgsToAdd);
|
||||
std::string Value, CmdLine;
|
||||
ASSERT_FALSE(Cmd.hasFlag("fred"));
|
||||
|
||||
Value = Cmd.getFlagValue("fred");
|
||||
EXPECT_EQ(Value, "");
|
||||
|
||||
CmdLine = Cmd.toString();
|
||||
EXPECT_EQ(CmdLine, makeCmdLine("", ""));
|
||||
|
||||
Cmd.addFlag("fred", "plugh");
|
||||
EXPECT_TRUE(Cmd.hasFlag("fred"));
|
||||
|
||||
Value = Cmd.getFlagValue("fred");
|
||||
EXPECT_EQ(Value, "plugh");
|
||||
|
||||
CmdLine = Cmd.toString();
|
||||
EXPECT_EQ(CmdLine, makeCmdLine("-fred=plugh", ""));
|
||||
|
||||
Cmd.removeFlag("fred");
|
||||
EXPECT_FALSE(Cmd.hasFlag("fred"));
|
||||
|
||||
Value = Cmd.getFlagValue("fred");
|
||||
EXPECT_EQ(Value, "");
|
||||
|
||||
CmdLine = Cmd.toString();
|
||||
EXPECT_EQ(CmdLine, makeCmdLine("", ""));
|
||||
}
|
||||
|
||||
TEST(FuzzerCommand, SetOutput) {
|
||||
Vector<std::string> ArgsToAdd;
|
||||
makeCommandArgs(&ArgsToAdd);
|
||||
Command Cmd(ArgsToAdd);
|
||||
std::string CmdLine;
|
||||
ASSERT_FALSE(Cmd.hasOutputFile());
|
||||
ASSERT_FALSE(Cmd.isOutAndErrCombined());
|
||||
|
||||
Cmd.combineOutAndErr(true);
|
||||
EXPECT_TRUE(Cmd.isOutAndErrCombined());
|
||||
|
||||
CmdLine = Cmd.toString();
|
||||
EXPECT_EQ(CmdLine, makeCmdLine("", "2>&1"));
|
||||
|
||||
Cmd.combineOutAndErr(false);
|
||||
EXPECT_FALSE(Cmd.isOutAndErrCombined());
|
||||
|
||||
Cmd.setOutputFile("xyzzy");
|
||||
EXPECT_TRUE(Cmd.hasOutputFile());
|
||||
|
||||
CmdLine = Cmd.toString();
|
||||
EXPECT_EQ(CmdLine, makeCmdLine("", ">xyzzy"));
|
||||
|
||||
Cmd.setOutputFile("thud");
|
||||
EXPECT_TRUE(Cmd.hasOutputFile());
|
||||
|
||||
CmdLine = Cmd.toString();
|
||||
EXPECT_EQ(CmdLine, makeCmdLine("", ">thud"));
|
||||
|
||||
Cmd.combineOutAndErr();
|
||||
EXPECT_TRUE(Cmd.isOutAndErrCombined());
|
||||
|
||||
CmdLine = Cmd.toString();
|
||||
EXPECT_EQ(CmdLine, makeCmdLine("", ">thud 2>&1"));
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
@ -1,2 +0,0 @@
|
||||
BasedOnStyle: Google
|
||||
AllowShortIfStatementsOnASingleLine: false
|
@ -1,179 +0,0 @@
|
||||
include_directories(..)
|
||||
|
||||
# Runtime library sources and build flags.
|
||||
set(HWASAN_RTL_SOURCES
|
||||
hwasan.cc
|
||||
hwasan_allocator.cc
|
||||
hwasan_dynamic_shadow.cc
|
||||
hwasan_interceptors.cc
|
||||
hwasan_linux.cc
|
||||
hwasan_memintrinsics.cc
|
||||
hwasan_poisoning.cc
|
||||
hwasan_report.cc
|
||||
hwasan_thread.cc
|
||||
hwasan_thread_list.cc
|
||||
)
|
||||
|
||||
set(HWASAN_RTL_CXX_SOURCES
|
||||
hwasan_new_delete.cc)
|
||||
|
||||
set(HWASAN_RTL_HEADERS
|
||||
hwasan.h
|
||||
hwasan_allocator.h
|
||||
hwasan_dynamic_shadow.h
|
||||
hwasan_flags.h
|
||||
hwasan_flags.inc
|
||||
hwasan_interface_internal.h
|
||||
hwasan_mapping.h
|
||||
hwasan_poisoning.h
|
||||
hwasan_report.h
|
||||
hwasan_thread.h
|
||||
hwasan_thread_list.h
|
||||
)
|
||||
|
||||
set(HWASAN_DEFINITIONS)
|
||||
append_list_if(COMPILER_RT_HWASAN_WITH_INTERCEPTORS HWASAN_WITH_INTERCEPTORS=1 HWASAN_DEFINITIONS)
|
||||
|
||||
set(HWASAN_RTL_CFLAGS ${SANITIZER_COMMON_CFLAGS})
|
||||
append_rtti_flag(OFF HWASAN_RTL_CFLAGS)
|
||||
append_list_if(COMPILER_RT_HAS_FPIC_FLAG -fPIC HWASAN_RTL_CFLAGS)
|
||||
# Prevent clang from generating libc calls.
|
||||
append_list_if(COMPILER_RT_HAS_FFREESTANDING_FLAG -ffreestanding HWASAN_RTL_CFLAGS)
|
||||
|
||||
set(HWASAN_DYNAMIC_LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS})
|
||||
|
||||
if(ANDROID)
|
||||
# Put most Sanitizer shared libraries in the global group. For more details, see
|
||||
# android-changes-for-ndk-developers.md#changes-to-library-search-order
|
||||
if (COMPILER_RT_HAS_Z_GLOBAL)
|
||||
list(APPEND HWASAN_DYNAMIC_LINK_FLAGS -Wl,-z,global)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(HWASAN_DYNAMIC_CFLAGS ${HWASAN_RTL_CFLAGS})
|
||||
append_list_if(COMPILER_RT_HAS_FTLS_MODEL_INITIAL_EXEC
|
||||
-ftls-model=initial-exec HWASAN_DYNAMIC_CFLAGS)
|
||||
append_list_if(MSVC /DEBUG HWASAN_DYNAMIC_LINK_FLAGS)
|
||||
|
||||
set(HWASAN_DYNAMIC_LIBS ${SANITIZER_CXX_ABI_LIBRARY} ${SANITIZER_COMMON_LINK_LIBS})
|
||||
|
||||
append_list_if(COMPILER_RT_HAS_LIBDL dl HWASAN_DYNAMIC_LIBS)
|
||||
append_list_if(COMPILER_RT_HAS_LIBRT rt HWASAN_DYNAMIC_LIBS)
|
||||
append_list_if(COMPILER_RT_HAS_LIBM m HWASAN_DYNAMIC_LIBS)
|
||||
append_list_if(COMPILER_RT_HAS_LIBPTHREAD pthread HWASAN_DYNAMIC_LIBS)
|
||||
|
||||
if (TARGET cxx-headers OR HAVE_LIBCXX)
|
||||
set(HWASAN_DEPS cxx-headers)
|
||||
endif()
|
||||
|
||||
# Static runtime library.
|
||||
add_compiler_rt_component(hwasan)
|
||||
|
||||
add_compiler_rt_object_libraries(RTHwasan
|
||||
ARCHS ${HWASAN_SUPPORTED_ARCH}
|
||||
SOURCES ${HWASAN_RTL_SOURCES}
|
||||
ADDITIONAL_HEADERS ${HWASAN_RTL_HEADERS}
|
||||
CFLAGS ${HWASAN_RTL_CFLAGS}
|
||||
DEFS ${HWASAN_DEFINITIONS}
|
||||
DEPS ${HWASAN_DEPS})
|
||||
add_compiler_rt_object_libraries(RTHwasan_cxx
|
||||
ARCHS ${HWASAN_SUPPORTED_ARCH}
|
||||
SOURCES ${HWASAN_RTL_CXX_SOURCES}
|
||||
ADDITIONAL_HEADERS ${HWASAN_RTL_HEADERS}
|
||||
CFLAGS ${HWASAN_RTL_CFLAGS}
|
||||
DEFS ${HWASAN_DEFINITIONS}
|
||||
DEPS ${HWASAN_DEPS})
|
||||
add_compiler_rt_object_libraries(RTHwasan_dynamic
|
||||
ARCHS ${HWASAN_SUPPORTED_ARCH}
|
||||
SOURCES ${HWASAN_RTL_SOURCES} ${HWASAN_RTL_CXX_SOURCES}
|
||||
ADDITIONAL_HEADERS ${HWASAN_RTL_HEADERS}
|
||||
CFLAGS ${HWASAN_DYNAMIC_CFLAGS}
|
||||
DEFS ${HWASAN_DEFINITIONS}
|
||||
DEPS ${HWASAN_DEPS})
|
||||
|
||||
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/dummy.cc "")
|
||||
add_compiler_rt_object_libraries(RTHwasan_dynamic_version_script_dummy
|
||||
ARCHS ${HWASAN_SUPPORTED_ARCH}
|
||||
SOURCES ${CMAKE_CURRENT_BINARY_DIR}/dummy.cc
|
||||
CFLAGS ${HWASAN_DYNAMIC_CFLAGS}
|
||||
DEFS ${HWASAN_DEFINITIONS}
|
||||
DEPS ${HWASAN_DEPS})
|
||||
|
||||
foreach(arch ${HWASAN_SUPPORTED_ARCH})
|
||||
add_compiler_rt_runtime(clang_rt.hwasan
|
||||
STATIC
|
||||
ARCHS ${arch}
|
||||
OBJECT_LIBS RTHwasan
|
||||
RTInterception
|
||||
RTSanitizerCommon
|
||||
RTSanitizerCommonLibc
|
||||
RTSanitizerCommonCoverage
|
||||
RTSanitizerCommonSymbolizer
|
||||
RTUbsan
|
||||
CFLAGS ${HWASAN_RTL_CFLAGS}
|
||||
PARENT_TARGET hwasan)
|
||||
add_compiler_rt_runtime(clang_rt.hwasan_cxx
|
||||
STATIC
|
||||
ARCHS ${arch}
|
||||
OBJECT_LIBS RTHwasan_cxx
|
||||
RTUbsan_cxx
|
||||
CFLAGS ${HWASAN_RTL_CFLAGS}
|
||||
PARENT_TARGET hwasan)
|
||||
|
||||
if (UNIX)
|
||||
add_sanitizer_rt_version_list(clang_rt.hwasan-dynamic-${arch}
|
||||
LIBS clang_rt.hwasan-${arch} clang_rt.hwasan_cxx-${arch}
|
||||
EXTRA hwasan.syms.extra)
|
||||
set(VERSION_SCRIPT_FLAG
|
||||
-Wl,--version-script,${CMAKE_CURRENT_BINARY_DIR}/clang_rt.hwasan-dynamic-${arch}.vers)
|
||||
set_property(SOURCE
|
||||
${CMAKE_CURRENT_BINARY_DIR}/dummy.cc
|
||||
APPEND PROPERTY
|
||||
OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/clang_rt.hwasan-dynamic-${arch}.vers)
|
||||
else()
|
||||
set(VERSION_SCRIPT_FLAG)
|
||||
endif()
|
||||
|
||||
|
||||
add_compiler_rt_runtime(clang_rt.hwasan
|
||||
SHARED
|
||||
ARCHS ${arch}
|
||||
OBJECT_LIBS
|
||||
RTHwasan_dynamic
|
||||
RTInterception
|
||||
RTSanitizerCommon
|
||||
RTSanitizerCommonLibc
|
||||
RTSanitizerCommonCoverage
|
||||
RTSanitizerCommonSymbolizer
|
||||
RTUbsan
|
||||
RTUbsan_cxx
|
||||
# The only purpose of RTHWAsan_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.
|
||||
RTHwasan_dynamic_version_script_dummy
|
||||
CFLAGS ${HWASAN_DYNAMIC_CFLAGS}
|
||||
LINK_FLAGS ${HWASAN_DYNAMIC_LINK_FLAGS}
|
||||
${VERSION_SCRIPT_FLAG}
|
||||
LINK_LIBS ${HWASAN_DYNAMIC_LIBS}
|
||||
DEFS ${ASAN_DYNAMIC_DEFINITIONS}
|
||||
PARENT_TARGET hwasan)
|
||||
|
||||
if(SANITIZER_USE_SYMBOLS)
|
||||
add_sanitizer_rt_symbols(clang_rt.hwasan
|
||||
ARCHS ${arch}
|
||||
EXTRA hwasan.syms.extra)
|
||||
add_sanitizer_rt_symbols(clang_rt.hwasan_cxx
|
||||
ARCHS ${arch}
|
||||
EXTRA hwasan.syms.extra)
|
||||
add_dependencies(hwasan clang_rt.hwasan-${arch}-symbols
|
||||
clang_rt.hwasan_cxx-${arch}-symbols)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
add_compiler_rt_resource_file(hwasan_blacklist hwasan_blacklist.txt hwasan)
|
||||
|
||||
# if(COMPILER_RT_INCLUDE_TESTS)
|
||||
# add_subdirectory(tests)
|
||||
# endif()
|
@ -1,2 +0,0 @@
|
||||
BasedOnStyle: Google
|
||||
AllowShortIfStatementsOnASingleLine: false
|
@ -1,29 +0,0 @@
|
||||
# Build for the runtime interception helper library.
|
||||
|
||||
set(INTERCEPTION_SOURCES
|
||||
interception_linux.cc
|
||||
interception_mac.cc
|
||||
interception_win.cc
|
||||
interception_type_test.cc)
|
||||
|
||||
set(INTERCEPTION_HEADERS
|
||||
interception.h
|
||||
interception_linux.h
|
||||
interception_mac.h
|
||||
interception_win.h)
|
||||
|
||||
include_directories(..)
|
||||
|
||||
set(INTERCEPTION_CFLAGS ${SANITIZER_COMMON_CFLAGS})
|
||||
append_rtti_flag(OFF INTERCEPTION_CFLAGS)
|
||||
|
||||
add_compiler_rt_object_libraries(RTInterception
|
||||
OS ${SANITIZER_COMMON_SUPPORTED_OS}
|
||||
ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH}
|
||||
SOURCES ${INTERCEPTION_SOURCES}
|
||||
ADDITIONAL_HEADERS ${INTERCEPTION_HEADERS}
|
||||
CFLAGS ${INTERCEPTION_CFLAGS})
|
||||
|
||||
if(COMPILER_RT_INCLUDE_TESTS)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
@ -1,113 +0,0 @@
|
||||
include(CompilerRTCompile)
|
||||
|
||||
filter_available_targets(INTERCEPTION_UNITTEST_SUPPORTED_ARCH x86_64 i386 mips64 mips64el)
|
||||
|
||||
set(INTERCEPTION_UNITTESTS
|
||||
interception_linux_test.cc
|
||||
interception_test_main.cc
|
||||
interception_win_test.cc
|
||||
)
|
||||
|
||||
set(INTERCEPTION_TEST_HEADERS)
|
||||
|
||||
set(INTERCEPTION_TEST_CFLAGS_COMMON
|
||||
${COMPILER_RT_UNITTEST_CFLAGS}
|
||||
${COMPILER_RT_GTEST_CFLAGS}
|
||||
-I${COMPILER_RT_SOURCE_DIR}/include
|
||||
-I${COMPILER_RT_SOURCE_DIR}/lib
|
||||
-I${COMPILER_RT_SOURCE_DIR}/lib/interception
|
||||
-fno-rtti
|
||||
-O2
|
||||
-Werror=sign-compare
|
||||
-Wno-non-virtual-dtor)
|
||||
|
||||
# -gline-tables-only must be enough for these tests, so use it if possible.
|
||||
if(COMPILER_RT_TEST_COMPILER_ID MATCHES "Clang")
|
||||
list(APPEND INTERCEPTION_TEST_CFLAGS_COMMON -gline-tables-only)
|
||||
else()
|
||||
list(APPEND INTERCEPTION_TEST_CFLAGS_COMMON -g)
|
||||
endif()
|
||||
if(MSVC)
|
||||
list(APPEND INTERCEPTION_TEST_CFLAGS_COMMON -gcodeview)
|
||||
list(APPEND INTERCEPTION_TEST_LINK_FLAGS_COMMON -Wl,-largeaddressaware)
|
||||
endif()
|
||||
list(APPEND INTERCEPTION_TEST_LINK_FLAGS_COMMON -g)
|
||||
|
||||
if(NOT MSVC)
|
||||
list(APPEND INTERCEPTION_TEST_LINK_FLAGS_COMMON --driver-mode=g++)
|
||||
endif()
|
||||
|
||||
if(ANDROID)
|
||||
list(APPEND INTERCEPTION_TEST_LINK_FLAGS_COMMON -pie)
|
||||
endif()
|
||||
|
||||
set(INTERCEPTION_TEST_LINK_LIBS)
|
||||
append_list_if(COMPILER_RT_HAS_LIBLOG log INTERCEPTION_TEST_LINK_LIBS)
|
||||
# NDK r10 requires -latomic almost always.
|
||||
append_list_if(ANDROID atomic INTERCEPTION_TEST_LINK_LIBS)
|
||||
|
||||
append_list_if(COMPILER_RT_HAS_LIBDL -ldl INTERCEPTION_TEST_LINK_FLAGS_COMMON)
|
||||
append_list_if(COMPILER_RT_HAS_LIBRT -lrt INTERCEPTION_TEST_LINK_FLAGS_COMMON)
|
||||
append_list_if(COMPILER_RT_HAS_LIBPTHREAD -pthread INTERCEPTION_TEST_LINK_FLAGS_COMMON)
|
||||
# x86_64 FreeBSD 9.2 additionally requires libc++ to build the tests. Also,
|
||||
# 'libm' shall be specified explicitly to build i386 tests.
|
||||
if(CMAKE_SYSTEM MATCHES "FreeBSD-9.2-RELEASE")
|
||||
list(APPEND INTERCEPTION_TEST_LINK_FLAGS_COMMON "-lc++ -lm")
|
||||
endif()
|
||||
|
||||
include_directories(..)
|
||||
include_directories(../..)
|
||||
|
||||
# Adds static library which contains interception object file
|
||||
# (universal binary on Mac and arch-specific object files on Linux).
|
||||
macro(add_interceptor_lib library)
|
||||
add_library(${library} STATIC ${ARGN})
|
||||
set_target_properties(${library} PROPERTIES
|
||||
ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
FOLDER "Compiler-RT Runtime tests")
|
||||
endmacro()
|
||||
|
||||
function(get_interception_lib_for_arch arch lib)
|
||||
if(APPLE)
|
||||
set(tgt_name "RTInterception.test.osx")
|
||||
else()
|
||||
set(tgt_name "RTInterception.test.${arch}")
|
||||
endif()
|
||||
set(${lib} "${tgt_name}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Interception unit tests testsuite.
|
||||
add_custom_target(InterceptionUnitTests)
|
||||
set_target_properties(InterceptionUnitTests PROPERTIES
|
||||
FOLDER "Compiler-RT Tests")
|
||||
|
||||
# Adds interception tests for architecture.
|
||||
macro(add_interception_tests_for_arch arch)
|
||||
set(INTERCEPTION_TEST_OBJECTS)
|
||||
get_interception_lib_for_arch(${arch} INTERCEPTION_COMMON_LIB)
|
||||
generate_compiler_rt_tests(INTERCEPTION_TEST_OBJECTS
|
||||
InterceptionUnitTests "Interception-${arch}-Test" ${arch}
|
||||
RUNTIME ${INTERCEPTION_COMMON_LIB}
|
||||
SOURCES ${INTERCEPTION_UNITTESTS} ${COMPILER_RT_GTEST_SOURCE}
|
||||
COMPILE_DEPS ${INTERCEPTION_TEST_HEADERS}
|
||||
DEPS gtest
|
||||
CFLAGS ${INTERCEPTION_TEST_CFLAGS_COMMON}
|
||||
LINK_FLAGS ${INTERCEPTION_TEST_LINK_FLAGS_COMMON})
|
||||
endmacro()
|
||||
|
||||
if(COMPILER_RT_CAN_EXECUTE_TESTS AND NOT ANDROID AND NOT APPLE)
|
||||
# We use just-built clang to build interception unittests, so we must
|
||||
# be sure that produced binaries would work.
|
||||
if(APPLE)
|
||||
add_interceptor_lib("RTInterception.test.osx"
|
||||
$<TARGET_OBJECTS:RTInterception.osx>)
|
||||
else()
|
||||
foreach(arch ${INTERCEPTION_UNITTEST_SUPPORTED_ARCH})
|
||||
add_interceptor_lib("RTInterception.test.${arch}"
|
||||
$<TARGET_OBJECTS:RTInterception.${arch}>)
|
||||
endforeach()
|
||||
endif()
|
||||
foreach(arch ${INTERCEPTION_UNITTEST_SUPPORTED_ARCH})
|
||||
add_interception_tests_for_arch(${arch})
|
||||
endforeach()
|
||||
endif()
|
@ -1,68 +0,0 @@
|
||||
//===-- interception_linux_test.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 ThreadSanitizer/AddressSanitizer runtime.
|
||||
// Tests for interception_linux.h.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Do not declare isdigit in ctype.h.
|
||||
#define __NO_CTYPE
|
||||
|
||||
#include "interception/interception.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
// Too slow for debug build
|
||||
#if !SANITIZER_DEBUG
|
||||
#if SANITIZER_LINUX
|
||||
|
||||
static int InterceptorFunctionCalled;
|
||||
|
||||
DECLARE_REAL(int, isdigit, int);
|
||||
|
||||
INTERCEPTOR(int, isdigit, int d) {
|
||||
++InterceptorFunctionCalled;
|
||||
return d >= '0' && d <= '9';
|
||||
}
|
||||
|
||||
namespace __interception {
|
||||
|
||||
TEST(Interception, GetRealFunctionAddress) {
|
||||
uptr malloc_address = 0;
|
||||
EXPECT_TRUE(GetRealFunctionAddress("malloc", &malloc_address, 0, 0));
|
||||
EXPECT_NE(0U, malloc_address);
|
||||
|
||||
uptr dummy_address = 0;
|
||||
EXPECT_TRUE(
|
||||
GetRealFunctionAddress("dummy_doesnt_exist__", &dummy_address, 0, 0));
|
||||
EXPECT_EQ(0U, dummy_address);
|
||||
}
|
||||
|
||||
TEST(Interception, Basic) {
|
||||
ASSERT_TRUE(INTERCEPT_FUNCTION(isdigit));
|
||||
|
||||
// After interception, the counter should be incremented.
|
||||
InterceptorFunctionCalled = 0;
|
||||
EXPECT_NE(0, isdigit('1'));
|
||||
EXPECT_EQ(1, InterceptorFunctionCalled);
|
||||
EXPECT_EQ(0, isdigit('a'));
|
||||
EXPECT_EQ(2, InterceptorFunctionCalled);
|
||||
|
||||
// Calling the REAL function should not affect the counter.
|
||||
InterceptorFunctionCalled = 0;
|
||||
EXPECT_NE(0, REAL(isdigit)('1'));
|
||||
EXPECT_EQ(0, REAL(isdigit)('a'));
|
||||
EXPECT_EQ(0, InterceptorFunctionCalled);
|
||||
}
|
||||
|
||||
} // namespace __interception
|
||||
|
||||
#endif // SANITIZER_LINUX
|
||||
#endif // #if !SANITIZER_DEBUG
|
@ -1,22 +0,0 @@
|
||||
//===-- interception_test_main.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.
|
||||
//
|
||||
// Testing the machinery for providing replacements/wrappers for system
|
||||
// functions.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
testing::GTEST_FLAG(death_test_style) = "threadsafe";
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
@ -1,637 +0,0 @@
|
||||
//===-- interception_win_test.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 ThreadSanitizer/AddressSanitizer runtime.
|
||||
// Tests for interception_win.h.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "interception/interception.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
// Too slow for debug build
|
||||
#if !SANITIZER_DEBUG
|
||||
#if SANITIZER_WINDOWS
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
namespace __interception {
|
||||
namespace {
|
||||
|
||||
enum FunctionPrefixKind {
|
||||
FunctionPrefixNone,
|
||||
FunctionPrefixPadding,
|
||||
FunctionPrefixHotPatch,
|
||||
FunctionPrefixDetour,
|
||||
};
|
||||
|
||||
typedef bool (*TestOverrideFunction)(uptr, uptr, uptr*);
|
||||
typedef int (*IdentityFunction)(int);
|
||||
|
||||
#if SANITIZER_WINDOWS64
|
||||
|
||||
const u8 kIdentityCodeWithPrologue[] = {
|
||||
0x55, // push rbp
|
||||
0x48, 0x89, 0xE5, // mov rbp,rsp
|
||||
0x8B, 0xC1, // mov eax,ecx
|
||||
0x5D, // pop rbp
|
||||
0xC3, // ret
|
||||
};
|
||||
|
||||
const u8 kIdentityCodeWithPushPop[] = {
|
||||
0x55, // push rbp
|
||||
0x48, 0x89, 0xE5, // mov rbp,rsp
|
||||
0x53, // push rbx
|
||||
0x50, // push rax
|
||||
0x58, // pop rax
|
||||
0x8B, 0xC1, // mov rax,rcx
|
||||
0x5B, // pop rbx
|
||||
0x5D, // pop rbp
|
||||
0xC3, // ret
|
||||
};
|
||||
|
||||
const u8 kIdentityTwiceOffset = 16;
|
||||
const u8 kIdentityTwice[] = {
|
||||
0x55, // push rbp
|
||||
0x48, 0x89, 0xE5, // mov rbp,rsp
|
||||
0x8B, 0xC1, // mov eax,ecx
|
||||
0x5D, // pop rbp
|
||||
0xC3, // ret
|
||||
0x90, 0x90, 0x90, 0x90,
|
||||
0x90, 0x90, 0x90, 0x90,
|
||||
0x55, // push rbp
|
||||
0x48, 0x89, 0xE5, // mov rbp,rsp
|
||||
0x8B, 0xC1, // mov eax,ecx
|
||||
0x5D, // pop rbp
|
||||
0xC3, // ret
|
||||
};
|
||||
|
||||
const u8 kIdentityCodeWithMov[] = {
|
||||
0x89, 0xC8, // mov eax, ecx
|
||||
0xC3, // ret
|
||||
};
|
||||
|
||||
const u8 kIdentityCodeWithJump[] = {
|
||||
0xE9, 0x04, 0x00, 0x00,
|
||||
0x00, // jmp + 4
|
||||
0xCC, 0xCC, 0xCC, 0xCC,
|
||||
0x89, 0xC8, // mov eax, ecx
|
||||
0xC3, // ret
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
const u8 kIdentityCodeWithPrologue[] = {
|
||||
0x55, // push ebp
|
||||
0x8B, 0xEC, // mov ebp,esp
|
||||
0x8B, 0x45, 0x08, // mov eax,dword ptr [ebp + 8]
|
||||
0x5D, // pop ebp
|
||||
0xC3, // ret
|
||||
};
|
||||
|
||||
const u8 kIdentityCodeWithPushPop[] = {
|
||||
0x55, // push ebp
|
||||
0x8B, 0xEC, // mov ebp,esp
|
||||
0x53, // push ebx
|
||||
0x50, // push eax
|
||||
0x58, // pop eax
|
||||
0x8B, 0x45, 0x08, // mov eax,dword ptr [ebp + 8]
|
||||
0x5B, // pop ebx
|
||||
0x5D, // pop ebp
|
||||
0xC3, // ret
|
||||
};
|
||||
|
||||
const u8 kIdentityTwiceOffset = 8;
|
||||
const u8 kIdentityTwice[] = {
|
||||
0x55, // push ebp
|
||||
0x8B, 0xEC, // mov ebp,esp
|
||||
0x8B, 0x45, 0x08, // mov eax,dword ptr [ebp + 8]
|
||||
0x5D, // pop ebp
|
||||
0xC3, // ret
|
||||
0x55, // push ebp
|
||||
0x8B, 0xEC, // mov ebp,esp
|
||||
0x8B, 0x45, 0x08, // mov eax,dword ptr [ebp + 8]
|
||||
0x5D, // pop ebp
|
||||
0xC3, // ret
|
||||
};
|
||||
|
||||
const u8 kIdentityCodeWithMov[] = {
|
||||
0x8B, 0x44, 0x24, 0x04, // mov eax,dword ptr [esp + 4]
|
||||
0xC3, // ret
|
||||
};
|
||||
|
||||
const u8 kIdentityCodeWithJump[] = {
|
||||
0xE9, 0x04, 0x00, 0x00,
|
||||
0x00, // jmp + 4
|
||||
0xCC, 0xCC, 0xCC, 0xCC,
|
||||
0x8B, 0x44, 0x24, 0x04, // mov eax,dword ptr [esp + 4]
|
||||
0xC3, // ret
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
const u8 kPatchableCode1[] = {
|
||||
0xB8, 0x4B, 0x00, 0x00, 0x00, // mov eax,4B
|
||||
0x33, 0xC9, // xor ecx,ecx
|
||||
0xC3, // ret
|
||||
};
|
||||
|
||||
const u8 kPatchableCode2[] = {
|
||||
0x55, // push ebp
|
||||
0x8B, 0xEC, // mov ebp,esp
|
||||
0x33, 0xC0, // xor eax,eax
|
||||
0x5D, // pop ebp
|
||||
0xC3, // ret
|
||||
};
|
||||
|
||||
const u8 kPatchableCode3[] = {
|
||||
0x55, // push ebp
|
||||
0x8B, 0xEC, // mov ebp,esp
|
||||
0x6A, 0x00, // push 0
|
||||
0xE8, 0x3D, 0xFF, 0xFF, 0xFF, // call <func>
|
||||
};
|
||||
|
||||
const u8 kPatchableCode4[] = {
|
||||
0xE9, 0xCC, 0xCC, 0xCC, 0xCC, // jmp <label>
|
||||
0x90, 0x90, 0x90, 0x90,
|
||||
};
|
||||
|
||||
const u8 kPatchableCode5[] = {
|
||||
0x55, // push ebp
|
||||
0x8b, 0xec, // mov ebp,esp
|
||||
0x8d, 0xa4, 0x24, 0x30, 0xfd, 0xff, 0xff, // lea esp,[esp-2D0h]
|
||||
0x54, // push esp
|
||||
};
|
||||
|
||||
#if SANITIZER_WINDOWS64
|
||||
u8 kLoadGlobalCode[] = {
|
||||
0x8B, 0x05, 0x00, 0x00, 0x00, 0x00, // mov eax [rip + global]
|
||||
0xC3, // ret
|
||||
};
|
||||
#endif
|
||||
|
||||
const u8 kUnpatchableCode1[] = {
|
||||
0xC3, // ret
|
||||
};
|
||||
|
||||
const u8 kUnpatchableCode2[] = {
|
||||
0x33, 0xC9, // xor ecx,ecx
|
||||
0xC3, // ret
|
||||
};
|
||||
|
||||
const u8 kUnpatchableCode3[] = {
|
||||
0x75, 0xCC, // jne <label>
|
||||
0x33, 0xC9, // xor ecx,ecx
|
||||
0xC3, // ret
|
||||
};
|
||||
|
||||
const u8 kUnpatchableCode4[] = {
|
||||
0x74, 0xCC, // jne <label>
|
||||
0x33, 0xC9, // xor ecx,ecx
|
||||
0xC3, // ret
|
||||
};
|
||||
|
||||
const u8 kUnpatchableCode5[] = {
|
||||
0xEB, 0x02, // jmp <label>
|
||||
0x33, 0xC9, // xor ecx,ecx
|
||||
0xC3, // ret
|
||||
};
|
||||
|
||||
const u8 kUnpatchableCode6[] = {
|
||||
0xE8, 0xCC, 0xCC, 0xCC, 0xCC, // call <func>
|
||||
0x90, 0x90, 0x90, 0x90,
|
||||
};
|
||||
|
||||
// A buffer holding the dynamically generated code under test.
|
||||
u8* ActiveCode;
|
||||
const size_t ActiveCodeLength = 4096;
|
||||
|
||||
int InterceptorFunction(int x);
|
||||
|
||||
/// Allocate code memory more than 2GB away from Base.
|
||||
u8 *AllocateCode2GBAway(u8 *Base) {
|
||||
// Find a 64K aligned location after Base plus 2GB.
|
||||
size_t TwoGB = 0x80000000;
|
||||
size_t AllocGranularity = 0x10000;
|
||||
Base = (u8 *)((((uptr)Base + TwoGB + AllocGranularity)) & ~(AllocGranularity - 1));
|
||||
|
||||
// Check if that location is free, and if not, loop over regions until we find
|
||||
// one that is.
|
||||
MEMORY_BASIC_INFORMATION mbi = {};
|
||||
while (sizeof(mbi) == VirtualQuery(Base, &mbi, sizeof(mbi))) {
|
||||
if (mbi.State & MEM_FREE) break;
|
||||
Base += mbi.RegionSize;
|
||||
}
|
||||
|
||||
// Allocate one RWX page at the free location.
|
||||
return (u8 *)::VirtualAlloc(Base, ActiveCodeLength, MEM_COMMIT | MEM_RESERVE,
|
||||
PAGE_EXECUTE_READWRITE);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
static void LoadActiveCode(
|
||||
const T &code,
|
||||
uptr *entry_point,
|
||||
FunctionPrefixKind prefix_kind = FunctionPrefixNone) {
|
||||
if (ActiveCode == nullptr) {
|
||||
ActiveCode = AllocateCode2GBAway((u8*)&InterceptorFunction);
|
||||
ASSERT_NE(ActiveCode, nullptr) << "failed to allocate RWX memory 2GB away";
|
||||
}
|
||||
|
||||
size_t position = 0;
|
||||
|
||||
// Add padding to avoid memory violation when scanning the prefix.
|
||||
for (int i = 0; i < 16; ++i)
|
||||
ActiveCode[position++] = 0xC3; // Instruction 'ret'.
|
||||
|
||||
// Add function padding.
|
||||
size_t padding = 0;
|
||||
if (prefix_kind == FunctionPrefixPadding)
|
||||
padding = 16;
|
||||
else if (prefix_kind == FunctionPrefixDetour ||
|
||||
prefix_kind == FunctionPrefixHotPatch)
|
||||
padding = FIRST_32_SECOND_64(5, 6);
|
||||
// Insert |padding| instructions 'nop'.
|
||||
for (size_t i = 0; i < padding; ++i)
|
||||
ActiveCode[position++] = 0x90;
|
||||
|
||||
// Keep track of the entry point.
|
||||
*entry_point = (uptr)&ActiveCode[position];
|
||||
|
||||
// Add the detour instruction (i.e. mov edi, edi)
|
||||
if (prefix_kind == FunctionPrefixDetour) {
|
||||
#if SANITIZER_WINDOWS64
|
||||
// Note that "mov edi,edi" is NOP in 32-bit only, in 64-bit it clears
|
||||
// higher bits of RDI.
|
||||
// Use 66,90H as NOP for Windows64.
|
||||
ActiveCode[position++] = 0x66;
|
||||
ActiveCode[position++] = 0x90;
|
||||
#else
|
||||
// mov edi,edi.
|
||||
ActiveCode[position++] = 0x8B;
|
||||
ActiveCode[position++] = 0xFF;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
// Copy the function body.
|
||||
for (size_t i = 0; i < sizeof(T); ++i)
|
||||
ActiveCode[position++] = code[i];
|
||||
}
|
||||
|
||||
int InterceptorFunctionCalled;
|
||||
IdentityFunction InterceptedRealFunction;
|
||||
|
||||
int InterceptorFunction(int x) {
|
||||
++InterceptorFunctionCalled;
|
||||
return InterceptedRealFunction(x);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// Tests for interception_win.h
|
||||
TEST(Interception, InternalGetProcAddress) {
|
||||
HMODULE ntdll_handle = ::GetModuleHandle("ntdll");
|
||||
ASSERT_NE(nullptr, ntdll_handle);
|
||||
uptr DbgPrint_expected = (uptr)::GetProcAddress(ntdll_handle, "DbgPrint");
|
||||
uptr isdigit_expected = (uptr)::GetProcAddress(ntdll_handle, "isdigit");
|
||||
uptr DbgPrint_adddress = InternalGetProcAddress(ntdll_handle, "DbgPrint");
|
||||
uptr isdigit_address = InternalGetProcAddress(ntdll_handle, "isdigit");
|
||||
|
||||
EXPECT_EQ(DbgPrint_expected, DbgPrint_adddress);
|
||||
EXPECT_EQ(isdigit_expected, isdigit_address);
|
||||
EXPECT_NE(DbgPrint_adddress, isdigit_address);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
static void TestIdentityFunctionPatching(
|
||||
const T &code,
|
||||
TestOverrideFunction override,
|
||||
FunctionPrefixKind prefix_kind = FunctionPrefixNone) {
|
||||
uptr identity_address;
|
||||
LoadActiveCode(code, &identity_address, prefix_kind);
|
||||
IdentityFunction identity = (IdentityFunction)identity_address;
|
||||
|
||||
// Validate behavior before dynamic patching.
|
||||
InterceptorFunctionCalled = 0;
|
||||
EXPECT_EQ(0, identity(0));
|
||||
EXPECT_EQ(42, identity(42));
|
||||
EXPECT_EQ(0, InterceptorFunctionCalled);
|
||||
|
||||
// Patch the function.
|
||||
uptr real_identity_address = 0;
|
||||
bool success = override(identity_address,
|
||||
(uptr)&InterceptorFunction,
|
||||
&real_identity_address);
|
||||
EXPECT_TRUE(success);
|
||||
EXPECT_NE(0U, real_identity_address);
|
||||
IdentityFunction real_identity = (IdentityFunction)real_identity_address;
|
||||
InterceptedRealFunction = real_identity;
|
||||
|
||||
// Don't run tests if hooking failed or the real function is not valid.
|
||||
if (!success || !real_identity_address)
|
||||
return;
|
||||
|
||||
// Calling the redirected function.
|
||||
InterceptorFunctionCalled = 0;
|
||||
EXPECT_EQ(0, identity(0));
|
||||
EXPECT_EQ(42, identity(42));
|
||||
EXPECT_EQ(2, InterceptorFunctionCalled);
|
||||
|
||||
// Calling the real function.
|
||||
InterceptorFunctionCalled = 0;
|
||||
EXPECT_EQ(0, real_identity(0));
|
||||
EXPECT_EQ(42, real_identity(42));
|
||||
EXPECT_EQ(0, InterceptorFunctionCalled);
|
||||
|
||||
TestOnlyReleaseTrampolineRegions();
|
||||
}
|
||||
|
||||
#if !SANITIZER_WINDOWS64
|
||||
TEST(Interception, OverrideFunctionWithDetour) {
|
||||
TestOverrideFunction override = OverrideFunctionWithDetour;
|
||||
FunctionPrefixKind prefix = FunctionPrefixDetour;
|
||||
TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix);
|
||||
TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix);
|
||||
TestIdentityFunctionPatching(kIdentityCodeWithMov, override, prefix);
|
||||
TestIdentityFunctionPatching(kIdentityCodeWithJump, override, prefix);
|
||||
}
|
||||
#endif // !SANITIZER_WINDOWS64
|
||||
|
||||
TEST(Interception, OverrideFunctionWithRedirectJump) {
|
||||
TestOverrideFunction override = OverrideFunctionWithRedirectJump;
|
||||
TestIdentityFunctionPatching(kIdentityCodeWithJump, override);
|
||||
}
|
||||
|
||||
TEST(Interception, OverrideFunctionWithHotPatch) {
|
||||
TestOverrideFunction override = OverrideFunctionWithHotPatch;
|
||||
FunctionPrefixKind prefix = FunctionPrefixHotPatch;
|
||||
TestIdentityFunctionPatching(kIdentityCodeWithMov, override, prefix);
|
||||
}
|
||||
|
||||
TEST(Interception, OverrideFunctionWithTrampoline) {
|
||||
TestOverrideFunction override = OverrideFunctionWithTrampoline;
|
||||
FunctionPrefixKind prefix = FunctionPrefixNone;
|
||||
TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix);
|
||||
TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix);
|
||||
|
||||
prefix = FunctionPrefixPadding;
|
||||
TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix);
|
||||
TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix);
|
||||
}
|
||||
|
||||
TEST(Interception, OverrideFunction) {
|
||||
TestOverrideFunction override = OverrideFunction;
|
||||
FunctionPrefixKind prefix = FunctionPrefixNone;
|
||||
TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix);
|
||||
TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix);
|
||||
TestIdentityFunctionPatching(kIdentityCodeWithJump, override, prefix);
|
||||
|
||||
prefix = FunctionPrefixPadding;
|
||||
TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix);
|
||||
TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix);
|
||||
TestIdentityFunctionPatching(kIdentityCodeWithMov, override, prefix);
|
||||
TestIdentityFunctionPatching(kIdentityCodeWithJump, override, prefix);
|
||||
|
||||
prefix = FunctionPrefixHotPatch;
|
||||
TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix);
|
||||
TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix);
|
||||
TestIdentityFunctionPatching(kIdentityCodeWithMov, override, prefix);
|
||||
TestIdentityFunctionPatching(kIdentityCodeWithJump, override, prefix);
|
||||
|
||||
prefix = FunctionPrefixDetour;
|
||||
TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix);
|
||||
TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix);
|
||||
TestIdentityFunctionPatching(kIdentityCodeWithMov, override, prefix);
|
||||
TestIdentityFunctionPatching(kIdentityCodeWithJump, override, prefix);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
static void TestIdentityFunctionMultiplePatching(
|
||||
const T &code,
|
||||
TestOverrideFunction override,
|
||||
FunctionPrefixKind prefix_kind = FunctionPrefixNone) {
|
||||
uptr identity_address;
|
||||
LoadActiveCode(code, &identity_address, prefix_kind);
|
||||
|
||||
// Patch the function.
|
||||
uptr real_identity_address = 0;
|
||||
bool success = override(identity_address,
|
||||
(uptr)&InterceptorFunction,
|
||||
&real_identity_address);
|
||||
EXPECT_TRUE(success);
|
||||
EXPECT_NE(0U, real_identity_address);
|
||||
|
||||
// Re-patching the function should not work.
|
||||
success = override(identity_address,
|
||||
(uptr)&InterceptorFunction,
|
||||
&real_identity_address);
|
||||
EXPECT_FALSE(success);
|
||||
|
||||
TestOnlyReleaseTrampolineRegions();
|
||||
}
|
||||
|
||||
TEST(Interception, OverrideFunctionMultiplePatchingIsFailing) {
|
||||
#if !SANITIZER_WINDOWS64
|
||||
TestIdentityFunctionMultiplePatching(kIdentityCodeWithPrologue,
|
||||
OverrideFunctionWithDetour,
|
||||
FunctionPrefixDetour);
|
||||
#endif
|
||||
|
||||
TestIdentityFunctionMultiplePatching(kIdentityCodeWithMov,
|
||||
OverrideFunctionWithHotPatch,
|
||||
FunctionPrefixHotPatch);
|
||||
|
||||
TestIdentityFunctionMultiplePatching(kIdentityCodeWithPushPop,
|
||||
OverrideFunctionWithTrampoline,
|
||||
FunctionPrefixPadding);
|
||||
}
|
||||
|
||||
TEST(Interception, OverrideFunctionTwice) {
|
||||
uptr identity_address1;
|
||||
LoadActiveCode(kIdentityTwice, &identity_address1);
|
||||
uptr identity_address2 = identity_address1 + kIdentityTwiceOffset;
|
||||
IdentityFunction identity1 = (IdentityFunction)identity_address1;
|
||||
IdentityFunction identity2 = (IdentityFunction)identity_address2;
|
||||
|
||||
// Patch the two functions.
|
||||
uptr real_identity_address = 0;
|
||||
EXPECT_TRUE(OverrideFunction(identity_address1,
|
||||
(uptr)&InterceptorFunction,
|
||||
&real_identity_address));
|
||||
EXPECT_TRUE(OverrideFunction(identity_address2,
|
||||
(uptr)&InterceptorFunction,
|
||||
&real_identity_address));
|
||||
IdentityFunction real_identity = (IdentityFunction)real_identity_address;
|
||||
InterceptedRealFunction = real_identity;
|
||||
|
||||
// Calling the redirected function.
|
||||
InterceptorFunctionCalled = 0;
|
||||
EXPECT_EQ(42, identity1(42));
|
||||
EXPECT_EQ(42, identity2(42));
|
||||
EXPECT_EQ(2, InterceptorFunctionCalled);
|
||||
|
||||
TestOnlyReleaseTrampolineRegions();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
static bool TestFunctionPatching(
|
||||
const T &code,
|
||||
TestOverrideFunction override,
|
||||
FunctionPrefixKind prefix_kind = FunctionPrefixNone) {
|
||||
uptr address;
|
||||
LoadActiveCode(code, &address, prefix_kind);
|
||||
uptr unused_real_address = 0;
|
||||
bool result = override(
|
||||
address, (uptr)&InterceptorFunction, &unused_real_address);
|
||||
|
||||
TestOnlyReleaseTrampolineRegions();
|
||||
return result;
|
||||
}
|
||||
|
||||
TEST(Interception, PatchableFunction) {
|
||||
TestOverrideFunction override = OverrideFunction;
|
||||
// Test without function padding.
|
||||
EXPECT_TRUE(TestFunctionPatching(kPatchableCode1, override));
|
||||
EXPECT_TRUE(TestFunctionPatching(kPatchableCode2, override));
|
||||
#if SANITIZER_WINDOWS64
|
||||
EXPECT_FALSE(TestFunctionPatching(kPatchableCode3, override));
|
||||
#else
|
||||
EXPECT_TRUE(TestFunctionPatching(kPatchableCode3, override));
|
||||
#endif
|
||||
EXPECT_TRUE(TestFunctionPatching(kPatchableCode4, override));
|
||||
EXPECT_TRUE(TestFunctionPatching(kPatchableCode5, override));
|
||||
|
||||
#if SANITIZER_WINDOWS64
|
||||
EXPECT_TRUE(TestFunctionPatching(kLoadGlobalCode, override));
|
||||
#endif
|
||||
|
||||
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1, override));
|
||||
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode2, override));
|
||||
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode3, override));
|
||||
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode4, override));
|
||||
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode5, override));
|
||||
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode6, override));
|
||||
}
|
||||
|
||||
#if !SANITIZER_WINDOWS64
|
||||
TEST(Interception, PatchableFunctionWithDetour) {
|
||||
TestOverrideFunction override = OverrideFunctionWithDetour;
|
||||
// Without the prefix, no function can be detoured.
|
||||
EXPECT_FALSE(TestFunctionPatching(kPatchableCode1, override));
|
||||
EXPECT_FALSE(TestFunctionPatching(kPatchableCode2, override));
|
||||
EXPECT_FALSE(TestFunctionPatching(kPatchableCode3, override));
|
||||
EXPECT_FALSE(TestFunctionPatching(kPatchableCode4, override));
|
||||
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1, override));
|
||||
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode2, override));
|
||||
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode3, override));
|
||||
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode4, override));
|
||||
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode5, override));
|
||||
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode6, override));
|
||||
|
||||
// With the prefix, all functions can be detoured.
|
||||
FunctionPrefixKind prefix = FunctionPrefixDetour;
|
||||
EXPECT_TRUE(TestFunctionPatching(kPatchableCode1, override, prefix));
|
||||
EXPECT_TRUE(TestFunctionPatching(kPatchableCode2, override, prefix));
|
||||
EXPECT_TRUE(TestFunctionPatching(kPatchableCode3, override, prefix));
|
||||
EXPECT_TRUE(TestFunctionPatching(kPatchableCode4, override, prefix));
|
||||
EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode1, override, prefix));
|
||||
EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode2, override, prefix));
|
||||
EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode3, override, prefix));
|
||||
EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode4, override, prefix));
|
||||
EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode5, override, prefix));
|
||||
EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode6, override, prefix));
|
||||
}
|
||||
#endif // !SANITIZER_WINDOWS64
|
||||
|
||||
TEST(Interception, PatchableFunctionWithRedirectJump) {
|
||||
TestOverrideFunction override = OverrideFunctionWithRedirectJump;
|
||||
EXPECT_FALSE(TestFunctionPatching(kPatchableCode1, override));
|
||||
EXPECT_FALSE(TestFunctionPatching(kPatchableCode2, override));
|
||||
EXPECT_FALSE(TestFunctionPatching(kPatchableCode3, override));
|
||||
EXPECT_TRUE(TestFunctionPatching(kPatchableCode4, override));
|
||||
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1, override));
|
||||
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode2, override));
|
||||
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode3, override));
|
||||
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode4, override));
|
||||
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode5, override));
|
||||
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode6, override));
|
||||
}
|
||||
|
||||
TEST(Interception, PatchableFunctionWithHotPatch) {
|
||||
TestOverrideFunction override = OverrideFunctionWithHotPatch;
|
||||
FunctionPrefixKind prefix = FunctionPrefixHotPatch;
|
||||
|
||||
EXPECT_TRUE(TestFunctionPatching(kPatchableCode1, override, prefix));
|
||||
EXPECT_FALSE(TestFunctionPatching(kPatchableCode2, override, prefix));
|
||||
EXPECT_FALSE(TestFunctionPatching(kPatchableCode3, override, prefix));
|
||||
EXPECT_FALSE(TestFunctionPatching(kPatchableCode4, override, prefix));
|
||||
|
||||
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1, override, prefix));
|
||||
EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode2, override, prefix));
|
||||
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode3, override, prefix));
|
||||
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode4, override, prefix));
|
||||
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode5, override, prefix));
|
||||
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode6, override, prefix));
|
||||
}
|
||||
|
||||
TEST(Interception, PatchableFunctionWithTrampoline) {
|
||||
TestOverrideFunction override = OverrideFunctionWithTrampoline;
|
||||
FunctionPrefixKind prefix = FunctionPrefixPadding;
|
||||
|
||||
EXPECT_TRUE(TestFunctionPatching(kPatchableCode1, override, prefix));
|
||||
EXPECT_TRUE(TestFunctionPatching(kPatchableCode2, override, prefix));
|
||||
#if SANITIZER_WINDOWS64
|
||||
EXPECT_FALSE(TestFunctionPatching(kPatchableCode3, override, prefix));
|
||||
#else
|
||||
EXPECT_TRUE(TestFunctionPatching(kPatchableCode3, override, prefix));
|
||||
#endif
|
||||
EXPECT_FALSE(TestFunctionPatching(kPatchableCode4, override, prefix));
|
||||
|
||||
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1, override, prefix));
|
||||
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode2, override, prefix));
|
||||
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode3, override, prefix));
|
||||
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode4, override, prefix));
|
||||
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode5, override, prefix));
|
||||
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode6, override, prefix));
|
||||
}
|
||||
|
||||
TEST(Interception, PatchableFunctionPadding) {
|
||||
TestOverrideFunction override = OverrideFunction;
|
||||
FunctionPrefixKind prefix = FunctionPrefixPadding;
|
||||
|
||||
EXPECT_TRUE(TestFunctionPatching(kPatchableCode1, override, prefix));
|
||||
EXPECT_TRUE(TestFunctionPatching(kPatchableCode2, override, prefix));
|
||||
#if SANITIZER_WINDOWS64
|
||||
EXPECT_FALSE(TestFunctionPatching(kPatchableCode3, override, prefix));
|
||||
#else
|
||||
EXPECT_TRUE(TestFunctionPatching(kPatchableCode3, override, prefix));
|
||||
#endif
|
||||
EXPECT_TRUE(TestFunctionPatching(kPatchableCode4, override, prefix));
|
||||
|
||||
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1, override, prefix));
|
||||
EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode2, override, prefix));
|
||||
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode3, override, prefix));
|
||||
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode4, override, prefix));
|
||||
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode5, override, prefix));
|
||||
EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode6, override, prefix));
|
||||
}
|
||||
|
||||
TEST(Interception, EmptyExportTable) {
|
||||
// We try to get a pointer to a function from an executable that doesn't
|
||||
// export any symbol (empty export table).
|
||||
uptr FunPtr = InternalGetProcAddress((void *)GetModuleHandleA(0), "example");
|
||||
EXPECT_EQ(0U, FunPtr);
|
||||
}
|
||||
|
||||
} // namespace __interception
|
||||
|
||||
#endif // SANITIZER_WINDOWS
|
||||
#endif // #if !SANITIZER_DEBUG
|
@ -1,2 +0,0 @@
|
||||
BasedOnStyle: Google
|
||||
AllowShortIfStatementsOnASingleLine: false
|
@ -1,78 +0,0 @@
|
||||
include_directories(..)
|
||||
|
||||
set(LSAN_CFLAGS ${SANITIZER_COMMON_CFLAGS})
|
||||
append_rtti_flag(OFF LSAN_CFLAGS)
|
||||
|
||||
set(LSAN_COMMON_SOURCES
|
||||
lsan_common.cc
|
||||
lsan_common_linux.cc
|
||||
lsan_common_mac.cc)
|
||||
|
||||
set(LSAN_SOURCES
|
||||
lsan.cc
|
||||
lsan_allocator.cc
|
||||
lsan_linux.cc
|
||||
lsan_interceptors.cc
|
||||
lsan_mac.cc
|
||||
lsan_malloc_mac.cc
|
||||
lsan_preinit.cc
|
||||
lsan_thread.cc)
|
||||
|
||||
set(LSAN_HEADERS
|
||||
lsan.h
|
||||
lsan_allocator.h
|
||||
lsan_common.h
|
||||
lsan_flags.inc
|
||||
lsan_thread.h)
|
||||
|
||||
set(LSAN_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
add_compiler_rt_object_libraries(RTLSanCommon
|
||||
OS ${SANITIZER_COMMON_SUPPORTED_OS}
|
||||
ARCHS ${LSAN_COMMON_SUPPORTED_ARCH}
|
||||
SOURCES ${LSAN_COMMON_SOURCES}
|
||||
ADDITIONAL_HEADERS ${LSAN_HEADERS}
|
||||
CFLAGS ${LSAN_CFLAGS})
|
||||
|
||||
if(COMPILER_RT_HAS_LSAN)
|
||||
add_compiler_rt_component(lsan)
|
||||
if(APPLE)
|
||||
set(LSAN_LINK_LIBS ${SANITIZER_COMMON_LINK_LIBS})
|
||||
|
||||
add_weak_symbols("lsan" WEAK_SYMBOL_LINK_FLAGS)
|
||||
add_weak_symbols("sanitizer_common" WEAK_SYMBOL_LINK_FLAGS)
|
||||
|
||||
add_compiler_rt_runtime(clang_rt.lsan
|
||||
SHARED
|
||||
OS ${SANITIZER_COMMON_SUPPORTED_OS}
|
||||
ARCHS ${LSAN_SUPPORTED_ARCH}
|
||||
SOURCES ${LSAN_SOURCES}
|
||||
ADDITIONAL_HEADERS ${LSAN_HEADERS}
|
||||
OBJECT_LIBS RTLSanCommon
|
||||
RTInterception
|
||||
RTSanitizerCommon
|
||||
RTSanitizerCommonLibc
|
||||
RTSanitizerCommonCoverage
|
||||
RTSanitizerCommonSymbolizer
|
||||
CFLAGS ${LSAN_CFLAGS}
|
||||
LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS} ${WEAK_SYMBOL_LINK_FLAGS}
|
||||
LINK_LIBS ${LSAN_LINK_LIBS}
|
||||
PARENT_TARGET lsan)
|
||||
else()
|
||||
foreach(arch ${LSAN_SUPPORTED_ARCH})
|
||||
add_compiler_rt_runtime(clang_rt.lsan
|
||||
STATIC
|
||||
ARCHS ${arch}
|
||||
SOURCES ${LSAN_SOURCES}
|
||||
$<TARGET_OBJECTS:RTInterception.${arch}>
|
||||
$<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
|
||||
$<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
|
||||
$<TARGET_OBJECTS:RTSanitizerCommonCoverage.${arch}>
|
||||
$<TARGET_OBJECTS:RTSanitizerCommonSymbolizer.${arch}>
|
||||
$<TARGET_OBJECTS:RTLSanCommon.${arch}>
|
||||
ADDITIONAL_HEADERS ${LSAN_HEADERS}
|
||||
CFLAGS ${LSAN_CFLAGS}
|
||||
PARENT_TARGET lsan)
|
||||
endforeach()
|
||||
endif()
|
||||
endif()
|
@ -1,2 +0,0 @@
|
||||
BasedOnStyle: Google
|
||||
AllowShortIfStatementsOnASingleLine: false
|
@ -1,86 +0,0 @@
|
||||
include_directories(..)
|
||||
|
||||
# Runtime library sources and build flags.
|
||||
set(MSAN_RTL_SOURCES
|
||||
msan.cc
|
||||
msan_allocator.cc
|
||||
msan_chained_origin_depot.cc
|
||||
msan_interceptors.cc
|
||||
msan_linux.cc
|
||||
msan_report.cc
|
||||
msan_thread.cc
|
||||
msan_poisoning.cc
|
||||
)
|
||||
|
||||
set(MSAN_RTL_CXX_SOURCES
|
||||
msan_new_delete.cc)
|
||||
|
||||
set(MSAN_RTL_HEADERS
|
||||
msan.h
|
||||
msan_allocator.h
|
||||
msan_chained_origin_depot.h
|
||||
msan_flags.h
|
||||
msan_flags.inc
|
||||
msan_interface_internal.h
|
||||
msan_origin.h
|
||||
msan_poisoning.h
|
||||
msan_report.h
|
||||
msan_thread.h)
|
||||
|
||||
set(MSAN_RTL_CFLAGS ${SANITIZER_COMMON_CFLAGS})
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
|
||||
append_list_if(COMPILER_RT_HAS_FTLS_MODEL_INITIAL_EXEC -ftls-model=initial-exec MSAN_RTL_CFLAGS)
|
||||
endif()
|
||||
append_rtti_flag(OFF MSAN_RTL_CFLAGS)
|
||||
if(NOT CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
|
||||
append_list_if(COMPILER_RT_HAS_FPIE_FLAG -fPIE MSAN_RTL_CFLAGS)
|
||||
endif()
|
||||
# Prevent clang from generating libc calls.
|
||||
append_list_if(COMPILER_RT_HAS_FFREESTANDING_FLAG -ffreestanding MSAN_RTL_CFLAGS)
|
||||
|
||||
set(MSAN_RUNTIME_LIBRARIES)
|
||||
|
||||
# Static runtime library.
|
||||
add_compiler_rt_component(msan)
|
||||
|
||||
foreach(arch ${MSAN_SUPPORTED_ARCH})
|
||||
add_compiler_rt_runtime(clang_rt.msan
|
||||
STATIC
|
||||
ARCHS ${arch}
|
||||
SOURCES ${MSAN_RTL_SOURCES}
|
||||
$<TARGET_OBJECTS:RTInterception.${arch}>
|
||||
$<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
|
||||
$<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
|
||||
$<TARGET_OBJECTS:RTSanitizerCommonCoverage.${arch}>
|
||||
$<TARGET_OBJECTS:RTSanitizerCommonSymbolizer.${arch}>
|
||||
$<TARGET_OBJECTS:RTUbsan.${arch}>
|
||||
ADDITIONAL_HEADERS ${MSAN_RTL_HEADERS}
|
||||
CFLAGS ${MSAN_RTL_CFLAGS}
|
||||
PARENT_TARGET msan)
|
||||
add_compiler_rt_runtime(clang_rt.msan_cxx
|
||||
STATIC
|
||||
ARCHS ${arch}
|
||||
SOURCES ${MSAN_RTL_CXX_SOURCES}
|
||||
$<TARGET_OBJECTS:RTUbsan_cxx.${arch}>
|
||||
ADDITIONAL_HEADERS ${MSAN_RTL_HEADERS}
|
||||
CFLAGS ${MSAN_RTL_CFLAGS}
|
||||
PARENT_TARGET msan)
|
||||
list(APPEND MSAN_RUNTIME_LIBRARIES clang_rt.msan-${arch}
|
||||
clang_rt.msan_cxx-${arch})
|
||||
if(SANITIZER_USE_SYMBOLS)
|
||||
add_sanitizer_rt_symbols(clang_rt.msan
|
||||
ARCHS ${arch}
|
||||
EXTRA msan.syms.extra)
|
||||
add_sanitizer_rt_symbols(clang_rt.msan_cxx
|
||||
ARCHS ${arch}
|
||||
EXTRA msan.syms.extra)
|
||||
add_dependencies(msan clang_rt.msan-${arch}-symbols
|
||||
clang_rt.msan_cxx-${arch}-symbols)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
add_compiler_rt_resource_file(msan_blacklist msan_blacklist.txt msan)
|
||||
|
||||
if(COMPILER_RT_INCLUDE_TESTS)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
@ -1,142 +0,0 @@
|
||||
include(CheckCXXCompilerFlag)
|
||||
include(CompilerRTCompile)
|
||||
include(CompilerRTLink)
|
||||
|
||||
include_directories(..)
|
||||
include_directories(../..)
|
||||
|
||||
set(MSAN_LIBCXX_CFLAGS
|
||||
-fsanitize=memory
|
||||
-fsanitize-memory-track-origins
|
||||
-Wno-pedantic)
|
||||
|
||||
# Unittest sources and build flags.
|
||||
set(MSAN_UNITTEST_SOURCES msan_test.cc msan_test_main.cc)
|
||||
set(MSAN_LOADABLE_SOURCE msan_loadable.cc)
|
||||
set(MSAN_UNITTEST_HEADERS
|
||||
msan_test_config.h
|
||||
../../../include/sanitizer/msan_interface.h
|
||||
)
|
||||
set(MSAN_UNITTEST_COMMON_CFLAGS
|
||||
-nostdinc++
|
||||
-isystem ${COMPILER_RT_LIBCXX_PATH}/include
|
||||
${COMPILER_RT_UNITTEST_CFLAGS}
|
||||
${COMPILER_RT_GTEST_CFLAGS}
|
||||
-I${COMPILER_RT_SOURCE_DIR}/include
|
||||
-I${COMPILER_RT_SOURCE_DIR}/lib
|
||||
-I${COMPILER_RT_SOURCE_DIR}/lib/msan
|
||||
-g
|
||||
-O2
|
||||
-fno-exceptions
|
||||
-fno-omit-frame-pointer
|
||||
-mno-omit-leaf-frame-pointer
|
||||
-Wno-deprecated-declarations
|
||||
-Wno-unused-variable
|
||||
-Wno-zero-length-array
|
||||
-Wno-uninitialized
|
||||
-Werror=sign-compare
|
||||
-Wno-gnu-zero-variadic-macro-arguments
|
||||
)
|
||||
# Remove -stdlib= which is unused when passing -nostdinc++.
|
||||
string(REGEX REPLACE "-stdlib=[a-zA-Z+]*" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
|
||||
|
||||
set(MSAN_UNITTEST_INSTRUMENTED_CFLAGS
|
||||
${MSAN_UNITTEST_COMMON_CFLAGS}
|
||||
-fsanitize=memory
|
||||
-fsanitize-memory-track-origins
|
||||
-mllvm -msan-keep-going=1
|
||||
)
|
||||
set(MSAN_UNITTEST_LINK_FLAGS
|
||||
-fsanitize=memory
|
||||
# Don't need -stdlib=libc++ because we explicitly list libc++.so in the linker
|
||||
# inputs.
|
||||
# FIXME: we build libcxx without cxxabi and need libstdc++ to provide it.
|
||||
-lstdc++
|
||||
)
|
||||
|
||||
append_list_if(COMPILER_RT_HAS_LIBDL -ldl MSAN_UNITTEST_LINK_FLAGS)
|
||||
|
||||
macro(msan_compile obj_list source arch kind cflags)
|
||||
sanitizer_test_compile(
|
||||
${obj_list} ${source} ${arch}
|
||||
KIND ${kind}
|
||||
COMPILE_DEPS ${MSAN_UNITTEST_HEADERS}
|
||||
DEPS gtest msan
|
||||
CFLAGS ${MSAN_UNITTEST_INSTRUMENTED_CFLAGS} ${cflags}
|
||||
)
|
||||
endmacro()
|
||||
|
||||
macro(msan_link_shared so_list so_name arch kind)
|
||||
cmake_parse_arguments(SOURCE "" "" "OBJECTS;LINK_FLAGS;DEPS" ${ARGN})
|
||||
set(output_so "${CMAKE_CURRENT_BINARY_DIR}/${so_name}.${arch}${kind}.so")
|
||||
get_target_flags_for_arch(${arch} TARGET_LINK_FLAGS)
|
||||
if(NOT COMPILER_RT_STANDALONE_BUILD)
|
||||
list(APPEND SOURCE_DEPS msan)
|
||||
endif()
|
||||
clang_link_shared(${output_so}
|
||||
OBJECTS ${SOURCE_OBJECTS}
|
||||
LINK_FLAGS ${TARGET_LINK_FLAGS} ${SOURCE_LINK_FLAGS}
|
||||
DEPS ${SOURCE_DEPS})
|
||||
list(APPEND ${so_list} ${output_so})
|
||||
endmacro()
|
||||
|
||||
# Main MemorySanitizer unit tests.
|
||||
add_custom_target(MsanUnitTests)
|
||||
set_target_properties(MsanUnitTests PROPERTIES FOLDER "MSan unit tests")
|
||||
|
||||
# Adds MSan unit tests and benchmarks for architecture.
|
||||
macro(add_msan_tests_for_arch arch kind cflags)
|
||||
# Build gtest instrumented with MSan.
|
||||
set(MSAN_INST_GTEST)
|
||||
msan_compile(MSAN_INST_GTEST ${COMPILER_RT_GTEST_SOURCE} ${arch} "${kind}"
|
||||
"${cflags}")
|
||||
|
||||
# Instrumented tests.
|
||||
set(MSAN_INST_TEST_OBJECTS)
|
||||
foreach (SOURCE ${MSAN_UNITTEST_SOURCES})
|
||||
msan_compile(MSAN_INST_TEST_OBJECTS ${SOURCE} ${arch} "${kind}" "${cflags}")
|
||||
endforeach(SOURCE)
|
||||
|
||||
# Instrumented loadable module objects.
|
||||
set(MSAN_INST_LOADABLE_OBJECTS)
|
||||
msan_compile(MSAN_INST_LOADABLE_OBJECTS ${MSAN_LOADABLE_SOURCE} ${arch} "${kind}"
|
||||
"-fPIC;${cflags}")
|
||||
|
||||
# Instrumented loadable library tests.
|
||||
set(MSAN_LOADABLE_SO)
|
||||
msan_link_shared(MSAN_LOADABLE_SO "libmsan_loadable" ${arch} "${kind}"
|
||||
OBJECTS ${MSAN_INST_LOADABLE_OBJECTS}
|
||||
DEPS ${MSAN_INST_LOADABLE_OBJECTS})
|
||||
|
||||
set(MSAN_TEST_OBJECTS ${MSAN_INST_TEST_OBJECTS} ${MSAN_INST_GTEST})
|
||||
set(MSAN_TEST_DEPS ${MSAN_TEST_OBJECTS} libcxx_msan_${arch}-build
|
||||
${MSAN_LOADABLE_SO})
|
||||
if(NOT COMPILER_RT_STANDALONE_BUILD)
|
||||
list(APPEND MSAN_TEST_DEPS msan)
|
||||
endif()
|
||||
get_target_flags_for_arch(${arch} TARGET_LINK_FLAGS)
|
||||
add_compiler_rt_test(MsanUnitTests "Msan-${arch}${kind}-Test" ${arch}
|
||||
OBJECTS ${MSAN_TEST_OBJECTS} ${MSAN_LIBCXX_SO}
|
||||
DEPS ${MSAN_TEST_DEPS}
|
||||
LINK_FLAGS ${MSAN_UNITTEST_LINK_FLAGS}
|
||||
${TARGET_LINK_FLAGS}
|
||||
"-Wl,-rpath=${CMAKE_CURRENT_BINARY_DIR}"
|
||||
"-Wl,-rpath=${LIBCXX_PREFIX}/lib")
|
||||
endmacro()
|
||||
|
||||
# We should only build MSan unit tests if we can build instrumented libcxx.
|
||||
if(COMPILER_RT_CAN_EXECUTE_TESTS AND COMPILER_RT_LIBCXX_PATH)
|
||||
foreach(arch ${MSAN_SUPPORTED_ARCH})
|
||||
get_target_flags_for_arch(${arch} TARGET_CFLAGS)
|
||||
set(LIBCXX_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/../libcxx_msan_${arch})
|
||||
add_custom_libcxx(libcxx_msan_${arch} ${LIBCXX_PREFIX}
|
||||
DEPS ${MSAN_RUNTIME_LIBRARIES}
|
||||
CFLAGS ${MSAN_LIBCXX_CFLAGS} ${TARGET_CFLAGS}
|
||||
USE_TOOLCHAIN)
|
||||
set(MSAN_LIBCXX_SO ${LIBCXX_PREFIX}/lib/libc++.so)
|
||||
|
||||
add_msan_tests_for_arch(${arch} "" "")
|
||||
add_msan_tests_for_arch(${arch} "-with-call"
|
||||
"-mllvm;-msan-instrumentation-with-call-threshold=0")
|
||||
endforeach()
|
||||
endif()
|
@ -1,27 +0,0 @@
|
||||
//===-- msan_loadable.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 MemorySanitizer.
|
||||
//
|
||||
// MemorySanitizer unit tests.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "msan/msan_interface_internal.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
static void *dso_global;
|
||||
|
||||
// No name mangling.
|
||||
extern "C" {
|
||||
|
||||
void **get_dso_global() {
|
||||
return &dso_global;
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,20 +0,0 @@
|
||||
//===-- msan_test_config.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 MemorySanitizer.
|
||||
//
|
||||
// MemorySanitizer unit tests.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef MSAN_TEST_CONFIG_H
|
||||
#define MSAN_TEST_CONFIG_H
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#endif // MSAN_TEST_CONFIG_H
|
@ -1,21 +0,0 @@
|
||||
//===-- msan_test_main.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 MemorySanitizer.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef MSAN_EXTERNAL_TEST_CONFIG
|
||||
#include "msan_test_config.h"
|
||||
#endif // MSAN_EXTERNAL_TEST_CONFIG
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
testing::GTEST_FLAG(death_test_style) = "threadsafe";
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
@ -1,126 +0,0 @@
|
||||
|
||||
CHECK_CXX_SOURCE_COMPILES("
|
||||
#ifdef _MSC_VER
|
||||
#include <Intrin.h> /* Workaround for PR19898. */
|
||||
#include <windows.h>
|
||||
#endif
|
||||
int main() {
|
||||
#ifdef _MSC_VER
|
||||
volatile LONG val = 1;
|
||||
MemoryBarrier();
|
||||
InterlockedCompareExchange(&val, 0, 1);
|
||||
InterlockedIncrement(&val);
|
||||
InterlockedDecrement(&val);
|
||||
#else
|
||||
volatile unsigned long val = 1;
|
||||
__sync_synchronize();
|
||||
__sync_val_compare_and_swap(&val, 1, 0);
|
||||
__sync_add_and_fetch(&val, 1);
|
||||
__sync_sub_and_fetch(&val, 1);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
" COMPILER_RT_TARGET_HAS_ATOMICS)
|
||||
|
||||
CHECK_CXX_SOURCE_COMPILES("
|
||||
#if defined(__linux__)
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
int fd;
|
||||
int main() {
|
||||
struct flock s_flock;
|
||||
|
||||
s_flock.l_type = F_WRLCK;
|
||||
fcntl(fd, F_SETLKW, &s_flock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
" COMPILER_RT_TARGET_HAS_FCNTL_LCK)
|
||||
|
||||
CHECK_CXX_SOURCE_COMPILES("
|
||||
#include <sys/utsname.h>
|
||||
int main() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
" COMPILER_RT_TARGET_HAS_UNAME)
|
||||
|
||||
add_compiler_rt_component(profile)
|
||||
|
||||
set(PROFILE_SOURCES
|
||||
GCDAProfiling.c
|
||||
InstrProfiling.c
|
||||
InstrProfilingValue.c
|
||||
InstrProfilingBuffer.c
|
||||
InstrProfilingFile.c
|
||||
InstrProfilingMerge.c
|
||||
InstrProfilingMergeFile.c
|
||||
InstrProfilingNameVar.c
|
||||
InstrProfilingWriter.c
|
||||
InstrProfilingPlatformDarwin.c
|
||||
InstrProfilingPlatformFuchsia.c
|
||||
InstrProfilingPlatformLinux.c
|
||||
InstrProfilingPlatformOther.c
|
||||
InstrProfilingRuntime.cc
|
||||
InstrProfilingUtil.c)
|
||||
|
||||
set(PROFILE_HEADERS
|
||||
InstrProfData.inc
|
||||
InstrProfiling.h
|
||||
InstrProfilingInternal.h
|
||||
InstrProfilingPort.h
|
||||
InstrProfilingUtil.h
|
||||
WindowsMMap.h)
|
||||
|
||||
if(WIN32)
|
||||
list(APPEND PROFILE_SOURCES WindowsMMap.c)
|
||||
endif()
|
||||
|
||||
if(FUCHSIA OR UNIX)
|
||||
set(EXTRA_FLAGS
|
||||
-fPIC
|
||||
-Wno-pedantic)
|
||||
endif()
|
||||
|
||||
if(COMPILER_RT_TARGET_HAS_ATOMICS)
|
||||
set(EXTRA_FLAGS
|
||||
${EXTRA_FLAGS}
|
||||
-DCOMPILER_RT_HAS_ATOMICS=1)
|
||||
endif()
|
||||
|
||||
if(COMPILER_RT_TARGET_HAS_FCNTL_LCK)
|
||||
set(EXTRA_FLAGS
|
||||
${EXTRA_FLAGS}
|
||||
-DCOMPILER_RT_HAS_FCNTL_LCK=1)
|
||||
endif()
|
||||
|
||||
if(COMPILER_RT_TARGET_HAS_UNAME)
|
||||
set(EXTRA_FLAGS
|
||||
${EXTRA_FLAGS}
|
||||
-DCOMPILER_RT_HAS_UNAME=1)
|
||||
endif()
|
||||
|
||||
# This appears to be a C-only warning banning the use of locals in aggregate
|
||||
# initializers. All other compilers accept this, though.
|
||||
# nonstandard extension used : 'identifier' : cannot be initialized using address of automatic variable
|
||||
append_list_if(COMPILER_RT_HAS_WD4221_FLAG /wd4221 EXTRA_FLAGS)
|
||||
|
||||
if(APPLE)
|
||||
add_compiler_rt_runtime(clang_rt.profile
|
||||
STATIC
|
||||
OS ${PROFILE_SUPPORTED_OS}
|
||||
ARCHS ${PROFILE_SUPPORTED_ARCH}
|
||||
CFLAGS ${EXTRA_FLAGS}
|
||||
SOURCES ${PROFILE_SOURCES}
|
||||
ADDITIONAL_HEADERS ${PROFILE_HEADERS}
|
||||
PARENT_TARGET profile)
|
||||
else()
|
||||
add_compiler_rt_runtime(clang_rt.profile
|
||||
STATIC
|
||||
ARCHS ${PROFILE_SUPPORTED_ARCH}
|
||||
CFLAGS ${EXTRA_FLAGS}
|
||||
SOURCES ${PROFILE_SOURCES}
|
||||
ADDITIONAL_HEADERS ${PROFILE_HEADERS}
|
||||
PARENT_TARGET profile)
|
||||
endif()
|
@ -1,2 +0,0 @@
|
||||
BasedOnStyle: Google
|
||||
AllowShortIfStatementsOnASingleLine: false
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user