Import compiler-rt r182741.
This commit is contained in:
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
130
CMakeLists.txt
130
CMakeLists.txt
@ -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)
|
||||
|
||||
|
4
Makefile
4
Makefile
@ -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
|
||||
|
17
SDKs/darwin/usr/include/fcntl.h
Normal file
17
SDKs/darwin/usr/include/fcntl.h
Normal 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>
|
@ -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)
|
||||
|
@ -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__ */
|
||||
|
@ -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 *);
|
||||
|
52
SDKs/darwin/usr/include/sys/fcntl.h
Normal file
52
SDKs/darwin/usr/include/sys/fcntl.h
Normal 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_ */
|
42
SDKs/darwin/usr/include/sys/mman.h
Normal file
42
SDKs/darwin/usr/include/sys/mman.h
Normal 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__ */
|
17
SDKs/linux/usr/include/fcntl.h
Normal file
17
SDKs/linux/usr/include/fcntl.h
Normal 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>
|
@ -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);
|
||||
|
@ -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__ */
|
||||
|
@ -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 *);
|
||||
|
29
SDKs/linux/usr/include/sys/fcntl.h
Normal file
29
SDKs/linux/usr/include/sys/fcntl.h
Normal 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_ */
|
@ -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__));
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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
39
include/CMakeLists.txt
Normal 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)
|
@ -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
|
||||
|
@ -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
|
||||
|
802
include/sanitizer/linux_syscall_hooks.h
Normal file
802
include/sanitizer/linux_syscall_hooks.h
Normal 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
|
@ -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"
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
39
lib/arm/aeabi_dcmp.S
Normal 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
39
lib/arm/aeabi_fcmp.S
Normal 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)
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
5
lib/asan/asan.syms
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
__asan_*;
|
||||
__sanitizer_syscall_pre_*;
|
||||
__sanitizer_syscall_post_*;
|
||||
};
|
@ -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
|
@ -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
|
||||
|
@ -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
|
||||
|
10
lib/asan/asan_blacklist.txt
Normal file
10
lib/asan/asan_blacklist.txt
Normal 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*
|
@ -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
117
lib/asan/asan_fake_stack.h
Normal 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
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
141
lib/asan/asan_interface_internal.h
Normal file
141
lib/asan/asan_interface_internal.h
Normal 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
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
58
lib/asan/asan_poisoning.h
Normal 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
|
@ -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
31
lib/asan/asan_preinit.cc
Normal 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
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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); \
|
||||
}
|
||||
|
||||
|
@ -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() {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -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
|
@ -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;
|
||||
|
||||
|
@ -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__
|
@ -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
|
||||
)
|
||||
|
39
lib/asan/lit_tests/Darwin/interface_symbols_darwin.c
Normal file
39
lib/asan/lit_tests/Darwin/interface_symbols_darwin.c
Normal 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; }
|
9
lib/asan/lit_tests/Darwin/lit.local.cfg
Normal file
9
lib/asan/lit_tests/Darwin/lit.local.cfg
Normal 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
|
20
lib/asan/lit_tests/Darwin/reexec-insert-libraries-env.cc
Normal file
20
lib/asan/lit_tests/Darwin/reexec-insert-libraries-env.cc
Normal 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;
|
||||
}
|
20
lib/asan/lit_tests/Darwin/unset-insert-libraries-on-exec.cc
Normal file
20
lib/asan/lit_tests/Darwin/unset-insert-libraries-on-exec.cc
Normal 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;
|
||||
}
|
16
lib/asan/lit_tests/Helpers/init-order-atexit-extra.cc
Normal file
16
lib/asan/lit_tests/Helpers/init-order-atexit-extra.cc
Normal 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; }
|
@ -0,0 +1,4 @@
|
||||
int zero_init();
|
||||
int badSrcGlobal = zero_init();
|
||||
int readBadSrcGlobal() { return badSrcGlobal; }
|
||||
|
@ -1,2 +1,3 @@
|
||||
global-init:*badGlobal*
|
||||
global-init-type:*badNamespace::BadClass*
|
||||
global-init-src:*initialization-blacklist-extra2.cc
|
||||
|
@ -0,0 +1,3 @@
|
||||
// Constexpr:
|
||||
int getCoolestInteger();
|
||||
static int coolest_integer = getCoolestInteger();
|
@ -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();
|
||||
|
28
lib/asan/lit_tests/Linux/asan_prelink_test.cc
Normal file
28
lib/asan/lit_tests/Linux/asan_prelink_test.cc
Normal 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
|
30
lib/asan/lit_tests/Linux/glob.cc
Normal file
30
lib/asan/lit_tests/Linux/glob.cc
Normal 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;
|
||||
}
|
0
lib/asan/lit_tests/Linux/glob_test_root/aa
Normal file
0
lib/asan/lit_tests/Linux/glob_test_root/aa
Normal file
0
lib/asan/lit_tests/Linux/glob_test_root/ab
Normal file
0
lib/asan/lit_tests/Linux/glob_test_root/ab
Normal file
0
lib/asan/lit_tests/Linux/glob_test_root/ba
Normal file
0
lib/asan/lit_tests/Linux/glob_test_root/ba
Normal file
55
lib/asan/lit_tests/Linux/heavy_uar_test.cc
Normal file
55
lib/asan/lit_tests/Linux/heavy_uar_test.cc
Normal 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;
|
||||
}
|
@ -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.
|
||||
|
@ -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; }
|
@ -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>
|
||||
|
||||
|
@ -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>
|
||||
|
||||
|
27
lib/asan/lit_tests/Linux/preinit_test.cc
Normal file
27
lib/asan/lit_tests/Linux/preinit_test.cc
Normal 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();
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
22
lib/asan/lit_tests/Linux/syscalls.cc
Normal file
22
lib/asan/lit_tests/Linux/syscalls.cc
Normal 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;
|
||||
}
|
20
lib/asan/lit_tests/Linux/time_null_regtest.cc
Normal file
20
lib/asan/lit_tests/Linux/time_null_regtest.cc
Normal 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;
|
||||
}
|
31
lib/asan/lit_tests/Linux/zero-base-shadow.cc
Normal file
31
lib/asan/lit_tests/Linux/zero-base-shadow.cc
Normal 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;
|
||||
}
|
13
lib/asan/lit_tests/SharedLibs/darwin-dummy-shared-lib-so.cc
Normal file
13
lib/asan/lit_tests/SharedLibs/darwin-dummy-shared-lib-so.cc
Normal 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() {}
|
12
lib/asan/lit_tests/SharedLibs/init-order-dlopen-so.cc
Normal file
12
lib/asan/lit_tests/SharedLibs/init-order-dlopen-so.cc
Normal 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
Loading…
Reference in New Issue
Block a user