Import compiler-rt r182741.

This commit is contained in:
Ed Schouten 2013-05-27 18:27:12 +00:00
parent 58aabf08b7
commit 11023dc647
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/vendor/compiler-rt/dist/; revision=251034
svn path=/vendor/compiler-rt/compiler-rt-r182741/; revision=251036; tag=vendor/compiler-rt/compiler-rt-r182741
434 changed files with 22305 additions and 8915 deletions

View File

@ -15,6 +15,19 @@ include(LLVMParseArguments)
# runtime libraries.
cmake_minimum_required(VERSION 2.8.8)
# Compute the Clang version from the LLVM version.
# FIXME: We should be able to reuse CLANG_VERSION variable calculated
# in Clang cmake files, instead of copying the rules here.
string(REGEX MATCH "[0-9]+\\.[0-9]+(\\.[0-9]+)?" CLANG_VERSION
${PACKAGE_VERSION})
# Setup the paths where compiler-rt runtimes and headers should be stored.
set(LIBCLANG_INSTALL_PATH lib${LLVM_LIBDIR_SUFFIX}/clang/${CLANG_VERSION})
string(TOLOWER ${CMAKE_SYSTEM_NAME} LIBCLANG_OS_DIR)
set(CLANG_RESOURCE_DIR ${LLVM_BINARY_DIR}/lib/clang/${CLANG_VERSION})
set(COMPILER_RT_LIBRARY_OUTPUT_DIR ${CLANG_RESOURCE_DIR}/lib/${LIBCLANG_OS_DIR})
set(COMPILER_RT_LIBRARY_INSTALL_DIR
${LIBCLANG_INSTALL_PATH}/lib/${LIBCLANG_OS_DIR})
# Add path for custom modules
set(CMAKE_MODULE_PATH
${CMAKE_MODULE_PATH}
@ -23,6 +36,9 @@ set(CMAKE_MODULE_PATH
include(AddCompilerRT)
set(COMPILER_RT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
# Setup custom SDK sysroots.
set(COMPILER_RT_DARWIN_SDK_SYSROOT ${COMPILER_RT_SOURCE_DIR}/SDKs/darwin)
set(COMPILER_RT_LINUX_SDK_SYSROOT ${COMPILER_RT_SOURCE_DIR}/SDKs/linux)
# 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.
@ -37,15 +53,8 @@ else()
set(TARGET_32_BIT_CFLAGS "-m32")
endif()
# FIXME: Below we assume that the target build of LLVM/Clang is x86, which is
# not at all valid. Much of this can be fixed just by switching to use
# a just-built-clang binary for the compiles.
set(TARGET_x86_64_CFLAGS ${TARGET_64_BIT_CFLAGS})
set(TARGET_i386_CFLAGS ${TARGET_32_BIT_CFLAGS})
set(COMPILER_RT_SUPPORTED_ARCH
x86_64 i386)
# List of architectures we can target.
set(COMPILER_RT_SUPPORTED_ARCH)
function(get_target_flags_for_arch arch out_var)
list(FIND COMPILER_RT_SUPPORTED_ARCH ${arch} ARCH_INDEX)
@ -60,27 +69,45 @@ endfunction()
# 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_SOURCE64 ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/simple64.c)
file(WRITE ${SIMPLE_SOURCE64} "#include <stdlib.h>\nint main() {}")
try_compile(CAN_TARGET_x86_64 ${CMAKE_BINARY_DIR} ${SIMPLE_SOURCE64}
COMPILE_DEFINITIONS "${TARGET_x86_64_CFLAGS}"
CMAKE_FLAGS "-DCMAKE_EXE_LINKER_FLAGS:STRING=${TARGET_x86_64_CFLAGS}")
set(SIMPLE_SOURCE ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/simple.c)
file(WRITE ${SIMPLE_SOURCE} "#include <stdlib.h>\nint main() {}")
set(SIMPLE_SOURCE32 ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/simple32.c)
file(WRITE ${SIMPLE_SOURCE32} "#include <stdlib.h>\nint main() {}")
try_compile(CAN_TARGET_i386 ${CMAKE_BINARY_DIR} ${SIMPLE_SOURCE32}
COMPILE_DEFINITIONS "${TARGET_i386_CFLAGS}"
CMAKE_FLAGS "-DCMAKE_EXE_LINKER_FLAGS:STRING=${TARGET_i386_CFLAGS}")
# test_target_arch(<arch> <target flags...>)
# Sets the target flags for a given architecture and determines if this
# architecture is supported by trying to build a simple file.
macro(test_target_arch arch)
set(TARGET_${arch}_CFLAGS ${ARGN})
try_compile(CAN_TARGET_${arch} ${CMAKE_BINARY_DIR} ${SIMPLE_SOURCE}
COMPILE_DEFINITIONS "${TARGET_${arch}_CFLAGS}"
CMAKE_FLAGS "-DCMAKE_EXE_LINKER_FLAGS:STRING=${TARGET_${arch}_CFLAGS}")
if(${CAN_TARGET_${arch}})
list(APPEND COMPILER_RT_SUPPORTED_ARCH ${arch})
endif()
endmacro()
if("${LLVM_NATIVE_ARCH}" STREQUAL "X86")
test_target_arch(x86_64 ${TARGET_64_BIT_CFLAGS})
test_target_arch(i386 ${TARGET_32_BIT_CFLAGS})
elseif("${LLVM_NATIVE_ARCH}" STREQUAL "PowerPC")
# Explicitly set -m flag on powerpc, because on ppc64 defaults for gcc and
# clang are different.
test_target_arch(powerpc64 "-m64")
test_target_arch(powerpc "-m32")
endif()
# We only support running instrumented tests when we're not cross compiling
# and target a unix-like system. On Android we define the rules for building
# unit tests, but don't execute them.
if("${CMAKE_HOST_SYSTEM}" STREQUAL "${CMAKE_SYSTEM}" AND UNIX AND NOT ANDROID)
set(COMPILER_RT_CAN_EXECUTE_TESTS TRUE)
option(COMPILER_RT_CAN_EXECUTE_TESTS "Can we execute instrumented tests" ON)
else()
set(COMPILER_RT_CAN_EXECUTE_TESTS FALSE)
option(COMPILER_RT_CAN_EXECUTE_TESTS "Can we execute instrumented tests" OFF)
endif()
# Check if compiler-rt is built with libc++.
find_flag_in_string("${CMAKE_CXX_FLAGS}" "-stdlib=libc++"
COMPILER_RT_USES_LIBCXX)
function(filter_available_targets out_var)
set(archs)
foreach(arch ${ARGN})
@ -99,6 +126,8 @@ set(SANITIZER_COMMON_CFLAGS
-fno-exceptions
-fomit-frame-pointer
-funwind-tables
-fno-stack-protector
-Wno-gnu # Variadic macros with 0 arguments for ...
-O3
)
if(NOT WIN32)
@ -120,51 +149,36 @@ check_cxx_compiler_flag(-Wno-c99-extensions SUPPORTS_NO_C99_EXTENSIONS_FLAG)
if(SUPPORTS_NO_C99_EXTENSIONS_FLAG)
list(APPEND SANITIZER_COMMON_CFLAGS -Wno-c99-extensions)
endif()
# Sanitizer may not have libstdc++, so we can have problems with virtual
# destructors.
check_cxx_compiler_flag(-Wno-non-virtual-dtor SUPPORTS_NO_NON_VIRTUAL_DTOR_FLAG)
if (SUPPORTS_NO_NON_VIRTUAL_DTOR_FLAG)
list(APPEND SANITIZER_COMMON_CFLAGS -Wno-non-virtual-dtor)
endif()
# Setup min Mac OS X version.
if(APPLE)
list(APPEND SANITIZER_COMMON_CFLAGS -mmacosx-version-min=10.5)
if(COMPILER_RT_USES_LIBCXX)
set(SANITIZER_MIN_OSX_VERSION 10.7)
else()
set(SANITIZER_MIN_OSX_VERSION 10.5)
endif()
list(APPEND SANITIZER_COMMON_CFLAGS
-mmacosx-version-min=${SANITIZER_MIN_OSX_VERSION})
endif()
# Architectures supported by Sanitizer runtimes. Specific sanitizers may
# support only subset of these (e.g. TSan works on x86_64 only).
filter_available_targets(SANITIZER_COMMON_SUPPORTED_ARCH
x86_64 i386)
# Compute the Clang version from the LLVM version.
# FIXME: We should be able to reuse CLANG_VERSION variable calculated
# in Clang cmake files, instead of copying the rules here.
string(REGEX MATCH "[0-9]+\\.[0-9]+(\\.[0-9]+)?" CLANG_VERSION
${PACKAGE_VERSION})
# Setup the paths where compiler-rt runtimes and headers should be stored.
set(LIBCLANG_INSTALL_PATH lib${LLVM_LIBDIR_SUFFIX}/clang/${CLANG_VERSION})
string(TOLOWER ${CMAKE_SYSTEM_NAME} LIBCLANG_OS_DIR)
# Install compiler-rt headers.
install(DIRECTORY include/
DESTINATION ${LIBCLANG_INSTALL_PATH}/include
FILES_MATCHING
PATTERN "*.h"
PATTERN ".svn" EXCLUDE
)
# Call add_clang_compiler_rt_libraries to make sure that targets are built
# and installed in the directories where Clang driver expects to find them.
macro(add_clang_compiler_rt_libraries)
# Setup output directories so that clang in build tree works.
set_target_properties(${ARGN} PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY
${LLVM_BINARY_DIR}/lib/clang/${CLANG_VERSION}/lib/${LIBCLANG_OS_DIR}
LIBRARY_OUTPUT_DIRECTORY
${LLVM_BINARY_DIR}/lib/clang/${CLANG_VERSION}/lib/${LIBCLANG_OS_DIR}
)
# Add installation command.
install(TARGETS ${ARGN}
ARCHIVE DESTINATION ${LIBCLANG_INSTALL_PATH}/lib/${LIBCLANG_OS_DIR}
LIBRARY DESTINATION ${LIBCLANG_INSTALL_PATH}/lib/${LIBCLANG_OS_DIR}
)
endmacro(add_clang_compiler_rt_libraries)
x86_64 i386 powerpc64 powerpc)
# Add the public header's directory to the includes for all of compiler-rt.
include_directories(include)
add_subdirectory(include)
set(SANITIZER_COMMON_LIT_TEST_DEPS
clang clang-headers FileCheck count not llvm-nm llvm-symbolizer
compiler-rt-headers)
add_subdirectory(lib)

View File

@ -255,10 +255,10 @@ $(Tmp.ObjPath)/%.o: $(Tmp.SrcPath)/%.S $(Tmp.Dependencies) $(Tmp.ObjPath)/.dir
$(Verb) $(Tmp.CC) $(Tmp.CFLAGS) -c -o $$@ $$<
$(Tmp.ObjPath)/%.o: $(Tmp.SrcPath)/%.c $(Tmp.Dependencies) $(Tmp.ObjPath)/.dir
$(Summary) " COMPILE: $(Tmp.Name)/$(Tmp.Config)/$(Tmp.Arch): $$<"
$(Verb) $(Tmp.CC) $(Tmp.CFLAGS) -c $(COMMON_CFLAGS) -o $$@ $$<
$(Verb) $(Tmp.CC) $(COMMON_CFLAGS) $(Tmp.CFLAGS) -c -o $$@ $$<
$(Tmp.ObjPath)/%.o: $(Tmp.SrcPath)/%.cc $(Tmp.Dependencies) $(Tmp.ObjPath)/.dir
$(Summary) " COMPILE: $(Tmp.Name)/$(Tmp.Config)/$(Tmp.Arch): $$<"
$(Verb) $(Tmp.CC) $(Tmp.CFLAGS) -c $(COMMON_CXXFLAGS) -o $$@ $$<
$(Verb) $(Tmp.CC) $(COMMON_CXXFLAGS) $(Tmp.CFLAGS) -c -o $$@ $$<
.PRECIOUS: $(Tmp.ObjPath)/.dir
endef

View File

@ -0,0 +1,17 @@
/* ===-- fcntl.h - stub SDK header for compiler-rt --------------------------===
*
* The LLVM Compiler Infrastructure
*
* This file is dual licensed under the MIT and the University of Illinois Open
* Source Licenses. See LICENSE.TXT for details.
*
* ===-----------------------------------------------------------------------===
*
* This is a stub SDK header file. This file is not part of the interface of
* this library nor an official version of the appropriate SDK header. It is
* intended only to stub the features of this header required by compiler-rt.
*
* ===-----------------------------------------------------------------------===
*/
#include <sys/fcntl.h>

View File

@ -24,15 +24,18 @@ extern "C" {
typedef struct __sFILE FILE;
typedef __SIZE_TYPE__ size_t;
/* Determine the appropriate fopen() and fwrite() functions. */
/* Determine the appropriate fdopen, fopen(), and fwrite() functions. */
#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__)
# if defined(__i386)
# define __FDOPEN_NAME "_fdopen$UNIX2003"
# define __FOPEN_NAME "_fopen$UNIX2003"
# define __FWRITE_NAME "_fwrite$UNIX2003"
# elif defined(__x86_64__)
# define __FDOPEN_NAME "_fdopen"
# define __FOPEN_NAME "_fopen"
# define __FWRITE_NAME "_fwrite"
# elif defined(__arm)
# define __FDOPEN_NAME "_fdopen"
# define __FOPEN_NAME "_fopen"
# define __FWRITE_NAME "_fwrite"
# else
@ -40,9 +43,11 @@ typedef __SIZE_TYPE__ size_t;
# endif
#elif defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__)
# if defined(__i386) || defined (__x86_64)
# define __FDOPEN_NAME "_fdopen"
# define __FOPEN_NAME "_fopen"
# define __FWRITE_NAME "_fwrite"
# elif defined(__arm)
# define __FDOPEN_NAME "_fdopen"
# define __FOPEN_NAME "_fopen"
# define __FWRITE_NAME "_fwrite"
# else
@ -68,13 +73,13 @@ extern FILE *__stderrp;
int fclose(FILE *);
int fflush(FILE *);
FILE *fopen(const char * __restrict, const char * __restrict) __asm(__FOPEN_NAME);
FILE *fdopen(int, const char *) __asm(__FDOPEN_NAME);
int fprintf(FILE * __restrict, const char * __restrict, ...);
size_t fwrite(const void * __restrict, size_t, size_t, FILE * __restrict)
__asm(__FWRITE_NAME);
size_t fread(void * __restrict, size_t, size_t, FILE * __restrict);
long ftell(FILE *);
int fseek(FILE *, long, int);
int snprintf(char * __restrict, size_t, const char * __restrict, ...);
#if defined(__cplusplus)

View File

@ -22,9 +22,11 @@
typedef __SIZE_TYPE__ size_t;
void abort(void) __attribute__((__noreturn__));
int atexit(void (*)(void));
int atoi(const char *);
void free(void *);
char *getenv(const char *);
void *malloc(size_t);
void *realloc(void *, size_t);
#endif /* __STDLIB_H__ */

View File

@ -21,6 +21,7 @@ typedef __SIZE_TYPE__ size_t;
int memcmp(const void *, const void *, size_t);
void *memcpy(void *, const void *, size_t);
void *memset(void *, int, size_t);
char *strcat(char *, const char *);
char *strcpy(char *, const char *);
char *strdup(const char *);

View File

@ -0,0 +1,52 @@
/* ===-- fcntl.h - stub SDK header for compiler-rt --------------------------===
*
* The LLVM Compiler Infrastructure
*
* This file is dual licensed under the MIT and the University of Illinois Open
* Source Licenses. See LICENSE.TXT for details.
*
* ===-----------------------------------------------------------------------===
*
* This is a stub SDK header file. This file is not part of the interface of
* this library nor an official version of the appropriate SDK header. It is
* intended only to stub the features of this header required by compiler-rt.
*
* ===-----------------------------------------------------------------------===
*/
#ifndef _SYS_FCNTL_H_
#define _SYS_FCNTL_H_
/* Determine the appropriate open function. */
#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__)
# if defined(__i386)
# define __OPEN_NAME "_open$UNIX2003"
# elif defined(__x86_64__)
# define __OPEN_NAME "_open"
# elif defined(__arm)
# define __OPEN_NAME "_open"
# else
# error "unrecognized architecture for targetting OS X"
# endif
#elif defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__)
# if defined(__i386) || defined (__x86_64)
# define __OPEN_NAME "_open"
# elif defined(__arm)
# define __OPEN_NAME "_open"
# else
# error "unrecognized architecture for targetting iOS"
# endif
#else
# error "unrecognized architecture for targetting Darwin"
#endif
#define O_RDONLY 0x0000 /* open for reading only */
#define O_WRONLY 0x0001 /* open for writing only */
#define O_RDWR 0x0002 /* open for reading and writing */
#define O_ACCMODE 0x0003 /* mask for above modes */
#define O_CREAT 0x0200 /* create if nonexistant */
int open(const char *, int, ...) __asm(__OPEN_NAME);
#endif /* !_SYS_FCNTL_H_ */

View File

@ -0,0 +1,42 @@
/* ===-- mman.h - stub SDK header for compiler-rt ---------------------------===
*
* The LLVM Compiler Infrastructure
*
* This file is dual licensed under the MIT and the University of Illinois Open
* Source Licenses. See LICENSE.TXT for details.
*
* ===-----------------------------------------------------------------------===
*
* This is a stub SDK header file. This file is not part of the interface of
* this library nor an official version of the appropriate SDK header. It is
* intended only to stub the features of this header required by compiler-rt.
*
* ===-----------------------------------------------------------------------===
*/
#ifndef __SYS_MMAN_H__
#define __SYS_MMAN_H__
typedef __SIZE_TYPE__ size_t;
#define PROT_NONE 0x00
#define PROT_READ 0x01
#define PROT_WRITE 0x02
#define PROT_EXEC 0x04
#define MAP_SHARED 0x0001
#define MAP_PRIVATE 0x0002
#define MAP_FILE 0x0000
#define MAP_ANON 0x1000
#define MS_ASYNC 0x0001
#define MS_INVALIDATE 0x0002
#define MS_SYNC 0x0010
void *mmap(void *addr, size_t len, int prot, int flags, int fd,
long long offset);
int munmap(void *addr, size_t len);
int msync(void *addr, size_t len, int flags);
#endif /* __SYS_MMAN_H__ */

View File

@ -0,0 +1,17 @@
/* ===-- fcntl.h - stub SDK header for compiler-rt --------------------------===
*
* The LLVM Compiler Infrastructure
*
* This file is dual licensed under the MIT and the University of Illinois Open
* Source Licenses. See LICENSE.TXT for details.
*
* ===-----------------------------------------------------------------------===
*
* This is a stub SDK header file. This file is not part of the interface of
* this library nor an official version of the appropriate SDK header. It is
* intended only to stub the features of this header required by compiler-rt.
*
* ===-----------------------------------------------------------------------===
*/
#include <sys/fcntl.h>

View File

@ -33,6 +33,7 @@ extern struct _IO_FILE *stderr;
extern int fclose(FILE *);
extern int fflush(FILE *);
extern FILE *fopen(const char * restrict, const char * restrict);
extern FILE *fdopen(int, const char * restrict);
extern int fprintf(FILE * restrict, const char * restrict, ...);
extern size_t fwrite(const void * restrict, size_t, size_t, FILE * restrict);
extern size_t fread(void * restrict, size_t, size_t, FILE * restrict);

View File

@ -22,6 +22,7 @@
typedef __SIZE_TYPE__ size_t;
void abort(void) __attribute__((__nothrow__)) __attribute__((__noreturn__));
int atexit(void (*)(void)) __attribute__((__nothrow__));
int atoi(const char *) __attribute__((__nothrow__));
void free(void *) __attribute__((__nothrow__));
char *getenv(const char *) __attribute__((__nothrow__))
@ -29,5 +30,7 @@ char *getenv(const char *) __attribute__((__nothrow__))
__attribute__((__warn_unused_result__));
void *malloc(size_t) __attribute__((__nothrow__)) __attribute((__malloc__))
__attribute__((__warn_unused_result__));
void *realloc(void *, size_t) __attribute__((__nothrow__)) __attribute((__malloc__))
__attribute__((__warn_unused_result__));
#endif /* __STDLIB_H__ */

View File

@ -21,6 +21,7 @@ typedef __SIZE_TYPE__ size_t;
int memcmp(const void *, const void *, size_t);
void *memcpy(void *, const void *, size_t);
void *memset(void *, int, size_t);
char *strcat(char *, const char *);
char *strcpy(char *, const char *);
char *strdup(const char *);

View File

@ -0,0 +1,29 @@
/* ===-- fcntl.h - stub SDK header for compiler-rt --------------------------===
*
* The LLVM Compiler Infrastructure
*
* This file is dual licensed under the MIT and the University of Illinois Open
* Source Licenses. See LICENSE.TXT for details.
*
* ===-----------------------------------------------------------------------===
*
* This is a stub SDK header file. This file is not part of the interface of
* this library nor an official version of the appropriate SDK header. It is
* intended only to stub the features of this header required by compiler-rt.
*
* ===-----------------------------------------------------------------------===
*/
#ifndef _SYS_FCNTL_H_
#define _SYS_FCNTL_H_
#define O_RDONLY 0x0000
#define O_WRONLY 0x0001
#define O_RDWR 0x0002
#define O_ACCMODE 0x0003
#define O_CREAT 0x0200
int open(const char *, int, ...);
#endif /* _SYS_FCNTL_H_ */

View File

@ -19,10 +19,28 @@
typedef __SIZE_TYPE__ size_t;
#define PROT_READ 0x1
#define PROT_WRITE 0x2
#define PROT_EXEC 0x4
#define PROT_NONE 0x00
#define PROT_READ 0x01
#define PROT_WRITE 0x02
#define PROT_EXEC 0x04
#define MAP_SHARED 0x0001
#define MAP_PRIVATE 0x0002
#define MAP_FILE 0x0000
#define MAP_ANON 0x1000
#define MS_ASYNC 0x0001
#define MS_INVALIDATE 0x0002
#define MS_SYNC 0x0010
extern void *mmap(void *addr, size_t len, int prot, int flags, int fd,
long long offset)
__attribute__((__nothrow__));
extern int munmap(void *addr, size_t len)
__attribute__((__nothrow__));
extern int msync(void *addr, size_t len, int flags)
__attribute__((__nothrow__));
extern int mprotect (void *__addr, size_t __len, int __prot)
__attribute__((__nothrow__));

View File

@ -18,6 +18,92 @@ macro(add_compiler_rt_object_library name arch)
endif()
endmacro()
# Same as above, but adds universal osx library with name "<name>.osx"
# targeting multiple architectures.
# add_compiler_rt_osx_object_library(<name> ARCH <architectures>
# SOURCES <source files>
# CFLAGS <compile flags>)
macro(add_compiler_rt_osx_object_library name)
parse_arguments(LIB "ARCH;SOURCES;CFLAGS" "" ${ARGN})
set(libname "${name}.osx")
add_library(${libname} OBJECT ${LIB_SOURCES})
set_target_compile_flags(${libname} ${LIB_CFLAGS})
set_target_properties(${libname} PROPERTIES OSX_ARCHITECTURES "${LIB_ARCH}")
endmacro()
# Adds static runtime for a given architecture and puts it in the proper
# directory in the build and install trees.
# add_compiler_rt_static_runtime(<name> <arch>
# SOURCES <source files>
# CFLAGS <compile flags>
# DEFS <compile definitions>
# SYMS <symbols file>)
macro(add_compiler_rt_static_runtime name arch)
if(CAN_TARGET_${arch})
parse_arguments(LIB "SOURCES;CFLAGS;DEFS;SYMS" "" ${ARGN})
add_library(${name} STATIC ${LIB_SOURCES})
# Setup compile flags and definitions.
set_target_compile_flags(${name}
${TARGET_${arch}_CFLAGS} ${LIB_CFLAGS})
set_property(TARGET ${name} APPEND PROPERTY
COMPILE_DEFINITIONS ${LIB_DEFS})
# Setup correct output directory in the build tree.
set_target_properties(${name} PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY ${COMPILER_RT_LIBRARY_OUTPUT_DIR})
# Add installation command.
install(TARGETS ${name}
ARCHIVE DESTINATION ${COMPILER_RT_LIBRARY_INSTALL_DIR})
# Generate the .syms file if possible.
if(LIB_SYMS)
get_target_property(libfile ${name} LOCATION)
configure_file(${LIB_SYMS} ${libfile}.syms)
install(FILES ${libfile}.syms
DESTINATION ${COMPILER_RT_LIBRARY_INSTALL_DIR})
endif(LIB_SYMS)
else()
message(FATAL_ERROR "Archtecture ${arch} can't be targeted")
endif()
endmacro()
# Same as add_compiler_rt_static_runtime, but creates a universal library
# for several architectures.
# add_compiler_rt_osx_static_runtime(<name> ARCH <architectures>
# SOURCES <source files>
# CFLAGS <compile flags>
# DEFS <compile definitions>)
macro(add_compiler_rt_osx_static_runtime name)
parse_arguments(LIB "ARCH;SOURCES;CFLAGS;DEFS" "" ${ARGN})
add_library(${name} STATIC ${LIB_SOURCES})
set_target_compile_flags(${name} ${LIB_CFLAGS})
set_property(TARGET ${name} APPEND PROPERTY
COMPILE_DEFINITIONS ${LIB_DEFS})
set_target_properties(${name} PROPERTIES
OSX_ARCHITECTURES "${LIB_ARCH}"
ARCHIVE_OUTPUT_DIRECTORY ${COMPILER_RT_LIBRARY_OUTPUT_DIR})
install(TARGETS ${name}
ARCHIVE DESTINATION ${COMPILER_RT_LIBRARY_INSTALL_DIR})
endmacro()
# Adds dynamic runtime library on osx, which supports multiple architectures.
# add_compiler_rt_osx_dynamic_runtime(<name> ARCH <architectures>
# SOURCES <source files>
# CFLAGS <compile flags>
# DEFS <compile definitions>
# LINKFLAGS <link flags>)
macro(add_compiler_rt_osx_dynamic_runtime name)
parse_arguments(LIB "ARCH;SOURCES;CFLAGS;DEFS;LINKFLAGS" "" ${ARGN})
add_library(${name} SHARED ${LIB_SOURCES})
set_target_compile_flags(${name} ${LIB_CFLAGS})
set_target_link_flags(${name} ${LIB_LINKFLAGS})
set_property(TARGET ${name} APPEND PROPERTY
COMPILE_DEFINITIONS ${LIB_DEFS})
set_target_properties(${name} PROPERTIES
OSX_ARCHITECTURES "${LIB_ARCH}"
LIBRARY_OUTPUT_DIRECTORY ${COMPILER_RT_LIBRARY_OUTPUT_DIR})
install(TARGETS ${name}
LIBRARY DESTINATION ${COMPILER_RT_LIBRARY_INSTALL_DIR})
endmacro()
# Unittests support.
set(COMPILER_RT_GTEST_PATH ${LLVM_MAIN_SRC_DIR}/utils/unittest/googletest)
set(COMPILER_RT_GTEST_SOURCE ${COMPILER_RT_GTEST_PATH}/gtest-all.cc)
@ -35,15 +121,21 @@ set(COMPILER_RT_GTEST_INCLUDE_CFLAGS
# LINK_FLAGS <link flags>)
macro(add_compiler_rt_test test_suite test_name)
parse_arguments(TEST "OBJECTS;DEPS;LINK_FLAGS" "" ${ARGN})
get_unittest_directory(OUTPUT_DIR)
file(MAKE_DIRECTORY ${OUTPUT_DIR})
set(output_bin "${OUTPUT_DIR}/${test_name}")
add_custom_command(
OUTPUT ${output_bin}
set(output_bin "${CMAKE_CURRENT_BINARY_DIR}/${test_name}")
add_custom_target(${test_name}
COMMAND clang ${TEST_OBJECTS} -o "${output_bin}"
${TEST_LINK_FLAGS}
DEPENDS clang ${TEST_DEPS})
add_custom_target(${test_name} DEPENDS ${output_bin})
# Make the test suite depend on the binary.
add_dependencies(${test_suite} ${test_name})
endmacro()
macro(add_compiler_rt_resource_file target_name file_name)
set(src_file "${CMAKE_CURRENT_SOURCE_DIR}/${file_name}")
set(dst_file "${CLANG_RESOURCE_DIR}/${file_name}")
add_custom_target(${target_name}
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${src_file} ${dst_file}
DEPENDS ${file_name})
# Install in Clang resource directory.
install(FILES ${file_name} DESTINATION ${LIBCLANG_INSTALL_PATH})
endmacro()

View File

@ -15,3 +15,14 @@ function(set_target_link_flags target)
set_property(TARGET ${target} PROPERTY LINK_FLAGS "${argstring}")
endfunction()
# Check if a given flag is present in a space-separated flag_string.
# Store the result in out_var.
function(find_flag_in_string flag_string flag out_var)
string(REPLACE " " ";" flag_list ${flag_string})
list(FIND flag_list ${flag} flag_pos)
if(NOT flag_pos EQUAL -1)
set(${out_var} TRUE PARENT_SCOPE)
else()
set(${out_var} FALSE PARENT_SCOPE)
endif()
endfunction()

39
include/CMakeLists.txt Normal file
View File

@ -0,0 +1,39 @@
set(SANITIZER_HEADERS
sanitizer/asan_interface.h
sanitizer/common_interface_defs.h
sanitizer/linux_syscall_hooks.h
sanitizer/msan_interface.h)
set(output_dir ${LLVM_BINARY_DIR}/lib/clang/${CLANG_VERSION}/include)
if(MSVC_IDE OR XCODE)
set(other_output_dir ${LLVM_BINARY_DIR}/bin/lib/clang/${CLANG_VERSION}/include)
endif()
# Copy compiler-rt headers to the build tree.
set(out_files)
foreach( f ${SANITIZER_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})
if(other_output_dir)
set(other_dst ${other_output_dir}/${f})
add_custom_command(OUTPUT ${other_dst}
DEPENDS ${src}
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${src} ${other_dst}
COMMENT "Copying compiler-rt's ${f}...")
list(APPEND out_files ${other_dst})
endif()
endforeach( f )
add_custom_target(compiler-rt-headers ALL DEPENDS ${out_files})
# Install sanitizer headers.
install(FILES ${SANITIZER_HEADERS}
PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ
DESTINATION ${LIBCLANG_INSTALL_PATH}/include/sanitizer)

View File

@ -7,69 +7,18 @@
//
//===----------------------------------------------------------------------===//
//
// This file is a part of AddressSanitizer, an address sanity checker.
// This file is a part of AddressSanitizer.
//
// This header can be included by the instrumented program to fetch
// data (mostly allocator statistics) from ASan runtime library.
// Public interface header.
//===----------------------------------------------------------------------===//
#ifndef SANITIZER_ASAN_INTERFACE_H
#define SANITIZER_ASAN_INTERFACE_H
#include <sanitizer/common_interface_defs.h>
// ----------- ATTENTION -------------
// This header should NOT include any other headers from ASan runtime.
// All functions in this header are extern "C" and start with __asan_.
using __sanitizer::uptr;
#ifdef __cplusplus
extern "C" {
// This function should be called at the very beginning of the process,
// before any instrumented code is executed and before any call to malloc.
void __asan_init() SANITIZER_INTERFACE_ATTRIBUTE;
// This structure describes an instrumented global variable.
struct __asan_global {
uptr beg; // The address of the global.
uptr size; // The original size of the global.
uptr size_with_redzone; // The size with the redzone.
const char *name; // Name as a C string.
uptr has_dynamic_init; // Non-zero if the global has dynamic initializer.
};
// These two functions should be called by the instrumented code.
// 'globals' is an array of structures describing 'n' globals.
void __asan_register_globals(__asan_global *globals, uptr n)
SANITIZER_INTERFACE_ATTRIBUTE;
void __asan_unregister_globals(__asan_global *globals, uptr n)
SANITIZER_INTERFACE_ATTRIBUTE;
// These two functions should be called before and after dynamic initializers
// run, respectively. They should be called with parameters describing all
// dynamically initialized globals defined in the calling TU.
void __asan_before_dynamic_init(uptr first_addr, uptr last_addr)
SANITIZER_INTERFACE_ATTRIBUTE;
void __asan_after_dynamic_init()
SANITIZER_INTERFACE_ATTRIBUTE;
// These two functions are used by the instrumented code in the
// use-after-return mode. __asan_stack_malloc allocates size bytes of
// fake stack and __asan_stack_free poisons it. real_stack is a pointer to
// the real stack region.
uptr __asan_stack_malloc(uptr size, uptr real_stack)
SANITIZER_INTERFACE_ATTRIBUTE;
void __asan_stack_free(uptr ptr, uptr size, uptr real_stack)
SANITIZER_INTERFACE_ATTRIBUTE;
// These two functions are used by instrumented code in the
// use-after-scope mode. They mark memory for local variables as
// unaddressable when they leave scope and addressable before the
// function exits.
void __asan_poison_stack_memory(uptr addr, uptr size)
SANITIZER_INTERFACE_ATTRIBUTE;
void __asan_unpoison_stack_memory(uptr addr, uptr size)
SANITIZER_INTERFACE_ATTRIBUTE;
#endif
// Marks memory region [addr, addr+size) as unaddressable.
// This memory must be previously allocated by the user program. Accessing
// addresses in this region from instrumented code is forbidden until
@ -78,8 +27,7 @@ extern "C" {
// to ASan alignment restrictions.
// Method is NOT thread-safe in the sense that no two threads can
// (un)poison memory in the same memory region simultaneously.
void __asan_poison_memory_region(void const volatile *addr, uptr size)
SANITIZER_INTERFACE_ATTRIBUTE;
void __asan_poison_memory_region(void const volatile *addr, size_t size);
// Marks memory region [addr, addr+size) as addressable.
// This memory must be previously allocated by the user program. Accessing
// addresses in this region is allowed until this region is poisoned again.
@ -87,15 +35,10 @@ extern "C" {
// ASan alignment restrictions.
// Method is NOT thread-safe in the sense that no two threads can
// (un)poison memory in the same memory region simultaneously.
void __asan_unpoison_memory_region(void const volatile *addr, uptr size)
SANITIZER_INTERFACE_ATTRIBUTE;
void __asan_unpoison_memory_region(void const volatile *addr, size_t size);
// Performs cleanup before a NoReturn function. Must be called before things
// like _exit and execl to avoid false positives on stack.
void __asan_handle_no_return() SANITIZER_INTERFACE_ATTRIBUTE;
// User code should use macro instead of functions.
#if __has_feature(address_sanitizer)
// User code should use macros instead of functions.
#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
#define ASAN_POISON_MEMORY_REGION(addr, size) \
__asan_poison_memory_region((addr), (size))
#define ASAN_UNPOISON_MEMORY_REGION(addr, size) \
@ -109,104 +52,86 @@ extern "C" {
// Returns true iff addr is poisoned (i.e. 1-byte read/write access to this
// address will result in error report from AddressSanitizer).
bool __asan_address_is_poisoned(void const volatile *addr)
SANITIZER_INTERFACE_ATTRIBUTE;
bool __asan_address_is_poisoned(void const volatile *addr);
// If at least on byte in [beg, beg+size) is poisoned, return the address
// of the first such byte. Otherwise return 0.
uptr __asan_region_is_poisoned(uptr beg, uptr size)
SANITIZER_INTERFACE_ATTRIBUTE;
void *__asan_region_is_poisoned(void *beg, size_t size);
// Print the description of addr (useful when debugging in gdb).
void __asan_describe_address(uptr addr)
SANITIZER_INTERFACE_ATTRIBUTE;
void __asan_describe_address(void *addr);
// This is an internal function that is called to report an error.
// However it is still a part of the interface because users may want to
// set a breakpoint on this function in a debugger.
void __asan_report_error(uptr pc, uptr bp, uptr sp,
uptr addr, bool is_write, uptr access_size)
SANITIZER_INTERFACE_ATTRIBUTE;
void __asan_report_error(void *pc, void *bp, void *sp,
void *addr, bool is_write, size_t access_size);
// Sets the exit code to use when reporting an error.
// Returns the old value.
int __asan_set_error_exit_code(int exit_code)
SANITIZER_INTERFACE_ATTRIBUTE;
int __asan_set_error_exit_code(int exit_code);
// Sets the callback to be called right before death on error.
// Passing 0 will unset the callback.
void __asan_set_death_callback(void (*callback)(void))
SANITIZER_INTERFACE_ATTRIBUTE;
void __asan_set_death_callback(void (*callback)(void));
void __asan_set_error_report_callback(void (*callback)(const char*))
SANITIZER_INTERFACE_ATTRIBUTE;
void __asan_set_error_report_callback(void (*callback)(const char*));
// User may provide function that would be called right when ASan detects
// an error. This can be used to notice cases when ASan detects an error, but
// the program crashes before ASan report is printed.
/* OPTIONAL */ void __asan_on_error()
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
void __asan_on_error();
// User may provide its own implementation for symbolization function.
// It should print the description of instruction at address "pc" to
// "out_buffer". Description should be at most "out_size" bytes long.
// User-specified function should return true if symbolization was
// successful.
/* OPTIONAL */ bool __asan_symbolize(const void *pc, char *out_buffer,
int out_size)
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
bool __asan_symbolize(const void *pc, char *out_buffer,
int out_size);
// Returns the estimated number of bytes that will be reserved by allocator
// for request of "size" bytes. If ASan allocator can't allocate that much
// memory, returns the maximal possible allocation size, otherwise returns
// "size".
uptr __asan_get_estimated_allocated_size(uptr size)
SANITIZER_INTERFACE_ATTRIBUTE;
size_t __asan_get_estimated_allocated_size(size_t size);
// Returns true if p was returned by the ASan allocator and
// is not yet freed.
bool __asan_get_ownership(const void *p)
SANITIZER_INTERFACE_ATTRIBUTE;
bool __asan_get_ownership(const void *p);
// Returns the number of bytes reserved for the pointer p.
// Requires (get_ownership(p) == true) or (p == 0).
uptr __asan_get_allocated_size(const void *p)
SANITIZER_INTERFACE_ATTRIBUTE;
size_t __asan_get_allocated_size(const void *p);
// Number of bytes, allocated and not yet freed by the application.
uptr __asan_get_current_allocated_bytes()
SANITIZER_INTERFACE_ATTRIBUTE;
size_t __asan_get_current_allocated_bytes();
// Number of bytes, mmaped by asan allocator to fulfill allocation requests.
// Generally, for request of X bytes, allocator can reserve and add to free
// lists a large number of chunks of size X to use them for future requests.
// All these chunks count toward the heap size. Currently, allocator never
// releases memory to OS (instead, it just puts freed chunks to free lists).
uptr __asan_get_heap_size()
SANITIZER_INTERFACE_ATTRIBUTE;
size_t __asan_get_heap_size();
// Number of bytes, mmaped by asan allocator, which can be used to fulfill
// allocation requests. When a user program frees memory chunk, it can first
// fall into quarantine and will count toward __asan_get_free_bytes() later.
uptr __asan_get_free_bytes()
SANITIZER_INTERFACE_ATTRIBUTE;
size_t __asan_get_free_bytes();
// Number of bytes in unmapped pages, that are released to OS. Currently,
// always returns 0.
uptr __asan_get_unmapped_bytes()
SANITIZER_INTERFACE_ATTRIBUTE;
size_t __asan_get_unmapped_bytes();
// Prints accumulated stats to stderr. Used for debugging.
void __asan_print_accumulated_stats()
SANITIZER_INTERFACE_ATTRIBUTE;
void __asan_print_accumulated_stats();
// This function may be optionally provided by user and should return
// a string containing ASan runtime options. See asan_flags.h for details.
/* OPTIONAL */ const char* __asan_default_options()
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
const char* __asan_default_options();
// Malloc hooks that may be optionally provided by user.
// __asan_malloc_hook(ptr, size) is called immediately after
// allocation of "size" bytes, which returned "ptr".
// __asan_free_hook(ptr) is called immediately before
// deallocation of "ptr".
/* OPTIONAL */ void __asan_malloc_hook(void *ptr, uptr size)
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
/* OPTIONAL */ void __asan_free_hook(void *ptr)
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
void __asan_malloc_hook(void *ptr, size_t size);
void __asan_free_hook(void *ptr);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // SANITIZER_ASAN_INTERFACE_H

View File

@ -7,86 +7,52 @@
//
//===----------------------------------------------------------------------===//
//
// This file is shared between AddressSanitizer and ThreadSanitizer.
// It contains basic macro and types.
// NOTE: This file may be included into user code.
// Common part of the public sanitizer interface.
//===----------------------------------------------------------------------===//
#ifndef SANITIZER_COMMON_INTERFACE_DEFS_H
#define SANITIZER_COMMON_INTERFACE_DEFS_H
// ----------- ATTENTION -------------
// This header should NOT include any other headers to avoid portability issues.
#include <stddef.h>
#include <stdint.h>
#if defined(_WIN32)
// FIXME find out what we need on Windows. __declspec(dllexport) ?
# define SANITIZER_INTERFACE_ATTRIBUTE
# define SANITIZER_WEAK_ATTRIBUTE
#elif defined(SANITIZER_GO)
# define SANITIZER_INTERFACE_ATTRIBUTE
# define SANITIZER_WEAK_ATTRIBUTE
#else
# define SANITIZER_INTERFACE_ATTRIBUTE __attribute__((visibility("default")))
# define SANITIZER_WEAK_ATTRIBUTE __attribute__((weak))
#endif
#ifdef __linux__
# define SANITIZER_SUPPORTS_WEAK_HOOKS 1
#else
# define SANITIZER_SUPPORTS_WEAK_HOOKS 0
#endif
// __has_feature
// GCC does not understand __has_feature.
#if !defined(__has_feature)
# define __has_feature(x) 0
#endif
// For portability reasons we do not include stddef.h, stdint.h or any other
// system header, but we do need some basic types that are not defined
// in a portable way by the language itself.
namespace __sanitizer {
#if defined(_WIN64)
// 64-bit Windows uses LLP64 data model.
typedef unsigned long long uptr; // NOLINT
typedef signed long long sptr; // NOLINT
#else
typedef unsigned long uptr; // NOLINT
typedef signed long sptr; // NOLINT
#endif // defined(_WIN64)
#if defined(__x86_64__)
// Since x32 uses ILP32 data model in 64-bit hardware mode, we must use
// 64-bit pointer to unwind stack frame.
typedef unsigned long long uhwptr; // NOLINT
#else
typedef uptr uhwptr; // NOLINT
#endif
typedef unsigned char u8;
typedef unsigned short u16; // NOLINT
typedef unsigned int u32;
typedef unsigned long long u64; // NOLINT
typedef signed char s8;
typedef signed short s16; // NOLINT
typedef signed int s32;
typedef signed long long s64; // NOLINT
} // namespace __sanitizer
#ifdef __cplusplus
extern "C" {
#endif
// Tell the tools to write their reports to "path.<pid>" instead of stderr.
void __sanitizer_set_report_path(const char *path)
SANITIZER_INTERFACE_ATTRIBUTE;
void __sanitizer_set_report_path(const char *path);
// Tell the tools to write their reports to given file descriptor instead of
// stderr.
void __sanitizer_set_report_fd(int fd)
SANITIZER_INTERFACE_ATTRIBUTE;
void __sanitizer_set_report_fd(int fd);
// Notify the tools that the sandbox is going to be turned on. The reserved
// parameter will be used in the future to hold a structure with functions
// that the tools may call to bypass the sandbox.
void __sanitizer_sandbox_on_notify(void *reserved)
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
void __sanitizer_sandbox_on_notify(void *reserved);
// This function is called by the tool when it has just finished reporting
// an error. 'error_summary' is a one-line string that summarizes
// the error message. This function can be overridden by the client.
void __sanitizer_report_error_summary(const char *error_summary);
// Some of the sanitizers (e.g. asan/tsan) may miss bugs that happen
// in unaligned loads/stores. In order to find such bugs reliably one needs
// to replace plain unaligned loads/stores with these calls.
uint16_t __sanitizer_unaligned_load16(const void *p);
uint32_t __sanitizer_unaligned_load32(const void *p);
uint64_t __sanitizer_unaligned_load64(const void *p);
void __sanitizer_unaligned_store16(void *p, uint16_t x);
void __sanitizer_unaligned_store32(void *p, uint32_t x);
void __sanitizer_unaligned_store64(void *p, uint64_t x);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // SANITIZER_COMMON_INTERFACE_DEFS_H

View File

@ -0,0 +1,802 @@
//===-- linux_syscall_hooks.h ---------------------------------------------===//
//
// 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 public sanitizer interface.
//
// System call handlers.
//
// Interface methods declared in this header implement pre- and post- syscall
// actions for the active sanitizer.
// Usage:
// __sanitizer_syscall_pre_getfoo(...args...);
// int res = syscall(__NR_getfoo, ...args...);
// __sanitizer_syscall_post_getfoo(res, ...args...);
//===----------------------------------------------------------------------===//
#ifndef SANITIZER_LINUX_SYSCALL_HOOKS_H
#define SANITIZER_LINUX_SYSCALL_HOOKS_H
#ifdef __cplusplus
extern "C" {
#endif
void __sanitizer_syscall_pre_rt_sigpending(void *p, size_t s);
void __sanitizer_syscall_pre_getdents(int fd, void *dirp, int count);
void __sanitizer_syscall_pre_getdents64(int fd, void *dirp, int count);
void __sanitizer_syscall_pre_recvmsg(int sockfd, void *msg, int flags);
void __sanitizer_syscall_pre_wait4(int pid, int *status, int options, void *r);
void __sanitizer_syscall_pre_waitpid(int pid, int *status, int options);
void __sanitizer_syscall_post_rt_sigpending(long res, void *p, size_t s);
void __sanitizer_syscall_post_getdents(long res, int fd, void *dirp, int count);
void __sanitizer_syscall_post_getdents64(long res, int fd, void *dirp,
int count);
void __sanitizer_syscall_post_recvmsg(long res, int sockfd, void *msg,
int flags);
void __sanitizer_syscall_post_wait4(long res, int pid, int *status, int options,
void *r);
void __sanitizer_syscall_post_waitpid(long res, int pid, int *status,
int options);
// And now a few syscalls we don't handle yet.
#define __sanitizer_syscall_pre_accept(...)
#define __sanitizer_syscall_pre_accept4(...)
#define __sanitizer_syscall_pre_access(...)
#define __sanitizer_syscall_pre_acct(...)
#define __sanitizer_syscall_pre_add_key(...)
#define __sanitizer_syscall_pre_adjtimex(...)
#define __sanitizer_syscall_pre_afs_syscall(...)
#define __sanitizer_syscall_pre_alarm(...)
#define __sanitizer_syscall_pre_arch_prctl(...)
#define __sanitizer_syscall_pre_bdflush(...)
#define __sanitizer_syscall_pre_bind(...)
#define __sanitizer_syscall_pre_break(...)
#define __sanitizer_syscall_pre_brk(...)
#define __sanitizer_syscall_pre_capget(...)
#define __sanitizer_syscall_pre_capset(...)
#define __sanitizer_syscall_pre_chdir(...)
#define __sanitizer_syscall_pre_chmod(...)
#define __sanitizer_syscall_pre_chown(...)
#define __sanitizer_syscall_pre_chown32(...)
#define __sanitizer_syscall_pre_chroot(...)
#define __sanitizer_syscall_pre_clock_adjtime(...)
#define __sanitizer_syscall_pre_clock_getres(...)
#define __sanitizer_syscall_pre_clock_gettime(...)
#define __sanitizer_syscall_pre_clock_nanosleep(...)
#define __sanitizer_syscall_pre_clock_settime(...)
#define __sanitizer_syscall_pre_clone(...)
#define __sanitizer_syscall_pre_close(...)
#define __sanitizer_syscall_pre_connect(...)
#define __sanitizer_syscall_pre_creat(...)
#define __sanitizer_syscall_pre_create_module(...)
#define __sanitizer_syscall_pre_delete_module(...)
#define __sanitizer_syscall_pre_dup(...)
#define __sanitizer_syscall_pre_dup2(...)
#define __sanitizer_syscall_pre_dup3(...)
#define __sanitizer_syscall_pre_epoll_create(...)
#define __sanitizer_syscall_pre_epoll_create1(...)
#define __sanitizer_syscall_pre_epoll_ctl(...)
#define __sanitizer_syscall_pre_epoll_ctl_old(...)
#define __sanitizer_syscall_pre_epoll_pwait(...)
#define __sanitizer_syscall_pre_epoll_wait(...)
#define __sanitizer_syscall_pre_epoll_wait_old(...)
#define __sanitizer_syscall_pre_eventfd(...)
#define __sanitizer_syscall_pre_eventfd2(...)
#define __sanitizer_syscall_pre_execve(...)
#define __sanitizer_syscall_pre_exit(...)
#define __sanitizer_syscall_pre_exit_group(...)
#define __sanitizer_syscall_pre_faccessat(...)
#define __sanitizer_syscall_pre_fadvise64(...)
#define __sanitizer_syscall_pre_fadvise64_64(...)
#define __sanitizer_syscall_pre_fallocate(...)
#define __sanitizer_syscall_pre_fanotify_init(...)
#define __sanitizer_syscall_pre_fanotify_mark(...)
#define __sanitizer_syscall_pre_fchdir(...)
#define __sanitizer_syscall_pre_fchmod(...)
#define __sanitizer_syscall_pre_fchmodat(...)
#define __sanitizer_syscall_pre_fchown(...)
#define __sanitizer_syscall_pre_fchown32(...)
#define __sanitizer_syscall_pre_fchownat(...)
#define __sanitizer_syscall_pre_fcntl(...)
#define __sanitizer_syscall_pre_fcntl64(...)
#define __sanitizer_syscall_pre_fdatasync(...)
#define __sanitizer_syscall_pre_fgetxattr(...)
#define __sanitizer_syscall_pre_flistxattr(...)
#define __sanitizer_syscall_pre_flock(...)
#define __sanitizer_syscall_pre_fork(...)
#define __sanitizer_syscall_pre_fremovexattr(...)
#define __sanitizer_syscall_pre_fsetxattr(...)
#define __sanitizer_syscall_pre_fstat(...)
#define __sanitizer_syscall_pre_fstat64(...)
#define __sanitizer_syscall_pre_fstatat64(...)
#define __sanitizer_syscall_pre_fstatfs(...)
#define __sanitizer_syscall_pre_fstatfs64(...)
#define __sanitizer_syscall_pre_fsync(...)
#define __sanitizer_syscall_pre_ftime(...)
#define __sanitizer_syscall_pre_ftruncate(...)
#define __sanitizer_syscall_pre_ftruncate64(...)
#define __sanitizer_syscall_pre_futex(...)
#define __sanitizer_syscall_pre_futimesat(...)
#define __sanitizer_syscall_pre_getcpu(...)
#define __sanitizer_syscall_pre_getcwd(...)
#define __sanitizer_syscall_pre_getegid(...)
#define __sanitizer_syscall_pre_getegid32(...)
#define __sanitizer_syscall_pre_geteuid(...)
#define __sanitizer_syscall_pre_geteuid32(...)
#define __sanitizer_syscall_pre_getgid(...)
#define __sanitizer_syscall_pre_getgid32(...)
#define __sanitizer_syscall_pre_getgroups(...)
#define __sanitizer_syscall_pre_getgroups32(...)
#define __sanitizer_syscall_pre_getitimer(...)
#define __sanitizer_syscall_pre_get_kernel_syms(...)
#define __sanitizer_syscall_pre_get_mempolicy(...)
#define __sanitizer_syscall_pre_getpeername(...)
#define __sanitizer_syscall_pre_getpgid(...)
#define __sanitizer_syscall_pre_getpgrp(...)
#define __sanitizer_syscall_pre_getpid(...)
#define __sanitizer_syscall_pre_getpmsg(...)
#define __sanitizer_syscall_pre_getppid(...)
#define __sanitizer_syscall_pre_getpriority(...)
#define __sanitizer_syscall_pre_getresgid(...)
#define __sanitizer_syscall_pre_getresgid32(...)
#define __sanitizer_syscall_pre_getresuid(...)
#define __sanitizer_syscall_pre_getresuid32(...)
#define __sanitizer_syscall_pre_getrlimit(...)
#define __sanitizer_syscall_pre_get_robust_list(...)
#define __sanitizer_syscall_pre_getrusage(...)
#define __sanitizer_syscall_pre_getsid(...)
#define __sanitizer_syscall_pre_getsockname(...)
#define __sanitizer_syscall_pre_getsockopt(...)
#define __sanitizer_syscall_pre_get_thread_area(...)
#define __sanitizer_syscall_pre_gettid(...)
#define __sanitizer_syscall_pre_gettimeofday(...)
#define __sanitizer_syscall_pre_getuid(...)
#define __sanitizer_syscall_pre_getuid32(...)
#define __sanitizer_syscall_pre_getxattr(...)
#define __sanitizer_syscall_pre_gtty(...)
#define __sanitizer_syscall_pre_idle(...)
#define __sanitizer_syscall_pre_init_module(...)
#define __sanitizer_syscall_pre_inotify_add_watch(...)
#define __sanitizer_syscall_pre_inotify_init(...)
#define __sanitizer_syscall_pre_inotify_init1(...)
#define __sanitizer_syscall_pre_inotify_rm_watch(...)
#define __sanitizer_syscall_pre_io_cancel(...)
#define __sanitizer_syscall_pre_ioctl(...)
#define __sanitizer_syscall_pre_io_destroy(...)
#define __sanitizer_syscall_pre_io_getevents(...)
#define __sanitizer_syscall_pre_ioperm(...)
#define __sanitizer_syscall_pre_iopl(...)
#define __sanitizer_syscall_pre_ioprio_get(...)
#define __sanitizer_syscall_pre_ioprio_set(...)
#define __sanitizer_syscall_pre_io_setup(...)
#define __sanitizer_syscall_pre_io_submit(...)
#define __sanitizer_syscall_pre_ipc(...)
#define __sanitizer_syscall_pre_kexec_load(...)
#define __sanitizer_syscall_pre_keyctl(...)
#define __sanitizer_syscall_pre_kill(...)
#define __sanitizer_syscall_pre_lchown(...)
#define __sanitizer_syscall_pre_lchown32(...)
#define __sanitizer_syscall_pre_lgetxattr(...)
#define __sanitizer_syscall_pre_link(...)
#define __sanitizer_syscall_pre_linkat(...)
#define __sanitizer_syscall_pre_listen(...)
#define __sanitizer_syscall_pre_listxattr(...)
#define __sanitizer_syscall_pre_llistxattr(...)
#define __sanitizer_syscall_pre__llseek(...)
#define __sanitizer_syscall_pre_lock(...)
#define __sanitizer_syscall_pre_lookup_dcookie(...)
#define __sanitizer_syscall_pre_lremovexattr(...)
#define __sanitizer_syscall_pre_lseek(...)
#define __sanitizer_syscall_pre_lsetxattr(...)
#define __sanitizer_syscall_pre_lstat(...)
#define __sanitizer_syscall_pre_lstat64(...)
#define __sanitizer_syscall_pre_madvise(...)
#define __sanitizer_syscall_pre_madvise1(...)
#define __sanitizer_syscall_pre_mbind(...)
#define __sanitizer_syscall_pre_migrate_pages(...)
#define __sanitizer_syscall_pre_mincore(...)
#define __sanitizer_syscall_pre_mkdir(...)
#define __sanitizer_syscall_pre_mkdirat(...)
#define __sanitizer_syscall_pre_mknod(...)
#define __sanitizer_syscall_pre_mknodat(...)
#define __sanitizer_syscall_pre_mlock(...)
#define __sanitizer_syscall_pre_mlockall(...)
#define __sanitizer_syscall_pre_mmap(...)
#define __sanitizer_syscall_pre_mmap2(...)
#define __sanitizer_syscall_pre_modify_ldt(...)
#define __sanitizer_syscall_pre_mount(...)
#define __sanitizer_syscall_pre_move_pages(...)
#define __sanitizer_syscall_pre_mprotect(...)
#define __sanitizer_syscall_pre_mpx(...)
#define __sanitizer_syscall_pre_mq_getsetattr(...)
#define __sanitizer_syscall_pre_mq_notify(...)
#define __sanitizer_syscall_pre_mq_open(...)
#define __sanitizer_syscall_pre_mq_timedreceive(...)
#define __sanitizer_syscall_pre_mq_timedsend(...)
#define __sanitizer_syscall_pre_mq_unlink(...)
#define __sanitizer_syscall_pre_mremap(...)
#define __sanitizer_syscall_pre_msgctl(...)
#define __sanitizer_syscall_pre_msgget(...)
#define __sanitizer_syscall_pre_msgrcv(...)
#define __sanitizer_syscall_pre_msgsnd(...)
#define __sanitizer_syscall_pre_msync(...)
#define __sanitizer_syscall_pre_munlock(...)
#define __sanitizer_syscall_pre_munlockall(...)
#define __sanitizer_syscall_pre_munmap(...)
#define __sanitizer_syscall_pre_name_to_handle_at(...)
#define __sanitizer_syscall_pre_nanosleep(...)
#define __sanitizer_syscall_pre_newfstatat(...)
#define __sanitizer_syscall_pre__newselect(...)
#define __sanitizer_syscall_pre_nfsservctl(...)
#define __sanitizer_syscall_pre_nice(...)
#define __sanitizer_syscall_pre_oldfstat(...)
#define __sanitizer_syscall_pre_oldlstat(...)
#define __sanitizer_syscall_pre_oldolduname(...)
#define __sanitizer_syscall_pre_oldstat(...)
#define __sanitizer_syscall_pre_olduname(...)
#define __sanitizer_syscall_pre_open(...)
#define __sanitizer_syscall_pre_openat(...)
#define __sanitizer_syscall_pre_open_by_handle_at(...)
#define __sanitizer_syscall_pre_pause(...)
#define __sanitizer_syscall_pre_perf_event_open(...)
#define __sanitizer_syscall_pre_personality(...)
#define __sanitizer_syscall_pre_pipe(...)
#define __sanitizer_syscall_pre_pipe2(...)
#define __sanitizer_syscall_pre_pivot_root(...)
#define __sanitizer_syscall_pre_poll(...)
#define __sanitizer_syscall_pre_ppoll(...)
#define __sanitizer_syscall_pre_prctl(...)
#define __sanitizer_syscall_pre_pread64(...)
#define __sanitizer_syscall_pre_preadv(...)
#define __sanitizer_syscall_pre_prlimit64(...)
#define __sanitizer_syscall_pre_process_vm_readv(...)
#define __sanitizer_syscall_pre_process_vm_writev(...)
#define __sanitizer_syscall_pre_prof(...)
#define __sanitizer_syscall_pre_profil(...)
#define __sanitizer_syscall_pre_pselect6(...)
#define __sanitizer_syscall_pre_ptrace(...)
#define __sanitizer_syscall_pre_putpmsg(...)
#define __sanitizer_syscall_pre_pwrite64(...)
#define __sanitizer_syscall_pre_pwritev(...)
#define __sanitizer_syscall_pre_query_module(...)
#define __sanitizer_syscall_pre_quotactl(...)
#define __sanitizer_syscall_pre_read(...)
#define __sanitizer_syscall_pre_readahead(...)
#define __sanitizer_syscall_pre_readdir(...)
#define __sanitizer_syscall_pre_readlink(...)
#define __sanitizer_syscall_pre_readlinkat(...)
#define __sanitizer_syscall_pre_readv(...)
#define __sanitizer_syscall_pre_reboot(...)
#define __sanitizer_syscall_pre_recvfrom(...)
#define __sanitizer_syscall_pre_recvmmsg(...)
#define __sanitizer_syscall_pre_remap_file_pages(...)
#define __sanitizer_syscall_pre_removexattr(...)
#define __sanitizer_syscall_pre_rename(...)
#define __sanitizer_syscall_pre_renameat(...)
#define __sanitizer_syscall_pre_request_key(...)
#define __sanitizer_syscall_pre_restart_syscall(...)
#define __sanitizer_syscall_pre_rmdir(...)
#define __sanitizer_syscall_pre_rt_sigaction(...)
#define __sanitizer_syscall_pre_rt_sigprocmask(...)
#define __sanitizer_syscall_pre_rt_sigqueueinfo(...)
#define __sanitizer_syscall_pre_rt_sigreturn(...)
#define __sanitizer_syscall_pre_rt_sigsuspend(...)
#define __sanitizer_syscall_pre_rt_sigtimedwait(...)
#define __sanitizer_syscall_pre_rt_tgsigqueueinfo(...)
#define __sanitizer_syscall_pre_sched_getaffinity(...)
#define __sanitizer_syscall_pre_sched_getparam(...)
#define __sanitizer_syscall_pre_sched_get_priority_max(...)
#define __sanitizer_syscall_pre_sched_get_priority_min(...)
#define __sanitizer_syscall_pre_sched_getscheduler(...)
#define __sanitizer_syscall_pre_sched_rr_get_interval(...)
#define __sanitizer_syscall_pre_sched_setaffinity(...)
#define __sanitizer_syscall_pre_sched_setparam(...)
#define __sanitizer_syscall_pre_sched_setscheduler(...)
#define __sanitizer_syscall_pre_sched_yield(...)
#define __sanitizer_syscall_pre_security(...)
#define __sanitizer_syscall_pre_select(...)
#define __sanitizer_syscall_pre_semctl(...)
#define __sanitizer_syscall_pre_semget(...)
#define __sanitizer_syscall_pre_semop(...)
#define __sanitizer_syscall_pre_semtimedop(...)
#define __sanitizer_syscall_pre_sendfile(...)
#define __sanitizer_syscall_pre_sendfile64(...)
#define __sanitizer_syscall_pre_sendmmsg(...)
#define __sanitizer_syscall_pre_sendmsg(...)
#define __sanitizer_syscall_pre_sendto(...)
#define __sanitizer_syscall_pre_setdomainname(...)
#define __sanitizer_syscall_pre_setfsgid(...)
#define __sanitizer_syscall_pre_setfsgid32(...)
#define __sanitizer_syscall_pre_setfsuid(...)
#define __sanitizer_syscall_pre_setfsuid32(...)
#define __sanitizer_syscall_pre_setgid(...)
#define __sanitizer_syscall_pre_setgid32(...)
#define __sanitizer_syscall_pre_setgroups(...)
#define __sanitizer_syscall_pre_setgroups32(...)
#define __sanitizer_syscall_pre_sethostname(...)
#define __sanitizer_syscall_pre_setitimer(...)
#define __sanitizer_syscall_pre_set_mempolicy(...)
#define __sanitizer_syscall_pre_setns(...)
#define __sanitizer_syscall_pre_setpgid(...)
#define __sanitizer_syscall_pre_setpriority(...)
#define __sanitizer_syscall_pre_setregid(...)
#define __sanitizer_syscall_pre_setregid32(...)
#define __sanitizer_syscall_pre_setresgid(...)
#define __sanitizer_syscall_pre_setresgid32(...)
#define __sanitizer_syscall_pre_setresuid(...)
#define __sanitizer_syscall_pre_setresuid32(...)
#define __sanitizer_syscall_pre_setreuid(...)
#define __sanitizer_syscall_pre_setreuid32(...)
#define __sanitizer_syscall_pre_setrlimit(...)
#define __sanitizer_syscall_pre_set_robust_list(...)
#define __sanitizer_syscall_pre_setsid(...)
#define __sanitizer_syscall_pre_setsockopt(...)
#define __sanitizer_syscall_pre_set_thread_area(...)
#define __sanitizer_syscall_pre_set_tid_address(...)
#define __sanitizer_syscall_pre_settimeofday(...)
#define __sanitizer_syscall_pre_setuid(...)
#define __sanitizer_syscall_pre_setuid32(...)
#define __sanitizer_syscall_pre_setxattr(...)
#define __sanitizer_syscall_pre_sgetmask(...)
#define __sanitizer_syscall_pre_shmat(...)
#define __sanitizer_syscall_pre_shmctl(...)
#define __sanitizer_syscall_pre_shmdt(...)
#define __sanitizer_syscall_pre_shmget(...)
#define __sanitizer_syscall_pre_shutdown(...)
#define __sanitizer_syscall_pre_sigaction(...)
#define __sanitizer_syscall_pre_sigaltstack(...)
#define __sanitizer_syscall_pre_signal(...)
#define __sanitizer_syscall_pre_signalfd(...)
#define __sanitizer_syscall_pre_signalfd4(...)
#define __sanitizer_syscall_pre_sigpending(...)
#define __sanitizer_syscall_pre_sigprocmask(...)
#define __sanitizer_syscall_pre_sigreturn(...)
#define __sanitizer_syscall_pre_sigsuspend(...)
#define __sanitizer_syscall_pre_socket(...)
#define __sanitizer_syscall_pre_socketcall(...)
#define __sanitizer_syscall_pre_socketpair(...)
#define __sanitizer_syscall_pre_splice(...)
#define __sanitizer_syscall_pre_ssetmask(...)
#define __sanitizer_syscall_pre_stat(...)
#define __sanitizer_syscall_pre_stat64(...)
#define __sanitizer_syscall_pre_statfs(...)
#define __sanitizer_syscall_pre_statfs64(...)
#define __sanitizer_syscall_pre_stime(...)
#define __sanitizer_syscall_pre_stty(...)
#define __sanitizer_syscall_pre_swapoff(...)
#define __sanitizer_syscall_pre_swapon(...)
#define __sanitizer_syscall_pre_symlink(...)
#define __sanitizer_syscall_pre_symlinkat(...)
#define __sanitizer_syscall_pre_sync(...)
#define __sanitizer_syscall_pre_sync_file_range(...)
#define __sanitizer_syscall_pre_syncfs(...)
#define __sanitizer_syscall_pre__sysctl(...)
#define __sanitizer_syscall_pre_sysfs(...)
#define __sanitizer_syscall_pre_sysinfo(...)
#define __sanitizer_syscall_pre_syslog(...)
#define __sanitizer_syscall_pre_tee(...)
#define __sanitizer_syscall_pre_tgkill(...)
#define __sanitizer_syscall_pre_time(...)
#define __sanitizer_syscall_pre_timer_create(...)
#define __sanitizer_syscall_pre_timer_delete(...)
#define __sanitizer_syscall_pre_timerfd_create(...)
#define __sanitizer_syscall_pre_timerfd_gettime(...)
#define __sanitizer_syscall_pre_timerfd_settime(...)
#define __sanitizer_syscall_pre_timer_getoverrun(...)
#define __sanitizer_syscall_pre_timer_gettime(...)
#define __sanitizer_syscall_pre_timer_settime(...)
#define __sanitizer_syscall_pre_times(...)
#define __sanitizer_syscall_pre_tkill(...)
#define __sanitizer_syscall_pre_truncate(...)
#define __sanitizer_syscall_pre_truncate64(...)
#define __sanitizer_syscall_pre_tuxcall(...)
#define __sanitizer_syscall_pre_ugetrlimit(...)
#define __sanitizer_syscall_pre_ulimit(...)
#define __sanitizer_syscall_pre_umask(...)
#define __sanitizer_syscall_pre_umount(...)
#define __sanitizer_syscall_pre_umount2(...)
#define __sanitizer_syscall_pre_uname(...)
#define __sanitizer_syscall_pre_unlink(...)
#define __sanitizer_syscall_pre_unlinkat(...)
#define __sanitizer_syscall_pre_unshare(...)
#define __sanitizer_syscall_pre_uselib(...)
#define __sanitizer_syscall_pre_ustat(...)
#define __sanitizer_syscall_pre_utime(...)
#define __sanitizer_syscall_pre_utimensat(...)
#define __sanitizer_syscall_pre_utimes(...)
#define __sanitizer_syscall_pre_vfork(...)
#define __sanitizer_syscall_pre_vhangup(...)
#define __sanitizer_syscall_pre_vm86(...)
#define __sanitizer_syscall_pre_vm86old(...)
#define __sanitizer_syscall_pre_vmsplice(...)
#define __sanitizer_syscall_pre_vserver(...)
#define __sanitizer_syscall_pre_waitid(...)
#define __sanitizer_syscall_pre_write(...)
#define __sanitizer_syscall_pre_writev(...)
#define __sanitizer_syscall_post_accept4(res, ...)
#define __sanitizer_syscall_post_accept(res, ...)
#define __sanitizer_syscall_post_access(res, ...)
#define __sanitizer_syscall_post_acct(res, ...)
#define __sanitizer_syscall_post_add_key(res, ...)
#define __sanitizer_syscall_post_adjtimex(res, ...)
#define __sanitizer_syscall_post_afs_syscall(res, ...)
#define __sanitizer_syscall_post_alarm(res, ...)
#define __sanitizer_syscall_post_arch_prctl(res, ...)
#define __sanitizer_syscall_post_bdflush(res, ...)
#define __sanitizer_syscall_post_bind(res, ...)
#define __sanitizer_syscall_post_break(res, ...)
#define __sanitizer_syscall_post_brk(res, ...)
#define __sanitizer_syscall_post_capget(res, ...)
#define __sanitizer_syscall_post_capset(res, ...)
#define __sanitizer_syscall_post_chdir(res, ...)
#define __sanitizer_syscall_post_chmod(res, ...)
#define __sanitizer_syscall_post_chown32(res, ...)
#define __sanitizer_syscall_post_chown(res, ...)
#define __sanitizer_syscall_post_chroot(res, ...)
#define __sanitizer_syscall_post_clock_adjtime(res, ...)
#define __sanitizer_syscall_post_clock_getres(res, ...)
#define __sanitizer_syscall_post_clock_gettime(res, ...)
#define __sanitizer_syscall_post_clock_nanosleep(res, ...)
#define __sanitizer_syscall_post_clock_settime(res, ...)
#define __sanitizer_syscall_post_clone(res, ...)
#define __sanitizer_syscall_post_close(res, ...)
#define __sanitizer_syscall_post_connect(res, ...)
#define __sanitizer_syscall_post_create_module(res, ...)
#define __sanitizer_syscall_post_creat(res, ...)
#define __sanitizer_syscall_post_delete_module(res, ...)
#define __sanitizer_syscall_post_dup2(res, ...)
#define __sanitizer_syscall_post_dup3(res, ...)
#define __sanitizer_syscall_post_dup(res, ...)
#define __sanitizer_syscall_post_epoll_create1(res, ...)
#define __sanitizer_syscall_post_epoll_create(res, ...)
#define __sanitizer_syscall_post_epoll_ctl_old(res, ...)
#define __sanitizer_syscall_post_epoll_ctl(res, ...)
#define __sanitizer_syscall_post_epoll_pwait(res, ...)
#define __sanitizer_syscall_post_epoll_wait_old(res, ...)
#define __sanitizer_syscall_post_epoll_wait(res, ...)
#define __sanitizer_syscall_post_eventfd2(res, ...)
#define __sanitizer_syscall_post_eventfd(res, ...)
#define __sanitizer_syscall_post_execve(res, ...)
#define __sanitizer_syscall_post_exit_group(res, ...)
#define __sanitizer_syscall_post_exit(res, ...)
#define __sanitizer_syscall_post_faccessat(res, ...)
#define __sanitizer_syscall_post_fadvise64_64(res, ...)
#define __sanitizer_syscall_post_fadvise64(res, ...)
#define __sanitizer_syscall_post_fallocate(res, ...)
#define __sanitizer_syscall_post_fanotify_init(res, ...)
#define __sanitizer_syscall_post_fanotify_mark(res, ...)
#define __sanitizer_syscall_post_fchdir(res, ...)
#define __sanitizer_syscall_post_fchmodat(res, ...)
#define __sanitizer_syscall_post_fchmod(res, ...)
#define __sanitizer_syscall_post_fchown32(res, ...)
#define __sanitizer_syscall_post_fchownat(res, ...)
#define __sanitizer_syscall_post_fchown(res, ...)
#define __sanitizer_syscall_post_fcntl64(res, ...)
#define __sanitizer_syscall_post_fcntl(res, ...)
#define __sanitizer_syscall_post_fdatasync(res, ...)
#define __sanitizer_syscall_post_fgetxattr(res, ...)
#define __sanitizer_syscall_post_flistxattr(res, ...)
#define __sanitizer_syscall_post_flock(res, ...)
#define __sanitizer_syscall_post_fork(res, ...)
#define __sanitizer_syscall_post_fremovexattr(res, ...)
#define __sanitizer_syscall_post_fsetxattr(res, ...)
#define __sanitizer_syscall_post_fstat64(res, ...)
#define __sanitizer_syscall_post_fstatat64(res, ...)
#define __sanitizer_syscall_post_fstatfs64(res, ...)
#define __sanitizer_syscall_post_fstatfs(res, ...)
#define __sanitizer_syscall_post_fstat(res, ...)
#define __sanitizer_syscall_post_fsync(res, ...)
#define __sanitizer_syscall_post_ftime(res, ...)
#define __sanitizer_syscall_post_ftruncate64(res, ...)
#define __sanitizer_syscall_post_ftruncate(res, ...)
#define __sanitizer_syscall_post_futex(res, ...)
#define __sanitizer_syscall_post_futimesat(res, ...)
#define __sanitizer_syscall_post_getcpu(res, ...)
#define __sanitizer_syscall_post_getcwd(res, ...)
#define __sanitizer_syscall_post_getegid32(res, ...)
#define __sanitizer_syscall_post_getegid(res, ...)
#define __sanitizer_syscall_post_geteuid32(res, ...)
#define __sanitizer_syscall_post_geteuid(res, ...)
#define __sanitizer_syscall_post_getgid32(res, ...)
#define __sanitizer_syscall_post_getgid(res, ...)
#define __sanitizer_syscall_post_getgroups32(res, ...)
#define __sanitizer_syscall_post_getgroups(res, ...)
#define __sanitizer_syscall_post_getitimer(res, ...)
#define __sanitizer_syscall_post_get_kernel_syms(res, ...)
#define __sanitizer_syscall_post_get_mempolicy(res, ...)
#define __sanitizer_syscall_post_getpeername(res, ...)
#define __sanitizer_syscall_post_getpgid(res, ...)
#define __sanitizer_syscall_post_getpgrp(res, ...)
#define __sanitizer_syscall_post_getpid(res, ...)
#define __sanitizer_syscall_post_getpmsg(res, ...)
#define __sanitizer_syscall_post_getppid(res, ...)
#define __sanitizer_syscall_post_getpriority(res, ...)
#define __sanitizer_syscall_post_getresgid32(res, ...)
#define __sanitizer_syscall_post_getresgid(res, ...)
#define __sanitizer_syscall_post_getresuid32(res, ...)
#define __sanitizer_syscall_post_getresuid(res, ...)
#define __sanitizer_syscall_post_getrlimit(res, ...)
#define __sanitizer_syscall_post_get_robust_list(res, ...)
#define __sanitizer_syscall_post_getrusage(res, ...)
#define __sanitizer_syscall_post_getsid(res, ...)
#define __sanitizer_syscall_post_getsockname(res, ...)
#define __sanitizer_syscall_post_getsockopt(res, ...)
#define __sanitizer_syscall_post_get_thread_area(res, ...)
#define __sanitizer_syscall_post_gettid(res, ...)
#define __sanitizer_syscall_post_gettimeofday(res, ...)
#define __sanitizer_syscall_post_getuid32(res, ...)
#define __sanitizer_syscall_post_getuid(res, ...)
#define __sanitizer_syscall_post_getxattr(res, ...)
#define __sanitizer_syscall_post_gtty(res, ...)
#define __sanitizer_syscall_post_idle(res, ...)
#define __sanitizer_syscall_post_init_module(res, ...)
#define __sanitizer_syscall_post_inotify_add_watch(res, ...)
#define __sanitizer_syscall_post_inotify_init1(res, ...)
#define __sanitizer_syscall_post_inotify_init(res, ...)
#define __sanitizer_syscall_post_inotify_rm_watch(res, ...)
#define __sanitizer_syscall_post_io_cancel(res, ...)
#define __sanitizer_syscall_post_ioctl(res, ...)
#define __sanitizer_syscall_post_io_destroy(res, ...)
#define __sanitizer_syscall_post_io_getevents(res, ...)
#define __sanitizer_syscall_post_ioperm(res, ...)
#define __sanitizer_syscall_post_iopl(res, ...)
#define __sanitizer_syscall_post_ioprio_get(res, ...)
#define __sanitizer_syscall_post_ioprio_set(res, ...)
#define __sanitizer_syscall_post_io_setup(res, ...)
#define __sanitizer_syscall_post_io_submit(res, ...)
#define __sanitizer_syscall_post_ipc(res, ...)
#define __sanitizer_syscall_post_kexec_load(res, ...)
#define __sanitizer_syscall_post_keyctl(res, ...)
#define __sanitizer_syscall_post_kill(res, ...)
#define __sanitizer_syscall_post_lchown32(res, ...)
#define __sanitizer_syscall_post_lchown(res, ...)
#define __sanitizer_syscall_post_lgetxattr(res, ...)
#define __sanitizer_syscall_post_linkat(res, ...)
#define __sanitizer_syscall_post_link(res, ...)
#define __sanitizer_syscall_post_listen(res, ...)
#define __sanitizer_syscall_post_listxattr(res, ...)
#define __sanitizer_syscall_post_llistxattr(res, ...)
#define __sanitizer_syscall_post__llseek(res, ...)
#define __sanitizer_syscall_post_lock(res, ...)
#define __sanitizer_syscall_post_lookup_dcookie(res, ...)
#define __sanitizer_syscall_post_lremovexattr(res, ...)
#define __sanitizer_syscall_post_lseek(res, ...)
#define __sanitizer_syscall_post_lsetxattr(res, ...)
#define __sanitizer_syscall_post_lstat64(res, ...)
#define __sanitizer_syscall_post_lstat(res, ...)
#define __sanitizer_syscall_post_madvise1(res, ...)
#define __sanitizer_syscall_post_madvise(res, ...)
#define __sanitizer_syscall_post_mbind(res, ...)
#define __sanitizer_syscall_post_migrate_pages(res, ...)
#define __sanitizer_syscall_post_mincore(res, ...)
#define __sanitizer_syscall_post_mkdirat(res, ...)
#define __sanitizer_syscall_post_mkdir(res, ...)
#define __sanitizer_syscall_post_mknodat(res, ...)
#define __sanitizer_syscall_post_mknod(res, ...)
#define __sanitizer_syscall_post_mlockall(res, ...)
#define __sanitizer_syscall_post_mlock(res, ...)
#define __sanitizer_syscall_post_mmap2(res, ...)
#define __sanitizer_syscall_post_mmap(res, ...)
#define __sanitizer_syscall_post_modify_ldt(res, ...)
#define __sanitizer_syscall_post_mount(res, ...)
#define __sanitizer_syscall_post_move_pages(res, ...)
#define __sanitizer_syscall_post_mprotect(res, ...)
#define __sanitizer_syscall_post_mpx(res, ...)
#define __sanitizer_syscall_post_mq_getsetattr(res, ...)
#define __sanitizer_syscall_post_mq_notify(res, ...)
#define __sanitizer_syscall_post_mq_open(res, ...)
#define __sanitizer_syscall_post_mq_timedreceive(res, ...)
#define __sanitizer_syscall_post_mq_timedsend(res, ...)
#define __sanitizer_syscall_post_mq_unlink(res, ...)
#define __sanitizer_syscall_post_mremap(res, ...)
#define __sanitizer_syscall_post_msgctl(res, ...)
#define __sanitizer_syscall_post_msgget(res, ...)
#define __sanitizer_syscall_post_msgrcv(res, ...)
#define __sanitizer_syscall_post_msgsnd(res, ...)
#define __sanitizer_syscall_post_msync(res, ...)
#define __sanitizer_syscall_post_munlockall(res, ...)
#define __sanitizer_syscall_post_munlock(res, ...)
#define __sanitizer_syscall_post_munmap(res, ...)
#define __sanitizer_syscall_post_name_to_handle_at(res, ...)
#define __sanitizer_syscall_post_nanosleep(res, ...)
#define __sanitizer_syscall_post_newfstatat(res, ...)
#define __sanitizer_syscall_post__newselect(res, ...)
#define __sanitizer_syscall_post_nfsservctl(res, ...)
#define __sanitizer_syscall_post_nice(res, ...)
#define __sanitizer_syscall_post_oldfstat(res, ...)
#define __sanitizer_syscall_post_oldlstat(res, ...)
#define __sanitizer_syscall_post_oldolduname(res, ...)
#define __sanitizer_syscall_post_oldstat(res, ...)
#define __sanitizer_syscall_post_olduname(res, ...)
#define __sanitizer_syscall_post_openat(res, ...)
#define __sanitizer_syscall_post_open_by_handle_at(res, ...)
#define __sanitizer_syscall_post_open(res, ...)
#define __sanitizer_syscall_post_pause(res, ...)
#define __sanitizer_syscall_post_perf_event_open(res, ...)
#define __sanitizer_syscall_post_personality(res, ...)
#define __sanitizer_syscall_post_pipe2(res, ...)
#define __sanitizer_syscall_post_pipe(res, ...)
#define __sanitizer_syscall_post_pivot_root(res, ...)
#define __sanitizer_syscall_post_poll(res, ...)
#define __sanitizer_syscall_post_ppoll(res, ...)
#define __sanitizer_syscall_post_prctl(res, ...)
#define __sanitizer_syscall_post_pread64(res, ...)
#define __sanitizer_syscall_post_preadv(res, ...)
#define __sanitizer_syscall_post_prlimit64(res, ...)
#define __sanitizer_syscall_post_process_vm_readv(res, ...)
#define __sanitizer_syscall_post_process_vm_writev(res, ...)
#define __sanitizer_syscall_post_profil(res, ...)
#define __sanitizer_syscall_post_prof(res, ...)
#define __sanitizer_syscall_post_pselect6(res, ...)
#define __sanitizer_syscall_post_ptrace(res, ...)
#define __sanitizer_syscall_post_putpmsg(res, ...)
#define __sanitizer_syscall_post_pwrite64(res, ...)
#define __sanitizer_syscall_post_pwritev(res, ...)
#define __sanitizer_syscall_post_query_module(res, ...)
#define __sanitizer_syscall_post_quotactl(res, ...)
#define __sanitizer_syscall_post_readahead(res, ...)
#define __sanitizer_syscall_post_readdir(res, ...)
#define __sanitizer_syscall_post_readlinkat(res, ...)
#define __sanitizer_syscall_post_readlink(res, ...)
#define __sanitizer_syscall_post_read(res, ...)
#define __sanitizer_syscall_post_readv(res, ...)
#define __sanitizer_syscall_post_reboot(res, ...)
#define __sanitizer_syscall_post_recvfrom(res, ...)
#define __sanitizer_syscall_post_recvmmsg(res, ...)
#define __sanitizer_syscall_post_remap_file_pages(res, ...)
#define __sanitizer_syscall_post_removexattr(res, ...)
#define __sanitizer_syscall_post_renameat(res, ...)
#define __sanitizer_syscall_post_rename(res, ...)
#define __sanitizer_syscall_post_request_key(res, ...)
#define __sanitizer_syscall_post_restart_syscall(res, ...)
#define __sanitizer_syscall_post_rmdir(res, ...)
#define __sanitizer_syscall_post_rt_sigaction(res, ...)
#define __sanitizer_syscall_post_rt_sigprocmask(res, ...)
#define __sanitizer_syscall_post_rt_sigqueueinfo(res, ...)
#define __sanitizer_syscall_post_rt_sigreturn(res, ...)
#define __sanitizer_syscall_post_rt_sigsuspend(res, ...)
#define __sanitizer_syscall_post_rt_sigtimedwait(res, ...)
#define __sanitizer_syscall_post_rt_tgsigqueueinfo(res, ...)
#define __sanitizer_syscall_post_sched_getaffinity(res, ...)
#define __sanitizer_syscall_post_sched_getparam(res, ...)
#define __sanitizer_syscall_post_sched_get_priority_max(res, ...)
#define __sanitizer_syscall_post_sched_get_priority_min(res, ...)
#define __sanitizer_syscall_post_sched_getscheduler(res, ...)
#define __sanitizer_syscall_post_sched_rr_get_interval(res, ...)
#define __sanitizer_syscall_post_sched_setaffinity(res, ...)
#define __sanitizer_syscall_post_sched_setparam(res, ...)
#define __sanitizer_syscall_post_sched_setscheduler(res, ...)
#define __sanitizer_syscall_post_sched_yield(res, ...)
#define __sanitizer_syscall_post_security(res, ...)
#define __sanitizer_syscall_post_select(res, ...)
#define __sanitizer_syscall_post_semctl(res, ...)
#define __sanitizer_syscall_post_semget(res, ...)
#define __sanitizer_syscall_post_semop(res, ...)
#define __sanitizer_syscall_post_semtimedop(res, ...)
#define __sanitizer_syscall_post_sendfile64(res, ...)
#define __sanitizer_syscall_post_sendfile(res, ...)
#define __sanitizer_syscall_post_sendmmsg(res, ...)
#define __sanitizer_syscall_post_sendmsg(res, ...)
#define __sanitizer_syscall_post_sendto(res, ...)
#define __sanitizer_syscall_post_setdomainname(res, ...)
#define __sanitizer_syscall_post_setfsgid32(res, ...)
#define __sanitizer_syscall_post_setfsgid(res, ...)
#define __sanitizer_syscall_post_setfsuid32(res, ...)
#define __sanitizer_syscall_post_setfsuid(res, ...)
#define __sanitizer_syscall_post_setgid32(res, ...)
#define __sanitizer_syscall_post_setgid(res, ...)
#define __sanitizer_syscall_post_setgroups32(res, ...)
#define __sanitizer_syscall_post_setgroups(res, ...)
#define __sanitizer_syscall_post_sethostname(res, ...)
#define __sanitizer_syscall_post_setitimer(res, ...)
#define __sanitizer_syscall_post_set_mempolicy(res, ...)
#define __sanitizer_syscall_post_setns(res, ...)
#define __sanitizer_syscall_post_setpgid(res, ...)
#define __sanitizer_syscall_post_setpriority(res, ...)
#define __sanitizer_syscall_post_setregid32(res, ...)
#define __sanitizer_syscall_post_setregid(res, ...)
#define __sanitizer_syscall_post_setresgid32(res, ...)
#define __sanitizer_syscall_post_setresgid(res, ...)
#define __sanitizer_syscall_post_setresuid32(res, ...)
#define __sanitizer_syscall_post_setresuid(res, ...)
#define __sanitizer_syscall_post_setreuid32(res, ...)
#define __sanitizer_syscall_post_setreuid(res, ...)
#define __sanitizer_syscall_post_setrlimit(res, ...)
#define __sanitizer_syscall_post_set_robust_list(res, ...)
#define __sanitizer_syscall_post_setsid(res, ...)
#define __sanitizer_syscall_post_setsockopt(res, ...)
#define __sanitizer_syscall_post_set_thread_area(res, ...)
#define __sanitizer_syscall_post_set_tid_address(res, ...)
#define __sanitizer_syscall_post_settimeofday(res, ...)
#define __sanitizer_syscall_post_setuid32(res, ...)
#define __sanitizer_syscall_post_setuid(res, ...)
#define __sanitizer_syscall_post_setxattr(res, ...)
#define __sanitizer_syscall_post_sgetmask(res, ...)
#define __sanitizer_syscall_post_shmat(res, ...)
#define __sanitizer_syscall_post_shmctl(res, ...)
#define __sanitizer_syscall_post_shmdt(res, ...)
#define __sanitizer_syscall_post_shmget(res, ...)
#define __sanitizer_syscall_post_shutdown(res, ...)
#define __sanitizer_syscall_post_sigaction(res, ...)
#define __sanitizer_syscall_post_sigaltstack(res, ...)
#define __sanitizer_syscall_post_signalfd4(res, ...)
#define __sanitizer_syscall_post_signalfd(res, ...)
#define __sanitizer_syscall_post_signal(res, ...)
#define __sanitizer_syscall_post_sigpending(res, ...)
#define __sanitizer_syscall_post_sigprocmask(res, ...)
#define __sanitizer_syscall_post_sigreturn(res, ...)
#define __sanitizer_syscall_post_sigsuspend(res, ...)
#define __sanitizer_syscall_post_socketcall(res, ...)
#define __sanitizer_syscall_post_socketpair(res, ...)
#define __sanitizer_syscall_post_socket(res, ...)
#define __sanitizer_syscall_post_splice(res, ...)
#define __sanitizer_syscall_post_ssetmask(res, ...)
#define __sanitizer_syscall_post_stat64(res, ...)
#define __sanitizer_syscall_post_statfs64(res, ...)
#define __sanitizer_syscall_post_statfs(res, ...)
#define __sanitizer_syscall_post_stat(res, ...)
#define __sanitizer_syscall_post_stime(res, ...)
#define __sanitizer_syscall_post_stty(res, ...)
#define __sanitizer_syscall_post_swapoff(res, ...)
#define __sanitizer_syscall_post_swapon(res, ...)
#define __sanitizer_syscall_post_symlinkat(res, ...)
#define __sanitizer_syscall_post_symlink(res, ...)
#define __sanitizer_syscall_post_sync_file_range(res, ...)
#define __sanitizer_syscall_post_syncfs(res, ...)
#define __sanitizer_syscall_post_sync(res, ...)
#define __sanitizer_syscall_post__sysctl(res, ...)
#define __sanitizer_syscall_post_sysfs(res, ...)
#define __sanitizer_syscall_post_sysinfo(res, ...)
#define __sanitizer_syscall_post_syslog(res, ...)
#define __sanitizer_syscall_post_tee(res, ...)
#define __sanitizer_syscall_post_tgkill(res, ...)
#define __sanitizer_syscall_post_timer_create(res, ...)
#define __sanitizer_syscall_post_timer_delete(res, ...)
#define __sanitizer_syscall_post_time(res, ...)
#define __sanitizer_syscall_post_timerfd_create(res, ...)
#define __sanitizer_syscall_post_timerfd_gettime(res, ...)
#define __sanitizer_syscall_post_timerfd_settime(res, ...)
#define __sanitizer_syscall_post_timer_getoverrun(res, ...)
#define __sanitizer_syscall_post_timer_gettime(res, ...)
#define __sanitizer_syscall_post_timer_settime(res, ...)
#define __sanitizer_syscall_post_times(res, ...)
#define __sanitizer_syscall_post_tkill(res, ...)
#define __sanitizer_syscall_post_truncate64(res, ...)
#define __sanitizer_syscall_post_truncate(res, ...)
#define __sanitizer_syscall_post_tuxcall(res, ...)
#define __sanitizer_syscall_post_ugetrlimit(res, ...)
#define __sanitizer_syscall_post_ulimit(res, ...)
#define __sanitizer_syscall_post_umask(res, ...)
#define __sanitizer_syscall_post_umount2(res, ...)
#define __sanitizer_syscall_post_umount(res, ...)
#define __sanitizer_syscall_post_uname(res, ...)
#define __sanitizer_syscall_post_unlinkat(res, ...)
#define __sanitizer_syscall_post_unlink(res, ...)
#define __sanitizer_syscall_post_unshare(res, ...)
#define __sanitizer_syscall_post_uselib(res, ...)
#define __sanitizer_syscall_post_ustat(res, ...)
#define __sanitizer_syscall_post_utimensat(res, ...)
#define __sanitizer_syscall_post_utime(res, ...)
#define __sanitizer_syscall_post_utimes(res, ...)
#define __sanitizer_syscall_post_vfork(res, ...)
#define __sanitizer_syscall_post_vhangup(res, ...)
#define __sanitizer_syscall_post_vm86old(res, ...)
#define __sanitizer_syscall_post_vm86(res, ...)
#define __sanitizer_syscall_post_vmsplice(res, ...)
#define __sanitizer_syscall_post_vserver(res, ...)
#define __sanitizer_syscall_post_waitid(res, ...)
#define __sanitizer_syscall_post_write(res, ...)
#define __sanitizer_syscall_post_writev(res, ...)
#ifdef __cplusplus
} // extern "C"
#endif
#endif // SANITIZER_LINUX_SYSCALL_HOOKS_H

View File

@ -16,106 +16,87 @@
#include <sanitizer/common_interface_defs.h>
using __sanitizer::uptr;
using __sanitizer::sptr;
using __sanitizer::u32;
#ifdef __cplusplus
extern "C" {
#endif
// FIXME: document all interface functions.
#if __has_feature(memory_sanitizer)
/* Returns a string describing a stack origin.
Return NULL if the origin is invalid, or is not a stack origin. */
const char *__msan_get_origin_descr_if_stack(uint32_t id);
SANITIZER_INTERFACE_ATTRIBUTE
int __msan_get_track_origins();
SANITIZER_INTERFACE_ATTRIBUTE
void __msan_init();
/* Set raw origin for the memory range. */
void __msan_set_origin(const void *a, size_t size, uint32_t origin);
// Print a warning and maybe return.
// This function can die based on flags()->exit_code.
SANITIZER_INTERFACE_ATTRIBUTE
void __msan_warning();
/* Get raw origin for an address. */
uint32_t __msan_get_origin(const void *a);
// Print a warning and die.
// Intrumentation inserts calls to this function when building in "fast" mode
// (i.e. -mllvm -msan-keep-going)
SANITIZER_INTERFACE_ATTRIBUTE __attribute__((noreturn))
void __msan_warning_noreturn();
/* Returns non-zero if tracking origins. */
int __msan_get_track_origins();
SANITIZER_INTERFACE_ATTRIBUTE
void __msan_unpoison(void *a, uptr size);
SANITIZER_INTERFACE_ATTRIBUTE
void __msan_clear_and_unpoison(void *a, uptr size);
SANITIZER_INTERFACE_ATTRIBUTE
void* __msan_memcpy(void *dst, const void *src, uptr size);
SANITIZER_INTERFACE_ATTRIBUTE
void* __msan_memset(void *s, int c, uptr n);
SANITIZER_INTERFACE_ATTRIBUTE
void* __msan_memmove(void* dest, const void* src, uptr n);
SANITIZER_INTERFACE_ATTRIBUTE
void __msan_copy_poison(void *dst, const void *src, uptr size);
SANITIZER_INTERFACE_ATTRIBUTE
void __msan_copy_origin(void *dst, const void *src, uptr size);
SANITIZER_INTERFACE_ATTRIBUTE
void __msan_move_poison(void *dst, const void *src, uptr size);
SANITIZER_INTERFACE_ATTRIBUTE
void __msan_poison(void *a, uptr size);
SANITIZER_INTERFACE_ATTRIBUTE
void __msan_poison_stack(void *a, uptr size);
/* Returns the origin id of the latest UMR in the calling thread. */
uint32_t __msan_get_umr_origin();
// Copy size bytes from src to dst and unpoison the result.
// Useful to implement unsafe loads.
SANITIZER_INTERFACE_ATTRIBUTE
void __msan_load_unpoisoned(void *src, uptr size, void *dst);
/* Make memory region fully initialized (without changing its contents). */
void __msan_unpoison(const void *a, size_t size);
// Returns the offset of the first (at least partially) poisoned byte,
// or -1 if the whole range is good.
SANITIZER_INTERFACE_ATTRIBUTE
sptr __msan_test_shadow(const void *x, uptr size);
/* Make memory region fully uninitialized (without changing its contents). */
void __msan_poison(const void *a, size_t size);
SANITIZER_INTERFACE_ATTRIBUTE
void __msan_set_origin(void *a, uptr size, u32 origin);
SANITIZER_INTERFACE_ATTRIBUTE
void __msan_set_alloca_origin(void *a, uptr size, const char *descr);
SANITIZER_INTERFACE_ATTRIBUTE
u32 __msan_get_origin(void *a);
/* Make memory region partially uninitialized (without changing its contents).
*/
void __msan_partial_poison(const void* data, void* shadow, size_t size);
SANITIZER_INTERFACE_ATTRIBUTE
void __msan_clear_on_return();
/* Returns the offset of the first (at least partially) poisoned byte in the
memory range, or -1 if the whole range is good. */
intptr_t __msan_test_shadow(const void *x, size_t size);
// Default: -1 (don't exit on error).
SANITIZER_INTERFACE_ATTRIBUTE
void __msan_set_exit_code(int exit_code);
/* Set exit code when error(s) were detected.
Value of 0 means don't change the program exit code. */
void __msan_set_exit_code(int exit_code);
SANITIZER_INTERFACE_ATTRIBUTE
int __msan_set_poison_in_malloc(int do_poison);
/* For testing:
__msan_set_expect_umr(1);
... some buggy code ...
__msan_set_expect_umr(0);
The last line will verify that a UMR happened. */
void __msan_set_expect_umr(int expect_umr);
// For testing.
SANITIZER_INTERFACE_ATTRIBUTE
void __msan_set_expect_umr(int expect_umr);
SANITIZER_INTERFACE_ATTRIBUTE
void __msan_break_optimization(void *x);
SANITIZER_INTERFACE_ATTRIBUTE
void __msan_print_shadow(const void *x, uptr size);
SANITIZER_INTERFACE_ATTRIBUTE
void __msan_print_param_shadow();
SANITIZER_INTERFACE_ATTRIBUTE
int __msan_has_dynamic_component();
/* Print shadow and origin for the memory range to stdout in a human-readable
format. */
void __msan_print_shadow(const void *x, size_t size);
// Returns x such that %fs:x is the first byte of __msan_retval_tls.
SANITIZER_INTERFACE_ATTRIBUTE
int __msan_get_retval_tls_offset();
SANITIZER_INTERFACE_ATTRIBUTE
int __msan_get_param_tls_offset();
/* Print current function arguments shadow and origin to stdout in a
human-readable format. */
void __msan_print_param_shadow();
// For testing.
SANITIZER_INTERFACE_ATTRIBUTE
u32 __msan_get_origin_tls();
SANITIZER_INTERFACE_ATTRIBUTE
const char *__msan_get_origin_descr_if_stack(u32 id);
SANITIZER_INTERFACE_ATTRIBUTE
void __msan_partial_poison(void* data, void* shadow, uptr size);
/* Returns true if running under a dynamic tool (DynamoRio-based). */
int __msan_has_dynamic_component();
/* Tell MSan about newly allocated memory (ex.: custom allocator).
Memory will be marked uninitialized, with origin at the call site. */
void __msan_allocated_memory(const void* data, size_t size);
#else // __has_feature(memory_sanitizer)
#define __msan_get_origin_descr_if_stack(id) ((const char*)0)
#define __msan_set_origin(a, size, origin)
#define __msan_get_origin(a) ((uint32_t)-1)
#define __msan_get_track_origins() (0)
#define __msan_get_umr_origin() ((uint32_t)-1)
#define __msan_unpoison(a, size)
#define __msan_poison(a, size)
#define __msan_partial_poison(data, shadow, size)
#define __msan_test_shadow(x, size) ((intptr_t)-1)
#define __msan_set_exit_code(exit_code)
#define __msan_set_expect_umr(expect_umr)
#define __msan_print_shadow(x, size)
#define __msan_print_param_shadow()
#define __msan_has_dynamic_component() (0)
#define __msan_allocated_memory(data, size)
#endif // __has_feature(memory_sanitizer)
#ifdef __cplusplus
} // extern "C"

View File

@ -7,6 +7,7 @@ if(CMAKE_SYSTEM_NAME MATCHES "Darwin|Linux")
add_subdirectory(interception)
add_subdirectory(sanitizer_common)
if(NOT ANDROID)
add_subdirectory(profile)
add_subdirectory(ubsan)
endif()
endif()
@ -14,10 +15,10 @@ if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux" AND NOT ANDROID)
# ThreadSanitizer and MemorySanitizer are supported on Linux only.
add_subdirectory(tsan)
add_subdirectory(msan)
add_subdirectory(msandr)
add_subdirectory(lsan)
endif()
# FIXME: Add support for the profile library.
# The top-level lib directory contains a large amount of C code which provides
# generic implementations of the core runtime library along with optimized
# architecture-specific code in various subdirectories.
@ -36,6 +37,8 @@ set(GENERIC_SOURCES
ashlti3.c
ashrdi3.c
ashrti3.c
# FIXME: atomic.c may only be compiled if host compiler understands _Atomic
# atomic.c
clear_cache.c
clzdi2.c
clzsi2.c
@ -152,37 +155,36 @@ set(GENERIC_SOURCES
umodti3.c
)
if(CAN_TARGET_x86_64)
add_library(clang_rt.x86_64 STATIC
x86_64/floatdidf.c
x86_64/floatdisf.c
x86_64/floatdixf.c
x86_64/floatundidf.S
x86_64/floatundisf.S
x86_64/floatundixf.S
${GENERIC_SOURCES}
)
set_target_properties(clang_rt.x86_64 PROPERTIES COMPILE_FLAGS "-std=c99 ${TARGET_x86_64_CFLAGS}")
add_clang_compiler_rt_libraries(clang_rt.x86_64)
endif()
if(CAN_TARGET_i386)
add_library(clang_rt.i386 STATIC
i386/ashldi3.S
i386/ashrdi3.S
i386/divdi3.S
i386/floatdidf.S
i386/floatdisf.S
i386/floatdixf.S
i386/floatundidf.S
i386/floatundisf.S
i386/floatundixf.S
i386/lshrdi3.S
i386/moddi3.S
i386/muldi3.S
i386/udivdi3.S
i386/umoddi3.S
${GENERIC_SOURCES}
)
set_target_properties(clang_rt.i386 PROPERTIES COMPILE_FLAGS "-std=c99 ${TARGET_i386_CFLAGS}")
add_clang_compiler_rt_libraries(clang_rt.i386)
endif()
set(x86_64_SOURCES
x86_64/floatdidf.c
x86_64/floatdisf.c
x86_64/floatdixf.c
x86_64/floatundidf.S
x86_64/floatundisf.S
x86_64/floatundixf.S
${GENERIC_SOURCES})
set(i386_SOURCES
i386/ashldi3.S
i386/ashrdi3.S
i386/divdi3.S
i386/floatdidf.S
i386/floatdisf.S
i386/floatdixf.S
i386/floatundidf.S
i386/floatundisf.S
i386/floatundixf.S
i386/lshrdi3.S
i386/moddi3.S
i386/muldi3.S
i386/udivdi3.S
i386/umoddi3.S
${GENERIC_SOURCES})
foreach(arch x86_64 i386)
if(CAN_TARGET_${arch})
add_compiler_rt_static_runtime(clang_rt.${arch} ${arch}
SOURCES ${${arch}_SOURCES}
CFLAGS "-std=c99")
endif()
endforeach()

View File

@ -19,15 +19,12 @@ SubDirs += interception
SubDirs += profile
SubDirs += sanitizer_common
SubDirs += tsan
SubDirs += msan
SubDirs += ubsan
# FIXME: We don't currently support building an atomic library, and as it must
# be a separate library from the runtime library, we need to remove its source
# code from the source files list.
ExcludedSources := atomic.c
SubDirs += lsan
# Define the variables for this specific directory.
Sources := $(foreach file,$(wildcard $(Dir)/*.c),$(filter-out $(ExcludedSources),$(notdir $(file))))
Sources := $(foreach file,$(wildcard $(Dir)/*.c),$(notdir $(file)))
ObjNames := $(Sources:%.c=%.o)
Implementation := Generic

View File

@ -13,6 +13,7 @@
#if __APPLE__
#if __arm__
#define NOT_HERE_BEFORE_10_6(sym)
#define NOT_HERE_IN_10_8_AND_EARLIER(sym)
#elif __ppc__
#define NOT_HERE_BEFORE_10_6(sym) \
extern const char sym##_tmp3 __asm("$ld$hide$os10.3$_" #sym ); \
@ -27,6 +28,13 @@
__attribute__((visibility("default"))) const char sym##_tmp4 = 0; \
extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); \
__attribute__((visibility("default"))) const char sym##_tmp5 = 0;
#define NOT_HERE_IN_10_8_AND_EARLIER(sym) \
extern const char sym##_tmp8 __asm("$ld$hide$os10.8$_" #sym ); \
__attribute__((visibility("default"))) const char sym##_tmp8 = 0; \
extern const char sym##_tmp7 __asm("$ld$hide$os10.7$_" #sym ); \
__attribute__((visibility("default"))) const char sym##_tmp7 = 0; \
extern const char sym##_tmp6 __asm("$ld$hide$os10.6$_" #sym ); \
__attribute__((visibility("default"))) const char sym##_tmp6 = 0;
#endif /* __ppc__ */
@ -143,6 +151,56 @@ NOT_HERE_BEFORE_10_6(__gcc_qsub)
NOT_HERE_BEFORE_10_6(__trampoline_setup)
#endif /* __ppc__ */
NOT_HERE_IN_10_8_AND_EARLIER(__atomic_compare_exchange)
NOT_HERE_IN_10_8_AND_EARLIER(__atomic_compare_exchange_1)
NOT_HERE_IN_10_8_AND_EARLIER(__atomic_compare_exchange_2)
NOT_HERE_IN_10_8_AND_EARLIER(__atomic_compare_exchange_4)
NOT_HERE_IN_10_8_AND_EARLIER(__atomic_compare_exchange_8)
NOT_HERE_IN_10_8_AND_EARLIER(__atomic_exchange)
NOT_HERE_IN_10_8_AND_EARLIER(__atomic_exchange_1)
NOT_HERE_IN_10_8_AND_EARLIER(__atomic_exchange_2)
NOT_HERE_IN_10_8_AND_EARLIER(__atomic_exchange_4)
NOT_HERE_IN_10_8_AND_EARLIER(__atomic_exchange_8)
NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_add_1)
NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_add_2)
NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_add_4)
NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_add_8)
NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_and_1)
NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_and_2)
NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_and_4)
NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_and_8)
NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_or_1)
NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_or_2)
NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_or_4)
NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_or_8)
NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_sub_1)
NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_sub_2)
NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_sub_4)
NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_sub_8)
NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_xor_1)
NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_xor_2)
NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_xor_4)
NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_xor_8)
NOT_HERE_IN_10_8_AND_EARLIER(__atomic_load)
NOT_HERE_IN_10_8_AND_EARLIER(__atomic_load_1)
NOT_HERE_IN_10_8_AND_EARLIER(__atomic_load_2)
NOT_HERE_IN_10_8_AND_EARLIER(__atomic_load_4)
NOT_HERE_IN_10_8_AND_EARLIER(__atomic_load_8)
NOT_HERE_IN_10_8_AND_EARLIER(__atomic_store)
NOT_HERE_IN_10_8_AND_EARLIER(__atomic_store_1)
NOT_HERE_IN_10_8_AND_EARLIER(__atomic_store_2)
NOT_HERE_IN_10_8_AND_EARLIER(__atomic_store_4)
NOT_HERE_IN_10_8_AND_EARLIER(__atomic_store_8)
#if __arm__ && __DYNAMIC__
#define NOT_HERE_UNTIL_AFTER_4_3(sym) \
extern const char sym##_tmp1 __asm("$ld$hide$os3.0$_" #sym ); \

39
lib/arm/aeabi_dcmp.S Normal file
View File

@ -0,0 +1,39 @@
//===-- aeabi_dcmp.S - EABI dcmp* implementation ---------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "../assembly.h"
// int __aeabi_dcmp{eq,lt,le,ge,gt}(double a, double b) {
// int result = __{eq,lt,le,ge,gt}df2(a, b);
// if (result {==,<,<=,>=,>} 0) {
// return 1;
// } else {
// return 0;
// }
// }
#define DEFINE_AEABI_DCMP(cond) \
.syntax unified SEPARATOR \
.align 2 SEPARATOR \
DEFINE_COMPILERRT_FUNCTION(__aeabi_dcmp ## cond) \
push { r4, lr } SEPARATOR \
bl SYMBOL_NAME(__ ## cond ## df2) SEPARATOR \
cmp r0, #0 SEPARATOR \
b ## cond 1f SEPARATOR \
mov r0, #0 SEPARATOR \
pop { r4, pc } SEPARATOR \
1: SEPARATOR \
mov r0, #1 SEPARATOR \
pop { r4, pc }
DEFINE_AEABI_DCMP(eq)
DEFINE_AEABI_DCMP(lt)
DEFINE_AEABI_DCMP(le)
DEFINE_AEABI_DCMP(ge)
DEFINE_AEABI_DCMP(gt)

39
lib/arm/aeabi_fcmp.S Normal file
View File

@ -0,0 +1,39 @@
//===-- aeabi_fcmp.S - EABI fcmp* implementation ---------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "../assembly.h"
// int __aeabi_fcmp{eq,lt,le,ge,gt}(float a, float b) {
// int result = __{eq,lt,le,ge,gt}sf2(a, b);
// if (result {==,<,<=,>=,>} 0) {
// return 1;
// } else {
// return 0;
// }
// }
#define DEFINE_AEABI_FCMP(cond) \
.syntax unified SEPARATOR \
.align 2 SEPARATOR \
DEFINE_COMPILERRT_FUNCTION(__aeabi_fcmp ## cond) \
push { r4, lr } SEPARATOR \
bl SYMBOL_NAME(__ ## cond ## sf2) SEPARATOR \
cmp r0, #0 SEPARATOR \
b ## cond 1f SEPARATOR \
mov r0, #0 SEPARATOR \
pop { r4, pc } SEPARATOR \
1: SEPARATOR \
mov r0, #1 SEPARATOR \
pop { r4, pc }
DEFINE_AEABI_FCMP(eq)
DEFINE_AEABI_FCMP(lt)
DEFINE_AEABI_FCMP(le)
DEFINE_AEABI_FCMP(ge)
DEFINE_AEABI_FCMP(gt)

View File

@ -24,6 +24,18 @@
.syntax unified
.align 3
DEFINE_COMPILERRT_FUNCTION(__divmodsi4)
#if __ARM_ARCH_7S__
tst r1, r1
beq LOCAL_LABEL(divzero)
mov r3, r0
sdiv r0, r3, r1
mls r1, r0, r1, r3
str r1, [r2]
bx lr
LOCAL_LABEL(divzero):
mov r0, #0
bx lr
#else
ESTABLISH_FRAME
// Set aside the sign of the quotient and modulus, and the address for the
// modulus.
@ -45,3 +57,4 @@ DEFINE_COMPILERRT_FUNCTION(__divmodsi4)
sub r1, r1, r5, asr #31
str r1, [r6]
CLEAR_FRAME_AND_RETURN
#endif

View File

@ -23,6 +23,16 @@
.syntax unified
.align 3
DEFINE_COMPILERRT_FUNCTION(__modsi3)
#if __ARM_ARCH_7S__
tst r1, r1
beq LOCAL_LABEL(divzero)
sdiv r2, r0, r1
mls r0, r2, r1, r0
bx lr
LOCAL_LABEL(divzero):
mov r0, #0
bx lr
#else
ESTABLISH_FRAME
// Set aside the sign of the dividend.
mov r4, r0
@ -37,3 +47,4 @@ DEFINE_COMPILERRT_FUNCTION(__modsi3)
eor r0, r0, r4, asr #31
sub r0, r0, r4, asr #31
CLEAR_FRAME_AND_RETURN
#endif

View File

@ -31,6 +31,18 @@
.syntax unified
.align 3
DEFINE_COMPILERRT_FUNCTION(__udivmodsi4)
#if __ARM_ARCH_7S__
tst r1, r1
beq LOCAL_LABEL(divzero)
mov r3, r0
udiv r0, r3, r1
mls r1, r0, r1, r3
str r1, [r2]
bx lr
LOCAL_LABEL(divzero):
mov r0, #0
bx lr
#else
// We use a simple digit by digit algorithm; before we get into the actual
// divide loop, we must calculate the left-shift amount necessary to align
// the MSB of the divisor with that of the dividend (If this shift is
@ -78,3 +90,4 @@ LOCAL_LABEL(return):
str a, [r2]
mov r0, q
CLEAR_FRAME_AND_RETURN
#endif

View File

@ -23,6 +23,16 @@
.syntax unified
.align 3
DEFINE_COMPILERRT_FUNCTION(__umodsi3)
#if __ARM_ARCH_7S__
tst r1, r1
beq LOCAL_LABEL(divzero)
udiv r2, r0, r1
mls r0, r2, r1, r0
bx lr
LOCAL_LABEL(divzero):
mov r0, #0
bx lr
#else
// We use a simple digit by digit algorithm; before we get into the actual
// divide loop, we must calculate the left-shift amount necessary to align
// the MSB of the divisor with that of the dividend.
@ -56,3 +66,4 @@ LOCAL_LABEL(mainLoop):
subs r, a, b
movhs a, r
bx lr
#endif

View File

@ -1,7 +1,6 @@
# Build for the AddressSanitizer runtime support library.
set(ASAN_SOURCES
asan_allocator.cc
asan_allocator2.cc
asan_fake_stack.cc
asan_globals.cc
@ -14,60 +13,58 @@ set(ASAN_SOURCES
asan_new_delete.cc
asan_poisoning.cc
asan_posix.cc
asan_preinit.cc
asan_report.cc
asan_rtl.cc
asan_stack.cc
asan_stats.cc
asan_thread.cc
asan_thread_registry.cc
asan_win.cc
)
set(ASAN_DYLIB_SOURCES
${ASAN_SOURCES}
dynamic/asan_interceptors_dynamic.cc
)
include_directories(..)
set(ASAN_CFLAGS ${SANITIZER_COMMON_CFLAGS})
set(ASAN_CFLAGS
${SANITIZER_COMMON_CFLAGS}
-fno-rtti)
set(ASAN_COMMON_DEFINITIONS
ASAN_HAS_EXCEPTIONS=1)
if(ANDROID)
set(ASAN_COMMON_DEFINITIONS
ASAN_HAS_EXCEPTIONS=1
list(APPEND ASAN_COMMON_DEFINITIONS
ASAN_FLEXIBLE_MAPPING_AND_OFFSET=0
ASAN_NEEDS_SEGV=0
ASAN_LOW_MEMORY=1
)
ASAN_LOW_MEMORY=1)
else()
set(ASAN_COMMON_DEFINITIONS
ASAN_HAS_EXCEPTIONS=1
ASAN_FLEXIBLE_MAPPING_AND_OFFSET=0
ASAN_NEEDS_SEGV=1
)
list(APPEND ASAN_COMMON_DEFINITIONS
ASAN_FLEXIBLE_MAPPING_AND_OFFSET=1
ASAN_NEEDS_SEGV=1)
endif()
set(ASAN_DYLIB_DEFINITIONS
${ASAN_COMMON_DEFINITIONS}
MAC_INTERPOSE_FUNCTIONS=1
)
# Architectures supported by ASan.
filter_available_targets(ASAN_SUPPORTED_ARCH
x86_64 i386)
x86_64 i386 powerpc64 powerpc)
set(ASAN_RUNTIME_LIBRARIES)
if(APPLE)
# Build universal binary on APPLE.
add_library(clang_rt.asan_osx STATIC
${ASAN_SOURCES}
$<TARGET_OBJECTS:RTInterception.osx>
$<TARGET_OBJECTS:RTSanitizerCommon.osx>
)
set_target_compile_flags(clang_rt.asan_osx ${ASAN_CFLAGS})
set_target_properties(clang_rt.asan_osx PROPERTIES
OSX_ARCHITECTURES "${ASAN_SUPPORTED_ARCH}")
list(APPEND ASAN_RUNTIME_LIBRARIES clang_rt.asan_osx)
add_compiler_rt_osx_dynamic_runtime(clang_rt.asan_osx_dynamic
ARCH ${ASAN_SUPPORTED_ARCH}
SOURCES ${ASAN_DYLIB_SOURCES}
$<TARGET_OBJECTS:RTInterception.osx>
$<TARGET_OBJECTS:RTSanitizerCommon.osx>
CFLAGS ${ASAN_CFLAGS}
DEFS ${ASAN_COMMON_DEFINITIONS}
# Dynamic lookup is needed because shadow scale and offset are
# provided by the instrumented modules.
LINKFLAGS "-framework Foundation"
"-undefined dynamic_lookup")
list(APPEND ASAN_RUNTIME_LIBRARIES clang_rt.asan_osx_dynamic)
elseif(ANDROID)
add_library(clang_rt.asan-arm-android SHARED
${ASAN_SOURCES}
@ -75,44 +72,28 @@ elseif(ANDROID)
$<TARGET_OBJECTS:RTSanitizerCommon.arm.android>
)
set_target_compile_flags(clang_rt.asan-arm-android
${ASAN_CFLAGS}
)
${ASAN_CFLAGS})
set_property(TARGET clang_rt.asan-arm-android APPEND PROPERTY
COMPILE_DEFINITIONS ${ASAN_COMMON_DEFINITIONS})
target_link_libraries(clang_rt.asan-arm-android dl)
list(APPEND ASAN_RUNTIME_LIBRARIES clang_rt.asan-arm-android)
else()
# Otherwise, build separate libraries for each target.
foreach(arch ${ASAN_SUPPORTED_ARCH})
add_library(clang_rt.asan-${arch} STATIC
${ASAN_SOURCES}
$<TARGET_OBJECTS:RTInterception.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommon.${arch}>)
set_target_compile_flags(clang_rt.asan-${arch}
${ASAN_CFLAGS} ${TARGET_${arch}_CFLAGS})
add_compiler_rt_static_runtime(clang_rt.asan-${arch} ${arch}
SOURCES ${ASAN_SOURCES}
$<TARGET_OBJECTS:RTInterception.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
$<TARGET_OBJECTS:RTLSanCommon.${arch}>
CFLAGS ${ASAN_CFLAGS}
DEFS ${ASAN_COMMON_DEFINITIONS}
SYMS asan.syms)
list(APPEND ASAN_RUNTIME_LIBRARIES clang_rt.asan-${arch})
endforeach()
endif()
set_property(TARGET ${ASAN_RUNTIME_LIBRARIES} APPEND PROPERTY
COMPILE_DEFINITIONS ${ASAN_COMMON_DEFINITIONS})
add_clang_compiler_rt_libraries(${ASAN_RUNTIME_LIBRARIES})
set(ASAN_DYNAMIC_RUNTIME_LIBRARIES)
if(APPLE)
# Build universal binary on APPLE.
add_library(clang_rt.asan_osx_dynamic SHARED
${ASAN_DYLIB_SOURCES}
$<TARGET_OBJECTS:RTInterception.osx>
$<TARGET_OBJECTS:RTSanitizerCommon.osx>
)
set_target_compile_flags(clang_rt.asan_osx_dynamic ${ASAN_CFLAGS})
set_target_properties(clang_rt.asan_osx_dynamic PROPERTIES
COMPILE_DEFINITIONS "${ASAN_DYLIB_DEFINITIONS}"
OSX_ARCHITECTURES "${ASAN_SUPPORTED_ARCH}"
LINK_FLAGS "-framework Foundation")
list(APPEND ASAN_DYNAMIC_RUNTIME_LIBRARIES clang_rt.asan_osx_dynamic)
endif()
add_clang_compiler_rt_libraries(${ASAN_DYNAMIC_RUNTIME_LIBRARIES})
add_compiler_rt_resource_file(asan_blacklist asan_blacklist.txt)
if(LLVM_INCLUDE_TESTS)
add_subdirectory(tests)

View File

@ -8,7 +8,7 @@
#===------------------------------------------------------------------------===#
ModuleName := asan
SubDirs := dynamic
SubDirs :=
Sources := $(foreach file,$(wildcard $(Dir)/*.cc),$(notdir $(file)))
ObjNames := $(Sources:%.cc=%.o)
@ -18,7 +18,6 @@ Implementation := Generic
# FIXME: use automatic dependencies?
Dependencies := $(wildcard $(Dir)/*.h)
Dependencies += $(wildcard $(Dir)/../interception/*.h)
Dependencies += $(wildcard $(Dir)/../interception/mach_override/*.h)
Dependencies += $(wildcard $(Dir)/../sanitizer_common/*.h)
# Define a convenience variable for all the asan functions.

5
lib/asan/asan.syms Normal file
View File

@ -0,0 +1,5 @@
{
__asan_*;
__sanitizer_syscall_pre_*;
__sanitizer_syscall_post_*;
};

View File

@ -1,810 +0,0 @@
//===-- asan_allocator.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.
//
// Implementation of ASan's memory allocator.
// Evey piece of memory (AsanChunk) allocated by the allocator
// has a left redzone of REDZONE bytes and
// a right redzone such that the end of the chunk is aligned by REDZONE
// (i.e. the right redzone is between 0 and REDZONE-1).
// The left redzone is always poisoned.
// The right redzone is poisoned on malloc, the body is poisoned on free.
// Once freed, a chunk is moved to a quarantine (fifo list).
// After quarantine, a chunk is returned to freelists.
//
// The left redzone contains ASan's internal data and the stack trace of
// the malloc call.
// Once freed, the body of the chunk contains the stack trace of the free call.
//
//===----------------------------------------------------------------------===//
#include "asan_allocator.h"
#if ASAN_ALLOCATOR_VERSION == 1
#include "asan_interceptors.h"
#include "asan_internal.h"
#include "asan_mapping.h"
#include "asan_stats.h"
#include "asan_report.h"
#include "asan_thread.h"
#include "asan_thread_registry.h"
#include "sanitizer/asan_interface.h"
#include "sanitizer_common/sanitizer_atomic.h"
#include "sanitizer_common/sanitizer_mutex.h"
namespace __asan {
#define REDZONE ((uptr)(flags()->redzone))
static const uptr kMinAllocSize = REDZONE * 2;
static const u64 kMaxAvailableRam = 128ULL << 30; // 128G
static const uptr kMaxThreadLocalQuarantine = 1 << 20; // 1M
static const uptr kMinMmapSize = (ASAN_LOW_MEMORY) ? 4UL << 17 : 4UL << 20;
static const uptr kMaxSizeForThreadLocalFreeList =
(ASAN_LOW_MEMORY) ? 1 << 15 : 1 << 17;
// Size classes less than kMallocSizeClassStep are powers of two.
// All other size classes are multiples of kMallocSizeClassStep.
static const uptr kMallocSizeClassStepLog = 26;
static const uptr kMallocSizeClassStep = 1UL << kMallocSizeClassStepLog;
static const uptr kMaxAllowedMallocSize =
(SANITIZER_WORDSIZE == 32) ? 3UL << 30 : 8UL << 30;
static inline uptr SizeClassToSize(u8 size_class) {
CHECK(size_class < kNumberOfSizeClasses);
if (size_class <= kMallocSizeClassStepLog) {
return 1UL << size_class;
} else {
return (size_class - kMallocSizeClassStepLog) * kMallocSizeClassStep;
}
}
static inline u8 SizeToSizeClass(uptr size) {
u8 res = 0;
if (size <= kMallocSizeClassStep) {
uptr rounded = RoundUpToPowerOfTwo(size);
res = Log2(rounded);
} else {
res = ((size + kMallocSizeClassStep - 1) / kMallocSizeClassStep)
+ kMallocSizeClassStepLog;
}
CHECK(res < kNumberOfSizeClasses);
CHECK(size <= SizeClassToSize(res));
return res;
}
// Given REDZONE bytes, we need to mark first size bytes
// as addressable and the rest REDZONE-size bytes as unaddressable.
static void PoisonHeapPartialRightRedzone(uptr mem, uptr size) {
CHECK(size <= REDZONE);
CHECK(IsAligned(mem, REDZONE));
CHECK(IsPowerOfTwo(SHADOW_GRANULARITY));
CHECK(IsPowerOfTwo(REDZONE));
CHECK(REDZONE >= SHADOW_GRANULARITY);
PoisonShadowPartialRightRedzone(mem, size, REDZONE,
kAsanHeapRightRedzoneMagic);
}
static u8 *MmapNewPagesAndPoisonShadow(uptr size) {
CHECK(IsAligned(size, GetPageSizeCached()));
u8 *res = (u8*)MmapOrDie(size, __FUNCTION__);
PoisonShadow((uptr)res, size, kAsanHeapLeftRedzoneMagic);
if (flags()->debug) {
Printf("ASAN_MMAP: [%p, %p)\n", res, res + size);
}
return res;
}
// Every chunk of memory allocated by this allocator can be in one of 3 states:
// CHUNK_AVAILABLE: the chunk is in the free list and ready to be allocated.
// CHUNK_ALLOCATED: the chunk is allocated and not yet freed.
// CHUNK_QUARANTINE: the chunk was freed and put into quarantine zone.
//
// The pseudo state CHUNK_MEMALIGN is used to mark that the address is not
// the beginning of a AsanChunk (in which the actual chunk resides at
// this - this->used_size).
//
// The magic numbers for the enum values are taken randomly.
enum {
CHUNK_AVAILABLE = 0x57,
CHUNK_ALLOCATED = 0x32,
CHUNK_QUARANTINE = 0x19,
CHUNK_MEMALIGN = 0xDC
};
struct ChunkBase {
// First 8 bytes.
uptr chunk_state : 8;
uptr alloc_tid : 24;
uptr size_class : 8;
uptr free_tid : 24;
// Second 8 bytes.
uptr alignment_log : 8;
uptr alloc_type : 2;
uptr used_size : FIRST_32_SECOND_64(32, 54); // Size requested by the user.
// This field may overlap with the user area and thus should not
// be used while the chunk is in CHUNK_ALLOCATED state.
AsanChunk *next;
// Typically the beginning of the user-accessible memory is 'this'+REDZONE
// and is also aligned by REDZONE. However, if the memory is allocated
// by memalign, the alignment might be higher and the user-accessible memory
// starts at the first properly aligned address after 'this'.
uptr Beg() { return RoundUpTo((uptr)this + 1, 1 << alignment_log); }
uptr Size() { return SizeClassToSize(size_class); }
u8 SizeClass() { return size_class; }
};
struct AsanChunk: public ChunkBase {
u32 *compressed_alloc_stack() {
return (u32*)((uptr)this + sizeof(ChunkBase));
}
u32 *compressed_free_stack() {
return (u32*)((uptr)this + Max((uptr)REDZONE, (uptr)sizeof(ChunkBase)));
}
// The left redzone after the ChunkBase is given to the alloc stack trace.
uptr compressed_alloc_stack_size() {
if (REDZONE < sizeof(ChunkBase)) return 0;
return (REDZONE - sizeof(ChunkBase)) / sizeof(u32);
}
uptr compressed_free_stack_size() {
if (REDZONE < sizeof(ChunkBase)) return 0;
return (REDZONE) / sizeof(u32);
}
};
uptr AsanChunkView::Beg() { return chunk_->Beg(); }
uptr AsanChunkView::End() { return Beg() + UsedSize(); }
uptr AsanChunkView::UsedSize() { return chunk_->used_size; }
uptr AsanChunkView::AllocTid() { return chunk_->alloc_tid; }
uptr AsanChunkView::FreeTid() { return chunk_->free_tid; }
void AsanChunkView::GetAllocStack(StackTrace *stack) {
StackTrace::UncompressStack(stack, chunk_->compressed_alloc_stack(),
chunk_->compressed_alloc_stack_size());
}
void AsanChunkView::GetFreeStack(StackTrace *stack) {
StackTrace::UncompressStack(stack, chunk_->compressed_free_stack(),
chunk_->compressed_free_stack_size());
}
static AsanChunk *PtrToChunk(uptr ptr) {
AsanChunk *m = (AsanChunk*)(ptr - REDZONE);
if (m->chunk_state == CHUNK_MEMALIGN) {
m = (AsanChunk*)((uptr)m - m->used_size);
}
return m;
}
void AsanChunkFifoList::PushList(AsanChunkFifoList *q) {
CHECK(q->size() > 0);
size_ += q->size();
append_back(q);
q->clear();
}
void AsanChunkFifoList::Push(AsanChunk *n) {
push_back(n);
size_ += n->Size();
}
// Interesting performance observation: this function takes up to 15% of overal
// allocator time. That's because *first_ has been evicted from cache long time
// ago. Not sure if we can or want to do anything with this.
AsanChunk *AsanChunkFifoList::Pop() {
CHECK(first_);
AsanChunk *res = front();
size_ -= res->Size();
pop_front();
return res;
}
// All pages we ever allocated.
struct PageGroup {
uptr beg;
uptr end;
uptr size_of_chunk;
uptr last_chunk;
bool InRange(uptr addr) {
return addr >= beg && addr < end;
}
};
class MallocInfo {
public:
explicit MallocInfo(LinkerInitialized x) : mu_(x) { }
AsanChunk *AllocateChunks(u8 size_class, uptr n_chunks) {
AsanChunk *m = 0;
AsanChunk **fl = &free_lists_[size_class];
{
BlockingMutexLock lock(&mu_);
for (uptr i = 0; i < n_chunks; i++) {
if (!(*fl)) {
*fl = GetNewChunks(size_class);
}
AsanChunk *t = *fl;
*fl = t->next;
t->next = m;
CHECK(t->chunk_state == CHUNK_AVAILABLE);
m = t;
}
}
return m;
}
void SwallowThreadLocalMallocStorage(AsanThreadLocalMallocStorage *x,
bool eat_free_lists) {
CHECK(flags()->quarantine_size > 0);
BlockingMutexLock lock(&mu_);
AsanChunkFifoList *q = &x->quarantine_;
if (q->size() > 0) {
quarantine_.PushList(q);
while (quarantine_.size() > (uptr)flags()->quarantine_size) {
QuarantinePop();
}
}
if (eat_free_lists) {
for (uptr size_class = 0; size_class < kNumberOfSizeClasses;
size_class++) {
AsanChunk *m = x->free_lists_[size_class];
while (m) {
AsanChunk *t = m->next;
m->next = free_lists_[size_class];
free_lists_[size_class] = m;
m = t;
}
x->free_lists_[size_class] = 0;
}
}
}
void BypassThreadLocalQuarantine(AsanChunk *chunk) {
BlockingMutexLock lock(&mu_);
quarantine_.Push(chunk);
}
AsanChunk *FindChunkByAddr(uptr addr) {
BlockingMutexLock lock(&mu_);
return FindChunkByAddrUnlocked(addr);
}
uptr AllocationSize(uptr ptr) {
if (!ptr) return 0;
BlockingMutexLock lock(&mu_);
// Make sure this is our chunk and |ptr| actually points to the beginning
// of the allocated memory.
AsanChunk *m = FindChunkByAddrUnlocked(ptr);
if (!m || m->Beg() != ptr) return 0;
if (m->chunk_state == CHUNK_ALLOCATED) {
return m->used_size;
} else {
return 0;
}
}
void ForceLock() {
mu_.Lock();
}
void ForceUnlock() {
mu_.Unlock();
}
void PrintStatus() {
BlockingMutexLock lock(&mu_);
uptr malloced = 0;
Printf(" MallocInfo: in quarantine: %zu malloced: %zu; ",
quarantine_.size() >> 20, malloced >> 20);
for (uptr j = 1; j < kNumberOfSizeClasses; j++) {
AsanChunk *i = free_lists_[j];
if (!i) continue;
uptr t = 0;
for (; i; i = i->next) {
t += i->Size();
}
Printf("%zu:%zu ", j, t >> 20);
}
Printf("\n");
}
PageGroup *FindPageGroup(uptr addr) {
BlockingMutexLock lock(&mu_);
return FindPageGroupUnlocked(addr);
}
private:
PageGroup *FindPageGroupUnlocked(uptr addr) {
int n = atomic_load(&n_page_groups_, memory_order_relaxed);
// If the page groups are not sorted yet, sort them.
if (n_sorted_page_groups_ < n) {
SortArray((uptr*)page_groups_, n);
n_sorted_page_groups_ = n;
}
// Binary search over the page groups.
int beg = 0, end = n;
while (beg < end) {
int med = (beg + end) / 2;
uptr g = (uptr)page_groups_[med];
if (addr > g) {
// 'g' points to the end of the group, so 'addr'
// may not belong to page_groups_[med] or any previous group.
beg = med + 1;
} else {
// 'addr' may belong to page_groups_[med] or a previous group.
end = med;
}
}
if (beg >= n)
return 0;
PageGroup *g = page_groups_[beg];
CHECK(g);
if (g->InRange(addr))
return g;
return 0;
}
// We have an address between two chunks, and we want to report just one.
AsanChunk *ChooseChunk(uptr addr,
AsanChunk *left_chunk, AsanChunk *right_chunk) {
// Prefer an allocated chunk or a chunk from quarantine.
if (left_chunk->chunk_state == CHUNK_AVAILABLE &&
right_chunk->chunk_state != CHUNK_AVAILABLE)
return right_chunk;
if (right_chunk->chunk_state == CHUNK_AVAILABLE &&
left_chunk->chunk_state != CHUNK_AVAILABLE)
return left_chunk;
// Choose based on offset.
uptr l_offset = 0, r_offset = 0;
CHECK(AsanChunkView(left_chunk).AddrIsAtRight(addr, 1, &l_offset));
CHECK(AsanChunkView(right_chunk).AddrIsAtLeft(addr, 1, &r_offset));
if (l_offset < r_offset)
return left_chunk;
return right_chunk;
}
AsanChunk *FindChunkByAddrUnlocked(uptr addr) {
PageGroup *g = FindPageGroupUnlocked(addr);
if (!g) return 0;
CHECK(g->size_of_chunk);
uptr offset_from_beg = addr - g->beg;
uptr this_chunk_addr = g->beg +
(offset_from_beg / g->size_of_chunk) * g->size_of_chunk;
CHECK(g->InRange(this_chunk_addr));
AsanChunk *m = (AsanChunk*)this_chunk_addr;
CHECK(m->chunk_state == CHUNK_ALLOCATED ||
m->chunk_state == CHUNK_AVAILABLE ||
m->chunk_state == CHUNK_QUARANTINE);
uptr offset = 0;
AsanChunkView m_view(m);
if (m_view.AddrIsInside(addr, 1, &offset))
return m;
if (m_view.AddrIsAtRight(addr, 1, &offset)) {
if (this_chunk_addr == g->last_chunk) // rightmost chunk
return m;
uptr right_chunk_addr = this_chunk_addr + g->size_of_chunk;
CHECK(g->InRange(right_chunk_addr));
return ChooseChunk(addr, m, (AsanChunk*)right_chunk_addr);
} else {
CHECK(m_view.AddrIsAtLeft(addr, 1, &offset));
if (this_chunk_addr == g->beg) // leftmost chunk
return m;
uptr left_chunk_addr = this_chunk_addr - g->size_of_chunk;
CHECK(g->InRange(left_chunk_addr));
return ChooseChunk(addr, (AsanChunk*)left_chunk_addr, m);
}
}
void QuarantinePop() {
CHECK(quarantine_.size() > 0);
AsanChunk *m = quarantine_.Pop();
CHECK(m);
// if (F_v >= 2) Printf("MallocInfo::pop %p\n", m);
CHECK(m->chunk_state == CHUNK_QUARANTINE);
m->chunk_state = CHUNK_AVAILABLE;
PoisonShadow((uptr)m, m->Size(), kAsanHeapLeftRedzoneMagic);
CHECK(m->alloc_tid >= 0);
CHECK(m->free_tid >= 0);
uptr size_class = m->SizeClass();
m->next = free_lists_[size_class];
free_lists_[size_class] = m;
// Statistics.
AsanStats &thread_stats = asanThreadRegistry().GetCurrentThreadStats();
thread_stats.real_frees++;
thread_stats.really_freed += m->used_size;
thread_stats.really_freed_redzones += m->Size() - m->used_size;
thread_stats.really_freed_by_size[m->SizeClass()]++;
}
// Get a list of newly allocated chunks.
AsanChunk *GetNewChunks(u8 size_class) {
uptr size = SizeClassToSize(size_class);
CHECK(IsPowerOfTwo(kMinMmapSize));
CHECK(size < kMinMmapSize || (size % kMinMmapSize) == 0);
uptr mmap_size = Max(size, kMinMmapSize);
uptr n_chunks = mmap_size / size;
CHECK(n_chunks * size == mmap_size);
uptr PageSize = GetPageSizeCached();
if (size < PageSize) {
// Size is small, just poison the last chunk.
n_chunks--;
} else {
// Size is large, allocate an extra page at right and poison it.
mmap_size += PageSize;
}
CHECK(n_chunks > 0);
u8 *mem = MmapNewPagesAndPoisonShadow(mmap_size);
// Statistics.
AsanStats &thread_stats = asanThreadRegistry().GetCurrentThreadStats();
thread_stats.mmaps++;
thread_stats.mmaped += mmap_size;
thread_stats.mmaped_by_size[size_class] += n_chunks;
AsanChunk *res = 0;
for (uptr i = 0; i < n_chunks; i++) {
AsanChunk *m = (AsanChunk*)(mem + i * size);
m->chunk_state = CHUNK_AVAILABLE;
m->size_class = size_class;
m->next = res;
res = m;
}
PageGroup *pg = (PageGroup*)(mem + n_chunks * size);
// This memory is already poisoned, no need to poison it again.
pg->beg = (uptr)mem;
pg->end = pg->beg + mmap_size;
pg->size_of_chunk = size;
pg->last_chunk = (uptr)(mem + size * (n_chunks - 1));
int idx = atomic_fetch_add(&n_page_groups_, 1, memory_order_relaxed);
CHECK(idx < (int)ARRAY_SIZE(page_groups_));
page_groups_[idx] = pg;
return res;
}
AsanChunk *free_lists_[kNumberOfSizeClasses];
AsanChunkFifoList quarantine_;
BlockingMutex mu_;
PageGroup *page_groups_[kMaxAvailableRam / kMinMmapSize];
atomic_uint32_t n_page_groups_;
int n_sorted_page_groups_;
};
static MallocInfo malloc_info(LINKER_INITIALIZED);
void AsanThreadLocalMallocStorage::CommitBack() {
malloc_info.SwallowThreadLocalMallocStorage(this, true);
}
AsanChunkView FindHeapChunkByAddress(uptr address) {
return AsanChunkView(malloc_info.FindChunkByAddr(address));
}
static u8 *Allocate(uptr alignment, uptr size, StackTrace *stack,
AllocType alloc_type) {
__asan_init();
CHECK(stack);
if (size == 0) {
size = 1; // TODO(kcc): do something smarter
}
CHECK(IsPowerOfTwo(alignment));
uptr rounded_size = RoundUpTo(size, REDZONE);
uptr needed_size = rounded_size + REDZONE;
if (alignment > REDZONE) {
needed_size += alignment;
}
CHECK(IsAligned(needed_size, REDZONE));
if (size > kMaxAllowedMallocSize || needed_size > kMaxAllowedMallocSize) {
Report("WARNING: AddressSanitizer failed to allocate %p bytes\n",
(void*)size);
return 0;
}
u8 size_class = SizeToSizeClass(needed_size);
uptr size_to_allocate = SizeClassToSize(size_class);
CHECK(size_to_allocate >= kMinAllocSize);
CHECK(size_to_allocate >= needed_size);
CHECK(IsAligned(size_to_allocate, REDZONE));
if (flags()->verbosity >= 3) {
Printf("Allocate align: %zu size: %zu class: %u real: %zu\n",
alignment, size, size_class, size_to_allocate);
}
AsanThread *t = asanThreadRegistry().GetCurrent();
AsanStats &thread_stats = asanThreadRegistry().GetCurrentThreadStats();
// Statistics
thread_stats.mallocs++;
thread_stats.malloced += size;
thread_stats.malloced_redzones += size_to_allocate - size;
thread_stats.malloced_by_size[size_class]++;
AsanChunk *m = 0;
if (!t || size_to_allocate >= kMaxSizeForThreadLocalFreeList) {
// get directly from global storage.
m = malloc_info.AllocateChunks(size_class, 1);
thread_stats.malloc_large++;
} else {
// get from the thread-local storage.
AsanChunk **fl = &t->malloc_storage().free_lists_[size_class];
if (!*fl) {
uptr n_new_chunks = kMaxSizeForThreadLocalFreeList / size_to_allocate;
*fl = malloc_info.AllocateChunks(size_class, n_new_chunks);
thread_stats.malloc_small_slow++;
}
m = *fl;
*fl = (*fl)->next;
}
CHECK(m);
CHECK(m->chunk_state == CHUNK_AVAILABLE);
m->chunk_state = CHUNK_ALLOCATED;
m->alloc_type = alloc_type;
m->next = 0;
CHECK(m->Size() == size_to_allocate);
uptr addr = (uptr)m + REDZONE;
CHECK(addr <= (uptr)m->compressed_free_stack());
if (alignment > REDZONE && (addr & (alignment - 1))) {
addr = RoundUpTo(addr, alignment);
CHECK((addr & (alignment - 1)) == 0);
AsanChunk *p = (AsanChunk*)(addr - REDZONE);
p->chunk_state = CHUNK_MEMALIGN;
p->used_size = (uptr)p - (uptr)m;
m->alignment_log = Log2(alignment);
CHECK(m->Beg() == addr);
} else {
m->alignment_log = Log2(REDZONE);
}
CHECK(m == PtrToChunk(addr));
m->used_size = size;
CHECK(m->Beg() == addr);
m->alloc_tid = t ? t->tid() : 0;
m->free_tid = kInvalidTid;
StackTrace::CompressStack(stack, m->compressed_alloc_stack(),
m->compressed_alloc_stack_size());
PoisonShadow(addr, rounded_size, 0);
if (size < rounded_size) {
PoisonHeapPartialRightRedzone(addr + rounded_size - REDZONE,
size & (REDZONE - 1));
}
if (size <= (uptr)(flags()->max_malloc_fill_size)) {
REAL(memset)((void*)addr, 0, rounded_size);
}
return (u8*)addr;
}
static void Deallocate(u8 *ptr, StackTrace *stack, AllocType alloc_type) {
if (!ptr) return;
CHECK(stack);
if (flags()->debug) {
CHECK(malloc_info.FindPageGroup((uptr)ptr));
}
// Printf("Deallocate %p\n", ptr);
AsanChunk *m = PtrToChunk((uptr)ptr);
// Flip the chunk_state atomically to avoid race on double-free.
u8 old_chunk_state = atomic_exchange((atomic_uint8_t*)m, CHUNK_QUARANTINE,
memory_order_acq_rel);
if (old_chunk_state == CHUNK_QUARANTINE) {
ReportDoubleFree((uptr)ptr, stack);
} else if (old_chunk_state != CHUNK_ALLOCATED) {
ReportFreeNotMalloced((uptr)ptr, stack);
}
CHECK(old_chunk_state == CHUNK_ALLOCATED);
if (m->alloc_type != alloc_type && flags()->alloc_dealloc_mismatch)
ReportAllocTypeMismatch((uptr)ptr, stack,
(AllocType)m->alloc_type, (AllocType)alloc_type);
// With REDZONE==16 m->next is in the user area, otherwise it should be 0.
CHECK(REDZONE <= 16 || !m->next);
CHECK(m->free_tid == kInvalidTid);
CHECK(m->alloc_tid >= 0);
AsanThread *t = asanThreadRegistry().GetCurrent();
m->free_tid = t ? t->tid() : 0;
StackTrace::CompressStack(stack, m->compressed_free_stack(),
m->compressed_free_stack_size());
uptr rounded_size = RoundUpTo(m->used_size, REDZONE);
PoisonShadow((uptr)ptr, rounded_size, kAsanHeapFreeMagic);
// Statistics.
AsanStats &thread_stats = asanThreadRegistry().GetCurrentThreadStats();
thread_stats.frees++;
thread_stats.freed += m->used_size;
thread_stats.freed_by_size[m->SizeClass()]++;
CHECK(m->chunk_state == CHUNK_QUARANTINE);
if (t) {
AsanThreadLocalMallocStorage *ms = &t->malloc_storage();
ms->quarantine_.Push(m);
if (ms->quarantine_.size() > kMaxThreadLocalQuarantine) {
malloc_info.SwallowThreadLocalMallocStorage(ms, false);
}
} else {
malloc_info.BypassThreadLocalQuarantine(m);
}
}
static u8 *Reallocate(u8 *old_ptr, uptr new_size,
StackTrace *stack) {
CHECK(old_ptr && new_size);
// Statistics.
AsanStats &thread_stats = asanThreadRegistry().GetCurrentThreadStats();
thread_stats.reallocs++;
thread_stats.realloced += new_size;
AsanChunk *m = PtrToChunk((uptr)old_ptr);
CHECK(m->chunk_state == CHUNK_ALLOCATED);
uptr old_size = m->used_size;
uptr memcpy_size = Min(new_size, old_size);
u8 *new_ptr = Allocate(0, new_size, stack, FROM_MALLOC);
if (new_ptr) {
CHECK(REAL(memcpy) != 0);
REAL(memcpy)(new_ptr, old_ptr, memcpy_size);
Deallocate(old_ptr, stack, FROM_MALLOC);
}
return new_ptr;
}
} // namespace __asan
#if !SANITIZER_SUPPORTS_WEAK_HOOKS
// Provide default (no-op) implementation of malloc hooks.
extern "C" {
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
void __asan_malloc_hook(void *ptr, uptr size) {
(void)ptr;
(void)size;
}
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
void __asan_free_hook(void *ptr) {
(void)ptr;
}
} // extern "C"
#endif
namespace __asan {
void PrintInternalAllocatorStats() {
}
SANITIZER_INTERFACE_ATTRIBUTE
void *asan_memalign(uptr alignment, uptr size, StackTrace *stack,
AllocType alloc_type) {
void *ptr = (void*)Allocate(alignment, size, stack, alloc_type);
ASAN_MALLOC_HOOK(ptr, size);
return ptr;
}
SANITIZER_INTERFACE_ATTRIBUTE
void asan_free(void *ptr, StackTrace *stack, AllocType alloc_type) {
ASAN_FREE_HOOK(ptr);
Deallocate((u8*)ptr, stack, alloc_type);
}
SANITIZER_INTERFACE_ATTRIBUTE
void *asan_malloc(uptr size, StackTrace *stack) {
void *ptr = (void*)Allocate(0, size, stack, FROM_MALLOC);
ASAN_MALLOC_HOOK(ptr, size);
return ptr;
}
void *asan_calloc(uptr nmemb, uptr size, StackTrace *stack) {
void *ptr = (void*)Allocate(0, nmemb * size, stack, FROM_MALLOC);
if (ptr)
REAL(memset)(ptr, 0, nmemb * size);
ASAN_MALLOC_HOOK(ptr, size);
return ptr;
}
void *asan_realloc(void *p, uptr size, StackTrace *stack) {
if (p == 0) {
void *ptr = (void*)Allocate(0, size, stack, FROM_MALLOC);
ASAN_MALLOC_HOOK(ptr, size);
return ptr;
} else if (size == 0) {
ASAN_FREE_HOOK(p);
Deallocate((u8*)p, stack, FROM_MALLOC);
return 0;
}
return Reallocate((u8*)p, size, stack);
}
void *asan_valloc(uptr size, StackTrace *stack) {
void *ptr = (void*)Allocate(GetPageSizeCached(), size, stack, FROM_MALLOC);
ASAN_MALLOC_HOOK(ptr, size);
return ptr;
}
void *asan_pvalloc(uptr size, StackTrace *stack) {
uptr PageSize = GetPageSizeCached();
size = RoundUpTo(size, PageSize);
if (size == 0) {
// pvalloc(0) should allocate one page.
size = PageSize;
}
void *ptr = (void*)Allocate(PageSize, size, stack, FROM_MALLOC);
ASAN_MALLOC_HOOK(ptr, size);
return ptr;
}
int asan_posix_memalign(void **memptr, uptr alignment, uptr size,
StackTrace *stack) {
void *ptr = Allocate(alignment, size, stack, FROM_MALLOC);
CHECK(IsAligned((uptr)ptr, alignment));
ASAN_MALLOC_HOOK(ptr, size);
*memptr = ptr;
return 0;
}
uptr asan_malloc_usable_size(void *ptr, StackTrace *stack) {
CHECK(stack);
if (ptr == 0) return 0;
uptr usable_size = malloc_info.AllocationSize((uptr)ptr);
if (flags()->check_malloc_usable_size && (usable_size == 0)) {
ReportMallocUsableSizeNotOwned((uptr)ptr, stack);
}
return usable_size;
}
uptr asan_mz_size(const void *ptr) {
return malloc_info.AllocationSize((uptr)ptr);
}
void asan_mz_force_lock() {
malloc_info.ForceLock();
}
void asan_mz_force_unlock() {
malloc_info.ForceUnlock();
}
} // namespace __asan
// ---------------------- Interface ---------------- {{{1
using namespace __asan; // NOLINT
// ASan allocator doesn't reserve extra bytes, so normally we would
// just return "size".
uptr __asan_get_estimated_allocated_size(uptr size) {
if (size == 0) return 1;
return Min(size, kMaxAllowedMallocSize);
}
bool __asan_get_ownership(const void *p) {
return malloc_info.AllocationSize((uptr)p) > 0;
}
uptr __asan_get_allocated_size(const void *p) {
if (p == 0) return 0;
uptr allocated_size = malloc_info.AllocationSize((uptr)p);
// Die if p is not malloced or if it is already freed.
if (allocated_size == 0) {
GET_STACK_TRACE_FATAL_HERE;
ReportAsanGetAllocatedSizeNotOwned((uptr)p, &stack);
}
return allocated_size;
}
#endif // ASAN_ALLOCATOR_VERSION

View File

@ -9,7 +9,7 @@
//
// This file is a part of AddressSanitizer, an address sanity checker.
//
// ASan-private header for asan_allocator.cc.
// ASan-private header for asan_allocator2.cc.
//===----------------------------------------------------------------------===//
#ifndef ASAN_ALLOCATOR_H
@ -19,18 +19,6 @@
#include "asan_interceptors.h"
#include "sanitizer_common/sanitizer_list.h"
// We are in the process of transitioning from the old allocator (version 1)
// to a new one (version 2). The change is quite intrusive so both allocators
// will co-exist in the source base for a while. The actual allocator is chosen
// at build time by redefining this macro.
#ifndef ASAN_ALLOCATOR_VERSION
# if ASAN_LINUX && !ASAN_ANDROID
# define ASAN_ALLOCATOR_VERSION 2
# else
# define ASAN_ALLOCATOR_VERSION 1
# endif
#endif // ASAN_ALLOCATOR_VERSION
namespace __asan {
enum AllocType {
@ -42,6 +30,8 @@ enum AllocType {
static const uptr kNumberOfSizeClasses = 255;
struct AsanChunk;
void InitializeAllocator();
class AsanChunkView {
public:
explicit AsanChunkView(AsanChunk *chunk) : chunk_(chunk) {}
@ -53,14 +43,14 @@ class AsanChunkView {
uptr FreeTid();
void GetAllocStack(StackTrace *stack);
void GetFreeStack(StackTrace *stack);
bool AddrIsInside(uptr addr, uptr access_size, uptr *offset) {
bool AddrIsInside(uptr addr, uptr access_size, sptr *offset) {
if (addr >= Beg() && (addr + access_size) <= End()) {
*offset = addr - Beg();
return true;
}
return false;
}
bool AddrIsAtLeft(uptr addr, uptr access_size, uptr *offset) {
bool AddrIsAtLeft(uptr addr, uptr access_size, sptr *offset) {
(void)access_size;
if (addr < Beg()) {
*offset = Beg() - addr;
@ -68,12 +58,9 @@ class AsanChunkView {
}
return false;
}
bool AddrIsAtRight(uptr addr, uptr access_size, uptr *offset) {
if (addr + access_size >= End()) {
if (addr <= End())
*offset = 0;
else
*offset = addr - End();
bool AddrIsAtRight(uptr addr, uptr access_size, sptr *offset) {
if (addr + access_size > End()) {
*offset = addr - End();
return true;
}
return false;
@ -104,109 +91,17 @@ class AsanChunkFifoList: public IntrusiveList<AsanChunk> {
struct AsanThreadLocalMallocStorage {
explicit AsanThreadLocalMallocStorage(LinkerInitialized x)
#if ASAN_ALLOCATOR_VERSION == 1
: quarantine_(x)
#endif
{ }
AsanThreadLocalMallocStorage() {
CHECK(REAL(memset));
REAL(memset)(this, 0, sizeof(AsanThreadLocalMallocStorage));
}
#if ASAN_ALLOCATOR_VERSION == 1
AsanChunkFifoList quarantine_;
AsanChunk *free_lists_[kNumberOfSizeClasses];
#else
uptr quarantine_cache[16];
uptr allocator2_cache[96 * (512 * 8 + 16)]; // Opaque.
#endif
void CommitBack();
};
// Fake stack frame contains local variables of one function.
// This struct should fit into a stack redzone (32 bytes).
struct FakeFrame {
uptr magic; // Modified by the instrumented code.
uptr descr; // Modified by the instrumented code.
FakeFrame *next;
u64 real_stack : 48;
u64 size_minus_one : 16;
};
struct FakeFrameFifo {
public:
void FifoPush(FakeFrame *node);
FakeFrame *FifoPop();
private:
FakeFrame *first_, *last_;
};
class FakeFrameLifo {
public:
void LifoPush(FakeFrame *node) {
node->next = top_;
top_ = node;
}
void LifoPop() {
CHECK(top_);
top_ = top_->next;
}
FakeFrame *top() { return top_; }
private:
FakeFrame *top_;
};
// For each thread we create a fake stack and place stack objects on this fake
// stack instead of the real stack. The fake stack is not really a stack but
// a fast malloc-like allocator so that when a function exits the fake stack
// is not poped but remains there for quite some time until gets used again.
// So, we poison the objects on the fake stack when function returns.
// It helps us find use-after-return bugs.
// We can not rely on __asan_stack_free being called on every function exit,
// so we maintain a lifo list of all current fake frames and update it on every
// call to __asan_stack_malloc.
class FakeStack {
public:
FakeStack();
explicit FakeStack(LinkerInitialized) {}
void Init(uptr stack_size);
void StopUsingFakeStack() { alive_ = false; }
void Cleanup();
uptr AllocateStack(uptr size, uptr real_stack);
static void OnFree(uptr ptr, uptr size, uptr real_stack);
// Return the bottom of the maped region.
uptr AddrIsInFakeStack(uptr addr);
bool StackSize() { return stack_size_; }
private:
static const uptr kMinStackFrameSizeLog = 9; // Min frame is 512B.
static const uptr kMaxStackFrameSizeLog = 16; // Max stack frame is 64K.
static const uptr kMaxStackMallocSize = 1 << kMaxStackFrameSizeLog;
static const uptr kNumberOfSizeClasses =
kMaxStackFrameSizeLog - kMinStackFrameSizeLog + 1;
bool AddrIsInSizeClass(uptr addr, uptr size_class);
// Each size class should be large enough to hold all frames.
uptr ClassMmapSize(uptr size_class);
uptr ClassSize(uptr size_class) {
return 1UL << (size_class + kMinStackFrameSizeLog);
}
void DeallocateFrame(FakeFrame *fake_frame);
uptr ComputeSizeClass(uptr alloc_size);
void AllocateOneSizeClass(uptr size_class);
uptr stack_size_;
bool alive_;
uptr allocated_size_classes_[kNumberOfSizeClasses];
FakeFrameFifo size_classes_[kNumberOfSizeClasses];
FakeFrameLifo call_stack_;
};
void *asan_memalign(uptr alignment, uptr size, StackTrace *stack,
AllocType alloc_type);
void asan_free(void *ptr, StackTrace *stack, AllocType alloc_type);
@ -227,50 +122,5 @@ void asan_mz_force_unlock();
void PrintInternalAllocatorStats();
// Log2 and RoundUpToPowerOfTwo should be inlined for performance.
#if defined(_WIN32) && !defined(__clang__)
extern "C" {
unsigned char _BitScanForward(unsigned long *index, unsigned long mask); // NOLINT
unsigned char _BitScanReverse(unsigned long *index, unsigned long mask); // NOLINT
#if defined(_WIN64)
unsigned char _BitScanForward64(unsigned long *index, unsigned __int64 mask); // NOLINT
unsigned char _BitScanReverse64(unsigned long *index, unsigned __int64 mask); // NOLINT
#endif
}
#endif
static inline uptr Log2(uptr x) {
CHECK(IsPowerOfTwo(x));
#if !defined(_WIN32) || defined(__clang__)
return __builtin_ctzl(x);
#elif defined(_WIN64)
unsigned long ret; // NOLINT
_BitScanForward64(&ret, x);
return ret;
#else
unsigned long ret; // NOLINT
_BitScanForward(&ret, x);
return ret;
#endif
}
static inline uptr RoundUpToPowerOfTwo(uptr size) {
CHECK(size);
if (IsPowerOfTwo(size)) return size;
unsigned long up; // NOLINT
#if !defined(_WIN32) || defined(__clang__)
up = SANITIZER_WORDSIZE - 1 - __builtin_clzl(size);
#elif defined(_WIN64)
_BitScanReverse64(&up, size);
#else
_BitScanReverse(&up, size);
#endif
CHECK(size < (1ULL << (up + 1)));
CHECK(size > (1ULL << up));
return 1UL << (up + 1);
}
} // namespace __asan
#endif // ASAN_ALLOCATOR_H

View File

@ -13,21 +13,20 @@
// This variant uses the allocator from sanitizer_common, i.e. the one shared
// with ThreadSanitizer and MemorySanitizer.
//
// Status: under development, not enabled by default yet.
//===----------------------------------------------------------------------===//
#include "asan_allocator.h"
#if ASAN_ALLOCATOR_VERSION == 2
#include "asan_mapping.h"
#include "asan_poisoning.h"
#include "asan_report.h"
#include "asan_thread.h"
#include "asan_thread_registry.h"
#include "sanitizer/asan_interface.h"
#include "sanitizer_common/sanitizer_allocator.h"
#include "sanitizer_common/sanitizer_flags.h"
#include "sanitizer_common/sanitizer_internal_defs.h"
#include "sanitizer_common/sanitizer_list.h"
#include "sanitizer_common/sanitizer_stackdepot.h"
#include "sanitizer_common/sanitizer_quarantine.h"
#include "lsan/lsan_common.h"
namespace __asan {
@ -35,7 +34,7 @@ struct AsanMapUnmapCallback {
void OnMap(uptr p, uptr size) const {
PoisonShadow(p, size, kAsanHeapLeftRedzoneMagic);
// Statistics.
AsanStats &thread_stats = asanThreadRegistry().GetCurrentThreadStats();
AsanStats &thread_stats = GetCurrentThreadStats();
thread_stats.mmaps++;
thread_stats.mmaped += size;
}
@ -50,23 +49,32 @@ struct AsanMapUnmapCallback {
uptr shadow_end = RoundDownTo(MemToShadow(p + size), page_size);
FlushUnneededShadowMemory(shadow_beg, shadow_end - shadow_beg);
// Statistics.
AsanStats &thread_stats = asanThreadRegistry().GetCurrentThreadStats();
AsanStats &thread_stats = GetCurrentThreadStats();
thread_stats.munmaps++;
thread_stats.munmaped += size;
}
};
#if SANITIZER_WORDSIZE == 64
#if defined(__powerpc64__)
const uptr kAllocatorSpace = 0xa0000000000ULL;
const uptr kAllocatorSize = 0x20000000000ULL; // 2T.
#else
const uptr kAllocatorSpace = 0x600000000000ULL;
const uptr kAllocatorSize = 0x10000000000ULL; // 1T.
const uptr kAllocatorSize = 0x40000000000ULL; // 4T.
#endif
typedef DefaultSizeClassMap SizeClassMap;
typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, 0 /*metadata*/,
SizeClassMap, AsanMapUnmapCallback> PrimaryAllocator;
#elif SANITIZER_WORDSIZE == 32
static const u64 kAddressSpaceSize = 1ULL << 32;
typedef CompactSizeClassMap SizeClassMap;
static const uptr kRegionSizeLog = 20;
static const uptr kFlatByteMapSize = kAddressSpaceSize >> kRegionSizeLog;
typedef SizeClassAllocator32<0, kAddressSpaceSize, 16,
SizeClassMap, AsanMapUnmapCallback> PrimaryAllocator;
SizeClassMap, kRegionSizeLog,
FlatByteMap<kFlatByteMapSize>,
AsanMapUnmapCallback> PrimaryAllocator;
#endif
typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
@ -91,8 +99,6 @@ static const uptr kMaxAllowedMallocSize =
static const uptr kMaxThreadLocalQuarantine =
FIRST_32_SECOND_64(1 << 18, 1 << 20);
static const uptr kReturnOnZeroMalloc = 2048; // Zero page is protected.
// Every chunk of memory allocated by this allocator can be in one of 3 states:
// CHUNK_AVAILABLE: the chunk is in the free list and ready to be allocated.
// CHUNK_ALLOCATED: the chunk is allocated and not yet freed.
@ -114,7 +120,7 @@ static u32 RZSize2Log(u32 rz_size) {
CHECK_GE(rz_size, 16);
CHECK_LE(rz_size, 2048);
CHECK(IsPowerOfTwo(rz_size));
u32 res = __builtin_ctz(rz_size) - 4;
u32 res = Log2(rz_size) - 4;
CHECK_EQ(rz_size, RZLog2Size(res));
return res;
}
@ -158,6 +164,7 @@ struct ChunkHeader {
u32 from_memalign : 1;
u32 alloc_type : 2;
u32 rz_log : 3;
u32 lsan_tag : 2;
// 2-nd 8 bytes
// This field is used for small sizes. For large sizes it is equal to
// SizeClassMap::kMaxSize and the actual size is stored in the
@ -168,7 +175,6 @@ struct ChunkHeader {
struct ChunkBase : ChunkHeader {
// Header2, intersects with user memory.
AsanChunk *next;
u32 free_context_id;
};
@ -189,7 +195,8 @@ struct AsanChunk: ChunkBase {
return allocator.GetBlockBegin(reinterpret_cast<void *>(this));
return reinterpret_cast<void*>(Beg() - RZLog2Size(rz_log));
}
// We store the alloc/free stack traces in the chunk itself.
// If we don't use stack depot, we store the alloc/free stack traces
// in the chunk itself.
u32 *AllocStackBeg() {
return (u32*)(Beg() - RZLog2Size(rz_log));
}
@ -205,6 +212,9 @@ struct AsanChunk: ChunkBase {
uptr available = RoundUpTo(user_requested_size, SHADOW_GRANULARITY);
return (available - kChunkHeader2Size) / sizeof(u32);
}
bool AddrIsInside(uptr addr) {
return (addr >= Beg()) && (addr < Beg() + UsedSize());
}
};
uptr AsanChunkView::Beg() { return chunk_->Beg(); }
@ -258,8 +268,8 @@ struct QuarantineCallback {
}
void Recycle(AsanChunk *m) {
CHECK(m->chunk_state == CHUNK_QUARANTINE);
m->chunk_state = CHUNK_AVAILABLE;
CHECK_EQ(m->chunk_state, CHUNK_QUARANTINE);
atomic_store((atomic_uint8_t*)m, CHUNK_AVAILABLE, memory_order_relaxed);
CHECK_NE(m->alloc_tid, kInvalidTid);
CHECK_NE(m->free_tid, kInvalidTid);
PoisonShadow(m->Beg(),
@ -273,7 +283,7 @@ struct QuarantineCallback {
}
// Statistics.
AsanStats &thread_stats = asanThreadRegistry().GetCurrentThreadStats();
AsanStats &thread_stats = GetCurrentThreadStats();
thread_stats.real_frees++;
thread_stats.really_freed += m->UsedSize();
@ -291,34 +301,32 @@ struct QuarantineCallback {
AllocatorCache *cache_;
};
static void Init() {
static int inited = 0;
if (inited) return;
__asan_init();
inited = true; // this must happen before any threads are created.
void InitializeAllocator() {
allocator.Init();
quarantine.Init((uptr)flags()->quarantine_size, kMaxThreadLocalQuarantine);
}
static void *Allocate(uptr size, uptr alignment, StackTrace *stack,
AllocType alloc_type) {
Init();
AllocType alloc_type, bool can_fill) {
if (!asan_inited)
__asan_init();
Flags &fl = *flags();
CHECK(stack);
const uptr min_alignment = SHADOW_GRANULARITY;
if (alignment < min_alignment)
alignment = min_alignment;
if (size == 0) {
if (alignment <= kReturnOnZeroMalloc)
return reinterpret_cast<void *>(kReturnOnZeroMalloc);
else
return 0; // 0 bytes with large alignment requested. Just return 0.
// We'd be happy to avoid allocating memory for zero-size requests, but
// some programs/tests depend on this behavior and assume that malloc would
// not return NULL even for zero-size allocations. Moreover, it looks like
// operator new should never return NULL, and results of consecutive "new"
// calls must be different even if the allocated size is zero.
size = 1;
}
CHECK(IsPowerOfTwo(alignment));
uptr rz_log = ComputeRZLog(size);
uptr rz_size = RZLog2Size(rz_log);
uptr rounded_size = RoundUpTo(size, alignment);
if (rounded_size < kChunkHeader2Size)
rounded_size = kChunkHeader2Size;
uptr rounded_size = RoundUpTo(Max(size, kChunkHeader2Size), alignment);
uptr needed_size = rounded_size + rz_size;
if (alignment > min_alignment)
needed_size += alignment;
@ -336,7 +344,7 @@ static void *Allocate(uptr size, uptr alignment, StackTrace *stack,
return 0;
}
AsanThread *t = asanThreadRegistry().GetCurrent();
AsanThread *t = GetCurrentThread();
void *allocated;
if (t) {
AllocatorCache *cache = GetAllocatorCache(&t->malloc_storage());
@ -358,7 +366,6 @@ static void *Allocate(uptr size, uptr alignment, StackTrace *stack,
CHECK_LE(user_end, alloc_end);
uptr chunk_beg = user_beg - kChunkHeaderSize;
AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg);
m->chunk_state = CHUNK_ALLOCATED;
m->alloc_type = alloc_type;
m->rz_log = rz_log;
u32 alloc_tid = t ? t->tid() : 0;
@ -384,7 +391,7 @@ static void *Allocate(uptr size, uptr alignment, StackTrace *stack,
meta[1] = chunk_beg;
}
if (flags()->use_stack_depot) {
if (fl.use_stack_depot) {
m->alloc_context_id = StackDepotPut(stack->trace, stack->size);
} else {
m->alloc_context_id = 0;
@ -396,12 +403,12 @@ static void *Allocate(uptr size, uptr alignment, StackTrace *stack,
if (size_rounded_down_to_granularity)
PoisonShadow(user_beg, size_rounded_down_to_granularity, 0);
// Deal with the end of the region if size is not aligned to granularity.
if (size != size_rounded_down_to_granularity && flags()->poison_heap) {
if (size != size_rounded_down_to_granularity && fl.poison_heap) {
u8 *shadow = (u8*)MemToShadow(user_beg + size_rounded_down_to_granularity);
*shadow = size & (SHADOW_GRANULARITY - 1);
}
AsanStats &thread_stats = asanThreadRegistry().GetCurrentThreadStats();
AsanStats &thread_stats = GetCurrentThreadStats();
thread_stats.mallocs++;
thread_stats.malloced += size;
thread_stats.malloced_redzones += needed_size - size;
@ -411,25 +418,42 @@ static void *Allocate(uptr size, uptr alignment, StackTrace *stack,
thread_stats.malloc_large++;
void *res = reinterpret_cast<void *>(user_beg);
if (can_fill && fl.max_malloc_fill_size) {
uptr fill_size = Min(size, (uptr)fl.max_malloc_fill_size);
REAL(memset)(res, fl.malloc_fill_byte, fill_size);
}
// Must be the last mutation of metadata in this function.
atomic_store((atomic_uint8_t *)m, CHUNK_ALLOCATED, memory_order_release);
ASAN_MALLOC_HOOK(res, size);
return res;
}
static void Deallocate(void *ptr, StackTrace *stack, AllocType alloc_type) {
uptr p = reinterpret_cast<uptr>(ptr);
if (p == 0 || p == kReturnOnZeroMalloc) return;
uptr chunk_beg = p - kChunkHeaderSize;
AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg);
static void AtomicallySetQuarantineFlag(AsanChunk *m,
void *ptr, StackTrace *stack) {
u8 old_chunk_state = CHUNK_ALLOCATED;
// Flip the chunk_state atomically to avoid race on double-free.
u8 old_chunk_state = atomic_exchange((atomic_uint8_t*)m, CHUNK_QUARANTINE,
memory_order_relaxed);
if (!atomic_compare_exchange_strong((atomic_uint8_t*)m, &old_chunk_state,
CHUNK_QUARANTINE, memory_order_acquire)) {
if (old_chunk_state == CHUNK_QUARANTINE)
ReportDoubleFree((uptr)ptr, stack);
else
ReportFreeNotMalloced((uptr)ptr, stack);
}
CHECK_EQ(CHUNK_ALLOCATED, old_chunk_state);
}
// Expects the chunk to already be marked as quarantined by using
// AtomicallySetQuarantineFlag.
static void QuarantineChunk(AsanChunk *m, void *ptr,
StackTrace *stack, AllocType alloc_type) {
CHECK_EQ(m->chunk_state, CHUNK_QUARANTINE);
// FIXME: if the free hook produces an ASan report (e.g. due to a bug),
// printing the report may crash as the AsanChunk free-related fields have not
// been updated yet. We might need to introduce yet another chunk state to
// handle this correctly, but don't want to yet.
ASAN_FREE_HOOK(ptr);
if (old_chunk_state == CHUNK_QUARANTINE)
ReportDoubleFree((uptr)ptr, stack);
else if (old_chunk_state != CHUNK_ALLOCATED)
ReportFreeNotMalloced((uptr)ptr, stack);
CHECK(old_chunk_state == CHUNK_ALLOCATED);
if (m->alloc_type != alloc_type && flags()->alloc_dealloc_mismatch)
ReportAllocTypeMismatch((uptr)ptr, stack,
(AllocType)m->alloc_type, (AllocType)alloc_type);
@ -437,7 +461,7 @@ static void Deallocate(void *ptr, StackTrace *stack, AllocType alloc_type) {
CHECK_GE(m->alloc_tid, 0);
if (SANITIZER_WORDSIZE == 64) // On 32-bits this resides in user area.
CHECK_EQ(m->free_tid, kInvalidTid);
AsanThread *t = asanThreadRegistry().GetCurrent();
AsanThread *t = GetCurrentThread();
m->free_tid = t ? t->tid() : 0;
if (flags()->use_stack_depot) {
m->free_context_id = StackDepotPut(stack->trace, stack->size);
@ -445,13 +469,12 @@ static void Deallocate(void *ptr, StackTrace *stack, AllocType alloc_type) {
m->free_context_id = 0;
StackTrace::CompressStack(stack, m->FreeStackBeg(), m->FreeStackSize());
}
CHECK(m->chunk_state == CHUNK_QUARANTINE);
// Poison the region.
PoisonShadow(m->Beg(),
RoundUpTo(m->UsedSize(), SHADOW_GRANULARITY),
kAsanHeapFreeMagic);
AsanStats &thread_stats = asanThreadRegistry().GetCurrentThreadStats();
AsanStats &thread_stats = GetCurrentThreadStats();
thread_stats.frees++;
thread_stats.freed += m->UsedSize();
@ -467,8 +490,17 @@ static void Deallocate(void *ptr, StackTrace *stack, AllocType alloc_type) {
quarantine.Put(&fallback_quarantine_cache, QuarantineCallback(ac),
m, m->UsedSize());
}
}
ASAN_FREE_HOOK(ptr);
static void Deallocate(void *ptr, StackTrace *stack, AllocType alloc_type) {
uptr p = reinterpret_cast<uptr>(ptr);
if (p == 0) return;
uptr chunk_beg = p - kChunkHeaderSize;
AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg);
// Must mark the chunk as quarantined before any changes to its metadata.
AtomicallySetQuarantineFlag(m, ptr, stack);
QuarantineChunk(m, ptr, stack, alloc_type);
}
static void *Reallocate(void *old_ptr, uptr new_size, StackTrace *stack) {
@ -477,18 +509,21 @@ static void *Reallocate(void *old_ptr, uptr new_size, StackTrace *stack) {
uptr chunk_beg = p - kChunkHeaderSize;
AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg);
AsanStats &thread_stats = asanThreadRegistry().GetCurrentThreadStats();
AsanStats &thread_stats = GetCurrentThreadStats();
thread_stats.reallocs++;
thread_stats.realloced += new_size;
CHECK(m->chunk_state == CHUNK_ALLOCATED);
// Must mark the chunk as quarantined before any changes to its metadata.
// This also ensures that other threads can't deallocate it in the meantime.
AtomicallySetQuarantineFlag(m, old_ptr, stack);
uptr old_size = m->UsedSize();
uptr memcpy_size = Min(new_size, old_size);
void *new_ptr = Allocate(new_size, 8, stack, FROM_MALLOC);
void *new_ptr = Allocate(new_size, 8, stack, FROM_MALLOC, true);
if (new_ptr) {
CHECK(REAL(memcpy) != 0);
CHECK_NE(REAL(memcpy), (void*)0);
REAL(memcpy)(new_ptr, old_ptr, memcpy_size);
Deallocate(old_ptr, stack, FROM_MALLOC);
QuarantineChunk(m, old_ptr, stack, FROM_MALLOC);
}
return new_ptr;
}
@ -548,7 +583,7 @@ AsanChunk *ChooseChunk(uptr addr,
return right_chunk;
}
// Same chunk_state: choose based on offset.
uptr l_offset = 0, r_offset = 0;
sptr l_offset = 0, r_offset = 0;
CHECK(AsanChunkView(left_chunk).AddrIsAtRight(addr, 1, &l_offset));
CHECK(AsanChunkView(right_chunk).AddrIsAtLeft(addr, 1, &r_offset));
if (l_offset < r_offset)
@ -559,7 +594,7 @@ AsanChunk *ChooseChunk(uptr addr,
AsanChunkView FindHeapChunkByAddress(uptr addr) {
AsanChunk *m1 = GetAsanChunkByAddr(addr);
if (!m1) return AsanChunkView(m1);
uptr offset = 0;
sptr offset = 0;
if (AsanChunkView(m1).AddrIsAtLeft(addr, 1, &offset)) {
// The address is in the chunk's left redzone, so maybe it is actually
// a right buffer overflow from the other chunk to the left.
@ -589,7 +624,7 @@ void PrintInternalAllocatorStats() {
SANITIZER_INTERFACE_ATTRIBUTE
void *asan_memalign(uptr alignment, uptr size, StackTrace *stack,
AllocType alloc_type) {
return Allocate(size, alignment, stack, alloc_type);
return Allocate(size, alignment, stack, alloc_type, true);
}
SANITIZER_INTERFACE_ATTRIBUTE
@ -599,19 +634,22 @@ void asan_free(void *ptr, StackTrace *stack, AllocType alloc_type) {
SANITIZER_INTERFACE_ATTRIBUTE
void *asan_malloc(uptr size, StackTrace *stack) {
return Allocate(size, 8, stack, FROM_MALLOC);
return Allocate(size, 8, stack, FROM_MALLOC, true);
}
void *asan_calloc(uptr nmemb, uptr size, StackTrace *stack) {
void *ptr = Allocate(nmemb * size, 8, stack, FROM_MALLOC);
if (ptr)
if (CallocShouldReturnNullDueToOverflow(size, nmemb)) return 0;
void *ptr = Allocate(nmemb * size, 8, stack, FROM_MALLOC, false);
// If the memory comes from the secondary allocator no need to clear it
// as it comes directly from mmap.
if (ptr && allocator.FromPrimary(ptr))
REAL(memset)(ptr, 0, nmemb * size);
return ptr;
}
void *asan_realloc(void *p, uptr size, StackTrace *stack) {
if (p == 0)
return Allocate(size, 8, stack, FROM_MALLOC);
return Allocate(size, 8, stack, FROM_MALLOC, true);
if (size == 0) {
Deallocate(p, stack, FROM_MALLOC);
return 0;
@ -620,7 +658,7 @@ void *asan_realloc(void *p, uptr size, StackTrace *stack) {
}
void *asan_valloc(uptr size, StackTrace *stack) {
return Allocate(size, GetPageSizeCached(), stack, FROM_MALLOC);
return Allocate(size, GetPageSizeCached(), stack, FROM_MALLOC, true);
}
void *asan_pvalloc(uptr size, StackTrace *stack) {
@ -630,12 +668,12 @@ void *asan_pvalloc(uptr size, StackTrace *stack) {
// pvalloc(0) should allocate one page.
size = PageSize;
}
return Allocate(size, PageSize, stack, FROM_MALLOC);
return Allocate(size, PageSize, stack, FROM_MALLOC, true);
}
int asan_posix_memalign(void **memptr, uptr alignment, uptr size,
StackTrace *stack) {
void *ptr = Allocate(size, alignment, stack, FROM_MALLOC);
void *ptr = Allocate(size, alignment, stack, FROM_MALLOC, true);
CHECK(IsAligned((uptr)ptr, alignment));
*memptr = ptr;
return 0;
@ -651,20 +689,96 @@ uptr asan_malloc_usable_size(void *ptr, StackTrace *stack) {
}
uptr asan_mz_size(const void *ptr) {
UNIMPLEMENTED();
return 0;
return AllocationSize(reinterpret_cast<uptr>(ptr));
}
void asan_mz_force_lock() {
UNIMPLEMENTED();
allocator.ForceLock();
fallback_mutex.Lock();
}
void asan_mz_force_unlock() {
UNIMPLEMENTED();
fallback_mutex.Unlock();
allocator.ForceUnlock();
}
} // namespace __asan
// --- Implementation of LSan-specific functions --- {{{1
namespace __lsan {
void LockAllocator() {
__asan::allocator.ForceLock();
}
void UnlockAllocator() {
__asan::allocator.ForceUnlock();
}
void GetAllocatorGlobalRange(uptr *begin, uptr *end) {
*begin = (uptr)&__asan::allocator;
*end = *begin + sizeof(__asan::allocator);
}
void *PointsIntoChunk(void* p) {
uptr addr = reinterpret_cast<uptr>(p);
__asan::AsanChunk *m = __asan::GetAsanChunkByAddr(addr);
if (!m) return 0;
uptr chunk = m->Beg();
if ((m->chunk_state == __asan::CHUNK_ALLOCATED) && m->AddrIsInside(addr))
return reinterpret_cast<void *>(chunk);
return 0;
}
void *GetUserBegin(void *p) {
__asan::AsanChunk *m = __asan::GetAsanChunkByAddr(reinterpret_cast<uptr>(p));
CHECK(m);
return reinterpret_cast<void *>(m->Beg());
}
LsanMetadata::LsanMetadata(void *chunk) {
uptr addr = reinterpret_cast<uptr>(chunk);
metadata_ = reinterpret_cast<void *>(addr - __asan::kChunkHeaderSize);
}
bool LsanMetadata::allocated() const {
__asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_);
return m->chunk_state == __asan::CHUNK_ALLOCATED;
}
ChunkTag LsanMetadata::tag() const {
__asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_);
return static_cast<ChunkTag>(m->lsan_tag);
}
void LsanMetadata::set_tag(ChunkTag value) {
__asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_);
m->lsan_tag = value;
}
uptr LsanMetadata::requested_size() const {
__asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_);
return m->UsedSize();
}
u32 LsanMetadata::stack_trace_id() const {
__asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_);
return m->alloc_context_id;
}
template <typename Callable> void ForEachChunk(Callable const &callback) {
__asan::allocator.ForEachChunk(callback);
}
#if CAN_SANITIZE_LEAKS
template void ForEachChunk<ProcessPlatformSpecificAllocationsCb>(
ProcessPlatformSpecificAllocationsCb const &callback);
template void ForEachChunk<PrintLeakedCb>(PrintLeakedCb const &callback);
template void ForEachChunk<CollectLeaksCb>(CollectLeaksCb const &callback);
template void ForEachChunk<MarkIndirectlyLeakedCb>(
MarkIndirectlyLeakedCb const &callback);
template void ForEachChunk<ClearTagCb>(ClearTagCb const &callback);
#endif // CAN_SANITIZE_LEAKS
} // namespace __lsan
// ---------------------- Interface ---------------- {{{1
using namespace __asan; // NOLINT
@ -676,7 +790,7 @@ uptr __asan_get_estimated_allocated_size(uptr size) {
bool __asan_get_ownership(const void *p) {
uptr ptr = reinterpret_cast<uptr>(p);
return (ptr == kReturnOnZeroMalloc) || (AllocationSize(ptr) > 0);
return (AllocationSize(ptr) > 0);
}
uptr __asan_get_allocated_size(const void *p) {
@ -684,7 +798,7 @@ uptr __asan_get_allocated_size(const void *p) {
uptr ptr = reinterpret_cast<uptr>(p);
uptr allocated_size = AllocationSize(ptr);
// Die if p is not malloced or if it is already freed.
if (allocated_size == 0 && ptr != kReturnOnZeroMalloc) {
if (allocated_size == 0) {
GET_STACK_TRACE_FATAL_HERE;
ReportAsanGetAllocatedSizeNotOwned(ptr, &stack);
}
@ -705,6 +819,3 @@ void __asan_free_hook(void *ptr) {
}
} // extern "C"
#endif
#endif // ASAN_ALLOCATOR_VERSION

View File

@ -0,0 +1,10 @@
# Blacklist for AddressSanitizer. Turns off instrumentation of particular
# functions or sources. Use with care. You may set location of blacklist
# at compile-time using -fsanitize-blacklist=<path> flag.
# Example usage:
# fun:*bad_function_name*
# src:file_with_tricky_code.cc
# global:*global_with_bad_access_or_initialization*
# global-init:*global_with_initialization_issues*
# global-init-type:*Namespace::ClassName*

View File

@ -12,14 +12,13 @@
// FakeStack is used to detect use-after-return bugs.
//===----------------------------------------------------------------------===//
#include "asan_allocator.h"
#include "asan_poisoning.h"
#include "asan_thread.h"
#include "asan_thread_registry.h"
#include "sanitizer/asan_interface.h"
namespace __asan {
FakeStack::FakeStack() {
CHECK(REAL(memset) != 0);
CHECK(REAL(memset));
REAL(memset)(this, 0, sizeof(*this));
}
@ -31,24 +30,26 @@ bool FakeStack::AddrIsInSizeClass(uptr addr, uptr size_class) {
}
uptr FakeStack::AddrIsInFakeStack(uptr addr) {
for (uptr i = 0; i < kNumberOfSizeClasses; i++) {
if (AddrIsInSizeClass(addr, i)) return allocated_size_classes_[i];
for (uptr size_class = 0; size_class < kNumberOfSizeClasses; size_class++) {
if (!AddrIsInSizeClass(addr, size_class)) continue;
uptr size_class_first_ptr = allocated_size_classes_[size_class];
uptr size = ClassSize(size_class);
CHECK_LE(size_class_first_ptr, addr);
CHECK_GT(size_class_first_ptr + ClassMmapSize(size_class), addr);
return size_class_first_ptr + ((addr - size_class_first_ptr) / size) * size;
}
return 0;
}
// We may want to compute this during compilation.
inline uptr FakeStack::ComputeSizeClass(uptr alloc_size) {
ALWAYS_INLINE uptr FakeStack::ComputeSizeClass(uptr alloc_size) {
uptr rounded_size = RoundUpToPowerOfTwo(alloc_size);
uptr log = Log2(rounded_size);
CHECK(alloc_size <= (1UL << log));
if (!(alloc_size > (1UL << (log-1)))) {
Printf("alloc_size %zu log %zu\n", alloc_size, log);
}
CHECK(alloc_size > (1UL << (log-1)));
CHECK_LE(alloc_size, (1UL << log));
CHECK_GT(alloc_size, (1UL << (log-1)));
uptr res = log < kMinStackFrameSizeLog ? 0 : log - kMinStackFrameSizeLog;
CHECK(res < kNumberOfSizeClasses);
CHECK(ClassSize(res) >= rounded_size);
CHECK_LT(res, kNumberOfSizeClasses);
CHECK_GE(ClassSize(res), rounded_size);
return res;
}
@ -104,7 +105,7 @@ void FakeStack::AllocateOneSizeClass(uptr size_class) {
uptr new_mem = (uptr)MmapOrDie(
ClassMmapSize(size_class), __FUNCTION__);
// Printf("T%d new_mem[%zu]: %p-%p mmap %zu\n",
// asanThreadRegistry().GetCurrent()->tid(),
// GetCurrentThread()->tid(),
// size_class, new_mem, new_mem + ClassMmapSize(size_class),
// ClassMmapSize(size_class));
uptr i;
@ -116,7 +117,7 @@ void FakeStack::AllocateOneSizeClass(uptr size_class) {
allocated_size_classes_[size_class] = new_mem;
}
uptr FakeStack::AllocateStack(uptr size, uptr real_stack) {
ALWAYS_INLINE uptr FakeStack::AllocateStack(uptr size, uptr real_stack) {
if (!alive_) return real_stack;
CHECK(size <= kMaxStackMallocSize && size > 1);
uptr size_class = ComputeSizeClass(size);
@ -138,7 +139,7 @@ uptr FakeStack::AllocateStack(uptr size, uptr real_stack) {
return ptr;
}
void FakeStack::DeallocateFrame(FakeFrame *fake_frame) {
ALWAYS_INLINE void FakeStack::DeallocateFrame(FakeFrame *fake_frame) {
CHECK(alive_);
uptr size = fake_frame->size_minus_one + 1;
uptr size_class = ComputeSizeClass(size);
@ -149,11 +150,11 @@ void FakeStack::DeallocateFrame(FakeFrame *fake_frame) {
size_classes_[size_class].FifoPush(fake_frame);
}
void FakeStack::OnFree(uptr ptr, uptr size, uptr real_stack) {
ALWAYS_INLINE void FakeStack::OnFree(uptr ptr, uptr size, uptr real_stack) {
FakeFrame *fake_frame = (FakeFrame*)ptr;
CHECK(fake_frame->magic = kRetiredStackFrameMagic);
CHECK(fake_frame->descr != 0);
CHECK(fake_frame->size_minus_one == size - 1);
CHECK_EQ(fake_frame->magic, kRetiredStackFrameMagic);
CHECK_NE(fake_frame->descr, 0);
CHECK_EQ(fake_frame->size_minus_one, size - 1);
PoisonShadow(ptr, size, kAsanStackAfterReturnMagic);
}
@ -164,7 +165,7 @@ using namespace __asan; // NOLINT
uptr __asan_stack_malloc(uptr size, uptr real_stack) {
if (!flags()->use_fake_stack) return real_stack;
AsanThread *t = asanThreadRegistry().GetCurrent();
AsanThread *t = GetCurrentThread();
if (!t) {
// TSD is gone, use the real stack.
return real_stack;

117
lib/asan/asan_fake_stack.h Normal file
View File

@ -0,0 +1,117 @@
//===-- asan_fake_stack.h ---------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of AddressSanitizer, an address sanity checker.
//
// ASan-private header for asan_fake_stack.cc
//===----------------------------------------------------------------------===//
#ifndef ASAN_FAKE_STACK_H
#define ASAN_FAKE_STACK_H
namespace __asan {
// Fake stack frame contains local variables of one function.
struct FakeFrame {
uptr magic; // Modified by the instrumented code.
uptr descr; // Modified by the instrumented code.
uptr pc; // Modified by the instrumented code.
u64 real_stack : 48;
u64 size_minus_one : 16;
// End of the first 32 bytes.
// The rest should not be used when the frame is active.
FakeFrame *next;
};
struct FakeFrameFifo {
public:
void FifoPush(FakeFrame *node);
FakeFrame *FifoPop();
private:
FakeFrame *first_, *last_;
};
template<uptr kMaxNumberOfFrames>
class FakeFrameLifo {
public:
explicit FakeFrameLifo(LinkerInitialized) {}
FakeFrameLifo() : n_frames_(0) {}
void LifoPush(FakeFrame *node) {
CHECK_LT(n_frames_, kMaxNumberOfFrames);
frames_[n_frames_++] = node;
}
void LifoPop() {
CHECK(n_frames_);
n_frames_--;
}
FakeFrame *top() {
if (n_frames_ == 0)
return 0;
return frames_[n_frames_ - 1];
}
private:
uptr n_frames_;
FakeFrame *frames_[kMaxNumberOfFrames];
};
// For each thread we create a fake stack and place stack objects on this fake
// stack instead of the real stack. The fake stack is not really a stack but
// a fast malloc-like allocator so that when a function exits the fake stack
// is not poped but remains there for quite some time until gets used again.
// So, we poison the objects on the fake stack when function returns.
// It helps us find use-after-return bugs.
// We can not rely on __asan_stack_free being called on every function exit,
// so we maintain a lifo list of all current fake frames and update it on every
// call to __asan_stack_malloc.
class FakeStack {
public:
FakeStack();
explicit FakeStack(LinkerInitialized x) : call_stack_(x) {}
void Init(uptr stack_size);
void StopUsingFakeStack() { alive_ = false; }
void Cleanup();
uptr AllocateStack(uptr size, uptr real_stack);
static void OnFree(uptr ptr, uptr size, uptr real_stack);
// Return the bottom of the maped region.
uptr AddrIsInFakeStack(uptr addr);
bool StackSize() { return stack_size_; }
private:
static const uptr kMinStackFrameSizeLog = 9; // Min frame is 512B.
static const uptr kMaxStackFrameSizeLog = 16; // Max stack frame is 64K.
static const uptr kMaxStackMallocSize = 1 << kMaxStackFrameSizeLog;
static const uptr kNumberOfSizeClasses =
kMaxStackFrameSizeLog - kMinStackFrameSizeLog + 1;
static const uptr kMaxRecursionDepth = 1023;
bool AddrIsInSizeClass(uptr addr, uptr size_class);
// Each size class should be large enough to hold all frames.
uptr ClassMmapSize(uptr size_class);
uptr ClassSize(uptr size_class) {
return 1UL << (size_class + kMinStackFrameSizeLog);
}
void DeallocateFrame(FakeFrame *fake_frame);
uptr ComputeSizeClass(uptr alloc_size);
void AllocateOneSizeClass(uptr size_class);
uptr stack_size_;
bool alive_;
uptr allocated_size_classes_[kNumberOfSizeClasses];
FakeFrameFifo size_classes_[kNumberOfSizeClasses];
FakeFrameLifo<kMaxRecursionDepth> call_stack_;
};
} // namespace __asan
#endif // ASAN_FAKE_STACK_H

View File

@ -15,13 +15,15 @@
#ifndef ASAN_FLAGS_H
#define ASAN_FLAGS_H
#include "sanitizer/common_interface_defs.h"
#include "sanitizer_common/sanitizer_internal_defs.h"
// ASan flag values can be defined in three ways:
// ASan flag values can be defined in four ways:
// 1) initialized with default values at startup.
// 2) overriden from string returned by user-specified function
// 2) overriden during compilation of ASan runtime by providing
// compile definition ASAN_DEFAULT_OPTIONS.
// 3) overriden from string returned by user-specified function
// __asan_default_options().
// 3) overriden from env variable ASAN_OPTIONS.
// 4) overriden from env variable ASAN_OPTIONS.
namespace __asan {
@ -30,8 +32,6 @@ struct Flags {
// Lower value may reduce memory usage but increase the chance of
// false negatives.
int quarantine_size;
// If set, uses in-process symbolizer from common sanitizer runtime.
bool symbolize;
// Verbosity level (0 - silent, 1 - a bit of output, 2+ - more output).
int verbosity;
// Size (in bytes) of redzones around heap objects.
@ -45,22 +45,18 @@ struct Flags {
int report_globals;
// If set, attempts to catch initialization order issues.
bool check_initialization_order;
// Max number of stack frames kept for each allocation/deallocation.
int malloc_context_size;
// If set, uses custom wrappers and replacements for libc string functions
// to find more errors.
bool replace_str;
// If set, uses custom wrappers for memset/memcpy/memmove intinsics.
bool replace_intrin;
// Used on Mac only. See comments in asan_mac.cc and asan_malloc_mac.cc.
bool replace_cfallocator;
// Used on Mac only.
bool mac_ignore_invalid_free;
// ASan allocator flag. See asan_allocator.cc.
// ASan allocator flag.
bool use_fake_stack;
// ASan allocator flag. Sets the maximal size of allocation request
// that would return memory filled with zero bytes.
int max_malloc_fill_size;
// ASan allocator flag. max_malloc_fill_size is the maximal amount of bytes
// that will be filled with malloc_fill_byte on malloc.
int max_malloc_fill_size, malloc_fill_byte;
// Override exit status if something was reported.
int exitcode;
// If set, user may manually mark memory regions as poisoned or unpoisoned.
@ -71,6 +67,8 @@ struct Flags {
int sleep_before_dying;
// If set, registers ASan custom segv handler.
bool handle_segv;
// If set, allows user register segv handler even if ASan registers one.
bool allow_user_segv_handler;
// If set, uses alternate stack for signal handling.
bool use_sigaltstack;
// Allow the users to work around the bug in Nvidia drivers prior to 295.*.
@ -79,6 +77,10 @@ struct Flags {
bool unmap_shadow_on_exit;
// If set, calls abort() instead of _exit() after printing an error report.
bool abort_on_error;
// Print various statistics after printing an error message or if atexit=1.
bool print_stats;
// Print the legend for the shadow bytes.
bool print_legend;
// If set, prints ASan exit stats even after program terminates successfully.
bool atexit;
// By default, disable core dumper on 64-bit - it makes little sense
@ -87,18 +89,12 @@ struct Flags {
// Allow the tool to re-exec the program. This may interfere badly with the
// debugger.
bool allow_reexec;
// Strips this prefix from file paths in error reports.
const char *strip_path_prefix;
// If set, prints not only thread creation stacks for threads in error report,
// but also thread creation stacks for threads that created those threads,
// etc. up to main thread.
bool print_full_thread_history;
// ASan will write logs to "log_path.pid" instead of stderr.
const char *log_path;
// Use fast (frame-pointer-based) unwinder on fatal errors (if available).
bool fast_unwind_on_fatal;
// Use fast (frame-pointer-based) unwinder on malloc/free (if available).
bool fast_unwind_on_malloc;
// Poison (or not) the heap memory on [de]allocation. Zero value is useful
// for benchmarking the allocator or instrumentator.
bool poison_heap;
@ -106,9 +102,20 @@ struct Flags {
bool alloc_dealloc_mismatch;
// Use stack depot instead of storing stacks in the redzones.
bool use_stack_depot;
// If true, assume that memcmp(p1, p2, n) always reads n bytes before
// comparing p1 and p2.
bool strict_memcmp;
// If true, assume that dynamic initializers can never access globals from
// other modules, even if the latter are already initialized.
bool strict_init_order;
// Invoke LeakSanitizer at process exit.
bool detect_leaks;
};
Flags *flags();
extern Flags asan_flags_dont_use_directly;
inline Flags *flags() {
return &asan_flags_dont_use_directly;
}
void InitializeFlags(Flags *f, const char *env);
} // namespace __asan

View File

@ -14,12 +14,14 @@
#include "asan_interceptors.h"
#include "asan_internal.h"
#include "asan_mapping.h"
#include "asan_poisoning.h"
#include "asan_report.h"
#include "asan_stack.h"
#include "asan_stats.h"
#include "asan_thread.h"
#include "sanitizer/asan_interface.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_mutex.h"
#include "sanitizer_common/sanitizer_placement_new.h"
namespace __asan {
@ -33,38 +35,48 @@ struct ListOfGlobals {
static BlockingMutex mu_for_globals(LINKER_INITIALIZED);
static LowLevelAllocator allocator_for_globals;
static ListOfGlobals *list_of_all_globals;
static ListOfGlobals *list_of_dynamic_init_globals;
void PoisonRedZones(const Global &g) {
uptr shadow_rz_size = kGlobalAndStackRedzone >> SHADOW_SCALE;
CHECK(shadow_rz_size == 1 || shadow_rz_size == 2 || shadow_rz_size == 4);
// full right redzone
uptr g_aligned_size = kGlobalAndStackRedzone *
((g.size + kGlobalAndStackRedzone - 1) / kGlobalAndStackRedzone);
PoisonShadow(g.beg + g_aligned_size,
kGlobalAndStackRedzone, kAsanGlobalRedzoneMagic);
if ((g.size % kGlobalAndStackRedzone) != 0) {
// partial right redzone
u64 g_aligned_down_size = kGlobalAndStackRedzone *
(g.size / kGlobalAndStackRedzone);
CHECK(g_aligned_down_size == g_aligned_size - kGlobalAndStackRedzone);
PoisonShadowPartialRightRedzone(g.beg + g_aligned_down_size,
g.size % kGlobalAndStackRedzone,
kGlobalAndStackRedzone,
kAsanGlobalRedzoneMagic);
static const int kDynamicInitGlobalsInitialCapacity = 512;
struct DynInitGlobal {
Global g;
bool initialized;
};
typedef InternalVector<DynInitGlobal> VectorOfGlobals;
// Lazy-initialized and never deleted.
static VectorOfGlobals *dynamic_init_globals;
ALWAYS_INLINE void PoisonShadowForGlobal(const Global *g, u8 value) {
FastPoisonShadow(g->beg, g->size_with_redzone, value);
}
ALWAYS_INLINE void PoisonRedZones(const Global &g) {
uptr aligned_size = RoundUpTo(g.size, SHADOW_GRANULARITY);
FastPoisonShadow(g.beg + aligned_size, g.size_with_redzone - aligned_size,
kAsanGlobalRedzoneMagic);
if (g.size != aligned_size) {
FastPoisonShadowPartialRightRedzone(
g.beg + RoundDownTo(g.size, SHADOW_GRANULARITY),
g.size % SHADOW_GRANULARITY,
SHADOW_GRANULARITY,
kAsanGlobalRedzoneMagic);
}
}
bool DescribeAddressIfGlobal(uptr addr) {
static void ReportGlobal(const Global &g, const char *prefix) {
Report("%s Global: beg=%p size=%zu/%zu name=%s module=%s dyn_init=%zu\n",
prefix, (void*)g.beg, g.size, g.size_with_redzone, g.name,
g.module_name, g.has_dynamic_init);
}
bool DescribeAddressIfGlobal(uptr addr, uptr size) {
if (!flags()->report_globals) return false;
BlockingMutexLock lock(&mu_for_globals);
bool res = false;
for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
const Global &g = *l->g;
if (flags()->report_globals >= 2)
Report("Search Global: beg=%p size=%zu name=%s\n",
(void*)g.beg, g.size, (char*)g.name);
res |= DescribeAddressRelativeToGlobal(addr, g);
ReportGlobal(g, "Search");
res |= DescribeAddressRelativeToGlobal(addr, size, g);
}
return res;
}
@ -75,24 +87,26 @@ bool DescribeAddressIfGlobal(uptr addr) {
static void RegisterGlobal(const Global *g) {
CHECK(asan_inited);
if (flags()->report_globals >= 2)
Report("Added Global: beg=%p size=%zu/%zu name=%s dyn.init=%zu\n",
(void*)g->beg, g->size, g->size_with_redzone, g->name,
g->has_dynamic_init);
ReportGlobal(*g, "Added");
CHECK(flags()->report_globals);
CHECK(AddrIsInMem(g->beg));
CHECK(AddrIsAlignedByGranularity(g->beg));
CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
PoisonRedZones(*g);
if (flags()->poison_heap)
PoisonRedZones(*g);
ListOfGlobals *l =
(ListOfGlobals*)allocator_for_globals.Allocate(sizeof(ListOfGlobals));
l->g = g;
l->next = list_of_all_globals;
list_of_all_globals = l;
if (g->has_dynamic_init) {
l = (ListOfGlobals*)allocator_for_globals.Allocate(sizeof(ListOfGlobals));
l->g = g;
l->next = list_of_dynamic_init_globals;
list_of_dynamic_init_globals = l;
if (dynamic_init_globals == 0) {
void *mem = allocator_for_globals.Allocate(sizeof(VectorOfGlobals));
dynamic_init_globals = new(mem)
VectorOfGlobals(kDynamicInitGlobalsInitialCapacity);
}
DynInitGlobal dyn_global = { *g, false };
dynamic_init_globals->push_back(dyn_global);
}
}
@ -102,34 +116,26 @@ static void UnregisterGlobal(const Global *g) {
CHECK(AddrIsInMem(g->beg));
CHECK(AddrIsAlignedByGranularity(g->beg));
CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
PoisonShadow(g->beg, g->size_with_redzone, 0);
if (flags()->poison_heap)
PoisonShadowForGlobal(g, 0);
// We unpoison the shadow memory for the global but we do not remove it from
// the list because that would require O(n^2) time with the current list
// implementation. It might not be worth doing anyway.
}
// Poison all shadow memory for a single global.
static void PoisonGlobalAndRedzones(const Global *g) {
CHECK(asan_inited);
CHECK(flags()->check_initialization_order);
CHECK(AddrIsInMem(g->beg));
CHECK(AddrIsAlignedByGranularity(g->beg));
CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
if (flags()->report_globals >= 3)
Printf("DynInitPoison : %s\n", g->name);
PoisonShadow(g->beg, g->size_with_redzone, kAsanInitializationOrderMagic);
}
static void UnpoisonGlobal(const Global *g) {
CHECK(asan_inited);
CHECK(flags()->check_initialization_order);
CHECK(AddrIsInMem(g->beg));
CHECK(AddrIsAlignedByGranularity(g->beg));
CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
if (flags()->report_globals >= 3)
Printf("DynInitUnpoison: %s\n", g->name);
PoisonShadow(g->beg, g->size_with_redzone, 0);
PoisonRedZones(*g);
void StopInitOrderChecking() {
BlockingMutexLock lock(&mu_for_globals);
if (!flags()->check_initialization_order || !dynamic_init_globals)
return;
flags()->check_initialization_order = false;
for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) {
DynInitGlobal &dyn_g = (*dynamic_init_globals)[i];
const Global *g = &dyn_g.g;
// Unpoison the whole global.
PoisonShadowForGlobal(g, 0);
// Poison redzones back.
PoisonRedZones(*g);
}
}
} // namespace __asan
@ -160,31 +166,47 @@ void __asan_unregister_globals(__asan_global *globals, uptr n) {
// when all dynamically initialized globals are unpoisoned. This method
// poisons all global variables not defined in this TU, so that a dynamic
// initializer can only touch global variables in the same TU.
void __asan_before_dynamic_init(uptr first_addr, uptr last_addr) {
if (!flags()->check_initialization_order) return;
CHECK(list_of_dynamic_init_globals);
void __asan_before_dynamic_init(const char *module_name) {
if (!flags()->check_initialization_order ||
!flags()->poison_heap)
return;
bool strict_init_order = flags()->strict_init_order;
CHECK(dynamic_init_globals);
CHECK(module_name);
CHECK(asan_inited);
BlockingMutexLock lock(&mu_for_globals);
bool from_current_tu = false;
// The list looks like:
// a => ... => b => last_addr => ... => first_addr => c => ...
// The globals of the current TU reside between last_addr and first_addr.
for (ListOfGlobals *l = list_of_dynamic_init_globals; l; l = l->next) {
if (l->g->beg == last_addr)
from_current_tu = true;
if (!from_current_tu)
PoisonGlobalAndRedzones(l->g);
if (l->g->beg == first_addr)
from_current_tu = false;
if (flags()->report_globals >= 3)
Printf("DynInitPoison module: %s\n", module_name);
for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) {
DynInitGlobal &dyn_g = (*dynamic_init_globals)[i];
const Global *g = &dyn_g.g;
if (dyn_g.initialized)
continue;
if (g->module_name != module_name)
PoisonShadowForGlobal(g, kAsanInitializationOrderMagic);
else if (!strict_init_order)
dyn_g.initialized = true;
}
CHECK(!from_current_tu);
}
// This method runs immediately after dynamic initialization in each TU, when
// all dynamically initialized globals except for those defined in the current
// TU are poisoned. It simply unpoisons all dynamically initialized globals.
void __asan_after_dynamic_init() {
if (!flags()->check_initialization_order) return;
if (!flags()->check_initialization_order ||
!flags()->poison_heap)
return;
CHECK(asan_inited);
BlockingMutexLock lock(&mu_for_globals);
for (ListOfGlobals *l = list_of_dynamic_init_globals; l; l = l->next)
UnpoisonGlobal(l->g);
// FIXME: Optionally report that we're unpoisoning globals from a module.
for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) {
DynInitGlobal &dyn_g = (*dynamic_init_globals)[i];
const Global *g = &dyn_g.g;
if (!dyn_g.initialized) {
// Unpoison the whole global.
PoisonShadowForGlobal(g, 0);
// Poison redzones back.
PoisonRedZones(*g);
}
}
}

View File

@ -19,16 +19,16 @@
#include "sanitizer_common/sanitizer_platform_interceptors.h"
#include <stdarg.h>
#include <stddef.h>
using __sanitizer::uptr;
// Use macro to describe if specific function should be
// intercepted on a given platform.
#if !defined(_WIN32)
#if !SANITIZER_WINDOWS
# define ASAN_INTERCEPT_ATOLL_AND_STRTOLL 1
# define ASAN_INTERCEPT__LONGJMP 1
# define ASAN_INTERCEPT_STRDUP 1
# define ASAN_INTERCEPT_STRCASECMP_AND_STRNCASECMP 1
# define ASAN_INTERCEPT_INDEX 1
# define ASAN_INTERCEPT_PTHREAD_CREATE 1
# define ASAN_INTERCEPT_MLOCKX 1
@ -36,225 +36,79 @@ using __sanitizer::uptr;
# define ASAN_INTERCEPT_ATOLL_AND_STRTOLL 0
# define ASAN_INTERCEPT__LONGJMP 0
# define ASAN_INTERCEPT_STRDUP 0
# define ASAN_INTERCEPT_STRCASECMP_AND_STRNCASECMP 0
# define ASAN_INTERCEPT_INDEX 0
# define ASAN_INTERCEPT_PTHREAD_CREATE 0
# define ASAN_INTERCEPT_MLOCKX 0
#endif
#if defined(__linux__)
#if SANITIZER_LINUX
# define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 1
#else
# define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 0
#endif
#if !defined(__APPLE__)
#if !SANITIZER_MAC
# define ASAN_INTERCEPT_STRNLEN 1
#else
# define ASAN_INTERCEPT_STRNLEN 0
#endif
#if defined(__linux__) && !defined(ANDROID)
#if SANITIZER_LINUX && !SANITIZER_ANDROID
# define ASAN_INTERCEPT_SWAPCONTEXT 1
#else
# define ASAN_INTERCEPT_SWAPCONTEXT 0
#endif
#if !defined(ANDROID) && !defined(_WIN32)
#if !SANITIZER_ANDROID && !SANITIZER_WINDOWS
# define ASAN_INTERCEPT_SIGNAL_AND_SIGACTION 1
#else
# define ASAN_INTERCEPT_SIGNAL_AND_SIGACTION 0
#endif
// On Darwin siglongjmp tailcalls longjmp, so we don't want to intercept it
// there.
#if !defined(_WIN32) && (!defined(__APPLE__) || MAC_INTERPOSE_FUNCTIONS)
#if !SANITIZER_WINDOWS
# define ASAN_INTERCEPT_SIGLONGJMP 1
#else
# define ASAN_INTERCEPT_SIGLONGJMP 0
#endif
#if ASAN_HAS_EXCEPTIONS && !defined(_WIN32)
#if ASAN_HAS_EXCEPTIONS && !SANITIZER_WINDOWS
# define ASAN_INTERCEPT___CXA_THROW 1
#else
# define ASAN_INTERCEPT___CXA_THROW 0
#endif
#define DECLARE_FUNCTION_AND_WRAPPER(ret_type, func, ...) \
ret_type func(__VA_ARGS__); \
ret_type WRAP(func)(__VA_ARGS__)
#if !SANITIZER_WINDOWS
# define ASAN_INTERCEPT___CXA_ATEXIT 1
#else
# define ASAN_INTERCEPT___CXA_ATEXIT 0
#endif
// Use extern declarations of intercepted functions on Mac and Windows
// to avoid including system headers.
#if defined(__APPLE__) || (defined(_WIN32) && !defined(_DLL))
# if SANITIZER_WINDOWS
extern "C" {
// signal.h
# if ASAN_INTERCEPT_SIGNAL_AND_SIGACTION
struct sigaction;
DECLARE_FUNCTION_AND_WRAPPER(int, sigaction, int sig,
const struct sigaction *act,
struct sigaction *oldact);
DECLARE_FUNCTION_AND_WRAPPER(void*, signal, int signum, void *handler);
# endif
// setjmp.h
DECLARE_FUNCTION_AND_WRAPPER(void, longjmp, void *env, int value);
# if ASAN_INTERCEPT__LONGJMP
DECLARE_FUNCTION_AND_WRAPPER(void, _longjmp, void *env, int value);
# endif
# if ASAN_INTERCEPT_SIGLONGJMP
DECLARE_FUNCTION_AND_WRAPPER(void, siglongjmp, void *env, int value);
# endif
# if ASAN_INTERCEPT___CXA_THROW
DECLARE_FUNCTION_AND_WRAPPER(void, __cxa_throw, void *a, void *b, void *c);
#endif
// string.h / strings.h
DECLARE_FUNCTION_AND_WRAPPER(int, memcmp,
const void *a1, const void *a2, uptr size);
DECLARE_FUNCTION_AND_WRAPPER(void*, memmove,
void *to, const void *from, uptr size);
DECLARE_FUNCTION_AND_WRAPPER(void*, memcpy,
void *to, const void *from, uptr size);
DECLARE_FUNCTION_AND_WRAPPER(void*, memset, void *block, int c, uptr size);
DECLARE_FUNCTION_AND_WRAPPER(char*, strchr, const char *str, int c);
DECLARE_FUNCTION_AND_WRAPPER(char*, strcat, /* NOLINT */
char *to, const char* from);
DECLARE_FUNCTION_AND_WRAPPER(char*, strncat,
char *to, const char* from, uptr size);
DECLARE_FUNCTION_AND_WRAPPER(char*, strcpy, /* NOLINT */
char *to, const char* from);
DECLARE_FUNCTION_AND_WRAPPER(char*, strncpy,
char *to, const char* from, uptr size);
DECLARE_FUNCTION_AND_WRAPPER(int, strcmp, const char *s1, const char* s2);
DECLARE_FUNCTION_AND_WRAPPER(int, strncmp,
const char *s1, const char* s2, uptr size);
DECLARE_FUNCTION_AND_WRAPPER(uptr, strlen, const char *s);
# if ASAN_INTERCEPT_STRCASECMP_AND_STRNCASECMP
DECLARE_FUNCTION_AND_WRAPPER(int, strcasecmp, const char *s1, const char *s2);
DECLARE_FUNCTION_AND_WRAPPER(int, strncasecmp,
const char *s1, const char *s2, uptr n);
# endif
# if ASAN_INTERCEPT_STRDUP
DECLARE_FUNCTION_AND_WRAPPER(char*, strdup, const char *s);
# endif
# if ASAN_INTERCEPT_STRNLEN
DECLARE_FUNCTION_AND_WRAPPER(uptr, strnlen, const char *s, uptr maxlen);
# endif
#if ASAN_INTERCEPT_INDEX
DECLARE_FUNCTION_AND_WRAPPER(char*, index, const char *string, int c);
#endif
// stdlib.h
DECLARE_FUNCTION_AND_WRAPPER(int, atoi, const char *nptr);
DECLARE_FUNCTION_AND_WRAPPER(long, atol, const char *nptr); // NOLINT
DECLARE_FUNCTION_AND_WRAPPER(long, strtol, const char *nptr, char **endptr, int base); // NOLINT
# if ASAN_INTERCEPT_ATOLL_AND_STRTOLL
DECLARE_FUNCTION_AND_WRAPPER(long long, atoll, const char *nptr); // NOLINT
DECLARE_FUNCTION_AND_WRAPPER(long long, strtoll, const char *nptr, char **endptr, int base); // NOLINT
# endif
// unistd.h
# if SANITIZER_INTERCEPT_READ
DECLARE_FUNCTION_AND_WRAPPER(SSIZE_T, read, int fd, void *buf, SIZE_T count);
# endif
# if SANITIZER_INTERCEPT_PREAD
DECLARE_FUNCTION_AND_WRAPPER(SSIZE_T, pread, int fd, void *buf,
SIZE_T count, OFF_T offset);
# endif
# if SANITIZER_INTERCEPT_PREAD64
DECLARE_FUNCTION_AND_WRAPPER(SSIZE_T, pread64, int fd, void *buf,
SIZE_T count, OFF64_T offset);
# endif
#if SANITIZER_INTERCEPT_WRITE
DECLARE_FUNCTION_AND_WRAPPER(SSIZE_T, write, int fd, void *ptr, SIZE_T count);
#endif
#if SANITIZER_INTERCEPT_PWRITE
DECLARE_FUNCTION_AND_WRAPPER(SSIZE_T, pwrite, int fd, void *ptr, SIZE_T count);
#endif
# if ASAN_INTERCEPT_MLOCKX
// mlock/munlock
DECLARE_FUNCTION_AND_WRAPPER(int, mlock, const void *addr, SIZE_T len);
DECLARE_FUNCTION_AND_WRAPPER(int, munlock, const void *addr, SIZE_T len);
DECLARE_FUNCTION_AND_WRAPPER(int, mlockall, int flags);
DECLARE_FUNCTION_AND_WRAPPER(int, munlockall, void);
# endif
// Windows threads.
# if defined(_WIN32)
__declspec(dllimport)
void* __stdcall CreateThread(void *sec, uptr st, void* start,
void *arg, DWORD fl, DWORD *id);
int memcmp(const void *a1, const void *a2, uptr size);
void memmove(void *to, const void *from, uptr size);
void* memset(void *block, int c, uptr size);
void* memcpy(void *to, const void *from, uptr size);
char* strcat(char *to, const char* from); // NOLINT
char* strchr(const char *str, int c);
int strcmp(const char *s1, const char* s2);
char* strcpy(char *to, const char* from); // NOLINT
uptr strlen(const char *s);
char* strncat(char *to, const char* from, uptr size);
int strncmp(const char *s1, const char* s2, uptr size);
char* strncpy(char *to, const char* from, uptr size);
uptr strnlen(const char *s, uptr maxlen);
int atoi(const char *nptr);
long atol(const char *nptr); // NOLINT
long strtol(const char *nptr, char **endptr, int base); // NOLINT
void longjmp(void *env, int value);
double frexp(double x, int *expptr);
}
# endif
// Posix threads.
# if ASAN_INTERCEPT_PTHREAD_CREATE
DECLARE_FUNCTION_AND_WRAPPER(int, pthread_create,
void *thread, void *attr,
void *(*start_routine)(void*), void *arg);
# endif
#if defined(__APPLE__)
typedef void* pthread_workqueue_t;
typedef void* pthread_workitem_handle_t;
typedef void* dispatch_group_t;
typedef void* dispatch_queue_t;
typedef void* dispatch_source_t;
typedef u64 dispatch_time_t;
typedef void (*dispatch_function_t)(void *block);
typedef void* (*worker_t)(void *block);
typedef void* CFStringRef;
typedef void* CFAllocatorRef;
DECLARE_FUNCTION_AND_WRAPPER(void, dispatch_async_f,
dispatch_queue_t dq,
void *ctxt, dispatch_function_t func);
DECLARE_FUNCTION_AND_WRAPPER(void, dispatch_sync_f,
dispatch_queue_t dq,
void *ctxt, dispatch_function_t func);
DECLARE_FUNCTION_AND_WRAPPER(void, dispatch_after_f,
dispatch_time_t when, dispatch_queue_t dq,
void *ctxt, dispatch_function_t func);
DECLARE_FUNCTION_AND_WRAPPER(void, dispatch_barrier_async_f,
dispatch_queue_t dq,
void *ctxt, dispatch_function_t func);
DECLARE_FUNCTION_AND_WRAPPER(void, dispatch_group_async_f,
dispatch_group_t group, dispatch_queue_t dq,
void *ctxt, dispatch_function_t func);
DECLARE_FUNCTION_AND_WRAPPER(void, __CFInitialize, void);
DECLARE_FUNCTION_AND_WRAPPER(CFStringRef, CFStringCreateCopy,
CFAllocatorRef alloc, CFStringRef str);
DECLARE_FUNCTION_AND_WRAPPER(void, free, void* ptr);
DECLARE_FUNCTION_AND_WRAPPER(int, vscanf, const char *format, va_list ap);
DECLARE_FUNCTION_AND_WRAPPER(int, vsscanf, const char *str, const char *format,
va_list ap);
DECLARE_FUNCTION_AND_WRAPPER(int, vfscanf, void *stream, const char *format,
va_list ap);
DECLARE_FUNCTION_AND_WRAPPER(int, scanf, const char *format, ...);
DECLARE_FUNCTION_AND_WRAPPER(int, fscanf,
void* stream, const char *format, ...);
DECLARE_FUNCTION_AND_WRAPPER(int, sscanf, // NOLINT
const char *str, const char *format, ...);
#if MAC_INTERPOSE_FUNCTIONS && !defined(MISSING_BLOCKS_SUPPORT)
DECLARE_FUNCTION_AND_WRAPPER(void, dispatch_group_async,
dispatch_group_t dg,
dispatch_queue_t dq, void (^work)(void));
DECLARE_FUNCTION_AND_WRAPPER(void, dispatch_async,
dispatch_queue_t dq, void (^work)(void));
DECLARE_FUNCTION_AND_WRAPPER(void, dispatch_after,
dispatch_queue_t dq, void (^work)(void));
DECLARE_FUNCTION_AND_WRAPPER(void, dispatch_source_set_event_handler,
dispatch_source_t ds, void (^work)(void));
DECLARE_FUNCTION_AND_WRAPPER(void, dispatch_source_set_cancel_handler,
dispatch_source_t ds, void (^work)(void));
#endif // MAC_INTERPOSE_FUNCTIONS
#endif // __APPLE__
} // extern "C"
#endif
#endif // ASAN_INTERCEPTED_FUNCTIONS_H

View File

@ -17,27 +17,40 @@
#include "asan_intercepted_functions.h"
#include "asan_internal.h"
#include "asan_mapping.h"
#include "asan_poisoning.h"
#include "asan_report.h"
#include "asan_stack.h"
#include "asan_stats.h"
#include "asan_thread_registry.h"
#include "interception/interception.h"
#include "sanitizer/asan_interface.h"
#include "sanitizer_common/sanitizer_libc.h"
namespace __asan {
// Return true if we can quickly decide that the region is unpoisoned.
static inline bool QuickCheckForUnpoisonedRegion(uptr beg, uptr size) {
if (size == 0) return true;
if (size <= 32)
return !AddressIsPoisoned(beg) &&
!AddressIsPoisoned(beg + size - 1) &&
!AddressIsPoisoned(beg + size / 2);
return false;
}
// We implement ACCESS_MEMORY_RANGE, ASAN_READ_RANGE,
// and ASAN_WRITE_RANGE as macro instead of function so
// that no extra frames are created, and stack trace contains
// relevant information only.
// We check all shadow bytes.
#define ACCESS_MEMORY_RANGE(offset, size, isWrite) do { \
if (uptr __ptr = __asan_region_is_poisoned((uptr)(offset), size)) { \
GET_CURRENT_PC_BP_SP; \
__asan_report_error(pc, bp, sp, __ptr, isWrite, /* access_size */1); \
} \
} while (0)
#define ACCESS_MEMORY_RANGE(offset, size, isWrite) do { \
uptr __offset = (uptr)(offset); \
uptr __size = (uptr)(size); \
uptr __bad = 0; \
if (!QuickCheckForUnpoisonedRegion(__offset, __size) && \
(__bad = __asan_region_is_poisoned(__offset, __size))) { \
GET_CURRENT_PC_BP_SP; \
__asan_report_error(pc, bp, sp, __bad, isWrite, __size); \
} \
} while (0)
#define ASAN_READ_RANGE(offset, size) ACCESS_MEMORY_RANGE(offset, size, false)
#define ASAN_WRITE_RANGE(offset, size) ACCESS_MEMORY_RANGE(offset, size, true);
@ -76,9 +89,14 @@ static inline uptr MaybeRealStrnlen(const char *s, uptr maxlen) {
}
void SetThreadName(const char *name) {
AsanThread *t = asanThreadRegistry().GetCurrent();
AsanThread *t = GetCurrentThread();
if (t)
t->summary()->set_name(name);
asanThreadRegistry().SetThreadName(t->tid(), name);
}
static void DisableStrictInitOrderChecker() {
if (flags()->strict_init_order)
flags()->check_initialization_order = false;
}
} // namespace __asan
@ -89,37 +107,54 @@ using namespace __asan; // NOLINT
#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \
ASAN_WRITE_RANGE(ptr, size)
#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) ASAN_READ_RANGE(ptr, size)
#define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \
do { \
ctx = 0; \
(void)ctx; \
ENSURE_ASAN_INITED(); \
#define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \
do { \
if (asan_init_is_running) \
return REAL(func)(__VA_ARGS__); \
ctx = 0; \
(void)ctx; \
ENSURE_ASAN_INITED(); \
} while (false)
#define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) do { } while (false)
#define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) do { } while (false)
#define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) SetThreadName(name)
#include "sanitizer_common/sanitizer_common_interceptors.inc"
#define COMMON_SYSCALL_PRE_READ_RANGE(p, s) ASAN_READ_RANGE(p, s)
#define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) ASAN_WRITE_RANGE(p, s)
#define COMMON_SYSCALL_POST_READ_RANGE(p, s)
#define COMMON_SYSCALL_POST_WRITE_RANGE(p, s)
#include "sanitizer_common/sanitizer_common_syscalls.inc"
static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {
AsanThread *t = (AsanThread*)arg;
asanThreadRegistry().SetCurrent(t);
return t->ThreadStart();
SetCurrentThread(t);
return t->ThreadStart(GetTid());
}
#if ASAN_INTERCEPT_PTHREAD_CREATE
extern "C" int pthread_attr_getdetachstate(void *attr, int *v);
INTERCEPTOR(int, pthread_create, void *thread,
void *attr, void *(*start_routine)(void*), void *arg) {
// Strict init-order checking in thread-hostile.
DisableStrictInitOrderChecker();
GET_STACK_TRACE_THREAD;
u32 current_tid = asanThreadRegistry().GetCurrentTidOrInvalid();
AsanThread *t = AsanThread::Create(current_tid, start_routine, arg, &stack);
asanThreadRegistry().RegisterThread(t);
int detached = 0;
if (attr != 0)
pthread_attr_getdetachstate(attr, &detached);
u32 current_tid = GetCurrentTidOrInvalid();
AsanThread *t = AsanThread::Create(start_routine, arg);
CreateThreadContextArgs args = { t, &stack };
asanThreadRegistry().CreateThread(*(uptr*)t, detached, current_tid, &args);
return REAL(pthread_create)(thread, attr, asan_thread_start, t);
}
#endif // ASAN_INTERCEPT_PTHREAD_CREATE
#if ASAN_INTERCEPT_SIGNAL_AND_SIGACTION
INTERCEPTOR(void*, signal, int signum, void *handler) {
if (!AsanInterceptsSignal(signum)) {
if (!AsanInterceptsSignal(signum) || flags()->allow_user_segv_handler) {
return REAL(signal)(signum, handler);
}
return 0;
@ -127,12 +162,12 @@ INTERCEPTOR(void*, signal, int signum, void *handler) {
INTERCEPTOR(int, sigaction, int signum, const struct sigaction *act,
struct sigaction *oldact) {
if (!AsanInterceptsSignal(signum)) {
if (!AsanInterceptsSignal(signum) || flags()->allow_user_segv_handler) {
return REAL(sigaction)(signum, act, oldact);
}
return 0;
}
#elif ASAN_POSIX
#elif SANITIZER_POSIX
// We need to have defined REAL(sigaction) on posix systems.
DEFINE_REAL(int, sigaction, int signum, const struct sigaction *act,
struct sigaction *oldact);
@ -237,27 +272,32 @@ static inline int CharCmp(unsigned char c1, unsigned char c2) {
return (c1 == c2) ? 0 : (c1 < c2) ? -1 : 1;
}
static inline int CharCaseCmp(unsigned char c1, unsigned char c2) {
int c1_low = ToLower(c1);
int c2_low = ToLower(c2);
return c1_low - c2_low;
}
INTERCEPTOR(int, memcmp, const void *a1, const void *a2, uptr size) {
if (!asan_inited) return internal_memcmp(a1, a2, size);
ENSURE_ASAN_INITED();
unsigned char c1 = 0, c2 = 0;
const unsigned char *s1 = (const unsigned char*)a1;
const unsigned char *s2 = (const unsigned char*)a2;
uptr i;
for (i = 0; i < size; i++) {
c1 = s1[i];
c2 = s2[i];
if (c1 != c2) break;
if (flags()->replace_intrin) {
if (flags()->strict_memcmp) {
// Check the entire regions even if the first bytes of the buffers are
// different.
ASAN_READ_RANGE(a1, size);
ASAN_READ_RANGE(a2, size);
// Fallthrough to REAL(memcmp) below.
} else {
unsigned char c1 = 0, c2 = 0;
const unsigned char *s1 = (const unsigned char*)a1;
const unsigned char *s2 = (const unsigned char*)a2;
uptr i;
for (i = 0; i < size; i++) {
c1 = s1[i];
c2 = s2[i];
if (c1 != c2) break;
}
ASAN_READ_RANGE(s1, Min(i + 1, size));
ASAN_READ_RANGE(s2, Min(i + 1, size));
return CharCmp(c1, c2);
}
}
ASAN_READ_RANGE(s1, Min(i + 1, size));
ASAN_READ_RANGE(s2, Min(i + 1, size));
return CharCmp(c1, c2);
return REAL(memcmp(a1, a2, size));
}
INTERCEPTOR(void*, memcpy, void *to, const void *from, uptr size) {
@ -277,13 +317,9 @@ INTERCEPTOR(void*, memcpy, void *to, const void *from, uptr size) {
ASAN_READ_RANGE(from, size);
ASAN_WRITE_RANGE(to, size);
}
#if MAC_INTERPOSE_FUNCTIONS
// Interposing of resolver functions is broken on Mac OS 10.7 and 10.8.
// See also http://code.google.com/p/address-sanitizer/issues/detail?id=116.
return internal_memcpy(to, from, size);
#else
return REAL(memcpy)(to, from, size);
#endif
}
INTERCEPTOR(void*, memmove, void *to, const void *from, uptr size) {
@ -296,13 +332,9 @@ INTERCEPTOR(void*, memmove, void *to, const void *from, uptr size) {
ASAN_READ_RANGE(from, size);
ASAN_WRITE_RANGE(to, size);
}
#if MAC_INTERPOSE_FUNCTIONS
// Interposing of resolver functions is broken on Mac OS 10.7 and 10.8.
// See also http://code.google.com/p/address-sanitizer/issues/detail?id=116.
return internal_memmove(to, from, size);
#else
return REAL(memmove)(to, from, size);
#endif
}
INTERCEPTOR(void*, memset, void *block, int c, uptr size) {
@ -339,7 +371,12 @@ INTERCEPTOR(char*, strchr, const char *str, int c) {
INTERCEPTOR(char*, index, const char *string, int c)
ALIAS(WRAPPER_NAME(strchr));
# else
DEFINE_REAL(char*, index, const char *string, int c)
# if SANITIZER_MAC
DECLARE_REAL(char*, index, const char *string, int c)
OVERRIDE_FUNCTION(index, strchr);
# else
DEFINE_REAL(char*, index, const char *string, int c);
# endif
# endif
#endif // ASAN_INTERCEPT_INDEX
@ -400,7 +437,7 @@ INTERCEPTOR(int, strcmp, const char *s1, const char *s2) {
}
INTERCEPTOR(char*, strcpy, char *to, const char *from) { // NOLINT
#if MAC_INTERPOSE_FUNCTIONS
#if SANITIZER_MAC
if (!asan_inited) return REAL(strcpy)(to, from); // NOLINT
#endif
// strcpy is called from malloc_default_purgeable_zone()
@ -420,7 +457,7 @@ INTERCEPTOR(char*, strcpy, char *to, const char *from) { // NOLINT
#if ASAN_INTERCEPT_STRDUP
INTERCEPTOR(char*, strdup, const char *s) {
#if MAC_INTERPOSE_FUNCTIONS
#if SANITIZER_MAC
// FIXME: because internal_strdup() uses InternalAlloc(), which currently
// just calls malloc() on Mac, we can't use internal_strdup() with the
// dynamic runtime. We can remove the call to REAL(strdup) once InternalAlloc
@ -453,36 +490,6 @@ INTERCEPTOR(uptr, strlen, const char *s) {
return length;
}
#if ASAN_INTERCEPT_STRCASECMP_AND_STRNCASECMP
INTERCEPTOR(int, strcasecmp, const char *s1, const char *s2) {
ENSURE_ASAN_INITED();
unsigned char c1, c2;
uptr i;
for (i = 0; ; i++) {
c1 = (unsigned char)s1[i];
c2 = (unsigned char)s2[i];
if (CharCaseCmp(c1, c2) != 0 || c1 == '\0') break;
}
ASAN_READ_RANGE(s1, i + 1);
ASAN_READ_RANGE(s2, i + 1);
return CharCaseCmp(c1, c2);
}
INTERCEPTOR(int, strncasecmp, const char *s1, const char *s2, uptr n) {
ENSURE_ASAN_INITED();
unsigned char c1 = 0, c2 = 0;
uptr i;
for (i = 0; i < n; i++) {
c1 = (unsigned char)s1[i];
c2 = (unsigned char)s2[i];
if (CharCaseCmp(c1, c2) != 0 || c1 == '\0') break;
}
ASAN_READ_RANGE(s1, Min(i + 1, n));
ASAN_READ_RANGE(s2, Min(i + 1, n));
return CharCaseCmp(c1, c2);
}
#endif // ASAN_INTERCEPT_STRCASECMP_AND_STRNCASECMP
INTERCEPTOR(int, strncmp, const char *s1, const char *s2, uptr size) {
if (!asan_inited) return internal_strncmp(s1, s2, size);
// strncmp is called from malloc_default_purgeable_zone()
@ -530,7 +537,7 @@ static inline bool IsValidStrtolBase(int base) {
}
static inline void FixRealStrtolEndptr(const char *nptr, char **endptr) {
CHECK(endptr != 0);
CHECK(endptr);
if (nptr == *endptr) {
// No digits were found at strtol call, we need to find out the last
// symbol accessed by strtoll on our own.
@ -561,7 +568,7 @@ INTERCEPTOR(long, strtol, const char *nptr, // NOLINT
}
INTERCEPTOR(int, atoi, const char *nptr) {
#if MAC_INTERPOSE_FUNCTIONS
#if SANITIZER_MAC
if (!asan_inited) return REAL(atoi)(nptr);
#endif
ENSURE_ASAN_INITED();
@ -580,7 +587,7 @@ INTERCEPTOR(int, atoi, const char *nptr) {
}
INTERCEPTOR(long, atol, const char *nptr) { // NOLINT
#if MAC_INTERPOSE_FUNCTIONS
#if SANITIZER_MAC
if (!asan_inited) return REAL(atol)(nptr);
#endif
ENSURE_ASAN_INITED();
@ -629,20 +636,39 @@ INTERCEPTOR(long long, atoll, const char *nptr) { // NOLINT
}
#endif // ASAN_INTERCEPT_ATOLL_AND_STRTOLL
static void AtCxaAtexit(void *unused) {
(void)unused;
StopInitOrderChecking();
}
#if ASAN_INTERCEPT___CXA_ATEXIT
INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
void *dso_handle) {
ENSURE_ASAN_INITED();
int res = REAL(__cxa_atexit)(func, arg, dso_handle);
REAL(__cxa_atexit)(AtCxaAtexit, 0, 0);
return res;
}
#endif // ASAN_INTERCEPT___CXA_ATEXIT
#define ASAN_INTERCEPT_FUNC(name) do { \
if (!INTERCEPT_FUNCTION(name) && flags()->verbosity > 0) \
Report("AddressSanitizer: failed to intercept '" #name "'\n"); \
} while (0)
#if defined(_WIN32)
#if SANITIZER_WINDOWS
INTERCEPTOR_WINAPI(DWORD, CreateThread,
void* security, uptr stack_size,
DWORD (__stdcall *start_routine)(void*), void* arg,
DWORD flags, void* tid) {
// Strict init-order checking in thread-hostile.
DisableStrictInitOrderChecker();
GET_STACK_TRACE_THREAD;
u32 current_tid = asanThreadRegistry().GetCurrentTidOrInvalid();
AsanThread *t = AsanThread::Create(current_tid, start_routine, arg, &stack);
asanThreadRegistry().RegisterThread(t);
u32 current_tid = GetCurrentTidOrInvalid();
AsanThread *t = AsanThread::Create(start_routine, arg);
CreateThreadContextArgs args = { t, &stack };
int detached = 0; // FIXME: how can we determine it on Windows?
asanThreadRegistry().CreateThread(*(uptr*)t, detached, current_tid, &args);
return REAL(CreateThread)(security, stack_size,
asan_thread_start, t, flags, tid);
}
@ -661,10 +687,9 @@ void InitializeAsanInterceptors() {
static bool was_called_once;
CHECK(was_called_once == false);
was_called_once = true;
#if MAC_INTERPOSE_FUNCTIONS
#if SANITIZER_MAC
return;
#endif
#else
SANITIZER_COMMON_INTERCEPTORS_INIT;
// Intercept mem* functions.
@ -673,12 +698,6 @@ void InitializeAsanInterceptors() {
ASAN_INTERCEPT_FUNC(memset);
if (PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE) {
ASAN_INTERCEPT_FUNC(memcpy);
} else {
#if !MAC_INTERPOSE_FUNCTIONS
// If we're using dynamic interceptors on Mac, these two are just plain
// functions.
internal_memcpy(&REAL(memcpy), &REAL(memmove), sizeof(REAL(memmove)));
#endif
}
// Intercept str* functions.
@ -690,22 +709,14 @@ void InitializeAsanInterceptors() {
ASAN_INTERCEPT_FUNC(strncat);
ASAN_INTERCEPT_FUNC(strncmp);
ASAN_INTERCEPT_FUNC(strncpy);
#if ASAN_INTERCEPT_STRCASECMP_AND_STRNCASECMP
ASAN_INTERCEPT_FUNC(strcasecmp);
ASAN_INTERCEPT_FUNC(strncasecmp);
#endif
#if ASAN_INTERCEPT_STRDUP
ASAN_INTERCEPT_FUNC(strdup);
#endif
#if ASAN_INTERCEPT_STRNLEN
ASAN_INTERCEPT_FUNC(strnlen);
#endif
#if ASAN_INTERCEPT_INDEX
# if ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX
#if ASAN_INTERCEPT_INDEX && ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX
ASAN_INTERCEPT_FUNC(index);
# else
CHECK(OVERRIDE_FUNCTION(index, WRAP(strchr)));
# endif
#endif
ASAN_INTERCEPT_FUNC(atoi);
@ -750,19 +761,20 @@ void InitializeAsanInterceptors() {
ASAN_INTERCEPT_FUNC(pthread_create);
#endif
// Some Windows-specific interceptors.
#if defined(_WIN32)
InitializeWindowsInterceptors();
// Intercept atexit function.
#if ASAN_INTERCEPT___CXA_ATEXIT
ASAN_INTERCEPT_FUNC(__cxa_atexit);
#endif
// Some Mac-specific interceptors.
#if defined(__APPLE__)
InitializeMacInterceptors();
// Some Windows-specific interceptors.
#if SANITIZER_WINDOWS
InitializeWindowsInterceptors();
#endif
if (flags()->verbosity > 0) {
Report("AddressSanitizer: libc interceptors initialized\n");
}
#endif // SANITIZER_MAC
}
} // namespace __asan

View File

@ -32,9 +32,6 @@ DECLARE_REAL(int, sigaction, int signum, const struct sigaction *act,
namespace __asan {
void InitializeAsanInterceptors();
#if defined(__APPLE__)
void InitializeMacInterceptors();
#endif // __APPLE__
} // namespace __asan

View File

@ -0,0 +1,141 @@
//===-- asan_interface_internal.h -------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of AddressSanitizer, an address sanity checker.
//
// This header can be included by the instrumented program to fetch
// data (mostly allocator statistics) from ASan runtime library.
//===----------------------------------------------------------------------===//
#ifndef ASAN_INTERFACE_INTERNAL_H
#define ASAN_INTERFACE_INTERNAL_H
#include "sanitizer_common/sanitizer_internal_defs.h"
using __sanitizer::uptr;
extern "C" {
// This function should be called at the very beginning of the process,
// before any instrumented code is executed and before any call to malloc.
// Everytime the asan ABI changes we also change the version number in this
// name. Objects build with incompatible asan ABI version
// will not link with run-time.
// Changes between ABI versions:
// v1=>v2: added 'module_name' to __asan_global
// v2=>v3: stack frame description (created by the compiler)
// contains the function PC as the 3-rd field (see
// DescribeAddressIfStack).
void __asan_init_v3() SANITIZER_INTERFACE_ATTRIBUTE;
#define __asan_init __asan_init_v3
// This structure describes an instrumented global variable.
struct __asan_global {
uptr beg; // The address of the global.
uptr size; // The original size of the global.
uptr size_with_redzone; // The size with the redzone.
const char *name; // Name as a C string.
const char *module_name; // Module name as a C string. This pointer is a
// unique identifier of a module.
uptr has_dynamic_init; // Non-zero if the global has dynamic initializer.
};
// These two functions should be called by the instrumented code.
// 'globals' is an array of structures describing 'n' globals.
void __asan_register_globals(__asan_global *globals, uptr n)
SANITIZER_INTERFACE_ATTRIBUTE;
void __asan_unregister_globals(__asan_global *globals, uptr n)
SANITIZER_INTERFACE_ATTRIBUTE;
// These two functions should be called before and after dynamic initializers
// of a single module run, respectively.
void __asan_before_dynamic_init(const char *module_name)
SANITIZER_INTERFACE_ATTRIBUTE;
void __asan_after_dynamic_init()
SANITIZER_INTERFACE_ATTRIBUTE;
// These two functions are used by the instrumented code in the
// use-after-return mode. __asan_stack_malloc allocates size bytes of
// fake stack and __asan_stack_free poisons it. real_stack is a pointer to
// the real stack region.
uptr __asan_stack_malloc(uptr size, uptr real_stack)
SANITIZER_INTERFACE_ATTRIBUTE;
void __asan_stack_free(uptr ptr, uptr size, uptr real_stack)
SANITIZER_INTERFACE_ATTRIBUTE;
// These two functions are used by instrumented code in the
// use-after-scope mode. They mark memory for local variables as
// unaddressable when they leave scope and addressable before the
// function exits.
void __asan_poison_stack_memory(uptr addr, uptr size)
SANITIZER_INTERFACE_ATTRIBUTE;
void __asan_unpoison_stack_memory(uptr addr, uptr size)
SANITIZER_INTERFACE_ATTRIBUTE;
// Performs cleanup before a NoReturn function. Must be called before things
// like _exit and execl to avoid false positives on stack.
void __asan_handle_no_return() SANITIZER_INTERFACE_ATTRIBUTE;
void __asan_poison_memory_region(void const volatile *addr, uptr size)
SANITIZER_INTERFACE_ATTRIBUTE;
void __asan_unpoison_memory_region(void const volatile *addr, uptr size)
SANITIZER_INTERFACE_ATTRIBUTE;
bool __asan_address_is_poisoned(void const volatile *addr)
SANITIZER_INTERFACE_ATTRIBUTE;
uptr __asan_region_is_poisoned(uptr beg, uptr size)
SANITIZER_INTERFACE_ATTRIBUTE;
void __asan_describe_address(uptr addr)
SANITIZER_INTERFACE_ATTRIBUTE;
void __asan_report_error(uptr pc, uptr bp, uptr sp,
uptr addr, bool is_write, uptr access_size)
SANITIZER_INTERFACE_ATTRIBUTE;
int __asan_set_error_exit_code(int exit_code)
SANITIZER_INTERFACE_ATTRIBUTE;
void __asan_set_death_callback(void (*callback)(void))
SANITIZER_INTERFACE_ATTRIBUTE;
void __asan_set_error_report_callback(void (*callback)(const char*))
SANITIZER_INTERFACE_ATTRIBUTE;
/* OPTIONAL */ void __asan_on_error()
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
/* OPTIONAL */ bool __asan_symbolize(const void *pc, char *out_buffer,
int out_size)
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
uptr __asan_get_estimated_allocated_size(uptr size)
SANITIZER_INTERFACE_ATTRIBUTE;
bool __asan_get_ownership(const void *p)
SANITIZER_INTERFACE_ATTRIBUTE;
uptr __asan_get_allocated_size(const void *p)
SANITIZER_INTERFACE_ATTRIBUTE;
uptr __asan_get_current_allocated_bytes()
SANITIZER_INTERFACE_ATTRIBUTE;
uptr __asan_get_heap_size()
SANITIZER_INTERFACE_ATTRIBUTE;
uptr __asan_get_free_bytes()
SANITIZER_INTERFACE_ATTRIBUTE;
uptr __asan_get_unmapped_bytes()
SANITIZER_INTERFACE_ATTRIBUTE;
void __asan_print_accumulated_stats()
SANITIZER_INTERFACE_ATTRIBUTE;
/* OPTIONAL */ const char* __asan_default_options()
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
/* OPTIONAL */ void __asan_malloc_hook(void *ptr, uptr size)
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
/* OPTIONAL */ void __asan_free_hook(void *ptr)
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
} // extern "C"
#endif // ASAN_INTERFACE_INTERNAL_H

View File

@ -15,45 +15,15 @@
#define ASAN_INTERNAL_H
#include "asan_flags.h"
#include "asan_interface_internal.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_internal_defs.h"
#include "sanitizer_common/sanitizer_stacktrace.h"
#include "sanitizer_common/sanitizer_libc.h"
#if !defined(__linux__) && !defined(__APPLE__) && !defined(_WIN32)
# error "This operating system is not supported by AddressSanitizer"
#endif
#define ASAN_DEFAULT_FAILURE_EXITCODE 1
#if defined(__linux__)
# define ASAN_LINUX 1
#else
# define ASAN_LINUX 0
#endif
#if defined(__APPLE__)
# define ASAN_MAC 1
#else
# define ASAN_MAC 0
#endif
#if defined(_WIN32)
# define ASAN_WINDOWS 1
#else
# define ASAN_WINDOWS 0
#endif
#if defined(__ANDROID__) || defined(ANDROID)
# define ASAN_ANDROID 1
#else
# define ASAN_ANDROID 0
#endif
#define ASAN_POSIX (ASAN_LINUX || ASAN_MAC)
#if __has_feature(address_sanitizer)
#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
# error "The AddressSanitizer run-time should not be"
" instrumented by AddressSanitizer"
#endif
@ -62,7 +32,7 @@
// If set, asan will install its own SEGV signal handler.
#ifndef ASAN_NEEDS_SEGV
# if ASAN_ANDROID == 1
# if SANITIZER_ANDROID == 1
# define ASAN_NEEDS_SEGV 0
# else
# define ASAN_NEEDS_SEGV 1
@ -90,6 +60,10 @@
# endif
#endif
#ifndef ASAN_USE_PREINIT_ARRAY
# define ASAN_USE_PREINIT_ARRAY (SANITIZER_LINUX && !SANITIZER_ANDROID)
#endif
// All internal functions in asan reside inside the __asan namespace
// to avoid namespace collisions with the user programs.
// Seperate namespace also makes it simpler to distinguish the asan run-time
@ -118,6 +92,7 @@ void UnsetAlternateSignalStack();
void InstallSignalHandlers();
void ReadContextStack(void *context, uptr *stack, uptr *ssize);
void AsanPlatformThreadInit();
void StopInitOrderChecking();
// Wrapper for TLS/TSD.
void AsanTSDInit(void (*destructor)(void *tsd));
@ -126,24 +101,14 @@ void AsanTSDSet(void *tsd);
void AppendToErrorMessageBuffer(const char *buffer);
// asan_poisoning.cc
// Poisons the shadow memory for "size" bytes starting from "addr".
void PoisonShadow(uptr addr, uptr size, u8 value);
// Poisons the shadow memory for "redzone_size" bytes starting from
// "addr + size".
void PoisonShadowPartialRightRedzone(uptr addr,
uptr size,
uptr redzone_size,
u8 value);
// Platfrom-specific options.
#ifdef __APPLE__
#if SANITIZER_MAC
bool PlatformHasDifferentMemcpyAndMemmove();
# define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE \
(PlatformHasDifferentMemcpyAndMemmove())
#else
# define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE true
#endif // __APPLE__
#endif // SANITIZER_MAC
// Add convenient macro for interface functions that may be represented as
// weak hooks.

View File

@ -11,12 +11,13 @@
//
// Linux-specific details.
//===----------------------------------------------------------------------===//
#ifdef __linux__
#include "sanitizer_common/sanitizer_platform.h"
#if SANITIZER_LINUX
#include "asan_interceptors.h"
#include "asan_internal.h"
#include "asan_thread.h"
#include "asan_thread_registry.h"
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_procmaps.h"
@ -31,7 +32,7 @@
#include <unistd.h>
#include <unwind.h>
#if !ASAN_ANDROID
#if !SANITIZER_ANDROID
// FIXME: where to get ucontext on Android?
#include <sys/ucontext.h>
#endif
@ -50,7 +51,7 @@ void *AsanDoesNotSupportStaticLinkage() {
}
void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
#if ASAN_ANDROID
#if SANITIZER_ANDROID
*pc = *sp = *bp = 0;
#elif defined(__arm__)
ucontext_t *ucontext = (ucontext_t*)context;
@ -101,25 +102,7 @@ void AsanPlatformThreadInit() {
// Nothing here for now.
}
void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp, bool fast) {
#if defined(__arm__) || \
defined(__powerpc__) || defined(__powerpc64__) || \
defined(__sparc__)
fast = false;
#endif
if (!fast)
return stack->SlowUnwindStack(pc, max_s);
stack->size = 0;
stack->trace[0] = pc;
if (max_s > 1) {
stack->max_size = max_s;
if (!asan_inited) return;
if (AsanThread *t = asanThreadRegistry().GetCurrent())
stack->FastUnwindStack(pc, bp, t->stack_top(), t->stack_bottom());
}
}
#if !ASAN_ANDROID
#if !SANITIZER_ANDROID
void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
ucontext_t *ucp = (ucontext_t*)context;
*stack = (uptr)ucp->uc_stack.ss_sp;
@ -133,4 +116,4 @@ void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
} // namespace __asan
#endif // __linux__
#endif // SANITIZER_LINUX

View File

@ -12,7 +12,8 @@
// Mac-specific details.
//===----------------------------------------------------------------------===//
#ifdef __APPLE__
#include "sanitizer_common/sanitizer_platform.h"
#if SANITIZER_MAC
#include "asan_interceptors.h"
#include "asan_internal.h"
@ -20,7 +21,6 @@
#include "asan_mapping.h"
#include "asan_stack.h"
#include "asan_thread.h"
#include "asan_thread_registry.h"
#include "sanitizer_common/sanitizer_libc.h"
#include <crt_externs.h> // for _NSGetArgv
@ -36,7 +36,6 @@
#include <stdlib.h> // for free()
#include <unistd.h>
#include <libkern/OSAtomic.h>
#include <CoreFoundation/CFString.h>
namespace __asan {
@ -59,9 +58,9 @@ int GetMacosVersion() {
uptr len = 0, maxlen = sizeof(version) / sizeof(version[0]);
for (uptr i = 0; i < maxlen; i++) version[i] = '\0';
// Get the version length.
CHECK(sysctl(mib, 2, 0, &len, 0, 0) != -1);
CHECK(len < maxlen);
CHECK(sysctl(mib, 2, version, &len, 0, 0) != -1);
CHECK_NE(sysctl(mib, 2, 0, &len, 0, 0), -1);
CHECK_LT(len, maxlen);
CHECK_NE(sysctl(mib, 2, version, &len, 0, 0), -1);
switch (version[0]) {
case '9': return MACOS_VERSION_LEOPARD;
case '1': {
@ -89,16 +88,52 @@ extern "C"
void __asan_init();
static const char kDyldInsertLibraries[] = "DYLD_INSERT_LIBRARIES";
LowLevelAllocator allocator_for_env;
// Change the value of the env var |name|, leaking the original value.
// If |name_value| is NULL, the variable is deleted from the environment,
// otherwise the corresponding "NAME=value" string is replaced with
// |name_value|.
void LeakyResetEnv(const char *name, const char *name_value) {
char ***env_ptr = _NSGetEnviron();
CHECK(env_ptr);
char **environ = *env_ptr;
CHECK(environ);
uptr name_len = internal_strlen(name);
while (*environ != 0) {
uptr len = internal_strlen(*environ);
if (len > name_len) {
const char *p = *environ;
if (!internal_memcmp(p, name, name_len) && p[name_len] == '=') {
// Match.
if (name_value) {
// Replace the old value with the new one.
*environ = const_cast<char*>(name_value);
} else {
// Shift the subsequent pointers back.
char **del = environ;
do {
del[0] = del[1];
} while (*del++);
}
}
}
environ++;
}
}
void MaybeReexec() {
if (!flags()->allow_reexec) return;
#if MAC_INTERPOSE_FUNCTIONS
// If the program is linked with the dynamic ASan runtime library, make sure
// the library is preloaded so that the wrappers work. If it is not, set
// DYLD_INSERT_LIBRARIES and re-exec ourselves.
// Make sure the dynamic ASan runtime library is preloaded so that the
// wrappers work. If it is not, set DYLD_INSERT_LIBRARIES and re-exec
// ourselves.
Dl_info info;
CHECK(dladdr((void*)((uptr)__asan_init), &info));
const char *dyld_insert_libraries = GetEnv(kDyldInsertLibraries);
char *dyld_insert_libraries =
const_cast<char*>(GetEnv(kDyldInsertLibraries));
uptr old_env_len = dyld_insert_libraries ?
internal_strlen(dyld_insert_libraries) : 0;
uptr fname_len = internal_strlen(info.dli_fname);
if (!dyld_insert_libraries ||
!REAL(strstr)(dyld_insert_libraries, info.dli_fname)) {
// DYLD_INSERT_LIBRARIES is not set or does not contain the runtime
@ -106,19 +141,80 @@ void MaybeReexec() {
char program_name[1024];
uint32_t buf_size = sizeof(program_name);
_NSGetExecutablePath(program_name, &buf_size);
// Ok to use setenv() since the wrappers don't depend on the value of
// asan_inited.
setenv(kDyldInsertLibraries, info.dli_fname, /*overwrite*/0);
char *new_env = const_cast<char*>(info.dli_fname);
if (dyld_insert_libraries) {
// Append the runtime dylib name to the existing value of
// DYLD_INSERT_LIBRARIES.
new_env = (char*)allocator_for_env.Allocate(old_env_len + fname_len + 2);
internal_strncpy(new_env, dyld_insert_libraries, old_env_len);
new_env[old_env_len] = ':';
// Copy fname_len and add a trailing zero.
internal_strncpy(new_env + old_env_len + 1, info.dli_fname,
fname_len + 1);
// Ok to use setenv() since the wrappers don't depend on the value of
// asan_inited.
setenv(kDyldInsertLibraries, new_env, /*overwrite*/1);
} else {
// Set DYLD_INSERT_LIBRARIES equal to the runtime dylib name.
setenv(kDyldInsertLibraries, info.dli_fname, /*overwrite*/0);
}
if (flags()->verbosity >= 1) {
Report("exec()-ing the program with\n");
Report("%s=%s\n", kDyldInsertLibraries, info.dli_fname);
Report("%s=%s\n", kDyldInsertLibraries, new_env);
Report("to enable ASan wrappers.\n");
Report("Set ASAN_OPTIONS=allow_reexec=0 to disable this.\n");
}
execv(program_name, *_NSGetArgv());
} else {
// DYLD_INSERT_LIBRARIES is set and contains the runtime library.
if (old_env_len == fname_len) {
// It's just the runtime library name - fine to unset the variable.
LeakyResetEnv(kDyldInsertLibraries, NULL);
} else {
uptr env_name_len = internal_strlen(kDyldInsertLibraries);
// Allocate memory to hold the previous env var name, its value, the '='
// sign and the '\0' char.
char *new_env = (char*)allocator_for_env.Allocate(
old_env_len + 2 + env_name_len);
CHECK(new_env);
internal_memset(new_env, '\0', old_env_len + 2 + env_name_len);
internal_strncpy(new_env, kDyldInsertLibraries, env_name_len);
new_env[env_name_len] = '=';
char *new_env_pos = new_env + env_name_len + 1;
// Iterate over colon-separated pieces of |dyld_insert_libraries|.
char *piece_start = dyld_insert_libraries;
char *piece_end = NULL;
char *old_env_end = dyld_insert_libraries + old_env_len;
do {
if (piece_start[0] == ':') piece_start++;
piece_end = REAL(strchr)(piece_start, ':');
if (!piece_end) piece_end = dyld_insert_libraries + old_env_len;
if ((uptr)(piece_start - dyld_insert_libraries) > old_env_len) break;
uptr piece_len = piece_end - piece_start;
// If the current piece isn't the runtime library name,
// append it to new_env.
if ((piece_len != fname_len) ||
(internal_strncmp(piece_start, info.dli_fname, fname_len) != 0)) {
if (new_env_pos != new_env + env_name_len + 1) {
new_env_pos[0] = ':';
new_env_pos++;
}
internal_strncpy(new_env_pos, piece_start, piece_len);
}
// Move on to the next piece.
new_env_pos += piece_len;
piece_start = piece_end;
} while (piece_start < old_env_end);
// Can't use setenv() here, because it requires the allocator to be
// initialized.
// FIXME: instead of filtering DYLD_INSERT_LIBRARIES here, do it in
// a separate function called after InitializeAllocator().
LeakyResetEnv(kDyldInsertLibraries, new_env);
}
}
#endif // MAC_INTERPOSE_FUNCTIONS
// If we're not using the dynamic runtime, do nothing.
}
// No-op. Mac does not support static linkage anyway.
@ -131,83 +227,12 @@ bool AsanInterceptsSignal(int signum) {
}
void AsanPlatformThreadInit() {
// For the first program thread, we can't replace the allocator before
// __CFInitialize() has been called. If it hasn't, we'll call
// MaybeReplaceCFAllocator() later on this thread.
// For other threads __CFInitialize() has been called before their creation.
// See also asan_malloc_mac.cc.
if (((CFRuntimeBase*)kCFAllocatorSystemDefault)->_cfisa) {
MaybeReplaceCFAllocator();
}
}
void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp, bool fast) {
(void)fast;
stack->size = 0;
stack->trace[0] = pc;
if ((max_s) > 1) {
stack->max_size = max_s;
if (!asan_inited) return;
if (AsanThread *t = asanThreadRegistry().GetCurrent())
stack->FastUnwindStack(pc, bp, t->stack_top(), t->stack_bottom());
}
}
void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
UNIMPLEMENTED();
}
// The range of pages to be used for escape islands.
// TODO(glider): instead of mapping a fixed range we must find a range of
// unmapped pages in vmmap and take them.
// These constants were chosen empirically and may not work if the shadow
// memory layout changes. Unfortunately they do necessarily depend on
// kHighMemBeg or kHighMemEnd.
static void *island_allocator_pos = 0;
#if SANITIZER_WORDSIZE == 32
# define kIslandEnd (0xffdf0000 - GetPageSizeCached())
# define kIslandBeg (kIslandEnd - 256 * GetPageSizeCached())
#else
# define kIslandEnd (0x7fffffdf0000 - GetPageSizeCached())
# define kIslandBeg (kIslandEnd - 256 * GetPageSizeCached())
#endif
extern "C"
mach_error_t __interception_allocate_island(void **ptr,
uptr unused_size,
void *unused_hint) {
if (!island_allocator_pos) {
island_allocator_pos =
internal_mmap((void*)kIslandBeg, kIslandEnd - kIslandBeg,
PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_PRIVATE | MAP_ANON | MAP_FIXED,
-1, 0);
if (island_allocator_pos != (void*)kIslandBeg) {
return KERN_NO_SPACE;
}
if (flags()->verbosity) {
Report("Mapped pages %p--%p for branch islands.\n",
(void*)kIslandBeg, (void*)kIslandEnd);
}
// Should not be very performance-critical.
internal_memset(island_allocator_pos, 0xCC, kIslandEnd - kIslandBeg);
};
*ptr = island_allocator_pos;
island_allocator_pos = (char*)island_allocator_pos + GetPageSizeCached();
if (flags()->verbosity) {
Report("Branch island allocated at %p\n", *ptr);
}
return err_none;
}
extern "C"
mach_error_t __interception_deallocate_island(void *ptr) {
// Do nothing.
// TODO(glider): allow to free and reuse the island memory.
return err_none;
}
// Support for the following functions from libdispatch on Mac OS:
// dispatch_async_f()
// dispatch_async()
@ -237,9 +262,6 @@ mach_error_t __interception_deallocate_island(void *ptr) {
// The implementation details are at
// http://libdispatch.macosforge.org/trac/browser/trunk/src/queue.c
typedef void* pthread_workqueue_t;
typedef void* pthread_workitem_handle_t;
typedef void* dispatch_group_t;
typedef void* dispatch_queue_t;
typedef void* dispatch_source_t;
@ -254,32 +276,16 @@ typedef struct {
u32 parent_tid;
} asan_block_context_t;
// We use extern declarations of libdispatch functions here instead
// of including <dispatch/dispatch.h>. This header is not present on
// Mac OS X Leopard and eariler, and although we don't expect ASan to
// work on legacy systems, it's bad to break the build of
// LLVM compiler-rt there.
extern "C" {
void dispatch_async_f(dispatch_queue_t dq, void *ctxt,
dispatch_function_t func);
void dispatch_sync_f(dispatch_queue_t dq, void *ctxt,
dispatch_function_t func);
void dispatch_after_f(dispatch_time_t when, dispatch_queue_t dq, void *ctxt,
dispatch_function_t func);
void dispatch_barrier_async_f(dispatch_queue_t dq, void *ctxt,
dispatch_function_t func);
void dispatch_group_async_f(dispatch_group_t group, dispatch_queue_t dq,
void *ctxt, dispatch_function_t func);
} // extern "C"
static ALWAYS_INLINE
ALWAYS_INLINE
void asan_register_worker_thread(int parent_tid, StackTrace *stack) {
AsanThread *t = asanThreadRegistry().GetCurrent();
AsanThread *t = GetCurrentThread();
if (!t) {
t = AsanThread::Create(parent_tid, 0, 0, stack);
asanThreadRegistry().RegisterThread(t);
t = AsanThread::Create(0, 0);
CreateThreadContextArgs args = { t, stack };
asanThreadRegistry().CreateThread(*(uptr*)t, true, parent_tid, &args);
t->Init();
asanThreadRegistry().SetCurrent(t);
asanThreadRegistry().StartThread(t->tid(), 0, 0);
SetCurrentThread(t);
}
}
@ -313,7 +319,7 @@ asan_block_context_t *alloc_asan_context(void *ctxt, dispatch_function_t func,
(asan_block_context_t*) asan_malloc(sizeof(asan_block_context_t), stack);
asan_ctxt->block = ctxt;
asan_ctxt->func = func;
asan_ctxt->parent_tid = asanThreadRegistry().GetCurrentTidOrInvalid();
asan_ctxt->parent_tid = GetCurrentTidOrInvalid();
return asan_ctxt;
}
@ -364,14 +370,7 @@ INTERCEPTOR(void, dispatch_group_async_f, dispatch_group_t group,
asan_dispatch_call_block_and_release);
}
#if MAC_INTERPOSE_FUNCTIONS && !defined(MISSING_BLOCKS_SUPPORT)
// dispatch_async, dispatch_group_async and others tailcall the corresponding
// dispatch_*_f functions. When wrapping functions with mach_override, those
// dispatch_*_f are intercepted automatically. But with dylib interposition
// this does not work, because the calls within the same library are not
// interposed.
// Therefore we need to re-implement dispatch_async and friends.
#if !defined(MISSING_BLOCKS_SUPPORT)
extern "C" {
// FIXME: consolidate these declarations with asan_intercepted_functions.h.
void dispatch_async(dispatch_queue_t dq, void(^work)(void));
@ -386,7 +385,7 @@ void dispatch_source_set_event_handler(dispatch_source_t ds, void(^work)(void));
#define GET_ASAN_BLOCK(work) \
void (^asan_block)(void); \
int parent_tid = asanThreadRegistry().GetCurrentTidOrInvalid(); \
int parent_tid = GetCurrentTidOrInvalid(); \
asan_block = ^(void) { \
GET_STACK_TRACE_THREAD; \
asan_register_worker_thread(parent_tid, &stack); \
@ -424,53 +423,4 @@ INTERCEPTOR(void, dispatch_source_set_event_handler,
}
#endif
// See http://opensource.apple.com/source/CF/CF-635.15/CFString.c
int __CFStrIsConstant(CFStringRef str) {
CFRuntimeBase *base = (CFRuntimeBase*)str;
#if __LP64__
return base->_rc == 0;
#else
return (base->_cfinfo[CF_RC_BITS]) == 0;
#endif
}
INTERCEPTOR(CFStringRef, CFStringCreateCopy, CFAllocatorRef alloc,
CFStringRef str) {
if (__CFStrIsConstant(str)) {
return str;
} else {
return REAL(CFStringCreateCopy)(alloc, str);
}
}
DECLARE_REAL_AND_INTERCEPTOR(void, free, void *ptr)
DECLARE_REAL_AND_INTERCEPTOR(void, __CFInitialize, void)
namespace __asan {
void InitializeMacInterceptors() {
CHECK(INTERCEPT_FUNCTION(dispatch_async_f));
CHECK(INTERCEPT_FUNCTION(dispatch_sync_f));
CHECK(INTERCEPT_FUNCTION(dispatch_after_f));
CHECK(INTERCEPT_FUNCTION(dispatch_barrier_async_f));
CHECK(INTERCEPT_FUNCTION(dispatch_group_async_f));
// Normally CFStringCreateCopy should not copy constant CF strings.
// Replacing the default CFAllocator causes constant strings to be copied
// rather than just returned, which leads to bugs in big applications like
// Chromium and WebKit, see
// http://code.google.com/p/address-sanitizer/issues/detail?id=10
// Until this problem is fixed we need to check that the string is
// non-constant before calling CFStringCreateCopy.
CHECK(INTERCEPT_FUNCTION(CFStringCreateCopy));
// Some of the library functions call free() directly, so we have to
// intercept it.
CHECK(INTERCEPT_FUNCTION(free));
if (flags()->replace_cfallocator) {
CHECK(INTERCEPT_FUNCTION(__CFInitialize));
}
}
} // namespace __asan
#endif // __APPLE__
#endif // SANITIZER_MAC

View File

@ -12,7 +12,7 @@
// Mac-specific ASan definitions.
//===----------------------------------------------------------------------===//
#ifndef ASAN_MAC_H
#define ASAN_MAC_H
#define ASAN__MAC_H
// CF_RC_BITS, the layout of CFRuntimeBase and __CFStrIsConstant are internal
// and subject to change in further CoreFoundation versions. Apple does not

View File

@ -13,16 +13,16 @@
// We simply define functions like malloc, free, realloc, etc.
// They will replace the corresponding libc functions automagically.
//===----------------------------------------------------------------------===//
#ifdef __linux__
#include "sanitizer_common/sanitizer_platform.h"
#if SANITIZER_LINUX
#include "asan_allocator.h"
#include "asan_interceptors.h"
#include "asan_internal.h"
#include "asan_stack.h"
#include "asan_thread_registry.h"
#include "sanitizer/asan_interface.h"
#if ASAN_ANDROID
#if SANITIZER_ANDROID
DECLARE_REAL_AND_INTERCEPTOR(void*, malloc, uptr size)
DECLARE_REAL_AND_INTERCEPTOR(void, free, void *ptr)
DECLARE_REAL_AND_INTERCEPTOR(void*, calloc, uptr nmemb, uptr size)
@ -147,4 +147,4 @@ INTERCEPTOR(void, malloc_stats, void) {
__asan_print_accumulated_stats();
}
#endif // __linux__
#endif // SANITIZER_LINUX

View File

@ -12,7 +12,8 @@
// Mac-specific malloc interception.
//===----------------------------------------------------------------------===//
#ifdef __APPLE__
#include "sanitizer_common/sanitizer_platform.h"
#if SANITIZER_MAC
#include <AvailabilityMacros.h>
#include <CoreFoundation/CFBase.h>
@ -26,7 +27,6 @@
#include "asan_report.h"
#include "asan_stack.h"
#include "asan_stats.h"
#include "asan_thread_registry.h"
// Similar code is used in Google Perftools,
// http://code.google.com/p/google-perftools.
@ -36,85 +36,108 @@ using namespace __asan; // NOLINT
// TODO(glider): do we need both zones?
static malloc_zone_t *system_malloc_zone = 0;
static malloc_zone_t *system_purgeable_zone = 0;
static malloc_zone_t asan_zone;
CFAllocatorRef cf_asan = 0;
// _CFRuntimeCreateInstance() checks whether the supplied allocator is
// kCFAllocatorSystemDefault and, if it is not, stores the allocator reference
// at the beginning of the allocated memory and returns the pointer to the
// allocated memory plus sizeof(CFAllocatorRef). See
// http://www.opensource.apple.com/source/CF/CF-635.21/CFRuntime.c
// Pointers returned by _CFRuntimeCreateInstance() can then be passed directly
// to free() or CFAllocatorDeallocate(), which leads to false invalid free
// reports.
// The corresponding rdar bug is http://openradar.appspot.com/radar?id=1796404.
void* ALWAYS_INLINE get_saved_cfallocator_ref(void *ptr) {
if (flags()->replace_cfallocator) {
// Make sure we're not hitting the previous page. This may be incorrect
// if ASan's malloc returns an address ending with 0xFF8, which will be
// then padded to a page boundary with a CFAllocatorRef.
uptr arith_ptr = (uptr)ptr;
if ((arith_ptr & 0xFFF) > sizeof(CFAllocatorRef)) {
CFAllocatorRef *saved =
(CFAllocatorRef*)(arith_ptr - sizeof(CFAllocatorRef));
if ((*saved == cf_asan) && asan_mz_size(saved)) ptr = (void*)saved;
}
}
return ptr;
INTERCEPTOR(malloc_zone_t *, malloc_create_zone,
vm_size_t start_size, unsigned zone_flags) {
if (!asan_inited) __asan_init();
GET_STACK_TRACE_MALLOC;
malloc_zone_t *new_zone =
(malloc_zone_t*)asan_malloc(sizeof(asan_zone), &stack);
internal_memcpy(new_zone, &asan_zone, sizeof(asan_zone));
new_zone->zone_name = NULL; // The name will be changed anyway.
return new_zone;
}
INTERCEPTOR(malloc_zone_t *, malloc_default_zone, void) {
if (!asan_inited) __asan_init();
return &asan_zone;
}
INTERCEPTOR(malloc_zone_t *, malloc_default_purgeable_zone, void) {
// FIXME: ASan should support purgeable allocations.
// https://code.google.com/p/address-sanitizer/issues/detail?id=139
if (!asan_inited) __asan_init();
return &asan_zone;
}
INTERCEPTOR(void, malloc_make_purgeable, void *ptr) {
// FIXME: ASan should support purgeable allocations. Ignoring them is fine
// for now.
if (!asan_inited) __asan_init();
}
INTERCEPTOR(int, malloc_make_nonpurgeable, void *ptr) {
// FIXME: ASan should support purgeable allocations. Ignoring them is fine
// for now.
if (!asan_inited) __asan_init();
// Must return 0 if the contents were not purged since the last call to
// malloc_make_purgeable().
return 0;
}
INTERCEPTOR(void, malloc_set_zone_name, malloc_zone_t *zone, const char *name) {
if (!asan_inited) __asan_init();
// Allocate |strlen("asan-") + 1 + internal_strlen(name)| bytes.
size_t buflen = 6 + (name ? internal_strlen(name) : 0);
InternalScopedBuffer<char> new_name(buflen);
if (name && zone->introspect == asan_zone.introspect) {
internal_snprintf(new_name.data(), buflen, "asan-%s", name);
name = new_name.data();
}
// Call the system malloc's implementation for both external and our zones,
// since that appropriately changes VM region protections on the zone.
REAL(malloc_set_zone_name)(zone, name);
}
INTERCEPTOR(void *, malloc, size_t size) {
if (!asan_inited) __asan_init();
GET_STACK_TRACE_MALLOC;
void *res = asan_malloc(size, &stack);
return res;
}
// The free() implementation provided by OS X calls malloc_zone_from_ptr()
// to find the owner of |ptr|. If the result is 0, an invalid free() is
// reported. Our implementation falls back to asan_free() in this case
// in order to print an ASan-style report.
//
// For the objects created by _CFRuntimeCreateInstance a CFAllocatorRef is
// placed at the beginning of the allocated chunk and the pointer returned by
// our allocator is off by sizeof(CFAllocatorRef). This pointer can be then
// passed directly to free(), which will lead to errors.
// To overcome this we're checking whether |ptr-sizeof(CFAllocatorRef)|
// contains a pointer to our CFAllocator (assuming no other allocator is used).
// See http://code.google.com/p/address-sanitizer/issues/detail?id=70 for more
// info.
INTERCEPTOR(void, free, void *ptr) {
malloc_zone_t *zone = malloc_zone_from_ptr(ptr);
if (zone) {
#if defined(MAC_OS_X_VERSION_10_6) && \
MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
if ((zone->version >= 6) && (zone->free_definite_size)) {
zone->free_definite_size(zone, ptr, malloc_size(ptr));
} else {
malloc_zone_free(zone, ptr);
}
#else
malloc_zone_free(zone, ptr);
#endif
} else {
if (!asan_mz_size(ptr)) ptr = get_saved_cfallocator_ref(ptr);
GET_STACK_TRACE_FREE;
asan_free(ptr, &stack, FROM_MALLOC);
}
if (!asan_inited) __asan_init();
if (!ptr) return;
GET_STACK_TRACE_FREE;
asan_free(ptr, &stack, FROM_MALLOC);
}
// We can't always replace the default CFAllocator with cf_asan right in
// ReplaceSystemMalloc(), because it is sometimes called before
// __CFInitialize(), when the default allocator is invalid and replacing it may
// crash the program. Instead we wait for the allocator to initialize and jump
// in just after __CFInitialize(). Nobody is going to allocate memory using
// CFAllocators before that, so we won't miss anything.
//
// See http://code.google.com/p/address-sanitizer/issues/detail?id=87
// and http://opensource.apple.com/source/CF/CF-550.43/CFRuntime.c
INTERCEPTOR(void, __CFInitialize, void) {
// If the runtime is built as dynamic library, __CFInitialize wrapper may be
// called before __asan_init.
#if !MAC_INTERPOSE_FUNCTIONS
CHECK(flags()->replace_cfallocator);
CHECK(asan_inited);
#endif
REAL(__CFInitialize)();
if (!cf_asan && asan_inited) MaybeReplaceCFAllocator();
INTERCEPTOR(void *, realloc, void *ptr, size_t size) {
if (!asan_inited) __asan_init();
GET_STACK_TRACE_MALLOC;
return asan_realloc(ptr, size, &stack);
}
INTERCEPTOR(void *, calloc, size_t nmemb, size_t size) {
if (!asan_inited) __asan_init();
GET_STACK_TRACE_MALLOC;
return asan_calloc(nmemb, size, &stack);
}
INTERCEPTOR(void *, valloc, size_t size) {
if (!asan_inited) __asan_init();
GET_STACK_TRACE_MALLOC;
return asan_memalign(GetPageSizeCached(), size, &stack, FROM_MALLOC);
}
INTERCEPTOR(size_t, malloc_good_size, size_t size) {
if (!asan_inited) __asan_init();
return asan_zone.introspect->good_size(&asan_zone, size);
}
INTERCEPTOR(int, posix_memalign, void **memptr, size_t alignment, size_t size) {
if (!asan_inited) __asan_init();
CHECK(memptr);
GET_STACK_TRACE_MALLOC;
void *result = asan_memalign(alignment, size, &stack, FROM_MALLOC);
if (result) {
*memptr = result;
return 0;
}
return -1;
}
namespace {
@ -134,15 +157,6 @@ void *mz_malloc(malloc_zone_t *zone, size_t size) {
return asan_malloc(size, &stack);
}
void *cf_malloc(CFIndex size, CFOptionFlags hint, void *info) {
if (!asan_inited) {
CHECK(system_malloc_zone);
return malloc_zone_malloc(system_malloc_zone, size);
}
GET_STACK_TRACE_MALLOC;
return asan_malloc(size, &stack);
}
void *mz_calloc(malloc_zone_t *zone, size_t nmemb, size_t size) {
if (!asan_inited) {
// Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
@ -174,31 +188,14 @@ void *mz_valloc(malloc_zone_t *zone, size_t size) {
void ALWAYS_INLINE free_common(void *context, void *ptr) {
if (!ptr) return;
if (asan_mz_size(ptr)) {
GET_STACK_TRACE_FREE;
GET_STACK_TRACE_FREE;
// FIXME: need to retire this flag.
if (!flags()->mac_ignore_invalid_free) {
asan_free(ptr, &stack, FROM_MALLOC);
} else {
// If the pointer does not belong to any of the zones, use one of the
// fallback methods to free memory.
malloc_zone_t *zone_ptr = malloc_zone_from_ptr(ptr);
if (zone_ptr == system_purgeable_zone) {
// allocations from malloc_default_purgeable_zone() done before
// __asan_init() may be occasionally freed via free_common().
// see http://code.google.com/p/address-sanitizer/issues/detail?id=99.
malloc_zone_free(zone_ptr, ptr);
} else {
// If the memory chunk pointer was moved to store additional
// CFAllocatorRef, fix it back.
ptr = get_saved_cfallocator_ref(ptr);
GET_STACK_TRACE_FREE;
if (!flags()->mac_ignore_invalid_free) {
asan_free(ptr, &stack, FROM_MALLOC);
} else {
GET_ZONE_FOR_PTR(ptr);
WarnMacFreeUnallocated((uptr)ptr, (uptr)zone_ptr, zone_name, &stack);
return;
}
}
GET_ZONE_FOR_PTR(ptr);
WarnMacFreeUnallocated((uptr)ptr, (uptr)zone_ptr, zone_name, &stack);
return;
}
}
@ -207,10 +204,6 @@ void mz_free(malloc_zone_t *zone, void *ptr) {
free_common(zone, ptr);
}
void cf_free(void *ptr, void *info) {
free_common(info, ptr);
}
void *mz_realloc(malloc_zone_t *zone, void *ptr, size_t size) {
if (!ptr) {
GET_STACK_TRACE_MALLOC;
@ -230,29 +223,11 @@ void *mz_realloc(malloc_zone_t *zone, void *ptr, size_t size) {
}
}
void *cf_realloc(void *ptr, CFIndex size, CFOptionFlags hint, void *info) {
if (!ptr) {
GET_STACK_TRACE_MALLOC;
return asan_malloc(size, &stack);
} else {
if (asan_mz_size(ptr)) {
GET_STACK_TRACE_MALLOC;
return asan_realloc(ptr, size, &stack);
} else {
// We can't recover from reallocating an unknown address, because
// this would require reading at most |size| bytes from
// potentially unaccessible memory.
GET_STACK_TRACE_FREE;
GET_ZONE_FOR_PTR(ptr);
ReportMacCfReallocUnknown((uptr)ptr, (uptr)zone_ptr, zone_name, &stack);
}
}
}
void mz_destroy(malloc_zone_t* zone) {
// A no-op -- we will not be destroyed!
Printf("mz_destroy() called -- ignoring\n");
Report("mz_destroy() called -- ignoring\n");
}
// from AvailabilityMacros.h
#if defined(MAC_OS_X_VERSION_10_6) && \
MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
@ -309,7 +284,7 @@ void mi_force_unlock(malloc_zone_t *zone) {
void mi_statistics(malloc_zone_t *zone, malloc_statistics_t *stats) {
AsanMallocStats malloc_stats;
asanThreadRegistry().FillMallocStatistics(&malloc_stats);
FillMallocStatistics(&malloc_stats);
CHECK(sizeof(malloc_statistics_t) == sizeof(AsanMallocStats));
internal_memcpy(stats, &malloc_stats, sizeof(malloc_statistics_t));
}
@ -324,23 +299,7 @@ boolean_t mi_zone_locked(malloc_zone_t *zone) {
} // unnamed namespace
extern int __CFRuntimeClassTableSize;
namespace __asan {
void MaybeReplaceCFAllocator() {
static CFAllocatorContext asan_context = {
/*version*/ 0, /*info*/ &asan_zone,
/*retain*/ 0, /*release*/ 0,
/*copyDescription*/0,
/*allocate*/ &cf_malloc,
/*reallocate*/ &cf_realloc,
/*deallocate*/ &cf_free,
/*preferredSize*/ 0 };
if (!cf_asan)
cf_asan = CFAllocatorCreate(kCFAllocatorUseContext, &asan_context);
if (flags()->replace_cfallocator && CFAllocatorGetDefault() != cf_asan)
CFAllocatorSetDefault(cf_asan);
}
void ReplaceSystemMalloc() {
static malloc_introspection_t asan_introspection;
@ -380,42 +339,11 @@ void ReplaceSystemMalloc() {
asan_zone.free_definite_size = 0;
asan_zone.memalign = &mz_memalign;
asan_introspection.zone_locked = &mi_zone_locked;
// Request the default purgable zone to force its creation. The
// current default zone is registered with the purgable zone for
// doing tiny and small allocs. Sadly, it assumes that the default
// zone is the szone implementation from OS X and will crash if it
// isn't. By creating the zone now, this will be true and changing
// the default zone won't cause a problem. (OS X 10.6 and higher.)
system_purgeable_zone = malloc_default_purgeable_zone();
#endif
// Register the ASan zone. At this point, it will not be the
// default zone.
// Register the ASan zone.
malloc_zone_register(&asan_zone);
// Unregister and reregister the default zone. Unregistering swaps
// the specified zone with the last one registered which for the
// default zone makes the more recently registered zone the default
// zone. The default zone is then re-registered to ensure that
// allocations made from it earlier will be handled correctly.
// Things are not guaranteed to work that way, but it's how they work now.
system_malloc_zone = malloc_default_zone();
malloc_zone_unregister(system_malloc_zone);
malloc_zone_register(system_malloc_zone);
// Make sure the default allocator was replaced.
CHECK(malloc_default_zone() == &asan_zone);
// If __CFInitialize() hasn't been called yet, cf_asan will be created and
// installed as the default allocator after __CFInitialize() finishes (see
// the interceptor for __CFInitialize() above). Otherwise install cf_asan
// right now. On both Snow Leopard and Lion __CFInitialize() calls
// __CFAllocatorInitialize(), which initializes the _base._cfisa field of
// the default allocators we check here.
if (((CFRuntimeBase*)kCFAllocatorSystemDefault)->_cfisa) {
MaybeReplaceCFAllocator();
}
}
} // namespace __asan
#endif // __APPLE__
#endif // SANITIZER_MAC

View File

@ -11,7 +11,9 @@
//
// Windows-specific malloc interception.
//===----------------------------------------------------------------------===//
#ifdef _WIN32
#include "sanitizer_common/sanitizer_platform.h"
#if SANITIZER_WINDOWS
#include "asan_allocator.h"
#include "asan_interceptors.h"

View File

@ -18,6 +18,37 @@
// The full explanation of the memory mapping could be found here:
// http://code.google.com/p/address-sanitizer/wiki/AddressSanitizerAlgorithm
//
// Typical shadow mapping on Linux/x86_64 with SHADOW_OFFSET == 0x00007fff8000:
// || `[0x10007fff8000, 0x7fffffffffff]` || HighMem ||
// || `[0x02008fff7000, 0x10007fff7fff]` || HighShadow ||
// || `[0x00008fff7000, 0x02008fff6fff]` || ShadowGap ||
// || `[0x00007fff8000, 0x00008fff6fff]` || LowShadow ||
// || `[0x000000000000, 0x00007fff7fff]` || LowMem ||
//
// When SHADOW_OFFSET is zero (-pie):
// || `[0x100000000000, 0x7fffffffffff]` || HighMem ||
// || `[0x020000000000, 0x0fffffffffff]` || HighShadow ||
// || `[0x000000040000, 0x01ffffffffff]` || ShadowGap ||
//
// Special case when something is already mapped between
// 0x003000000000 and 0x005000000000 (e.g. when prelink is installed):
// || `[0x10007fff8000, 0x7fffffffffff]` || HighMem ||
// || `[0x02008fff7000, 0x10007fff7fff]` || HighShadow ||
// || `[0x005000000000, 0x02008fff6fff]` || ShadowGap3 ||
// || `[0x003000000000, 0x004fffffffff]` || MidMem ||
// || `[0x000a7fff8000, 0x002fffffffff]` || ShadowGap2 ||
// || `[0x00067fff8000, 0x000a7fff7fff]` || MidShadow ||
// || `[0x00008fff7000, 0x00067fff7fff]` || ShadowGap ||
// || `[0x00007fff8000, 0x00008fff6fff]` || LowShadow ||
// || `[0x000000000000, 0x00007fff7fff]` || LowMem ||
//
// Default Linux/i386 mapping:
// || `[0x40000000, 0xffffffff]` || HighMem ||
// || `[0x28000000, 0x3fffffff]` || HighShadow ||
// || `[0x24000000, 0x27ffffff]` || ShadowGap ||
// || `[0x20000000, 0x23ffffff]` || LowShadow ||
// || `[0x00000000, 0x1fffffff]` || LowMem ||
#if ASAN_FLEXIBLE_MAPPING_AND_OFFSET == 1
extern SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_mapping_scale;
@ -25,7 +56,7 @@ extern SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_mapping_offset;
# define SHADOW_SCALE (__asan_mapping_scale)
# define SHADOW_OFFSET (__asan_mapping_offset)
#else
# if ASAN_ANDROID
# if SANITIZER_ANDROID
# define SHADOW_SCALE (3)
# define SHADOW_OFFSET (0)
# else
@ -36,27 +67,20 @@ extern SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_mapping_offset;
# if defined(__powerpc64__)
# define SHADOW_OFFSET (1ULL << 41)
# else
# define SHADOW_OFFSET (1ULL << 44)
# if SANITIZER_MAC
# define SHADOW_OFFSET (1ULL << 44)
# else
# define SHADOW_OFFSET 0x7fff8000ULL
# endif
# endif
# endif
# endif
#endif // ASAN_FLEXIBLE_MAPPING_AND_OFFSET
#define SHADOW_GRANULARITY (1ULL << SHADOW_SCALE)
#define MEM_TO_SHADOW(mem) (((mem) >> SHADOW_SCALE) | (SHADOW_OFFSET))
#define MEM_TO_SHADOW(mem) (((mem) >> SHADOW_SCALE) + (SHADOW_OFFSET))
#define SHADOW_TO_MEM(shadow) (((shadow) - SHADOW_OFFSET) << SHADOW_SCALE)
#if SANITIZER_WORDSIZE == 64
# if defined(__powerpc64__)
static const uptr kHighMemEnd = 0x00000fffffffffffUL;
# else
static const uptr kHighMemEnd = 0x00007fffffffffffUL;
# endif
#else // SANITIZER_WORDSIZE == 32
static const uptr kHighMemEnd = 0xffffffff;
#endif // SANITIZER_WORDSIZE
#define kLowMemBeg 0
#define kLowMemEnd (SHADOW_OFFSET ? SHADOW_OFFSET - 1 : 0)
@ -68,59 +92,121 @@ extern SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_mapping_offset;
#define kHighShadowBeg MEM_TO_SHADOW(kHighMemBeg)
#define kHighShadowEnd MEM_TO_SHADOW(kHighMemEnd)
# define kMidShadowBeg MEM_TO_SHADOW(kMidMemBeg)
# define kMidShadowEnd MEM_TO_SHADOW(kMidMemEnd)
// With the zero shadow base we can not actually map pages starting from 0.
// This constant is somewhat arbitrary.
#define kZeroBaseShadowStart (1 << 18)
#define kShadowGapBeg (kLowShadowEnd ? kLowShadowEnd + 1 \
: kZeroBaseShadowStart)
#define kShadowGapEnd (kHighShadowBeg - 1)
#define kShadowGapEnd ((kMidMemBeg ? kMidShadowBeg : kHighShadowBeg) - 1)
#define kGlobalAndStackRedzone \
(SHADOW_GRANULARITY < 32 ? 32 : SHADOW_GRANULARITY)
#define kShadowGap2Beg (kMidMemBeg ? kMidShadowEnd + 1 : 0)
#define kShadowGap2End (kMidMemBeg ? kMidMemBeg - 1 : 0)
#define kShadowGap3Beg (kMidMemBeg ? kMidMemEnd + 1 : 0)
#define kShadowGap3End (kMidMemBeg ? kHighShadowBeg - 1 : 0)
#define DO_ASAN_MAPPING_PROFILE 0 // Set to 1 to profile the functions below.
#if DO_ASAN_MAPPING_PROFILE
# define PROFILE_ASAN_MAPPING() AsanMappingProfile[__LINE__]++;
#else
# define PROFILE_ASAN_MAPPING()
#endif
// If 1, all shadow boundaries are constants.
// Don't set to 1 other than for testing.
#define ASAN_FIXED_MAPPING 0
namespace __asan {
extern uptr AsanMappingProfile[];
#if ASAN_FIXED_MAPPING
// Fixed mapping for 64-bit Linux. Mostly used for performance comparison
// with non-fixed mapping. As of r175253 (Feb 2013) the performance
// difference between fixed and non-fixed mapping is below the noise level.
static uptr kHighMemEnd = 0x7fffffffffffULL;
static uptr kMidMemBeg = 0x3000000000ULL;
static uptr kMidMemEnd = 0x4fffffffffULL;
#else
SANITIZER_INTERFACE_ATTRIBUTE
extern uptr kHighMemEnd, kMidMemBeg, kMidMemEnd; // Initialized in __asan_init.
#endif
static inline bool AddrIsInLowMem(uptr a) {
PROFILE_ASAN_MAPPING();
return a < kLowMemEnd;
}
static inline bool AddrIsInLowShadow(uptr a) {
PROFILE_ASAN_MAPPING();
return a >= kLowShadowBeg && a <= kLowShadowEnd;
}
static inline bool AddrIsInHighMem(uptr a) {
PROFILE_ASAN_MAPPING();
return a >= kHighMemBeg && a <= kHighMemEnd;
}
static inline bool AddrIsInMidMem(uptr a) {
PROFILE_ASAN_MAPPING();
return kMidMemBeg && a >= kMidMemBeg && a <= kMidMemEnd;
}
static inline bool AddrIsInMem(uptr a) {
return AddrIsInLowMem(a) || AddrIsInHighMem(a);
PROFILE_ASAN_MAPPING();
return AddrIsInLowMem(a) || AddrIsInMidMem(a) || AddrIsInHighMem(a);
}
static inline uptr MemToShadow(uptr p) {
PROFILE_ASAN_MAPPING();
CHECK(AddrIsInMem(p));
return MEM_TO_SHADOW(p);
}
static inline bool AddrIsInHighShadow(uptr a) {
return a >= kHighShadowBeg && a <= kHighMemEnd;
PROFILE_ASAN_MAPPING();
return a >= kHighShadowBeg && a <= kHighMemEnd;
}
static inline bool AddrIsInMidShadow(uptr a) {
PROFILE_ASAN_MAPPING();
return kMidMemBeg && a >= kMidShadowBeg && a <= kMidMemEnd;
}
static inline bool AddrIsInShadow(uptr a) {
return AddrIsInLowShadow(a) || AddrIsInHighShadow(a);
PROFILE_ASAN_MAPPING();
return AddrIsInLowShadow(a) || AddrIsInMidShadow(a) || AddrIsInHighShadow(a);
}
static inline bool AddrIsInShadowGap(uptr a) {
PROFILE_ASAN_MAPPING();
if (kMidMemBeg) {
if (a <= kShadowGapEnd)
return SHADOW_OFFSET == 0 || a >= kShadowGapBeg;
return (a >= kShadowGap2Beg && a <= kShadowGap2End) ||
(a >= kShadowGap3Beg && a <= kShadowGap3End);
}
// In zero-based shadow mode we treat addresses near zero as addresses
// in shadow gap as well.
if (SHADOW_OFFSET == 0)
return a <= kShadowGapEnd;
return a >= kShadowGapBeg && a <= kShadowGapEnd;
}
static inline bool AddrIsAlignedByGranularity(uptr a) {
PROFILE_ASAN_MAPPING();
return (a & (SHADOW_GRANULARITY - 1)) == 0;
}
static inline bool AddressIsPoisoned(uptr a) {
PROFILE_ASAN_MAPPING();
const uptr kAccessSize = 1;
u8 *shadow_address = (u8*)MemToShadow(a);
u8 *shadow_address = (u8*)MEM_TO_SHADOW(a);
s8 shadow_value = *shadow_address;
if (shadow_value) {
u8 last_accessed_byte = (a & (SHADOW_GRANULARITY - 1))
@ -130,6 +216,9 @@ static inline bool AddressIsPoisoned(uptr a) {
return false;
}
// Must be after all calls to PROFILE_ASAN_MAPPING().
static const uptr kAsanMappingProfileSize = __LINE__;
} // namespace __asan
#endif // ASAN_MAPPING_H

View File

@ -28,7 +28,8 @@ void ReplaceOperatorsNewAndDelete() { }
using namespace __asan; // NOLINT
// On Android new() goes through malloc interceptors.
#if !ASAN_ANDROID
// See also https://code.google.com/p/address-sanitizer/issues/detail?id=131.
#if !SANITIZER_ANDROID
// Fake std::nothrow_t to avoid including <new>.
namespace std {
@ -39,6 +40,14 @@ struct nothrow_t {};
GET_STACK_TRACE_MALLOC;\
return asan_memalign(0, size, &stack, type);
// On OS X it's not enough to just provide our own 'operator new' and
// 'operator delete' implementations, because they're going to be in the
// runtime dylib, and the main executable will depend on both the runtime
// dylib and libstdc++, each of those'll have its implementation of new and
// delete.
// To make sure that C++ allocation/deallocation operators are overridden on
// OS X we need to intercept them using their mangled names.
#if !SANITIZER_MAC
INTERCEPTOR_ATTRIBUTE
void *operator new(size_t size) { OPERATOR_NEW_BODY(FROM_NEW); }
INTERCEPTOR_ATTRIBUTE
@ -50,10 +59,26 @@ INTERCEPTOR_ATTRIBUTE
void *operator new[](size_t size, std::nothrow_t const&)
{ OPERATOR_NEW_BODY(FROM_NEW_BR); }
#else // SANITIZER_MAC
INTERCEPTOR(void *, _Znwm, size_t size) {
OPERATOR_NEW_BODY(FROM_NEW);
}
INTERCEPTOR(void *, _Znam, size_t size) {
OPERATOR_NEW_BODY(FROM_NEW_BR);
}
INTERCEPTOR(void *, _ZnwmRKSt9nothrow_t, size_t size, std::nothrow_t const&) {
OPERATOR_NEW_BODY(FROM_NEW);
}
INTERCEPTOR(void *, _ZnamRKSt9nothrow_t, size_t size, std::nothrow_t const&) {
OPERATOR_NEW_BODY(FROM_NEW_BR);
}
#endif
#define OPERATOR_DELETE_BODY(type) \
GET_STACK_TRACE_FREE;\
asan_free(ptr, &stack, type);
#if !SANITIZER_MAC
INTERCEPTOR_ATTRIBUTE
void operator delete(void *ptr) { OPERATOR_DELETE_BODY(FROM_NEW); }
INTERCEPTOR_ATTRIBUTE
@ -65,4 +90,19 @@ INTERCEPTOR_ATTRIBUTE
void operator delete[](void *ptr, std::nothrow_t const&)
{ OPERATOR_DELETE_BODY(FROM_NEW_BR); }
#else // SANITIZER_MAC
INTERCEPTOR(void, _ZdlPv, void *ptr) {
OPERATOR_DELETE_BODY(FROM_NEW);
}
INTERCEPTOR(void, _ZdaPv, void *ptr) {
OPERATOR_DELETE_BODY(FROM_NEW_BR);
}
INTERCEPTOR(void, _ZdlPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&) {
OPERATOR_DELETE_BODY(FROM_NEW);
}
INTERCEPTOR(void, _ZdaPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&) {
OPERATOR_DELETE_BODY(FROM_NEW_BR);
}
#endif
#endif

View File

@ -12,10 +12,7 @@
// Shadow memory poisoning by ASan RTL and by user application.
//===----------------------------------------------------------------------===//
#include "asan_interceptors.h"
#include "asan_internal.h"
#include "asan_mapping.h"
#include "sanitizer/asan_interface.h"
#include "asan_poisoning.h"
#include "sanitizer_common/sanitizer_libc.h"
namespace __asan {
@ -23,11 +20,11 @@ namespace __asan {
void PoisonShadow(uptr addr, uptr size, u8 value) {
if (!flags()->poison_heap) return;
CHECK(AddrIsAlignedByGranularity(addr));
CHECK(AddrIsInMem(addr));
CHECK(AddrIsAlignedByGranularity(addr + size));
uptr shadow_beg = MemToShadow(addr);
uptr shadow_end = MemToShadow(addr + size - SHADOW_GRANULARITY) + 1;
CHECK(REAL(memset) != 0);
REAL(memset)((void*)shadow_beg, value, shadow_end - shadow_beg);
CHECK(AddrIsInMem(addr + size - SHADOW_GRANULARITY));
CHECK(REAL(memset));
FastPoisonShadow(addr, size, value);
}
void PoisonShadowPartialRightRedzone(uptr addr,
@ -36,20 +33,10 @@ void PoisonShadowPartialRightRedzone(uptr addr,
u8 value) {
if (!flags()->poison_heap) return;
CHECK(AddrIsAlignedByGranularity(addr));
u8 *shadow = (u8*)MemToShadow(addr);
for (uptr i = 0; i < redzone_size;
i += SHADOW_GRANULARITY, shadow++) {
if (i + SHADOW_GRANULARITY <= size) {
*shadow = 0; // fully addressable
} else if (i >= size) {
*shadow = (SHADOW_GRANULARITY == 128) ? 0xff : value; // unaddressable
} else {
*shadow = size - i; // first size-i bytes are addressable
}
}
CHECK(AddrIsInMem(addr));
FastPoisonShadowPartialRightRedzone(addr, size, redzone_size, value);
}
struct ShadowSegmentEndpoint {
u8 *chunk;
s8 offset; // in [0, SHADOW_GRANULARITY)
@ -182,6 +169,55 @@ uptr __asan_region_is_poisoned(uptr beg, uptr size) {
return 0;
}
#define CHECK_SMALL_REGION(p, size, isWrite) \
do { \
uptr __p = reinterpret_cast<uptr>(p); \
uptr __size = size; \
if (UNLIKELY(__asan::AddressIsPoisoned(__p) || \
__asan::AddressIsPoisoned(__p + __size - 1))) { \
GET_CURRENT_PC_BP_SP; \
uptr __bad = __asan_region_is_poisoned(__p, __size); \
__asan_report_error(pc, bp, sp, __bad, isWrite, __size);\
} \
} while (false); \
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
u16 __sanitizer_unaligned_load16(const u16 *p) {
CHECK_SMALL_REGION(p, sizeof(*p), false);
return *p;
}
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
u32 __sanitizer_unaligned_load32(const u32 *p) {
CHECK_SMALL_REGION(p, sizeof(*p), false);
return *p;
}
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
u64 __sanitizer_unaligned_load64(const u64 *p) {
CHECK_SMALL_REGION(p, sizeof(*p), false);
return *p;
}
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
void __sanitizer_unaligned_store16(u16 *p, u16 x) {
CHECK_SMALL_REGION(p, sizeof(*p), true);
*p = x;
}
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
void __sanitizer_unaligned_store32(u32 *p, u32 x) {
CHECK_SMALL_REGION(p, sizeof(*p), true);
*p = x;
}
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
void __sanitizer_unaligned_store64(u64 *p, u64 x) {
CHECK_SMALL_REGION(p, sizeof(*p), true);
*p = x;
}
// This is a simplified version of __asan_(un)poison_memory_region, which
// assumes that left border of region to be poisoned is properly aligned.
static void PoisonAlignedStackMemory(uptr addr, uptr size, bool do_poison) {

58
lib/asan/asan_poisoning.h Normal file
View File

@ -0,0 +1,58 @@
//===-- asan_poisoning.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.
//
// Shadow memory poisoning by ASan RTL and by user application.
//===----------------------------------------------------------------------===//
#include "asan_interceptors.h"
#include "asan_internal.h"
#include "asan_mapping.h"
namespace __asan {
// Poisons the shadow memory for "size" bytes starting from "addr".
void PoisonShadow(uptr addr, uptr size, u8 value);
// Poisons the shadow memory for "redzone_size" bytes starting from
// "addr + size".
void PoisonShadowPartialRightRedzone(uptr addr,
uptr size,
uptr redzone_size,
u8 value);
// Fast versions of PoisonShadow and PoisonShadowPartialRightRedzone that
// assume that memory addresses are properly aligned. Use in
// performance-critical code with care.
ALWAYS_INLINE void FastPoisonShadow(uptr aligned_beg, uptr aligned_size,
u8 value) {
DCHECK(flags()->poison_heap);
uptr shadow_beg = MEM_TO_SHADOW(aligned_beg);
uptr shadow_end = MEM_TO_SHADOW(
aligned_beg + aligned_size - SHADOW_GRANULARITY) + 1;
REAL(memset)((void*)shadow_beg, value, shadow_end - shadow_beg);
}
ALWAYS_INLINE void FastPoisonShadowPartialRightRedzone(
uptr aligned_addr, uptr size, uptr redzone_size, u8 value) {
DCHECK(flags()->poison_heap);
u8 *shadow = (u8*)MEM_TO_SHADOW(aligned_addr);
for (uptr i = 0; i < redzone_size; i += SHADOW_GRANULARITY, shadow++) {
if (i + SHADOW_GRANULARITY <= size) {
*shadow = 0; // fully addressable
} else if (i >= size) {
*shadow = (SHADOW_GRANULARITY == 128) ? 0xff : value; // unaddressable
} else {
*shadow = size - i; // first size-i bytes are addressable
}
}
}
} // namespace __asan

View File

@ -11,14 +11,15 @@
//
// Posix-specific details.
//===----------------------------------------------------------------------===//
#if defined(__linux__) || defined(__APPLE__)
#include "sanitizer_common/sanitizer_platform.h"
#if SANITIZER_LINUX || SANITIZER_MAC
#include "asan_internal.h"
#include "asan_interceptors.h"
#include "asan_mapping.h"
#include "asan_report.h"
#include "asan_stack.h"
#include "asan_thread_registry.h"
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_procmaps.h"
@ -42,7 +43,7 @@ static void MaybeInstallSigaction(int signum,
sigact.sa_sigaction = handler;
sigact.sa_flags = SA_SIGINFO;
if (flags()->use_sigaltstack) sigact.sa_flags |= SA_ONSTACK;
CHECK(0 == REAL(sigaction)(signum, &sigact, 0));
CHECK_EQ(0, REAL(sigaction)(signum, &sigact, 0));
if (flags()->verbosity >= 1) {
Report("Installed the sigaction for signal %d\n", signum);
}
@ -59,7 +60,7 @@ static void ASAN_OnSIGSEGV(int, siginfo_t *siginfo, void *context) {
void SetAlternateSignalStack() {
stack_t altstack, oldstack;
CHECK(0 == sigaltstack(0, &oldstack));
CHECK_EQ(0, sigaltstack(0, &oldstack));
// If the alternate stack is already in place, do nothing.
if ((oldstack.ss_flags & SS_DISABLE) == 0) return;
// TODO(glider): the mapped stack should have the MAP_STACK flag in the
@ -69,10 +70,10 @@ void SetAlternateSignalStack() {
altstack.ss_sp = base;
altstack.ss_flags = 0;
altstack.ss_size = kAltStackSize;
CHECK(0 == sigaltstack(&altstack, 0));
CHECK_EQ(0, sigaltstack(&altstack, 0));
if (flags()->verbosity > 0) {
Report("Alternative stack for T%d set: [%p,%p)\n",
asanThreadRegistry().GetCurrentTidOrInvalid(),
GetCurrentTidOrInvalid(),
altstack.ss_sp, (char*)altstack.ss_sp + altstack.ss_size);
}
}
@ -82,7 +83,7 @@ void UnsetAlternateSignalStack() {
altstack.ss_sp = 0;
altstack.ss_flags = SS_DISABLE;
altstack.ss_size = 0;
CHECK(0 == sigaltstack(&altstack, &oldstack));
CHECK_EQ(0, sigaltstack(&altstack, &oldstack));
UnmapOrDie(oldstack.ss_sp, oldstack.ss_size);
}
@ -102,7 +103,7 @@ static bool tsd_key_inited = false;
void AsanTSDInit(void (*destructor)(void *tsd)) {
CHECK(!tsd_key_inited);
tsd_key_inited = true;
CHECK(0 == pthread_key_create(&tsd_key, destructor));
CHECK_EQ(0, pthread_key_create(&tsd_key, destructor));
}
void *AsanTSDGet() {
@ -117,4 +118,4 @@ void AsanTSDSet(void *tsd) {
} // namespace __asan
#endif // __linux__ || __APPLE_
#endif // SANITIZER_LINUX || SANITIZER_MAC

31
lib/asan/asan_preinit.cc Normal file
View File

@ -0,0 +1,31 @@
//===-- asan_preinit.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.
//
// Call __asan_init at the very early stage of process startup.
// On Linux we use .preinit_array section (unless PIC macro is defined).
//===----------------------------------------------------------------------===//
#include "asan_internal.h"
#if ASAN_USE_PREINIT_ARRAY && !defined(PIC)
// On Linux, we force __asan_init to be called before anyone else
// by placing it into .preinit_array section.
// FIXME: do we have anything like this on Mac?
// The symbol is called __local_asan_preinit, because it's not intended to be
// exported.
__attribute__((section(".preinit_array"), used))
void (*__local_asan_preinit)(void) = __asan_init;
#elif SANITIZER_WINDOWS && defined(_DLL)
// On Windows, when using dynamic CRT (/MD), we can put a pointer
// to __asan_init into the global list of C initializers.
// See crt0dat.c in the CRT sources for the details.
#pragma section(".CRT$XIB", long, read) // NOLINT
__declspec(allocate(".CRT$XIB")) void (*__asan_preinit)() = __asan_init;
#endif

View File

@ -17,8 +17,8 @@
#include "asan_report.h"
#include "asan_stack.h"
#include "asan_thread.h"
#include "asan_thread_registry.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_flags.h"
#include "sanitizer_common/sanitizer_report_decorator.h"
#include "sanitizer_common/sanitizer_symbolizer.h"
@ -120,6 +120,29 @@ static void PrintShadowBytes(const char *before, u8 *bytes,
Printf("\n");
}
static void PrintLegend() {
Printf("Shadow byte legend (one shadow byte represents %d "
"application bytes):\n", (int)SHADOW_GRANULARITY);
PrintShadowByte(" Addressable: ", 0);
Printf(" Partially addressable: ");
for (uptr i = 1; i < SHADOW_GRANULARITY; i++)
PrintShadowByte("", i, " ");
Printf("\n");
PrintShadowByte(" Heap left redzone: ", kAsanHeapLeftRedzoneMagic);
PrintShadowByte(" Heap right redzone: ", kAsanHeapRightRedzoneMagic);
PrintShadowByte(" Freed heap region: ", kAsanHeapFreeMagic);
PrintShadowByte(" Stack left redzone: ", kAsanStackLeftRedzoneMagic);
PrintShadowByte(" Stack mid redzone: ", kAsanStackMidRedzoneMagic);
PrintShadowByte(" Stack right redzone: ", kAsanStackRightRedzoneMagic);
PrintShadowByte(" Stack partial redzone: ", kAsanStackPartialRedzoneMagic);
PrintShadowByte(" Stack after return: ", kAsanStackAfterReturnMagic);
PrintShadowByte(" Stack use after scope: ", kAsanStackUseAfterScopeMagic);
PrintShadowByte(" Global redzone: ", kAsanGlobalRedzoneMagic);
PrintShadowByte(" Global init order: ", kAsanInitializationOrderMagic);
PrintShadowByte(" Poisoned by user: ", kAsanUserPoisonedMemoryMagic);
PrintShadowByte(" ASan internal: ", kAsanInternalHeapMagic);
}
static void PrintShadowMemoryForAddress(uptr addr) {
if (!AddrIsInMem(addr))
return;
@ -133,26 +156,8 @@ static void PrintShadowMemoryForAddress(uptr addr) {
(u8*)(aligned_shadow + i * n_bytes_per_row),
(u8*)shadow_addr, n_bytes_per_row);
}
Printf("Shadow byte legend (one shadow byte represents %d "
"application bytes):\n", (int)SHADOW_GRANULARITY);
PrintShadowByte(" Addressable: ", 0);
Printf(" Partially addressable: ");
for (uptr i = 1; i < SHADOW_GRANULARITY; i++)
PrintShadowByte("", i, " ");
Printf("\n");
PrintShadowByte(" Heap left redzone: ", kAsanHeapLeftRedzoneMagic);
PrintShadowByte(" Heap righ redzone: ", kAsanHeapRightRedzoneMagic);
PrintShadowByte(" Freed Heap region: ", kAsanHeapFreeMagic);
PrintShadowByte(" Stack left redzone: ", kAsanStackLeftRedzoneMagic);
PrintShadowByte(" Stack mid redzone: ", kAsanStackMidRedzoneMagic);
PrintShadowByte(" Stack right redzone: ", kAsanStackRightRedzoneMagic);
PrintShadowByte(" Stack partial redzone: ", kAsanStackPartialRedzoneMagic);
PrintShadowByte(" Stack after return: ", kAsanStackAfterReturnMagic);
PrintShadowByte(" Stack use after scope: ", kAsanStackUseAfterScopeMagic);
PrintShadowByte(" Global redzone: ", kAsanGlobalRedzoneMagic);
PrintShadowByte(" Global init order: ", kAsanInitializationOrderMagic);
PrintShadowByte(" Poisoned by user: ", kAsanUserPoisonedMemoryMagic);
PrintShadowByte(" ASan internal: ", kAsanInternalHeapMagic);
if (flags()->print_legend)
PrintLegend();
}
static void PrintZoneForPointer(uptr ptr, uptr zone_ptr,
@ -176,30 +181,43 @@ static bool IsASCII(unsigned char c) {
return /*0x00 <= c &&*/ c <= 0x7F;
}
static const char *MaybeDemangleGlobalName(const char *name) {
// We can spoil names of globals with C linkage, so use an heuristic
// approach to check if the name should be demangled.
return (name[0] == '_' && name[1] == 'Z') ? Demangle(name) : name;
}
// Check if the global is a zero-terminated ASCII string. If so, print it.
static void PrintGlobalNameIfASCII(const __asan_global &g) {
for (uptr p = g.beg; p < g.beg + g.size - 1; p++) {
if (!IsASCII(*(unsigned char*)p)) return;
unsigned char c = *(unsigned char*)p;
if (c == '\0' || !IsASCII(c)) return;
}
if (*(char*)(g.beg + g.size - 1) != 0) return;
Printf(" '%s' is ascii string '%s'\n", g.name, (char*)g.beg);
if (*(char*)(g.beg + g.size - 1) != '\0') return;
Printf(" '%s' is ascii string '%s'\n",
MaybeDemangleGlobalName(g.name), (char*)g.beg);
}
bool DescribeAddressRelativeToGlobal(uptr addr, const __asan_global &g) {
if (addr < g.beg - kGlobalAndStackRedzone) return false;
bool DescribeAddressRelativeToGlobal(uptr addr, uptr size,
const __asan_global &g) {
static const uptr kMinimalDistanceFromAnotherGlobal = 64;
if (addr <= g.beg - kMinimalDistanceFromAnotherGlobal) return false;
if (addr >= g.beg + g.size_with_redzone) return false;
Decorator d;
Printf("%s", d.Location());
Printf("%p is located ", (void*)addr);
if (addr < g.beg) {
Printf("%zd bytes to the left", g.beg - addr);
} else if (addr >= g.beg + g.size) {
Printf("%zd bytes to the right", addr - (g.beg + g.size));
Printf("%p is located %zd bytes to the left", (void*)addr, g.beg - addr);
} else if (addr + size > g.beg + g.size) {
if (addr < g.beg + g.size)
addr = g.beg + g.size;
Printf("%p is located %zd bytes to the right", (void*)addr,
addr - (g.beg + g.size));
} else {
Printf("%zd bytes inside", addr - g.beg); // Can it happen?
// Can it happen?
Printf("%p is located %zd bytes inside", (void*)addr, addr - g.beg);
}
Printf(" of global variable '%s' (0x%zx) of size %zu\n",
g.name, g.beg, g.size);
Printf(" of global variable '%s' from '%s' (0x%zx) of size %zu\n",
MaybeDemangleGlobalName(g.name), g.module_name, g.beg, g.size);
Printf("%s", d.EndLocation());
PrintGlobalNameIfASCII(g);
return true;
@ -226,34 +244,70 @@ bool DescribeAddressIfShadow(uptr addr) {
return false;
}
// Return " (thread_name) " or an empty string if the name is empty.
const char *ThreadNameWithParenthesis(AsanThreadContext *t, char buff[],
uptr buff_len) {
const char *name = t->name;
if (name[0] == '\0') return "";
buff[0] = 0;
internal_strncat(buff, " (", 3);
internal_strncat(buff, name, buff_len - 4);
internal_strncat(buff, ")", 2);
return buff;
}
const char *ThreadNameWithParenthesis(u32 tid, char buff[],
uptr buff_len) {
if (tid == kInvalidTid) return "";
asanThreadRegistry().CheckLocked();
AsanThreadContext *t = GetThreadContextByTidLocked(tid);
return ThreadNameWithParenthesis(t, buff, buff_len);
}
bool DescribeAddressIfStack(uptr addr, uptr access_size) {
AsanThread *t = asanThreadRegistry().FindThreadByStackAddress(addr);
AsanThread *t = FindThreadByStackAddress(addr);
if (!t) return false;
const sptr kBufSize = 4095;
char buf[kBufSize];
uptr offset = 0;
const char *frame_descr = t->GetFrameNameByAddr(addr, &offset);
uptr frame_pc = 0;
char tname[128];
const char *frame_descr = t->GetFrameNameByAddr(addr, &offset, &frame_pc);
#ifdef __powerpc64__
// On PowerPC64, the address of a function actually points to a
// three-doubleword data structure with the first field containing
// the address of the function's code.
frame_pc = *reinterpret_cast<uptr *>(frame_pc);
#endif
// This string is created by the compiler and has the following form:
// "FunctioName n alloc_1 alloc_2 ... alloc_n"
// "n alloc_1 alloc_2 ... alloc_n"
// where alloc_i looks like "offset size len ObjectName ".
CHECK(frame_descr);
// Report the function name and the offset.
const char *name_end = internal_strchr(frame_descr, ' ');
CHECK(name_end);
buf[0] = 0;
internal_strncat(buf, frame_descr,
Min(kBufSize,
static_cast<sptr>(name_end - frame_descr)));
Decorator d;
Printf("%s", d.Location());
Printf("Address %p is located at offset %zu "
"in frame <%s> of T%d's stack:\n",
(void*)addr, offset, Demangle(buf), t->tid());
Printf("Address %p is located in stack of thread T%d%s "
"at offset %zu in frame\n",
addr, t->tid(),
ThreadNameWithParenthesis(t->tid(), tname, sizeof(tname)),
offset);
// Now we print the frame where the alloca has happened.
// We print this frame as a stack trace with one element.
// The symbolizer may print more than one frame if inlining was involved.
// The frame numbers may be different than those in the stack trace printed
// previously. That's unfortunate, but I have no better solution,
// especially given that the alloca may be from entirely different place
// (e.g. use-after-scope, or different thread's stack).
StackTrace alloca_stack;
alloca_stack.trace[0] = frame_pc + 16;
alloca_stack.size = 1;
Printf("%s", d.EndLocation());
PrintStack(&alloca_stack);
// Report the number of stack objects.
char *p;
uptr n_objects = internal_simple_strtoll(name_end, &p, 10);
CHECK(n_objects > 0);
uptr n_objects = internal_simple_strtoll(frame_descr, &p, 10);
CHECK_GT(n_objects, 0);
Printf(" This frame has %zu object(s):\n", n_objects);
// Report all objects in this frame.
for (uptr i = 0; i < n_objects; i++) {
@ -276,87 +330,73 @@ bool DescribeAddressIfStack(uptr addr, uptr access_size) {
Printf("HINT: this may be a false positive if your program uses "
"some custom stack unwind mechanism or swapcontext\n"
" (longjmp and C++ exceptions *are* supported)\n");
DescribeThread(t->summary());
DescribeThread(t->context());
return true;
}
static void DescribeAccessToHeapChunk(AsanChunkView chunk, uptr addr,
uptr access_size) {
uptr offset;
sptr offset;
Decorator d;
Printf("%s", d.Location());
Printf("%p is located ", (void*)addr);
if (chunk.AddrIsInside(addr, access_size, &offset)) {
Printf("%zu bytes inside of", offset);
} else if (chunk.AddrIsAtLeft(addr, access_size, &offset)) {
Printf("%zu bytes to the left of", offset);
if (chunk.AddrIsAtLeft(addr, access_size, &offset)) {
Printf("%p is located %zd bytes to the left of", (void*)addr, offset);
} else if (chunk.AddrIsAtRight(addr, access_size, &offset)) {
Printf("%zu bytes to the right of", offset);
if (offset < 0) {
addr -= offset;
offset = 0;
}
Printf("%p is located %zd bytes to the right of", (void*)addr, offset);
} else if (chunk.AddrIsInside(addr, access_size, &offset)) {
Printf("%p is located %zd bytes inside of", (void*)addr, offset);
} else {
Printf(" somewhere around (this is AddressSanitizer bug!)");
Printf("%p is located somewhere around (this is AddressSanitizer bug!)",
(void*)addr);
}
Printf(" %zu-byte region [%p,%p)\n", chunk.UsedSize(),
(void*)(chunk.Beg()), (void*)(chunk.End()));
Printf("%s", d.EndLocation());
}
// Return " (thread_name) " or an empty string if the name is empty.
const char *ThreadNameWithParenthesis(AsanThreadSummary *t, char buff[],
uptr buff_len) {
const char *name = t->name();
if (*name == 0) return "";
buff[0] = 0;
internal_strncat(buff, " (", 3);
internal_strncat(buff, name, buff_len - 4);
internal_strncat(buff, ")", 2);
return buff;
}
const char *ThreadNameWithParenthesis(u32 tid, char buff[],
uptr buff_len) {
if (tid == kInvalidTid) return "";
AsanThreadSummary *t = asanThreadRegistry().FindByTid(tid);
return ThreadNameWithParenthesis(t, buff, buff_len);
}
void DescribeHeapAddress(uptr addr, uptr access_size) {
AsanChunkView chunk = FindHeapChunkByAddress(addr);
if (!chunk.IsValid()) return;
DescribeAccessToHeapChunk(chunk, addr, access_size);
CHECK(chunk.AllocTid() != kInvalidTid);
AsanThreadSummary *alloc_thread =
asanThreadRegistry().FindByTid(chunk.AllocTid());
asanThreadRegistry().CheckLocked();
AsanThreadContext *alloc_thread =
GetThreadContextByTidLocked(chunk.AllocTid());
StackTrace alloc_stack;
chunk.GetAllocStack(&alloc_stack);
AsanThread *t = asanThreadRegistry().GetCurrent();
AsanThread *t = GetCurrentThread();
CHECK(t);
char tname[128];
Decorator d;
if (chunk.FreeTid() != kInvalidTid) {
AsanThreadSummary *free_thread =
asanThreadRegistry().FindByTid(chunk.FreeTid());
AsanThreadContext *free_thread =
GetThreadContextByTidLocked(chunk.FreeTid());
Printf("%sfreed by thread T%d%s here:%s\n", d.Allocation(),
free_thread->tid(),
free_thread->tid,
ThreadNameWithParenthesis(free_thread, tname, sizeof(tname)),
d.EndAllocation());
StackTrace free_stack;
chunk.GetFreeStack(&free_stack);
PrintStack(&free_stack);
Printf("%spreviously allocated by thread T%d%s here:%s\n",
d.Allocation(), alloc_thread->tid(),
d.Allocation(), alloc_thread->tid,
ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)),
d.EndAllocation());
PrintStack(&alloc_stack);
DescribeThread(t->summary());
DescribeThread(t->context());
DescribeThread(free_thread);
DescribeThread(alloc_thread);
} else {
Printf("%sallocated by thread T%d%s here:%s\n", d.Allocation(),
alloc_thread->tid(),
alloc_thread->tid,
ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)),
d.EndAllocation());
PrintStack(&alloc_stack);
DescribeThread(t->summary());
DescribeThread(t->context());
DescribeThread(alloc_thread);
}
}
@ -366,7 +406,7 @@ void DescribeAddress(uptr addr, uptr access_size) {
if (DescribeAddressIfShadow(addr))
return;
CHECK(AddrIsInMem(addr));
if (DescribeAddressIfGlobal(addr))
if (DescribeAddressIfGlobal(addr, access_size))
return;
if (DescribeAddressIfStack(addr, access_size))
return;
@ -376,26 +416,27 @@ void DescribeAddress(uptr addr, uptr access_size) {
// ------------------- Thread description -------------------- {{{1
void DescribeThread(AsanThreadSummary *summary) {
CHECK(summary);
void DescribeThread(AsanThreadContext *context) {
CHECK(context);
asanThreadRegistry().CheckLocked();
// No need to announce the main thread.
if (summary->tid() == 0 || summary->announced()) {
if (context->tid == 0 || context->announced) {
return;
}
summary->set_announced(true);
context->announced = true;
char tname[128];
Printf("Thread T%d%s", summary->tid(),
ThreadNameWithParenthesis(summary->tid(), tname, sizeof(tname)));
Printf("Thread T%d%s", context->tid,
ThreadNameWithParenthesis(context->tid, tname, sizeof(tname)));
Printf(" created by T%d%s here:\n",
summary->parent_tid(),
ThreadNameWithParenthesis(summary->parent_tid(),
context->parent_tid,
ThreadNameWithParenthesis(context->parent_tid,
tname, sizeof(tname)));
PrintStack(summary->stack());
PrintStack(&context->stack);
// Recursively described parent thread if needed.
if (flags()->print_full_thread_history) {
AsanThreadSummary *parent_summary =
asanThreadRegistry().FindByTid(summary->parent_tid());
DescribeThread(parent_summary);
AsanThreadContext *parent_context =
GetThreadContextByTidLocked(context->parent_tid);
DescribeThread(parent_context);
}
}
@ -414,25 +455,31 @@ class ScopedInErrorReport {
// they are defined as no-return.
Report("AddressSanitizer: while reporting a bug found another one."
"Ignoring.\n");
u32 current_tid = asanThreadRegistry().GetCurrentTidOrInvalid();
u32 current_tid = GetCurrentTidOrInvalid();
if (current_tid != reporting_thread_tid) {
// ASan found two bugs in different threads simultaneously. Sleep
// long enough to make sure that the thread which started to print
// an error report will finish doing it.
SleepForSeconds(Max(100, flags()->sleep_before_dying + 1));
}
// If we're still not dead for some reason, use raw Exit() instead of
// If we're still not dead for some reason, use raw _exit() instead of
// Die() to bypass any additional checks.
Exit(flags()->exitcode);
internal__exit(flags()->exitcode);
}
ASAN_ON_ERROR();
reporting_thread_tid = asanThreadRegistry().GetCurrentTidOrInvalid();
// Make sure the registry and sanitizer report mutexes are locked while
// we're printing an error report.
// We can lock them only here to avoid self-deadlock in case of
// recursive reports.
asanThreadRegistry().Lock();
CommonSanitizerReportMutex.Lock();
reporting_thread_tid = GetCurrentTidOrInvalid();
Printf("===================================================="
"=============\n");
if (reporting_thread_tid != kInvalidTid) {
// We started reporting an error message. Stop using the fake stack
// in case we call an instrumented function from a symbolizer.
AsanThread *curr_thread = asanThreadRegistry().GetCurrent();
AsanThread *curr_thread = GetCurrentThread();
CHECK(curr_thread);
curr_thread->fake_stack().StopUsingFakeStack();
}
@ -440,12 +487,13 @@ class ScopedInErrorReport {
// Destructor is NORETURN, as functions that report errors are.
NORETURN ~ScopedInErrorReport() {
// Make sure the current thread is announced.
AsanThread *curr_thread = asanThreadRegistry().GetCurrent();
AsanThread *curr_thread = GetCurrentThread();
if (curr_thread) {
DescribeThread(curr_thread->summary());
DescribeThread(curr_thread->context());
}
// Print memory stats.
__asan_print_accumulated_stats();
if (flags()->print_stats)
__asan_print_accumulated_stats();
if (error_report_callback) {
error_report_callback(error_message_buffer);
}
@ -454,6 +502,22 @@ class ScopedInErrorReport {
}
};
static void ReportSummary(const char *error_type, StackTrace *stack) {
if (!stack->size) return;
if (IsSymbolizerAvailable()) {
AddressInfo ai;
// Currently, we include the first stack frame into the report summary.
// Maybe sometimes we need to choose another frame (e.g. skip memcpy/etc).
uptr pc = StackTrace::GetPreviousInstructionPc(stack->trace[0]);
SymbolizeCode(pc, &ai, 1);
ReportErrorSummary(error_type,
StripPathPrefix(ai.file,
common_flags()->strip_path_prefix),
ai.line, ai.function);
}
// FIXME: do we need to print anything at all if there is no symbolizer?
}
void ReportSIGSEGV(uptr pc, uptr sp, uptr bp, uptr addr) {
ScopedInErrorReport in_report;
Decorator d;
@ -461,32 +525,44 @@ void ReportSIGSEGV(uptr pc, uptr sp, uptr bp, uptr addr) {
Report("ERROR: AddressSanitizer: SEGV on unknown address %p"
" (pc %p sp %p bp %p T%d)\n",
(void*)addr, (void*)pc, (void*)sp, (void*)bp,
asanThreadRegistry().GetCurrentTidOrInvalid());
GetCurrentTidOrInvalid());
Printf("%s", d.EndWarning());
Printf("AddressSanitizer can not provide additional info.\n");
GET_STACK_TRACE_FATAL(pc, bp);
PrintStack(&stack);
ReportSummary("SEGV", &stack);
}
void ReportDoubleFree(uptr addr, StackTrace *stack) {
ScopedInErrorReport in_report;
Decorator d;
Printf("%s", d.Warning());
Report("ERROR: AddressSanitizer: attempting double-free on %p:\n", addr);
char tname[128];
u32 curr_tid = GetCurrentTidOrInvalid();
Report("ERROR: AddressSanitizer: attempting double-free on %p in "
"thread T%d%s:\n",
addr, curr_tid,
ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname)));
Printf("%s", d.EndWarning());
PrintStack(stack);
DescribeHeapAddress(addr, 1);
ReportSummary("double-free", stack);
}
void ReportFreeNotMalloced(uptr addr, StackTrace *stack) {
ScopedInErrorReport in_report;
Decorator d;
Printf("%s", d.Warning());
char tname[128];
u32 curr_tid = GetCurrentTidOrInvalid();
Report("ERROR: AddressSanitizer: attempting free on address "
"which was not malloc()-ed: %p\n", addr);
"which was not malloc()-ed: %p in thread T%d%s\n", addr,
curr_tid, ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname)));
Printf("%s", d.EndWarning());
PrintStack(stack);
DescribeHeapAddress(addr, 1);
ReportSummary("bad-free", stack);
}
void ReportAllocTypeMismatch(uptr addr, StackTrace *stack,
@ -505,6 +581,7 @@ void ReportAllocTypeMismatch(uptr addr, StackTrace *stack,
Printf("%s", d.EndWarning());
PrintStack(stack);
DescribeHeapAddress(addr, 1);
ReportSummary("alloc-dealloc-mismatch", stack);
Report("HINT: if you don't care about these warnings you may set "
"ASAN_OPTIONS=alloc_dealloc_mismatch=0\n");
}
@ -519,6 +596,7 @@ void ReportMallocUsableSizeNotOwned(uptr addr, StackTrace *stack) {
Printf("%s", d.EndWarning());
PrintStack(stack);
DescribeHeapAddress(addr, 1);
ReportSummary("bad-malloc_usable_size", stack);
}
void ReportAsanGetAllocatedSizeNotOwned(uptr addr, StackTrace *stack) {
@ -531,6 +609,7 @@ void ReportAsanGetAllocatedSizeNotOwned(uptr addr, StackTrace *stack) {
Printf("%s", d.EndWarning());
PrintStack(stack);
DescribeHeapAddress(addr, 1);
ReportSummary("bad-__asan_get_allocated_size", stack);
}
void ReportStringFunctionMemoryRangesOverlap(
@ -538,14 +617,17 @@ void ReportStringFunctionMemoryRangesOverlap(
const char *offset2, uptr length2, StackTrace *stack) {
ScopedInErrorReport in_report;
Decorator d;
char bug_type[100];
internal_snprintf(bug_type, sizeof(bug_type), "%s-param-overlap", function);
Printf("%s", d.Warning());
Report("ERROR: AddressSanitizer: %s-param-overlap: "
Report("ERROR: AddressSanitizer: %s: "
"memory ranges [%p,%p) and [%p, %p) overlap\n", \
function, offset1, offset1 + length1, offset2, offset2 + length2);
bug_type, offset1, offset1 + length1, offset2, offset2 + length2);
Printf("%s", d.EndWarning());
PrintStack(stack);
DescribeAddress((uptr)offset1, length1);
DescribeAddress((uptr)offset2, length2);
ReportSummary(bug_type, stack);
}
// ----------------------- Mac-specific reports ----------------- {{{1
@ -642,7 +724,7 @@ void __asan_report_error(uptr pc, uptr bp, uptr sp,
bug_descr, (void*)addr, pc, bp, sp);
Printf("%s", d.EndWarning());
u32 curr_tid = asanThreadRegistry().GetCurrentTidOrInvalid();
u32 curr_tid = GetCurrentTidOrInvalid();
char tname[128];
Printf("%s%s of size %zu at %p thread T%d%s%s\n",
d.Access(),
@ -655,7 +737,7 @@ void __asan_report_error(uptr pc, uptr bp, uptr sp,
PrintStack(&stack);
DescribeAddress(addr, access_size);
ReportSummary(bug_descr, &stack);
PrintShadowMemoryForAddress(addr);
}

View File

@ -15,21 +15,21 @@
#include "asan_allocator.h"
#include "asan_internal.h"
#include "asan_thread.h"
#include "sanitizer/asan_interface.h"
namespace __asan {
// The following functions prints address description depending
// on the memory type (shadow/heap/stack/global).
void DescribeHeapAddress(uptr addr, uptr access_size);
bool DescribeAddressIfGlobal(uptr addr);
bool DescribeAddressRelativeToGlobal(uptr addr, const __asan_global &g);
bool DescribeAddressIfGlobal(uptr addr, uptr access_size);
bool DescribeAddressRelativeToGlobal(uptr addr, uptr access_size,
const __asan_global &g);
bool DescribeAddressIfShadow(uptr addr);
bool DescribeAddressIfStack(uptr addr, uptr access_size);
// Determines memory type on its own.
void DescribeAddress(uptr addr, uptr access_size);
void DescribeThread(AsanThreadSummary *summary);
void DescribeThread(AsanThreadContext *context);
// Different kinds of error reports.
void NORETURN ReportSIGSEGV(uptr pc, uptr sp, uptr bp, uptr addr);

View File

@ -15,19 +15,21 @@
#include "asan_interceptors.h"
#include "asan_internal.h"
#include "asan_mapping.h"
#include "asan_poisoning.h"
#include "asan_report.h"
#include "asan_stack.h"
#include "asan_stats.h"
#include "asan_thread.h"
#include "asan_thread_registry.h"
#include "sanitizer/asan_interface.h"
#include "sanitizer_common/sanitizer_atomic.h"
#include "sanitizer_common/sanitizer_flags.h"
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_symbolizer.h"
#include "lsan/lsan_common.h"
namespace __asan {
uptr AsanMappingProfile[kAsanMappingProfileSize];
static void AsanDie() {
static atomic_uint32_t num_calls;
if (atomic_fetch_add(&num_calls, 1, memory_order_relaxed) != 0) {
@ -38,13 +40,19 @@ static void AsanDie() {
Report("Sleeping for %d second(s)\n", flags()->sleep_before_dying);
SleepForSeconds(flags()->sleep_before_dying);
}
if (flags()->unmap_shadow_on_exit)
UnmapOrDie((void*)kLowShadowBeg, kHighShadowEnd - kLowShadowBeg);
if (flags()->unmap_shadow_on_exit) {
if (kMidMemBeg) {
UnmapOrDie((void*)kLowShadowBeg, kMidMemBeg - kLowShadowBeg);
UnmapOrDie((void*)kMidMemEnd, kHighShadowEnd - kMidMemEnd);
} else {
UnmapOrDie((void*)kLowShadowBeg, kHighShadowEnd - kLowShadowBeg);
}
}
if (death_callback)
death_callback();
if (flags()->abort_on_error)
Abort();
Exit(flags()->exitcode);
internal__exit(flags()->exitcode);
}
static void AsanCheckFailed(const char *file, int line, const char *cond,
@ -57,97 +65,118 @@ static void AsanCheckFailed(const char *file, int line, const char *cond,
}
// -------------------------- Flags ------------------------- {{{1
static const int kDeafultMallocContextSize = 30;
static const int kDefaultMallocContextSize = 30;
static Flags asan_flags;
Flags *flags() {
return &asan_flags;
}
Flags asan_flags_dont_use_directly; // use via flags().
static const char *MaybeCallAsanDefaultOptions() {
return (&__asan_default_options) ? __asan_default_options() : "";
}
static const char *MaybeUseAsanDefaultOptionsCompileDefiniton() {
#ifdef ASAN_DEFAULT_OPTIONS
// Stringize the macro value.
# define ASAN_STRINGIZE(x) #x
# define ASAN_STRINGIZE_OPTIONS(options) ASAN_STRINGIZE(options)
return ASAN_STRINGIZE_OPTIONS(ASAN_DEFAULT_OPTIONS);
#else
return "";
#endif
}
static void ParseFlagsFromString(Flags *f, const char *str) {
ParseCommonFlagsFromString(str);
CHECK((uptr)common_flags()->malloc_context_size <= kStackTraceMax);
ParseFlag(str, &f->quarantine_size, "quarantine_size");
ParseFlag(str, &f->symbolize, "symbolize");
ParseFlag(str, &f->verbosity, "verbosity");
ParseFlag(str, &f->redzone, "redzone");
CHECK(f->redzone >= 16);
CHECK_GE(f->redzone, 16);
CHECK(IsPowerOfTwo(f->redzone));
ParseFlag(str, &f->debug, "debug");
ParseFlag(str, &f->report_globals, "report_globals");
ParseFlag(str, &f->check_initialization_order, "initialization_order");
ParseFlag(str, &f->malloc_context_size, "malloc_context_size");
CHECK((uptr)f->malloc_context_size <= kStackTraceMax);
ParseFlag(str, &f->check_initialization_order, "check_initialization_order");
ParseFlag(str, &f->replace_str, "replace_str");
ParseFlag(str, &f->replace_intrin, "replace_intrin");
ParseFlag(str, &f->replace_cfallocator, "replace_cfallocator");
ParseFlag(str, &f->mac_ignore_invalid_free, "mac_ignore_invalid_free");
ParseFlag(str, &f->use_fake_stack, "use_fake_stack");
ParseFlag(str, &f->max_malloc_fill_size, "max_malloc_fill_size");
ParseFlag(str, &f->malloc_fill_byte, "malloc_fill_byte");
ParseFlag(str, &f->exitcode, "exitcode");
ParseFlag(str, &f->allow_user_poisoning, "allow_user_poisoning");
ParseFlag(str, &f->sleep_before_dying, "sleep_before_dying");
ParseFlag(str, &f->handle_segv, "handle_segv");
ParseFlag(str, &f->allow_user_segv_handler, "allow_user_segv_handler");
ParseFlag(str, &f->use_sigaltstack, "use_sigaltstack");
ParseFlag(str, &f->check_malloc_usable_size, "check_malloc_usable_size");
ParseFlag(str, &f->unmap_shadow_on_exit, "unmap_shadow_on_exit");
ParseFlag(str, &f->abort_on_error, "abort_on_error");
ParseFlag(str, &f->print_stats, "print_stats");
ParseFlag(str, &f->print_legend, "print_legend");
ParseFlag(str, &f->atexit, "atexit");
ParseFlag(str, &f->disable_core, "disable_core");
ParseFlag(str, &f->strip_path_prefix, "strip_path_prefix");
ParseFlag(str, &f->allow_reexec, "allow_reexec");
ParseFlag(str, &f->print_full_thread_history, "print_full_thread_history");
ParseFlag(str, &f->log_path, "log_path");
ParseFlag(str, &f->fast_unwind_on_fatal, "fast_unwind_on_fatal");
ParseFlag(str, &f->fast_unwind_on_malloc, "fast_unwind_on_malloc");
ParseFlag(str, &f->poison_heap, "poison_heap");
ParseFlag(str, &f->alloc_dealloc_mismatch, "alloc_dealloc_mismatch");
ParseFlag(str, &f->use_stack_depot, "use_stack_depot");
ParseFlag(str, &f->strict_memcmp, "strict_memcmp");
ParseFlag(str, &f->strict_init_order, "strict_init_order");
ParseFlag(str, &f->detect_leaks, "detect_leaks");
}
void InitializeFlags(Flags *f, const char *env) {
internal_memset(f, 0, sizeof(*f));
CommonFlags *cf = common_flags();
cf->external_symbolizer_path = GetEnv("ASAN_SYMBOLIZER_PATH");
cf->symbolize = true;
cf->malloc_context_size = kDefaultMallocContextSize;
cf->fast_unwind_on_fatal = false;
cf->fast_unwind_on_malloc = true;
cf->strip_path_prefix = "";
internal_memset(f, 0, sizeof(*f));
f->quarantine_size = (ASAN_LOW_MEMORY) ? 1UL << 26 : 1UL << 28;
f->symbolize = false;
f->verbosity = 0;
f->redzone = ASAN_ALLOCATOR_VERSION == 2 ? 16 : (ASAN_LOW_MEMORY) ? 64 : 128;
f->redzone = 16;
f->debug = false;
f->report_globals = 1;
f->check_initialization_order = true;
f->malloc_context_size = kDeafultMallocContextSize;
f->check_initialization_order = false;
f->replace_str = true;
f->replace_intrin = true;
f->replace_cfallocator = true;
f->mac_ignore_invalid_free = false;
f->use_fake_stack = true;
f->max_malloc_fill_size = 0;
f->max_malloc_fill_size = 0x1000; // By default, fill only the first 4K.
f->malloc_fill_byte = 0xbe;
f->exitcode = ASAN_DEFAULT_FAILURE_EXITCODE;
f->allow_user_poisoning = true;
f->sleep_before_dying = 0;
f->handle_segv = ASAN_NEEDS_SEGV;
f->allow_user_segv_handler = false;
f->use_sigaltstack = false;
f->check_malloc_usable_size = true;
f->unmap_shadow_on_exit = false;
f->abort_on_error = false;
f->print_stats = false;
f->print_legend = true;
f->atexit = false;
f->disable_core = (SANITIZER_WORDSIZE == 64);
f->strip_path_prefix = "";
f->allow_reexec = true;
f->print_full_thread_history = true;
f->log_path = 0;
f->fast_unwind_on_fatal = false;
f->fast_unwind_on_malloc = true;
f->poison_heap = true;
// Turn off alloc/dealloc mismatch checker on Mac for now.
// TODO(glider): Fix known issues and enable this back.
f->alloc_dealloc_mismatch = (ASAN_MAC == 0);
f->use_stack_depot = true; // Only affects allocator2.
f->alloc_dealloc_mismatch = (SANITIZER_MAC == 0);;
f->use_stack_depot = true;
f->strict_memcmp = true;
f->strict_init_order = false;
f->detect_leaks = false;
// Override from compile definition.
ParseFlagsFromString(f, MaybeUseAsanDefaultOptionsCompileDefiniton());
// Override from user-specified string.
ParseFlagsFromString(f, MaybeCallAsanDefaultOptions());
@ -158,6 +187,20 @@ void InitializeFlags(Flags *f, const char *env) {
// Override from command line.
ParseFlagsFromString(f, env);
#if !CAN_SANITIZE_LEAKS
if (f->detect_leaks) {
Report("%s: detect_leaks is not supported on this platform.\n",
SanitizerToolName);
f->detect_leaks = false;
}
#endif
if (f->detect_leaks && !f->use_stack_depot) {
Report("%s: detect_leaks is ignored (requires use_stack_depot).\n",
SanitizerToolName);
f->detect_leaks = false;
}
}
// -------------------------- Globals --------------------- {{{1
@ -165,6 +208,10 @@ int asan_inited;
bool asan_init_is_running;
void (*death_callback)(void);
#if !ASAN_FIXED_MAPPING
uptr kHighMemEnd, kMidMemBeg, kMidMemEnd;
#endif
// -------------------------- Misc ---------------- {{{1
void ShowStatsAndAbort() {
__asan_print_accumulated_stats();
@ -174,8 +221,8 @@ void ShowStatsAndAbort() {
// ---------------------- mmap -------------------- {{{1
// Reserve memory range [beg, end].
static void ReserveShadowMemoryRange(uptr beg, uptr end) {
CHECK((beg % GetPageSizeCached()) == 0);
CHECK(((end + 1) % GetPageSizeCached()) == 0);
CHECK_EQ((beg % GetPageSizeCached()), 0);
CHECK_EQ(((end + 1) % GetPageSizeCached()), 0);
uptr size = end - beg + 1;
void *res = MmapFixedNoReserve(beg, size);
if (res != (void*)beg) {
@ -211,6 +258,17 @@ ASAN_REPORT_ERROR(store, true, 4)
ASAN_REPORT_ERROR(store, true, 8)
ASAN_REPORT_ERROR(store, true, 16)
#define ASAN_REPORT_ERROR_N(type, is_write) \
extern "C" NOINLINE INTERFACE_ATTRIBUTE \
void __asan_report_ ## type ## _n(uptr addr, uptr size); \
void __asan_report_ ## type ## _n(uptr addr, uptr size) { \
GET_CALLER_PC_BP_SP; \
__asan_report_error(pc, bp, sp, addr, is_write, size); \
}
ASAN_REPORT_ERROR_N(load, false)
ASAN_REPORT_ERROR_N(store, true)
// Force the linker to keep the symbols for various ASan interface functions.
// We want to keep those in the executable in order to let the instrumented
// dynamic libraries access the symbol even if it is not used by the executable
@ -249,7 +307,7 @@ static NOINLINE void force_interface_symbols() {
case 27: __asan_set_error_exit_code(0); break;
case 28: __asan_stack_free(0, 0, 0); break;
case 29: __asan_stack_malloc(0, 0); break;
case 30: __asan_before_dynamic_init(0, 0); break;
case 30: __asan_before_dynamic_init(0); break;
case 31: __asan_after_dynamic_init(); break;
case 32: __asan_poison_stack_memory(0, 0); break;
case 33: __asan_unpoison_stack_memory(0, 0); break;
@ -261,6 +319,83 @@ static NOINLINE void force_interface_symbols() {
static void asan_atexit() {
Printf("AddressSanitizer exit stats:\n");
__asan_print_accumulated_stats();
// Print AsanMappingProfile.
for (uptr i = 0; i < kAsanMappingProfileSize; i++) {
if (AsanMappingProfile[i] == 0) continue;
Printf("asan_mapping.h:%zd -- %zd\n", i, AsanMappingProfile[i]);
}
}
static void InitializeHighMemEnd() {
#if !ASAN_FIXED_MAPPING
#if SANITIZER_WORDSIZE == 64
# if defined(__powerpc64__)
// FIXME:
// On PowerPC64 we have two different address space layouts: 44- and 46-bit.
// We somehow need to figure our which one we are using now and choose
// one of 0x00000fffffffffffUL and 0x00003fffffffffffUL.
// Note that with 'ulimit -s unlimited' the stack is moved away from the top
// of the address space, so simply checking the stack address is not enough.
kHighMemEnd = (1ULL << 44) - 1; // 0x00000fffffffffffUL
# else
kHighMemEnd = (1ULL << 47) - 1; // 0x00007fffffffffffUL;
# endif
#else // SANITIZER_WORDSIZE == 32
kHighMemEnd = (1ULL << 32) - 1; // 0xffffffff;
#endif // SANITIZER_WORDSIZE
#endif // !ASAN_FIXED_MAPPING
}
static void ProtectGap(uptr a, uptr size) {
CHECK_EQ(a, (uptr)Mprotect(a, size));
}
static void PrintAddressSpaceLayout() {
Printf("|| `[%p, %p]` || HighMem ||\n",
(void*)kHighMemBeg, (void*)kHighMemEnd);
Printf("|| `[%p, %p]` || HighShadow ||\n",
(void*)kHighShadowBeg, (void*)kHighShadowEnd);
if (kMidMemBeg) {
Printf("|| `[%p, %p]` || ShadowGap3 ||\n",
(void*)kShadowGap3Beg, (void*)kShadowGap3End);
Printf("|| `[%p, %p]` || MidMem ||\n",
(void*)kMidMemBeg, (void*)kMidMemEnd);
Printf("|| `[%p, %p]` || ShadowGap2 ||\n",
(void*)kShadowGap2Beg, (void*)kShadowGap2End);
Printf("|| `[%p, %p]` || MidShadow ||\n",
(void*)kMidShadowBeg, (void*)kMidShadowEnd);
}
Printf("|| `[%p, %p]` || ShadowGap ||\n",
(void*)kShadowGapBeg, (void*)kShadowGapEnd);
if (kLowShadowBeg) {
Printf("|| `[%p, %p]` || LowShadow ||\n",
(void*)kLowShadowBeg, (void*)kLowShadowEnd);
Printf("|| `[%p, %p]` || LowMem ||\n",
(void*)kLowMemBeg, (void*)kLowMemEnd);
}
Printf("MemToShadow(shadow): %p %p %p %p",
(void*)MEM_TO_SHADOW(kLowShadowBeg),
(void*)MEM_TO_SHADOW(kLowShadowEnd),
(void*)MEM_TO_SHADOW(kHighShadowBeg),
(void*)MEM_TO_SHADOW(kHighShadowEnd));
if (kMidMemBeg) {
Printf(" %p %p",
(void*)MEM_TO_SHADOW(kMidShadowBeg),
(void*)MEM_TO_SHADOW(kMidShadowEnd));
}
Printf("\n");
Printf("red_zone=%zu\n", (uptr)flags()->redzone);
Printf("malloc_context_size=%zu\n",
(uptr)common_flags()->malloc_context_size);
Printf("SHADOW_SCALE: %zx\n", (uptr)SHADOW_SCALE);
Printf("SHADOW_GRANULARITY: %zx\n", (uptr)SHADOW_GRANULARITY);
Printf("SHADOW_OFFSET: %zx\n", (uptr)SHADOW_OFFSET);
CHECK(SHADOW_SCALE >= 3 && SHADOW_SCALE <= 7);
if (kMidMemBeg)
CHECK(kMidShadowBeg > kLowShadowEnd &&
kMidMemBeg > kMidShadowEnd &&
kHighShadowBeg > kMidMemEnd);
}
} // namespace __asan
@ -283,11 +418,25 @@ int NOINLINE __asan_set_error_exit_code(int exit_code) {
void NOINLINE __asan_handle_no_return() {
int local_stack;
AsanThread *curr_thread = asanThreadRegistry().GetCurrent();
AsanThread *curr_thread = GetCurrentThread();
CHECK(curr_thread);
uptr PageSize = GetPageSizeCached();
uptr top = curr_thread->stack_top();
uptr bottom = ((uptr)&local_stack - PageSize) & ~(PageSize-1);
static const uptr kMaxExpectedCleanupSize = 64 << 20; // 64M
if (top - bottom > kMaxExpectedCleanupSize) {
static bool reported_warning = false;
if (reported_warning)
return;
reported_warning = true;
Report("WARNING: ASan is ignoring requested __asan_handle_no_return: "
"stack top: %p; bottom %p; size: %p (%zd)\n"
"False positive error reports may follow\n"
"For details see "
"http://code.google.com/p/address-sanitizer/issues/detail?id=189\n",
top, bottom, top - bottom, top - bottom);
return;
}
PoisonShadow(bottom, top - bottom, 0);
}
@ -297,8 +446,10 @@ void NOINLINE __asan_set_death_callback(void (*callback)(void)) {
void __asan_init() {
if (asan_inited) return;
SanitizerToolName = "AddressSanitizer";
CHECK(!asan_init_is_running && "ASan init calls itself!");
asan_init_is_running = true;
InitializeHighMemEnd();
// Make sure we are not statically linked.
AsanDoesNotSupportStaticLinkage();
@ -334,49 +485,48 @@ void __asan_init() {
ReplaceSystemMalloc();
ReplaceOperatorsNewAndDelete();
if (flags()->verbosity) {
Printf("|| `[%p, %p]` || HighMem ||\n",
(void*)kHighMemBeg, (void*)kHighMemEnd);
Printf("|| `[%p, %p]` || HighShadow ||\n",
(void*)kHighShadowBeg, (void*)kHighShadowEnd);
Printf("|| `[%p, %p]` || ShadowGap ||\n",
(void*)kShadowGapBeg, (void*)kShadowGapEnd);
Printf("|| `[%p, %p]` || LowShadow ||\n",
(void*)kLowShadowBeg, (void*)kLowShadowEnd);
Printf("|| `[%p, %p]` || LowMem ||\n",
(void*)kLowMemBeg, (void*)kLowMemEnd);
Printf("MemToShadow(shadow): %p %p %p %p\n",
(void*)MEM_TO_SHADOW(kLowShadowBeg),
(void*)MEM_TO_SHADOW(kLowShadowEnd),
(void*)MEM_TO_SHADOW(kHighShadowBeg),
(void*)MEM_TO_SHADOW(kHighShadowEnd));
Printf("red_zone=%zu\n", (uptr)flags()->redzone);
Printf("malloc_context_size=%zu\n", (uptr)flags()->malloc_context_size);
uptr shadow_start = kLowShadowBeg;
if (kLowShadowBeg) shadow_start -= GetMmapGranularity();
uptr shadow_end = kHighShadowEnd;
bool full_shadow_is_available =
MemoryRangeIsAvailable(shadow_start, shadow_end);
Printf("SHADOW_SCALE: %zx\n", (uptr)SHADOW_SCALE);
Printf("SHADOW_GRANULARITY: %zx\n", (uptr)SHADOW_GRANULARITY);
Printf("SHADOW_OFFSET: %zx\n", (uptr)SHADOW_OFFSET);
CHECK(SHADOW_SCALE >= 3 && SHADOW_SCALE <= 7);
#if SANITIZER_LINUX && defined(__x86_64__) && !ASAN_FIXED_MAPPING
if (!full_shadow_is_available) {
kMidMemBeg = kLowMemEnd < 0x3000000000ULL ? 0x3000000000ULL : 0;
kMidMemEnd = kLowMemEnd < 0x3000000000ULL ? 0x4fffffffffULL : 0;
}
#endif
if (flags()->verbosity)
PrintAddressSpaceLayout();
if (flags()->disable_core) {
DisableCoreDumper();
}
uptr shadow_start = kLowShadowBeg;
if (kLowShadowBeg > 0) shadow_start -= GetMmapGranularity();
uptr shadow_end = kHighShadowEnd;
if (MemoryRangeIsAvailable(shadow_start, shadow_end)) {
if (kLowShadowBeg != kLowShadowEnd) {
// mmap the low shadow plus at least one page.
ReserveShadowMemoryRange(kLowShadowBeg - GetMmapGranularity(),
kLowShadowEnd);
}
if (full_shadow_is_available) {
// mmap the low shadow plus at least one page at the left.
if (kLowShadowBeg)
ReserveShadowMemoryRange(shadow_start, kLowShadowEnd);
// mmap the high shadow.
ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd);
// protect the gap
void *prot = Mprotect(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
CHECK(prot == (void*)kShadowGapBeg);
// protect the gap.
ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
} else if (kMidMemBeg &&
MemoryRangeIsAvailable(shadow_start, kMidMemBeg - 1) &&
MemoryRangeIsAvailable(kMidMemEnd + 1, shadow_end)) {
CHECK(kLowShadowBeg != kLowShadowEnd);
// mmap the low shadow plus at least one page at the left.
ReserveShadowMemoryRange(shadow_start, kLowShadowEnd);
// mmap the mid shadow.
ReserveShadowMemoryRange(kMidShadowBeg, kMidShadowEnd);
// mmap the high shadow.
ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd);
// protect the gaps.
ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
ProtectGap(kShadowGap2Beg, kShadowGap2End - kShadowGap2Beg + 1);
ProtectGap(kShadowGap3Beg, kShadowGap3End - kShadowGap3Beg + 1);
} else {
Report("Shadow memory range interleaves with an existing memory mapping. "
"ASan cannot proceed correctly. ABORTING.\n");
@ -386,11 +536,10 @@ void __asan_init() {
InstallSignalHandlers();
// Start symbolizer process if necessary.
if (flags()->symbolize) {
const char *external_symbolizer = GetEnv("ASAN_SYMBOLIZER_PATH");
if (external_symbolizer) {
InitializeExternalSymbolizer(external_symbolizer);
}
const char* external_symbolizer = common_flags()->external_symbolizer_path;
if (common_flags()->symbolize && external_symbolizer &&
external_symbolizer[0]) {
InitializeExternalSymbolizer(external_symbolizer);
}
// On Linux AsanThread::ThreadStart() calls malloc() that's why asan_inited
@ -398,25 +547,27 @@ void __asan_init() {
asan_inited = 1;
asan_init_is_running = false;
asanThreadRegistry().Init();
asanThreadRegistry().GetMain()->ThreadStart();
// Create main thread.
AsanTSDInit(AsanThread::TSDDtor);
AsanThread *main_thread = AsanThread::Create(0, 0);
CreateThreadContextArgs create_main_args = { main_thread, 0 };
u32 main_tid = asanThreadRegistry().CreateThread(
0, true, 0, &create_main_args);
CHECK_EQ(0, main_tid);
SetCurrentThread(main_thread);
main_thread->ThreadStart(internal_getpid());
force_interface_symbols(); // no-op.
InitializeAllocator();
#if CAN_SANITIZE_LEAKS
__lsan::InitCommonLsan();
if (flags()->detect_leaks) {
Atexit(__lsan::DoLeakCheck);
}
#endif // CAN_SANITIZE_LEAKS
if (flags()->verbosity) {
Report("AddressSanitizer Init done\n");
}
}
#if defined(ASAN_USE_PREINIT_ARRAY)
// On Linux, we force __asan_init to be called before anyone else
// by placing it into .preinit_array section.
// FIXME: do we have anything like this on Mac?
__attribute__((section(".preinit_array")))
typeof(__asan_init) *__asan_preinit =__asan_init;
#elif defined(_WIN32) && defined(_DLL)
// On Windows, when using dynamic CRT (/MD), we can put a pointer
// to __asan_init into the global list of C initializers.
// See crt0dat.c in the CRT sources for the details.
#pragma section(".CRT$XIB", long, read) // NOLINT
__declspec(allocate(".CRT$XIB")) void (*__asan_preinit)() = __asan_init;
#endif

View File

@ -11,9 +11,10 @@
//
// Code for ASan stack trace.
//===----------------------------------------------------------------------===//
#include "asan_internal.h"
#include "asan_flags.h"
#include "asan_stack.h"
#include "sanitizer/asan_interface.h"
#include "sanitizer_common/sanitizer_flags.h"
namespace __asan {
@ -24,8 +25,8 @@ static bool MaybeCallAsanSymbolize(const void *pc, char *out_buffer,
}
void PrintStack(StackTrace *stack) {
stack->PrintStack(stack->trace, stack->size, flags()->symbolize,
flags()->strip_path_prefix, MaybeCallAsanSymbolize);
stack->PrintStack(stack->trace, stack->size, common_flags()->symbolize,
common_flags()->strip_path_prefix, MaybeCallAsanSymbolize);
}
} // namespace __asan
@ -35,7 +36,7 @@ void PrintStack(StackTrace *stack) {
// Provide default implementation of __asan_symbolize that does nothing
// and may be overriden by user if he wants to use his own symbolization.
// ASan on Windows has its own implementation of this.
#if !defined(_WIN32) && !SANITIZER_SUPPORTS_WEAK_HOOKS
#if !SANITIZER_WINDOWS && !SANITIZER_SUPPORTS_WEAK_HOOKS
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE NOINLINE
bool __asan_symbolize(const void *pc, char *out_buffer, int out_size) {
return false;

View File

@ -14,12 +14,13 @@
#ifndef ASAN_STACK_H
#define ASAN_STACK_H
#include "sanitizer_common/sanitizer_stacktrace.h"
#include "asan_flags.h"
#include "asan_thread.h"
#include "sanitizer_common/sanitizer_flags.h"
#include "sanitizer_common/sanitizer_stacktrace.h"
namespace __asan {
void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp, bool fast);
void PrintStack(StackTrace *stack);
} // namespace __asan
@ -27,10 +28,24 @@ void PrintStack(StackTrace *stack);
// Get the stack trace with the given pc and bp.
// The pc will be in the position 0 of the resulting stack trace.
// The bp may refer to the current frame or to the caller's frame.
// fast_unwind is currently unused.
#if SANITIZER_WINDOWS
#define GET_STACK_TRACE_WITH_PC_AND_BP(max_s, pc, bp, fast) \
StackTrace stack; \
GetStackTrace(&stack, max_s, pc, bp, fast)
GetStackTrace(&stack, max_s, pc, bp, 0, 0, fast)
#else
#define GET_STACK_TRACE_WITH_PC_AND_BP(max_s, pc, bp, fast) \
StackTrace stack; \
{ \
uptr stack_top = 0, stack_bottom = 0; \
AsanThread *t; \
if (asan_inited && (t = GetCurrentThread())) { \
stack_top = t->stack_top(); \
stack_bottom = t->stack_bottom(); \
} \
GetStackTrace(&stack, max_s, pc, bp, \
stack_top, stack_bottom, fast); \
}
#endif // SANITIZER_WINDOWS
// NOTE: A Rule of thumb is to retrieve stack trace in the interceptors
// as early as possible (in functions exposed to the user), as we generally
@ -42,24 +57,24 @@ void PrintStack(StackTrace *stack);
#define GET_STACK_TRACE_FATAL(pc, bp) \
GET_STACK_TRACE_WITH_PC_AND_BP(kStackTraceMax, pc, bp, \
flags()->fast_unwind_on_fatal)
common_flags()->fast_unwind_on_fatal)
#define GET_STACK_TRACE_FATAL_HERE \
GET_STACK_TRACE(kStackTraceMax, flags()->fast_unwind_on_fatal)
#define GET_STACK_TRACE_FATAL_HERE \
GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_fatal)
#define GET_STACK_TRACE_THREAD \
#define GET_STACK_TRACE_THREAD \
GET_STACK_TRACE(kStackTraceMax, true)
#define GET_STACK_TRACE_MALLOC \
GET_STACK_TRACE(flags()->malloc_context_size, \
flags()->fast_unwind_on_malloc)
#define GET_STACK_TRACE_MALLOC \
GET_STACK_TRACE(common_flags()->malloc_context_size, \
common_flags()->fast_unwind_on_malloc)
#define GET_STACK_TRACE_FREE GET_STACK_TRACE_MALLOC
#define PRINT_CURRENT_STACK() \
{ \
GET_STACK_TRACE(kStackTraceMax, \
flags()->fast_unwind_on_fatal); \
common_flags()->fast_unwind_on_fatal); \
PrintStack(&stack); \
}

View File

@ -14,14 +14,14 @@
#include "asan_interceptors.h"
#include "asan_internal.h"
#include "asan_stats.h"
#include "asan_thread_registry.h"
#include "sanitizer/asan_interface.h"
#include "asan_thread.h"
#include "sanitizer_common/sanitizer_mutex.h"
#include "sanitizer_common/sanitizer_stackdepot.h"
namespace __asan {
AsanStats::AsanStats() {
CHECK(REAL(memset) != 0);
CHECK(REAL(memset));
REAL(memset)(this, 0, sizeof(AsanStats));
}
@ -58,7 +58,7 @@ static BlockingMutex print_lock(LINKER_INITIALIZED);
static void PrintAccumulatedStats() {
AsanStats stats;
asanThreadRegistry().GetAccumulatedStats(&stats);
GetAccumulatedStats(&stats);
// Use lock to keep reports from mixing up.
BlockingMutexLock lock(&print_lock);
stats.Print();
@ -68,21 +68,103 @@ static void PrintAccumulatedStats() {
PrintInternalAllocatorStats();
}
static AsanStats unknown_thread_stats(LINKER_INITIALIZED);
static AsanStats accumulated_stats(LINKER_INITIALIZED);
// Required for malloc_zone_statistics() on OS X. This can't be stored in
// per-thread AsanStats.
static uptr max_malloced_memory;
static BlockingMutex acc_stats_lock(LINKER_INITIALIZED);
static void FlushToAccumulatedStatsUnlocked(AsanStats *stats) {
acc_stats_lock.CheckLocked();
uptr *dst = (uptr*)&accumulated_stats;
uptr *src = (uptr*)stats;
uptr num_fields = sizeof(*stats) / sizeof(uptr);
for (uptr i = 0; i < num_fields; i++) {
dst[i] += src[i];
src[i] = 0;
}
}
static void FlushThreadStats(ThreadContextBase *tctx_base, void *arg) {
AsanThreadContext *tctx = static_cast<AsanThreadContext*>(tctx_base);
if (AsanThread *t = tctx->thread)
FlushToAccumulatedStatsUnlocked(&t->stats());
}
static void UpdateAccumulatedStatsUnlocked() {
acc_stats_lock.CheckLocked();
{
ThreadRegistryLock l(&asanThreadRegistry());
asanThreadRegistry().RunCallbackForEachThreadLocked(FlushThreadStats, 0);
}
FlushToAccumulatedStatsUnlocked(&unknown_thread_stats);
// This is not very accurate: we may miss allocation peaks that happen
// between two updates of accumulated_stats_. For more accurate bookkeeping
// the maximum should be updated on every malloc(), which is unacceptable.
if (max_malloced_memory < accumulated_stats.malloced) {
max_malloced_memory = accumulated_stats.malloced;
}
}
void FlushToAccumulatedStats(AsanStats *stats) {
BlockingMutexLock lock(&acc_stats_lock);
FlushToAccumulatedStatsUnlocked(stats);
}
void GetAccumulatedStats(AsanStats *stats) {
BlockingMutexLock lock(&acc_stats_lock);
UpdateAccumulatedStatsUnlocked();
internal_memcpy(stats, &accumulated_stats, sizeof(accumulated_stats));
}
void FillMallocStatistics(AsanMallocStats *malloc_stats) {
BlockingMutexLock lock(&acc_stats_lock);
UpdateAccumulatedStatsUnlocked();
malloc_stats->blocks_in_use = accumulated_stats.mallocs;
malloc_stats->size_in_use = accumulated_stats.malloced;
malloc_stats->max_size_in_use = max_malloced_memory;
malloc_stats->size_allocated = accumulated_stats.mmaped;
}
AsanStats &GetCurrentThreadStats() {
AsanThread *t = GetCurrentThread();
return (t) ? t->stats() : unknown_thread_stats;
}
} // namespace __asan
// ---------------------- Interface ---------------- {{{1
using namespace __asan; // NOLINT
uptr __asan_get_current_allocated_bytes() {
return asanThreadRegistry().GetCurrentAllocatedBytes();
BlockingMutexLock lock(&acc_stats_lock);
UpdateAccumulatedStatsUnlocked();
uptr malloced = accumulated_stats.malloced;
uptr freed = accumulated_stats.freed;
// Return sane value if malloced < freed due to racy
// way we update accumulated stats.
return (malloced > freed) ? malloced - freed : 1;
}
uptr __asan_get_heap_size() {
return asanThreadRegistry().GetHeapSize();
BlockingMutexLock lock(&acc_stats_lock);
UpdateAccumulatedStatsUnlocked();
return accumulated_stats.mmaped - accumulated_stats.munmaped;
}
uptr __asan_get_free_bytes() {
return asanThreadRegistry().GetFreeBytes();
BlockingMutexLock lock(&acc_stats_lock);
UpdateAccumulatedStatsUnlocked();
uptr total_free = accumulated_stats.mmaped
- accumulated_stats.munmaped
+ accumulated_stats.really_freed
+ accumulated_stats.really_freed_redzones;
uptr total_used = accumulated_stats.malloced
+ accumulated_stats.malloced_redzones;
// Return sane value if total_free < total_used due to racy
// way we update accumulated stats.
return (total_free > total_used) ? total_free - total_used : 1;
}
uptr __asan_get_unmapped_bytes() {

View File

@ -56,6 +56,15 @@ struct AsanStats {
void Print();
};
// Returns stats for GetCurrentThread(), or stats for fake "unknown thread"
// if GetCurrentThread() returns 0.
AsanStats &GetCurrentThreadStats();
// Flushes all thread-local stats to accumulated stats, and makes
// a copy of accumulated stats.
void GetAccumulatedStats(AsanStats *stats);
// Flushes a given stats into accumulated stats.
void FlushToAccumulatedStats(AsanStats *stats);
// A cross-platform equivalent of malloc_statistics_t on Mac OS.
struct AsanMallocStats {
uptr blocks_in_use;
@ -64,6 +73,8 @@ struct AsanMallocStats {
uptr size_allocated;
};
void FillMallocStatistics(AsanMallocStats *malloc_stats);
} // namespace __asan
#endif // ASAN_STATS_H

View File

@ -13,46 +13,81 @@
//===----------------------------------------------------------------------===//
#include "asan_allocator.h"
#include "asan_interceptors.h"
#include "asan_poisoning.h"
#include "asan_stack.h"
#include "asan_thread.h"
#include "asan_thread_registry.h"
#include "asan_mapping.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_placement_new.h"
#include "lsan/lsan_common.h"
namespace __asan {
AsanThread::AsanThread(LinkerInitialized x)
: fake_stack_(x),
malloc_storage_(x),
stats_(x) { }
// AsanThreadContext implementation.
AsanThread *AsanThread::Create(u32 parent_tid, thread_callback_t start_routine,
void *arg, StackTrace *stack) {
void AsanThreadContext::OnCreated(void *arg) {
CreateThreadContextArgs *args = static_cast<CreateThreadContextArgs*>(arg);
if (args->stack) {
internal_memcpy(&stack, args->stack, sizeof(stack));
}
thread = args->thread;
thread->set_context(this);
}
void AsanThreadContext::OnFinished() {
// Drop the link to the AsanThread object.
thread = 0;
}
static char thread_registry_placeholder[sizeof(ThreadRegistry)];
static ThreadRegistry *asan_thread_registry;
static ThreadContextBase *GetAsanThreadContext(u32 tid) {
void *mem = MmapOrDie(sizeof(AsanThreadContext), "AsanThreadContext");
return new(mem) AsanThreadContext(tid);
}
ThreadRegistry &asanThreadRegistry() {
static bool initialized;
// Don't worry about thread_safety - this should be called when there is
// a single thread.
if (!initialized) {
// Never reuse ASan threads: we store pointer to AsanThreadContext
// in TSD and can't reliably tell when no more TSD destructors will
// be called. It would be wrong to reuse AsanThreadContext for another
// thread before all TSD destructors will be called for it.
asan_thread_registry = new(thread_registry_placeholder) ThreadRegistry(
GetAsanThreadContext, kMaxNumberOfThreads, kMaxNumberOfThreads);
initialized = true;
}
return *asan_thread_registry;
}
AsanThreadContext *GetThreadContextByTidLocked(u32 tid) {
return static_cast<AsanThreadContext *>(
asanThreadRegistry().GetThreadLocked(tid));
}
// AsanThread implementation.
AsanThread *AsanThread::Create(thread_callback_t start_routine,
void *arg) {
uptr PageSize = GetPageSizeCached();
uptr size = RoundUpTo(sizeof(AsanThread), PageSize);
AsanThread *thread = (AsanThread*)MmapOrDie(size, __FUNCTION__);
thread->start_routine_ = start_routine;
thread->arg_ = arg;
const uptr kSummaryAllocSize = PageSize;
CHECK_LE(sizeof(AsanThreadSummary), kSummaryAllocSize);
AsanThreadSummary *summary =
(AsanThreadSummary*)MmapOrDie(PageSize, "AsanThreadSummary");
summary->Init(parent_tid, stack);
summary->set_thread(thread);
thread->set_summary(summary);
thread->context_ = 0;
return thread;
}
void AsanThreadSummary::TSDDtor(void *tsd) {
AsanThreadSummary *summary = (AsanThreadSummary*)tsd;
if (flags()->verbosity >= 1) {
Report("T%d TSDDtor\n", summary->tid());
}
if (summary->thread()) {
summary->thread()->Destroy();
}
void AsanThread::TSDDtor(void *tsd) {
AsanThreadContext *context = (AsanThreadContext*)tsd;
if (flags()->verbosity >= 1)
Report("T%d TSDDtor\n", context->tid);
if (context->thread)
context->thread->Destroy();
}
void AsanThread::Destroy() {
@ -60,8 +95,8 @@ void AsanThread::Destroy() {
Report("T%d exited\n", tid());
}
asanThreadRegistry().UnregisterThread(this);
CHECK(summary()->thread() == 0);
asanThreadRegistry().FinishThread(tid());
FlushToAccumulatedStats(&stats_);
// We also clear the shadow on thread destruction because
// some code may still be executing in later TSD destructors
// and we don't want it to have any poisoned stack.
@ -86,15 +121,16 @@ void AsanThread::Init() {
AsanPlatformThreadInit();
}
thread_return_t AsanThread::ThreadStart() {
thread_return_t AsanThread::ThreadStart(uptr os_id) {
Init();
asanThreadRegistry().StartThread(tid(), os_id, 0);
if (flags()->use_sigaltstack) SetAlternateSignalStack();
if (!start_routine_) {
// start_routine_ == 0 if we're on the main thread or on one of the
// OS X libdispatch worker threads. But nobody is supposed to call
// ThreadStart() for the worker threads.
CHECK(tid() == 0);
CHECK_EQ(tid(), 0);
return 0;
}
@ -117,7 +153,8 @@ void AsanThread::ClearShadowForThreadStack() {
PoisonShadow(stack_bottom_, stack_top_ - stack_bottom_, 0);
}
const char *AsanThread::GetFrameNameByAddr(uptr addr, uptr *offset) {
const char *AsanThread::GetFrameNameByAddr(uptr addr, uptr *offset,
uptr *frame_pc) {
uptr bottom = 0;
if (AddrIsInStack(addr)) {
bottom = stack_bottom();
@ -125,6 +162,7 @@ const char *AsanThread::GetFrameNameByAddr(uptr addr, uptr *offset) {
bottom = fake_stack().AddrIsInFakeStack(addr);
CHECK(bottom);
*offset = addr - bottom;
*frame_pc = ((uptr*)bottom)[2];
return (const char *)((uptr*)bottom)[1];
}
uptr aligned_addr = addr & ~(SANITIZER_WORDSIZE/8 - 1); // align addr.
@ -149,7 +187,79 @@ const char *AsanThread::GetFrameNameByAddr(uptr addr, uptr *offset) {
uptr* ptr = (uptr*)SHADOW_TO_MEM((uptr)(shadow_ptr + 1));
CHECK(ptr[0] == kCurrentStackFrameMagic);
*offset = addr - (uptr)ptr;
*frame_pc = ptr[2];
return (const char*)ptr[1];
}
static bool ThreadStackContainsAddress(ThreadContextBase *tctx_base,
void *addr) {
AsanThreadContext *tctx = static_cast<AsanThreadContext*>(tctx_base);
AsanThread *t = tctx->thread;
return (t && t->fake_stack().StackSize() &&
(t->fake_stack().AddrIsInFakeStack((uptr)addr) ||
t->AddrIsInStack((uptr)addr)));
}
AsanThread *GetCurrentThread() {
AsanThreadContext *context = (AsanThreadContext*)AsanTSDGet();
if (!context) {
if (SANITIZER_ANDROID) {
// On Android, libc constructor is called _after_ asan_init, and cleans up
// TSD. Try to figure out if this is still the main thread by the stack
// address. We are not entirely sure that we have correct main thread
// limits, so only do this magic on Android, and only if the found thread
// is the main thread.
AsanThreadContext *tctx = GetThreadContextByTidLocked(0);
if (ThreadStackContainsAddress(tctx, &context)) {
SetCurrentThread(tctx->thread);
return tctx->thread;
}
}
return 0;
}
return context->thread;
}
void SetCurrentThread(AsanThread *t) {
CHECK(t->context());
if (flags()->verbosity >= 2) {
Report("SetCurrentThread: %p for thread %p\n",
t->context(), (void*)GetThreadSelf());
}
// Make sure we do not reset the current AsanThread.
CHECK_EQ(0, AsanTSDGet());
AsanTSDSet(t->context());
CHECK_EQ(t->context(), AsanTSDGet());
}
u32 GetCurrentTidOrInvalid() {
AsanThread *t = GetCurrentThread();
return t ? t->tid() : kInvalidTid;
}
AsanThread *FindThreadByStackAddress(uptr addr) {
asanThreadRegistry().CheckLocked();
AsanThreadContext *tctx = static_cast<AsanThreadContext *>(
asanThreadRegistry().FindThreadContextLocked(ThreadStackContainsAddress,
(void *)addr));
return tctx ? tctx->thread : 0;
}
} // namespace __asan
// --- Implementation of LSan-specific functions --- {{{1
namespace __lsan {
bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end,
uptr *tls_begin, uptr *tls_end,
uptr *cache_begin, uptr *cache_end) {
// FIXME: Stub.
return false;
}
void LockThreadRegistry() {
__asan::asanThreadRegistry().Lock();
}
void UnlockThreadRegistry() {
__asan::asanThreadRegistry().Unlock();
}
} // namespace __lsan

View File

@ -16,76 +16,58 @@
#include "asan_allocator.h"
#include "asan_internal.h"
#include "asan_fake_stack.h"
#include "asan_stack.h"
#include "asan_stats.h"
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_thread_registry.h"
namespace __asan {
const u32 kInvalidTid = 0xffffff; // Must fit into 24 bits.
const u32 kMaxNumberOfThreads = (1 << 22); // 4M
class AsanThread;
// These objects are created for every thread and are never deleted,
// so we can find them by tid even if the thread is long dead.
class AsanThreadSummary {
class AsanThreadContext : public ThreadContextBase {
public:
explicit AsanThreadSummary(LinkerInitialized) { } // for T0.
void Init(u32 parent_tid, StackTrace *stack) {
parent_tid_ = parent_tid;
announced_ = false;
tid_ = kInvalidTid;
if (stack) {
internal_memcpy(&stack_, stack, sizeof(*stack));
}
thread_ = 0;
name_[0] = 0;
explicit AsanThreadContext(int tid)
: ThreadContextBase(tid),
announced(false),
thread(0) {
internal_memset(&stack, 0, sizeof(stack));
}
u32 tid() { return tid_; }
void set_tid(u32 tid) { tid_ = tid; }
u32 parent_tid() { return parent_tid_; }
bool announced() { return announced_; }
void set_announced(bool announced) { announced_ = announced; }
StackTrace *stack() { return &stack_; }
AsanThread *thread() { return thread_; }
void set_thread(AsanThread *thread) { thread_ = thread; }
static void TSDDtor(void *tsd);
void set_name(const char *name) {
internal_strncpy(name_, name, sizeof(name_) - 1);
}
const char *name() { return name_; }
bool announced;
StackTrace stack;
AsanThread *thread;
private:
u32 tid_;
u32 parent_tid_;
bool announced_;
StackTrace stack_;
AsanThread *thread_;
char name_[128];
void OnCreated(void *arg);
void OnFinished();
};
// AsanThreadSummary objects are never freed, so we need many of them.
COMPILER_CHECK(sizeof(AsanThreadSummary) <= 4094);
// AsanThreadContext objects are never freed, so we need many of them.
COMPILER_CHECK(sizeof(AsanThreadContext) <= 4096);
// AsanThread are stored in TSD and destroyed when the thread dies.
class AsanThread {
public:
explicit AsanThread(LinkerInitialized); // for T0.
static AsanThread *Create(u32 parent_tid, thread_callback_t start_routine,
void *arg, StackTrace *stack);
static AsanThread *Create(thread_callback_t start_routine, void *arg);
static void TSDDtor(void *tsd);
void Destroy();
void Init(); // Should be called from the thread itself.
thread_return_t ThreadStart();
thread_return_t ThreadStart(uptr os_id);
uptr stack_top() { return stack_top_; }
uptr stack_bottom() { return stack_bottom_; }
uptr stack_size() { return stack_top_ - stack_bottom_; }
u32 tid() { return summary_->tid(); }
AsanThreadSummary *summary() { return summary_; }
void set_summary(AsanThreadSummary *summary) { summary_ = summary; }
u32 tid() { return context_->tid; }
AsanThreadContext *context() { return context_; }
void set_context(AsanThreadContext *context) { context_ = context; }
const char *GetFrameNameByAddr(uptr addr, uptr *offset);
const char *GetFrameNameByAddr(uptr addr, uptr *offset, uptr *frame_pc);
bool AddrIsInStack(uptr addr) {
return addr >= stack_bottom_ && addr < stack_top_;
@ -96,9 +78,10 @@ class AsanThread {
AsanStats &stats() { return stats_; }
private:
AsanThread() {}
void SetThreadStackTopAndBottom();
void ClearShadowForThreadStack();
AsanThreadSummary *summary_;
AsanThreadContext *context_;
thread_callback_t start_routine_;
void *arg_;
uptr stack_top_;
@ -109,6 +92,23 @@ class AsanThread {
AsanStats stats_;
};
struct CreateThreadContextArgs {
AsanThread *thread;
StackTrace *stack;
};
// Returns a single instance of registry.
ThreadRegistry &asanThreadRegistry();
// Must be called under ThreadRegistryLock.
AsanThreadContext *GetThreadContextByTidLocked(u32 tid);
// Get the current thread. May return 0.
AsanThread *GetCurrentThread();
void SetCurrentThread(AsanThread *t);
u32 GetCurrentTidOrInvalid();
AsanThread *FindThreadByStackAddress(uptr addr);
} // namespace __asan
#endif // ASAN_THREAD_H

View File

@ -1,198 +0,0 @@
//===-- asan_thread_registry.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.
//
// AsanThreadRegistry-related code. AsanThreadRegistry is a container
// for summaries of all created threads.
//===----------------------------------------------------------------------===//
#include "asan_stack.h"
#include "asan_thread.h"
#include "asan_thread_registry.h"
#include "sanitizer_common/sanitizer_common.h"
namespace __asan {
static AsanThreadRegistry asan_thread_registry(LINKER_INITIALIZED);
AsanThreadRegistry &asanThreadRegistry() {
return asan_thread_registry;
}
AsanThreadRegistry::AsanThreadRegistry(LinkerInitialized x)
: main_thread_(x),
main_thread_summary_(x),
accumulated_stats_(x),
max_malloced_memory_(x),
mu_(x) { }
void AsanThreadRegistry::Init() {
AsanTSDInit(AsanThreadSummary::TSDDtor);
main_thread_.set_summary(&main_thread_summary_);
main_thread_summary_.set_thread(&main_thread_);
RegisterThread(&main_thread_);
SetCurrent(&main_thread_);
// At this point only one thread exists.
inited_ = true;
}
void AsanThreadRegistry::RegisterThread(AsanThread *thread) {
BlockingMutexLock lock(&mu_);
u32 tid = n_threads_;
n_threads_++;
CHECK(n_threads_ < kMaxNumberOfThreads);
AsanThreadSummary *summary = thread->summary();
CHECK(summary != 0);
summary->set_tid(tid);
thread_summaries_[tid] = summary;
}
void AsanThreadRegistry::UnregisterThread(AsanThread *thread) {
BlockingMutexLock lock(&mu_);
FlushToAccumulatedStatsUnlocked(&thread->stats());
AsanThreadSummary *summary = thread->summary();
CHECK(summary);
summary->set_thread(0);
}
AsanThread *AsanThreadRegistry::GetMain() {
return &main_thread_;
}
AsanThread *AsanThreadRegistry::GetCurrent() {
AsanThreadSummary *summary = (AsanThreadSummary *)AsanTSDGet();
if (!summary) {
#if ASAN_ANDROID
// On Android, libc constructor is called _after_ asan_init, and cleans up
// TSD. Try to figure out if this is still the main thread by the stack
// address. We are not entirely sure that we have correct main thread
// limits, so only do this magic on Android, and only if the found thread is
// the main thread.
AsanThread* thread = FindThreadByStackAddress((uptr)&summary);
if (thread && thread->tid() == 0) {
SetCurrent(thread);
return thread;
}
#endif
return 0;
}
return summary->thread();
}
void AsanThreadRegistry::SetCurrent(AsanThread *t) {
CHECK(t->summary());
if (flags()->verbosity >= 2) {
Report("SetCurrent: %p for thread %p\n",
t->summary(), (void*)GetThreadSelf());
}
// Make sure we do not reset the current AsanThread.
CHECK(AsanTSDGet() == 0);
AsanTSDSet(t->summary());
CHECK(AsanTSDGet() == t->summary());
}
AsanStats &AsanThreadRegistry::GetCurrentThreadStats() {
AsanThread *t = GetCurrent();
return (t) ? t->stats() : main_thread_.stats();
}
void AsanThreadRegistry::GetAccumulatedStats(AsanStats *stats) {
BlockingMutexLock lock(&mu_);
UpdateAccumulatedStatsUnlocked();
internal_memcpy(stats, &accumulated_stats_, sizeof(accumulated_stats_));
}
uptr AsanThreadRegistry::GetCurrentAllocatedBytes() {
BlockingMutexLock lock(&mu_);
UpdateAccumulatedStatsUnlocked();
uptr malloced = accumulated_stats_.malloced;
uptr freed = accumulated_stats_.freed;
// Return sane value if malloced < freed due to racy
// way we update accumulated stats.
return (malloced > freed) ? malloced - freed : 1;
}
uptr AsanThreadRegistry::GetHeapSize() {
BlockingMutexLock lock(&mu_);
UpdateAccumulatedStatsUnlocked();
return accumulated_stats_.mmaped - accumulated_stats_.munmaped;
}
uptr AsanThreadRegistry::GetFreeBytes() {
BlockingMutexLock lock(&mu_);
UpdateAccumulatedStatsUnlocked();
uptr total_free = accumulated_stats_.mmaped
- accumulated_stats_.munmaped
+ accumulated_stats_.really_freed
+ accumulated_stats_.really_freed_redzones;
uptr total_used = accumulated_stats_.malloced
+ accumulated_stats_.malloced_redzones;
// Return sane value if total_free < total_used due to racy
// way we update accumulated stats.
return (total_free > total_used) ? total_free - total_used : 1;
}
// Return several stats counters with a single call to
// UpdateAccumulatedStatsUnlocked().
void AsanThreadRegistry::FillMallocStatistics(AsanMallocStats *malloc_stats) {
BlockingMutexLock lock(&mu_);
UpdateAccumulatedStatsUnlocked();
malloc_stats->blocks_in_use = accumulated_stats_.mallocs;
malloc_stats->size_in_use = accumulated_stats_.malloced;
malloc_stats->max_size_in_use = max_malloced_memory_;
malloc_stats->size_allocated = accumulated_stats_.mmaped;
}
AsanThreadSummary *AsanThreadRegistry::FindByTid(u32 tid) {
CHECK(tid < n_threads_);
CHECK(thread_summaries_[tid]);
return thread_summaries_[tid];
}
AsanThread *AsanThreadRegistry::FindThreadByStackAddress(uptr addr) {
BlockingMutexLock lock(&mu_);
for (u32 tid = 0; tid < n_threads_; tid++) {
AsanThread *t = thread_summaries_[tid]->thread();
if (!t || !(t->fake_stack().StackSize())) continue;
if (t->fake_stack().AddrIsInFakeStack(addr) || t->AddrIsInStack(addr)) {
return t;
}
}
return 0;
}
void AsanThreadRegistry::UpdateAccumulatedStatsUnlocked() {
for (u32 tid = 0; tid < n_threads_; tid++) {
AsanThread *t = thread_summaries_[tid]->thread();
if (t != 0) {
FlushToAccumulatedStatsUnlocked(&t->stats());
}
}
// This is not very accurate: we may miss allocation peaks that happen
// between two updates of accumulated_stats_. For more accurate bookkeeping
// the maximum should be updated on every malloc(), which is unacceptable.
if (max_malloced_memory_ < accumulated_stats_.malloced) {
max_malloced_memory_ = accumulated_stats_.malloced;
}
}
void AsanThreadRegistry::FlushToAccumulatedStatsUnlocked(AsanStats *stats) {
// AsanStats consists of variables of type uptr only.
uptr *dst = (uptr*)&accumulated_stats_;
uptr *src = (uptr*)stats;
uptr num_fields = sizeof(AsanStats) / sizeof(uptr);
for (uptr i = 0; i < num_fields; i++) {
dst[i] += src[i];
src[i] = 0;
}
}
} // namespace __asan

View File

@ -1,85 +0,0 @@
//===-- asan_thread_registry.h ----------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of AddressSanitizer, an address sanity checker.
//
// ASan-private header for asan_thread_registry.cc
//===----------------------------------------------------------------------===//
#ifndef ASAN_THREAD_REGISTRY_H
#define ASAN_THREAD_REGISTRY_H
#include "asan_stack.h"
#include "asan_stats.h"
#include "asan_thread.h"
#include "sanitizer_common/sanitizer_mutex.h"
namespace __asan {
// Stores summaries of all created threads, returns current thread,
// thread by tid, thread by stack address. There is a single instance
// of AsanThreadRegistry for the whole program.
// AsanThreadRegistry is thread-safe.
class AsanThreadRegistry {
public:
explicit AsanThreadRegistry(LinkerInitialized);
void Init();
void RegisterThread(AsanThread *thread);
void UnregisterThread(AsanThread *thread);
AsanThread *GetMain();
// Get the current thread. May return 0.
AsanThread *GetCurrent();
void SetCurrent(AsanThread *t);
u32 GetCurrentTidOrInvalid() {
if (!inited_) return 0;
AsanThread *t = GetCurrent();
return t ? t->tid() : kInvalidTid;
}
// Returns stats for GetCurrent(), or stats for
// T0 if GetCurrent() returns 0.
AsanStats &GetCurrentThreadStats();
// Flushes all thread-local stats to accumulated stats, and makes
// a copy of accumulated stats.
void GetAccumulatedStats(AsanStats *stats);
uptr GetCurrentAllocatedBytes();
uptr GetHeapSize();
uptr GetFreeBytes();
void FillMallocStatistics(AsanMallocStats *malloc_stats);
AsanThreadSummary *FindByTid(u32 tid);
AsanThread *FindThreadByStackAddress(uptr addr);
private:
void UpdateAccumulatedStatsUnlocked();
// Adds values of all counters in "stats" to accumulated stats,
// and fills "stats" with zeroes.
void FlushToAccumulatedStatsUnlocked(AsanStats *stats);
static const u32 kMaxNumberOfThreads = (1 << 22); // 4M
AsanThreadSummary *thread_summaries_[kMaxNumberOfThreads];
AsanThread main_thread_;
AsanThreadSummary main_thread_summary_;
AsanStats accumulated_stats_;
// Required for malloc_zone_statistics() on OS X. This can't be stored in
// per-thread AsanStats.
uptr max_malloced_memory_;
u32 n_threads_;
BlockingMutex mu_;
bool inited_;
};
// Returns a single instance of registry.
AsanThreadRegistry &asanThreadRegistry();
} // namespace __asan
#endif // ASAN_THREAD_REGISTRY_H

View File

@ -11,7 +11,9 @@
//
// Windows-specific details.
//===----------------------------------------------------------------------===//
#ifdef _WIN32
#include "sanitizer_common/sanitizer_platform.h"
#if SANITIZER_WINDOWS
#include <windows.h>
#include <dbghelp.h>
@ -30,30 +32,6 @@ static BlockingMutex dbghelp_lock(LINKER_INITIALIZED);
static bool dbghelp_initialized = false;
#pragma comment(lib, "dbghelp.lib")
void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp, bool fast) {
(void)fast;
stack->max_size = max_s;
void *tmp[kStackTraceMax];
// FIXME: CaptureStackBackTrace might be too slow for us.
// FIXME: Compare with StackWalk64.
// FIXME: Look at LLVMUnhandledExceptionFilter in Signals.inc
uptr cs_ret = CaptureStackBackTrace(1, stack->max_size, tmp, 0);
uptr offset = 0;
// Skip the RTL frames by searching for the PC in the stacktrace.
// FIXME: this doesn't work well for the malloc/free stacks yet.
for (uptr i = 0; i < cs_ret; i++) {
if (pc != (uptr)tmp[i])
continue;
offset = i;
break;
}
stack->size = cs_ret - offset;
for (uptr i = 0; i < stack->size; i++)
stack->trace[i] = (uptr)tmp[i + offset];
}
// ---------------------- TSD ---------------- {{{1
static bool tsd_key_inited = false;

View File

@ -1,111 +0,0 @@
//===-- asan_interceptors_dynamic.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.
//
// __DATA,__interpose section of the dynamic runtime library for Mac OS.
//===----------------------------------------------------------------------===//
#if defined(__APPLE__)
#include "../asan_interceptors.h"
#include "../asan_intercepted_functions.h"
namespace __asan {
#if !MAC_INTERPOSE_FUNCTIONS
# error \
Dynamic interposing library should be built with -DMAC_INTERPOSE_FUNCTIONS
#endif
#define INTERPOSE_FUNCTION(function) \
{ reinterpret_cast<const uptr>(WRAP(function)), \
reinterpret_cast<const uptr>(function) }
#define INTERPOSE_FUNCTION_2(function, wrapper) \
{ reinterpret_cast<const uptr>(wrapper), \
reinterpret_cast<const uptr>(function) }
struct interpose_substitution {
const uptr replacement;
const uptr original;
};
__attribute__((used))
const interpose_substitution substitutions[]
__attribute__((section("__DATA, __interpose"))) = {
INTERPOSE_FUNCTION(strlen),
INTERPOSE_FUNCTION(memcmp),
INTERPOSE_FUNCTION(memcpy),
INTERPOSE_FUNCTION(memmove),
INTERPOSE_FUNCTION(memset),
INTERPOSE_FUNCTION(strchr),
INTERPOSE_FUNCTION(strcat),
INTERPOSE_FUNCTION(strncat),
INTERPOSE_FUNCTION(strcpy),
INTERPOSE_FUNCTION(strncpy),
INTERPOSE_FUNCTION(pthread_create),
INTERPOSE_FUNCTION(longjmp),
#if ASAN_INTERCEPT__LONGJMP
INTERPOSE_FUNCTION(_longjmp),
#endif
#if ASAN_INTERCEPT_SIGLONGJMP
INTERPOSE_FUNCTION(siglongjmp),
#endif
#if ASAN_INTERCEPT_STRDUP
INTERPOSE_FUNCTION(strdup),
#endif
#if ASAN_INTERCEPT_STRNLEN
INTERPOSE_FUNCTION(strnlen),
#endif
#if ASAN_INTERCEPT_INDEX
INTERPOSE_FUNCTION_2(index, WRAP(strchr)),
#endif
INTERPOSE_FUNCTION(strcmp),
INTERPOSE_FUNCTION(strncmp),
#if ASAN_INTERCEPT_STRCASECMP_AND_STRNCASECMP
INTERPOSE_FUNCTION(strcasecmp),
INTERPOSE_FUNCTION(strncasecmp),
#endif
INTERPOSE_FUNCTION(atoi),
INTERPOSE_FUNCTION(atol),
INTERPOSE_FUNCTION(strtol),
#if ASAN_INTERCEPT_ATOLL_AND_STRTOLL
INTERPOSE_FUNCTION(atoll),
INTERPOSE_FUNCTION(strtoll),
#endif
#if ASAN_INTERCEPT_MLOCKX
INTERPOSE_FUNCTION(mlock),
INTERPOSE_FUNCTION(munlock),
INTERPOSE_FUNCTION(mlockall),
INTERPOSE_FUNCTION(munlockall),
#endif
INTERPOSE_FUNCTION(dispatch_async_f),
INTERPOSE_FUNCTION(dispatch_sync_f),
INTERPOSE_FUNCTION(dispatch_after_f),
INTERPOSE_FUNCTION(dispatch_barrier_async_f),
INTERPOSE_FUNCTION(dispatch_group_async_f),
#ifndef MISSING_BLOCKS_SUPPORT
INTERPOSE_FUNCTION(dispatch_group_async),
INTERPOSE_FUNCTION(dispatch_async),
INTERPOSE_FUNCTION(dispatch_after),
INTERPOSE_FUNCTION(dispatch_source_set_event_handler),
INTERPOSE_FUNCTION(dispatch_source_set_cancel_handler),
#endif
INTERPOSE_FUNCTION(signal),
INTERPOSE_FUNCTION(sigaction),
INTERPOSE_FUNCTION(__CFInitialize),
INTERPOSE_FUNCTION(CFStringCreateCopy),
INTERPOSE_FUNCTION(free),
};
} // namespace __asan
#endif // __APPLE__

View File

@ -14,9 +14,9 @@ configure_lit_site_cfg(
if(COMPILER_RT_CAN_EXECUTE_TESTS)
# Run ASan tests only if we're sure we may produce working binaries.
set(ASAN_TEST_DEPS
clang clang-headers FileCheck count not llvm-nm llvm-symbolizer
${SANITIZER_COMMON_LIT_TEST_DEPS}
${ASAN_RUNTIME_LIBRARIES}
)
asan_blacklist)
set(ASAN_TEST_PARAMS
asan_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
)

View File

@ -0,0 +1,39 @@
// Check the presense of interface symbols in the ASan runtime dylib.
// If you're changing this file, please also change
// ../Linux/interface_symbols.c
// RUN: %clang -fsanitize=address -dead_strip -O2 %s -o %t.exe
// RUN: rm -f %t.symbols %t.interface
// RUN: nm -g `otool -L %t.exe | grep "asan_osx_dynamic.dylib" | \
// RUN: tr -d '\011' | \
// RUN: sed "s/.dylib.*/.dylib/"` \
// RUN: | grep " T " | sed "s/.* T //" \
// RUN: | grep "__asan_" | sed "s/___asan_/__asan_/" \
// RUN: | grep -v "__asan_malloc_hook" \
// RUN: | grep -v "__asan_free_hook" \
// RUN: | grep -v "__asan_symbolize" \
// RUN: | grep -v "__asan_default_options" \
// RUN: | grep -v "__asan_on_error" > %t.symbols
// RUN: cat %p/../../asan_interface_internal.h \
// RUN: | sed "s/\/\/.*//" | sed "s/typedef.*//" \
// RUN: | grep -v "OPTIONAL" \
// RUN: | grep "__asan_.*(" | sed "s/.* __asan_/__asan_/;s/(.*//" \
// RUN: > %t.interface
// RUN: echo __asan_report_load1 >> %t.interface
// RUN: echo __asan_report_load2 >> %t.interface
// RUN: echo __asan_report_load4 >> %t.interface
// RUN: echo __asan_report_load8 >> %t.interface
// RUN: echo __asan_report_load16 >> %t.interface
// RUN: echo __asan_report_store1 >> %t.interface
// RUN: echo __asan_report_store2 >> %t.interface
// RUN: echo __asan_report_store4 >> %t.interface
// RUN: echo __asan_report_store8 >> %t.interface
// RUN: echo __asan_report_store16 >> %t.interface
// RUN: echo __asan_report_load_n >> %t.interface
// RUN: echo __asan_report_store_n >> %t.interface
// RUN: cat %t.interface | sort -u | diff %t.symbols -
int main() { return 0; }

View File

@ -0,0 +1,9 @@
def getRoot(config):
if not config.parent:
return config
return getRoot(config.parent)
root = getRoot(config)
if root.host_os not in ['Darwin']:
config.unsupported = True

View File

@ -0,0 +1,20 @@
// Make sure ASan doesn't hang in an exec loop if DYLD_INSERT_LIBRARIES is set.
// This is a regression test for
// https://code.google.com/p/address-sanitizer/issues/detail?id=159
// RUN: %clangxx_asan -m64 %s -o %t
// RUN: %clangxx -m64 %p/../SharedLibs/darwin-dummy-shared-lib-so.cc \
// RUN: -dynamiclib -o darwin-dummy-shared-lib-so.dylib
// FIXME: the following command line may hang in the case of a regression.
// RUN: DYLD_INSERT_LIBRARIES=darwin-dummy-shared-lib-so.dylib \
// RUN: %t 2>&1 | FileCheck %s || exit 1
#include <stdio.h>
#include <stdlib.h>
int main() {
const char kEnvName[] = "DYLD_INSERT_LIBRARIES";
printf("%s=%s\n", kEnvName, getenv(kEnvName));
// CHECK: {{DYLD_INSERT_LIBRARIES=.*darwin-dummy-shared-lib-so.dylib.*}}
return 0;
}

View File

@ -0,0 +1,20 @@
// Make sure ASan removes the runtime library from DYLD_INSERT_LIBRARIES before
// executing other programs.
// RUN: %clangxx_asan -m64 %s -o %t
// RUN: %clangxx -m64 %p/../SharedLibs/darwin-dummy-shared-lib-so.cc \
// RUN: -dynamiclib -o darwin-dummy-shared-lib-so.dylib
// Make sure DYLD_INSERT_LIBRARIES doesn't contain the runtime library before
// execl().
// RUN: %t >/dev/null 2>&1
// RUN: DYLD_INSERT_LIBRARIES=darwin-dummy-shared-lib-so.dylib \
// RUN: %t 2>&1 | FileCheck %s || exit 1
#include <unistd.h>
int main() {
execl("/bin/bash", "/bin/bash", "-c",
"echo DYLD_INSERT_LIBRARIES=$DYLD_INSERT_LIBRARIES", NULL);
// CHECK: {{DYLD_INSERT_LIBRARIES=.*darwin-dummy-shared-lib-so.dylib.*}}
return 0;
}

View File

@ -0,0 +1,16 @@
#include <stdio.h>
class C {
public:
C() { value = 42; }
~C() { }
int value;
};
C c;
void AccessC() {
printf("C value: %d\n", c.value);
}
int main() { return 0; }

View File

@ -0,0 +1,4 @@
int zero_init();
int badSrcGlobal = zero_init();
int readBadSrcGlobal() { return badSrcGlobal; }

View File

@ -1,2 +1,3 @@
global-init:*badGlobal*
global-init-type:*badNamespace::BadClass*
global-init-src:*initialization-blacklist-extra2.cc

View File

@ -0,0 +1,3 @@
// Constexpr:
int getCoolestInteger();
static int coolest_integer = getCoolestInteger();

View File

@ -4,6 +4,6 @@ static int ab = getAB();
// Function local statics:
int countCalls();
static int one = countCalls();
// Constexpr:
int getCoolestInteger();
static int coolest_integer = getCoolestInteger();
// Trivial constructor, non-trivial destructor:
int getStructWithDtorValue();
static int val = getStructWithDtorValue();

View File

@ -0,0 +1,28 @@
// Test if asan works with prelink.
// It does not actually use prelink, but relies on ld's flag -Ttext-segment
// or gold's flag -Ttext (we try the first flag first, if that fails we
// try the second flag).
//
// RUN: %clangxx_asan -m64 -c %s -o %t.o
// RUN: %clangxx_asan -m64 -DBUILD_SO=1 -fPIC -shared %s -o %t.so -Wl,-Ttext-segment=0x3600000000 ||\
// RUN: %clangxx_asan -m64 -DBUILD_SO=1 -fPIC -shared %s -o %t.so -Wl,-Ttext=0x3600000000
// RUN: %clangxx_asan -m64 %t.o %t.so -Wl,-R. -o %t
// RUN: ASAN_OPTIONS=verbosity=1 %t 2>&1 | FileCheck %s
// REQUIRES: x86_64-supported-target
#if BUILD_SO
int G;
int *getG() {
return &G;
}
#else
#include <stdio.h>
extern int *getG();
int main(int argc, char **argv) {
long p = (long)getG();
printf("SO mapped at %lx\n", p & ~0xffffffffUL);
*getG() = 0;
}
#endif
// CHECK: 0x003000000000, 0x004fffffffff{{.*}} MidMem
// CHECK: SO mapped at 3600000000

View File

@ -0,0 +1,30 @@
// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t %p 2>&1 | FileCheck %s
// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t %p 2>&1 | FileCheck %s
// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t %p 2>&1 | FileCheck %s
// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t %p 2>&1 | FileCheck %s
#include <assert.h>
#include <glob.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <string>
int main(int argc, char *argv[]) {
std::string path = argv[1];
std::string pattern = path + "/glob_test_root/*a";
printf("pattern: %s\n", pattern.c_str());
glob_t globbuf;
int res = glob(pattern.c_str(), 0, 0, &globbuf);
printf("%d %s\n", errno, strerror(errno));
assert(res == 0);
assert(globbuf.gl_pathc == 2);
printf("%zu\n", strlen(globbuf.gl_pathv[0]));
printf("%zu\n", strlen(globbuf.gl_pathv[1]));
printf("PASS\n");
// CHECK: PASS
return 0;
}

View File

@ -0,0 +1,55 @@
// RUN: %clangxx_asan -fsanitize=use-after-return -m64 -O0 %s -o %t && \
// RUN: %t 2>&1 | %symbolize | FileCheck %s
// RUN: %clangxx_asan -fsanitize=use-after-return -m64 -O2 %s -o %t && \
// RUN: %t 2>&1 | %symbolize | FileCheck %s
// RUN: %clangxx_asan -fsanitize=use-after-return -m32 -O2 %s -o %t && \
// RUN: %t 2>&1 | %symbolize | FileCheck %s
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
__attribute__((noinline))
char *pretend_to_do_something(char *x) {
__asm__ __volatile__("" : : "r" (x) : "memory");
return x;
}
__attribute__((noinline))
char *LeakStack() {
char x[1024];
memset(x, 0, sizeof(x));
return pretend_to_do_something(x);
}
template<size_t kFrameSize>
__attribute__((noinline))
void RecuriveFunctionWithStackFrame(int depth) {
if (depth <= 0) return;
char x[kFrameSize];
x[0] = depth;
pretend_to_do_something(x);
RecuriveFunctionWithStackFrame<kFrameSize>(depth - 1);
}
int main(int argc, char **argv) {
int n_iter = argc >= 2 ? atoi(argv[1]) : 1000;
int depth = argc >= 3 ? atoi(argv[2]) : 500;
for (int i = 0; i < n_iter; i++) {
RecuriveFunctionWithStackFrame<10>(depth);
RecuriveFunctionWithStackFrame<100>(depth);
RecuriveFunctionWithStackFrame<500>(depth);
RecuriveFunctionWithStackFrame<1024>(depth);
RecuriveFunctionWithStackFrame<2000>(depth);
RecuriveFunctionWithStackFrame<5000>(depth);
RecuriveFunctionWithStackFrame<10000>(depth);
}
char *stale_stack = LeakStack();
RecuriveFunctionWithStackFrame<1024>(10);
stale_stack[100]++;
// CHECK: ERROR: AddressSanitizer: stack-use-after-return on address
// CHECK: is located in stack of thread T0 at offset 132 in frame
// CHECK: in LeakStack(){{.*}}heavy_uar_test.cc:
// CHECK: [32, 1056) 'x'
return 0;
}

View File

@ -1,12 +1,13 @@
// Test to make sure basic initialization order errors are caught.
// Check that on Linux initialization order bugs are caught
// independently on order in which we list source files.
// independently on order in which we list source files (if we specify
// strict init-order checking).
// RUN: %clangxx_asan -m64 -O0 %s %p/../Helpers/initialization-bug-extra.cc\
// RUN: -fsanitize=init-order -o %t && %t 2>&1 \
// RUN: %clangxx_asan -m64 -O0 %s %p/../Helpers/initialization-bug-extra.cc -o %t
// RUN: ASAN_OPTIONS=check_initialization_order=true:strict_init_order=true %t 2>&1 \
// RUN: | %symbolize | FileCheck %s
// RUN: %clangxx_asan -m64 -O0 %p/../Helpers/initialization-bug-extra.cc %s\
// RUN: -fsanitize=init-order -o %t && %t 2>&1 \
// RUN: %clangxx_asan -m64 -O0 %p/../Helpers/initialization-bug-extra.cc %s -o %t
// RUN: ASAN_OPTIONS=check_initialization_order=true:strict_init_order=true %t 2>&1 \
// RUN: | %symbolize | FileCheck %s
// Do not test with optimization -- the error may be optimized away.

View File

@ -1,14 +1,14 @@
// Check the presense of interface symbols in compiled file.
// RUN: %clang -fsanitize=address -dead_strip -O2 %s -o %t.exe
// RUN: nm %t.exe | grep " T " | sed "s/.* T //" \
// RUN: %clang -fsanitize=address -O2 %s -o %t.exe
// RUN: nm -D %t.exe | grep " T " | sed "s/.* T //" \
// RUN: | grep "__asan_" | sed "s/___asan_/__asan_/" \
// RUN: | grep -v "__asan_malloc_hook" \
// RUN: | grep -v "__asan_free_hook" \
// RUN: | grep -v "__asan_symbolize" \
// RUN: | grep -v "__asan_default_options" \
// RUN: | grep -v "__asan_on_error" > %t.symbols
// RUN: cat %p/../../../include/sanitizer/asan_interface.h \
// RUN: cat %p/../../asan_interface_internal.h \
// RUN: | sed "s/\/\/.*//" | sed "s/typedef.*//" \
// RUN: | grep -v "OPTIONAL" \
// RUN: | grep "__asan_.*(" | sed "s/.* __asan_/__asan_/;s/(.*//" \
@ -23,6 +23,12 @@
// RUN: echo __asan_report_store4 >> %t.interface
// RUN: echo __asan_report_store8 >> %t.interface
// RUN: echo __asan_report_store16 >> %t.interface
// RUN: echo __asan_report_load_n >> %t.interface
// RUN: echo __asan_report_store_n >> %t.interface
// RUN: cat %t.interface | sort -u | diff %t.symbols -
// FIXME: nm -D on powerpc somewhy shows ASan interface symbols residing
// in "initialized data section".
// REQUIRES: x86_64-supported-target,i386-supported-target
int main() { return 0; }

View File

@ -1,10 +1,14 @@
// RUN: %clangxx_asan -O2 %s -o %t
// RUN: %clangxx_asan -m64 -O2 %s -o %t
// RUN: ASAN_OPTIONS=fast_unwind_on_malloc=1 %t 2>&1 | %symbolize | FileCheck %s --check-prefix=CHECK-FAST
// RUN: ASAN_OPTIONS=fast_unwind_on_malloc=0 %t 2>&1 | %symbolize | FileCheck %s --check-prefix=CHECK-SLOW
// Test how well we unwind in presence of qsort in the stack
// (i.e. if we can unwind through a function compiled w/o frame pointers).
// https://code.google.com/p/address-sanitizer/issues/detail?id=137
// Fast unwinder is only avaliable on x86_64 and i386.
// REQUIRES: x86_64-supported-target
#include <stdlib.h>
#include <stdio.h>

View File

@ -1,10 +1,14 @@
// RUN: %clangxx_asan -O2 %s -o %t
// RUN: %clangxx_asan -m64 -O2 %s -o %t
// RUN: ASAN_OPTIONS=fast_unwind_on_fatal=1 %t 2>&1 | %symbolize | FileCheck %s --check-prefix=CHECK-FAST
// RUN: ASAN_OPTIONS=fast_unwind_on_fatal=0 %t 2>&1 | %symbolize | FileCheck %s --check-prefix=CHECK-SLOW
// Test how well we unwind in presence of qsort in the stack
// (i.e. if we can unwind through a function compiled w/o frame pointers).
// https://code.google.com/p/address-sanitizer/issues/detail?id=137
// Fast unwinder is only avaliable on x86_64 and i386.
// REQUIRES: x86_64-supported-target
#include <stdlib.h>
#include <stdio.h>

View File

@ -0,0 +1,27 @@
// RUN: %clangxx -DFUNC=zzzz %s -shared -o %t.so -fPIC
// RUN: %clangxx_asan -DFUNC=main %s -o %t -Wl,-R. %t.so
// RUN: %t
// This test ensures that we call __asan_init early enough.
// We build a shared library w/o asan instrumentation
// and the binary with asan instrumentation.
// Both files include the same header (emulated by -DFUNC here)
// with C++ template magic which runs global initializer at library load time.
// The function get() is instrumented with asan, but called
// before the usual constructors are run.
// So, we must make sure that __asan_init is executed even earlier.
//
// See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=56393
struct A {
int foo() const { return 0; }
};
A get () { return A(); }
template <class> struct O {
static A const e;
};
template <class T> A const O <T>::e = get();
int FUNC() {
return O<int>::e.foo();
}

View File

@ -11,6 +11,6 @@ int main(int argc, char **argv) {
struct rlimit mmap_resource_limit = { 0, 0 };
assert(0 == setrlimit(RLIMIT_AS, &mmap_resource_limit));
x = malloc(10000000);
// CHECK: AddressSanitizer is unable to mmap
// CHECK: ERROR: Failed to mmap
return 0;
}

View File

@ -8,6 +8,9 @@
// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | FileCheck %s
// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | FileCheck %s
// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | FileCheck %s
//
// This test is too sublte to try on non-x86 arch for now.
// REQUIRES: x86_64-supported-target,i386-supported-target
#include <stdio.h>
#include <ucontext.h>
@ -16,9 +19,26 @@
ucontext_t orig_context;
ucontext_t child_context;
const int kStackSize = 1 << 20;
__attribute__((noinline))
void Throw() {
throw 1;
}
__attribute__((noinline))
void ThrowAndCatch() {
try {
Throw();
} catch(int a) {
printf("ThrowAndCatch: %d\n", a);
}
}
void Child(int mode) {
char x[32] = {0}; // Stack gets poisoned.
printf("Child: %p\n", x);
ThrowAndCatch(); // Simulate __asan_handle_no_return().
// (a) Do nothing, just return to parent function.
// (b) Jump into the original function. Stack remains poisoned unless we do
// something.
@ -30,9 +50,7 @@ void Child(int mode) {
}
}
int Run(int arg, int mode) {
const int kStackSize = 1 << 20;
char child_stack[kStackSize + 1];
int Run(int arg, int mode, char *child_stack) {
printf("Child stack: %p\n", child_stack);
// Setup child context.
getcontext(&child_context);
@ -54,13 +72,23 @@ int Run(int arg, int mode) {
}
int main(int argc, char **argv) {
char stack[kStackSize + 1];
// CHECK: WARNING: ASan doesn't fully support makecontext/swapcontext
int ret = 0;
ret += Run(argc - 1, 0);
ret += Run(argc - 1, 0, stack);
printf("Test1 passed\n");
// CHECK: Test1 passed
ret += Run(argc - 1, 1);
ret += Run(argc - 1, 1, stack);
printf("Test2 passed\n");
// CHECK: Test2 passed
char *heap = new char[kStackSize + 1];
ret += Run(argc - 1, 0, heap);
printf("Test3 passed\n");
// CHECK: Test3 passed
ret += Run(argc - 1, 1, heap);
printf("Test4 passed\n");
// CHECK: Test4 passed
delete [] heap;
return ret;
}

View File

@ -0,0 +1,22 @@
// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
#include <assert.h>
#include <errno.h>
#include <glob.h>
#include <stdio.h>
#include <string.h>
#include <sanitizer/linux_syscall_hooks.h>
/* Test the presence of __sanitizer_syscall_ in the tool runtime, and general
sanity of their behaviour. */
int main(int argc, char *argv[]) {
char buf[1000];
__sanitizer_syscall_pre_recvmsg(0, buf - 1, 0);
// CHECK: AddressSanitizer: stack-buffer-{{.*}}erflow
// CHECK: READ of size {{.*}} at {{.*}} thread T0
// CHECK: #0 {{.*}} in __sanitizer_syscall_pre_recvmsg
return 0;
}

View File

@ -0,0 +1,20 @@
// RUN: %clangxx_asan -m64 -O0 %s -fsanitize-address-zero-base-shadow -pie -o %t && %t 2>&1 | %symbolize | FileCheck %s
// Zero-base shadow only works on x86_64 and i386.
// REQUIRES: x86_64-supported-target
// A regression test for time(NULL), which caused ASan to crash in the
// zero-based shadow mode on Linux.
// FIXME: this test does not work on Darwin, because the code pages of the
// executable interleave with the zero-based shadow.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main() {
time_t t = time(NULL);
fprintf(stderr, "Time: %s\n", ctime(&t)); // NOLINT
// CHECK: {{Time: .* .* .*}}
return 0;
}

View File

@ -0,0 +1,31 @@
// RUN: %clangxx_asan -m64 -O0 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t && %t 2>&1 | %symbolize > %t.out
// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-64 < %t.out
// RUN: %clangxx_asan -m64 -O1 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t && %t 2>&1 | %symbolize > %t.out
// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-64 < %t.out
// RUN: %clangxx_asan -m64 -O2 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t && %t 2>&1 | %symbolize > %t.out
// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-64 < %t.out
// RUN: %clangxx_asan -m32 -O0 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t && %t 2>&1 | %symbolize > %t.out
// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-32 < %t.out
// RUN: %clangxx_asan -m32 -O1 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t && %t 2>&1 | %symbolize > %t.out
// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-32 < %t.out
// RUN: %clangxx_asan -m32 -O2 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t && %t 2>&1 | %symbolize > %t.out
// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-32 < %t.out
// Zero-base shadow only works on x86_64 and i386.
// REQUIRES: x86_64-supported-target,i386-supported-target
#include <string.h>
int main(int argc, char **argv) {
char x[10];
memset(x, 0, 10);
int res = x[argc * 10]; // BOOOM
// CHECK: {{READ of size 1 at 0x.* thread T0}}
// CHECK: {{ #0 0x.* in _?main .*zero-base-shadow.cc:}}[[@LINE-2]]
// CHECK: {{Address 0x.* is .* frame}}
// CHECK: main
// Check that shadow for stack memory occupies lower part of address space.
// CHECK-64: =>0x0f
// CHECK-32: =>0x1
return res;
}

View File

@ -0,0 +1,13 @@
//===----------- darwin-dummy-shared-lib-so.cc ------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of AddressSanitizer, an address sanity checker.
//
//===----------------------------------------------------------------------===//
void foo() {}

View File

@ -0,0 +1,12 @@
#include <stdio.h>
#include <unistd.h>
void inc_global();
int slow_init() {
sleep(1);
inc_global();
return 42;
}
int slowly_init_glob = slow_init();

Some files were not shown because too many files have changed in this diff Show More