diff options
author | Pirama Arumuga Nainar <pirama@google.com> | 2015-04-10 21:22:52 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2015-04-10 21:23:02 +0000 |
commit | 3d7bf861dbf6f15644b7afa060a02557e3ff8855 (patch) | |
tree | ffba1da06cea1fd707cfad245b93280a7df99700 | |
parent | 82f9cb33b564a9d72f09b478aabb44c4a83344c8 (diff) | |
parent | 7c9150579ed0278492f51cc8434b1d63a44b9bd1 (diff) | |
download | compiler-rt-3d7bf861dbf6f15644b7afa060a02557e3ff8855.tar.gz |
Merge "Update aosp/master compiler-rt for rebase to r233350"
283 files changed, 4258 insertions, 2424 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index f3485853f..d65b396f0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -160,8 +160,6 @@ include(CompilerRTUtils) set(COMPILER_RT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) set(COMPILER_RT_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}) -# Setup custom SDK sysroots. -set(COMPILER_RT_LINUX_SDK_SYSROOT ${COMPILER_RT_SOURCE_DIR}/SDKs/linux) # We support running instrumented tests when we're not cross compiling # and target a UNIX-like system or Windows. @@ -302,15 +300,22 @@ if(APPLE) set(SANITIZER_MIN_OSX_VERSION 10.7) set(CMAKE_OSX_DEPLOYMENT_TARGET "") # We're setting the flag manually below. set(DARWIN_osx_CFLAGS -mmacosx-version-min=${SANITIZER_MIN_OSX_VERSION} - -isysroot ${OSX_SDK_DIR} -stdlib=libc++) + -stdlib=libc++) set(DARWIN_iossim_CFLAGS + -stdlib=libc++ -mios-simulator-version-min=7.0 -isysroot ${IOSSIM_SDK_DIR}) set(DARWIN_osx_LINKFLAGS -mmacosx-version-min=${SANITIZER_MIN_OSX_VERSION} - -isysroot ${OSX_SDK_DIR} -stdlib=libc++) + -stdlib=libc++ -lc++) set(DARWIN_iossim_LINKFLAGS + -stdlib=libc++ -lc++ -Wl,-ios_simulator_version_min,7.0.0 -mios-simulator-version-min=7.0 -isysroot ${IOSSIM_SDK_DIR}) + + if(OSX_SDK_DIR) + list(APPEND DARWIN_osx_CFLAGS -isysroot ${OSX_SDK_DIR}) + list(APPEND DARWIN_osx_LINKFLAGS -isysroot ${OSX_SDK_DIR}) + endif() endif() add_subdirectory(include) diff --git a/LICENSE.TXT b/LICENSE.TXT index aee8347b0..aa4115e2a 100644 --- a/LICENSE.TXT +++ b/LICENSE.TXT @@ -14,7 +14,7 @@ Full text of the relevant licenses is included below. University of Illinois/NCSA Open Source License -Copyright (c) 2009-2014 by the contributors listed in CREDITS.TXT +Copyright (c) 2009-2015 by the contributors listed in CREDITS.TXT All rights reserved. @@ -55,7 +55,7 @@ SOFTWARE. ============================================================================== -Copyright (c) 2009-2014 by the contributors listed in CREDITS.TXT +Copyright (c) 2009-2015 by the contributors listed in CREDITS.TXT Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/SDKs/README.txt b/SDKs/README.txt deleted file mode 100644 index b95575e8c..000000000 --- a/SDKs/README.txt +++ /dev/null @@ -1,9 +0,0 @@ -It is often convenient to be able to build compiler-rt libraries for a certain -platform without having a full SDK or development environment installed. - -This makes it easy for users to build a compiler which can target a number of -different platforms, without having to actively maintain full development -environments for those platforms. - -Since compiler-rt's libraries typically have minimal interaction with the -system, we achieve this by stubbing out the SDKs of certain platforms. diff --git a/SDKs/linux/README.txt b/SDKs/linux/README.txt deleted file mode 100644 index aa0604af7..000000000 --- a/SDKs/linux/README.txt +++ /dev/null @@ -1,2 +0,0 @@ -This is a stub SDK for Linux. Currently, this has only been tested on i386 and -x86_64 using the Clang compiler. diff --git a/SDKs/linux/usr/include/endian.h b/SDKs/linux/usr/include/endian.h deleted file mode 100644 index 95528db15..000000000 --- a/SDKs/linux/usr/include/endian.h +++ /dev/null @@ -1,29 +0,0 @@ -/* ===-- endian.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 __ENDIAN_H__ -#define __ENDIAN_H__ - -#define __LITTLE_ENDIAN 1234 -#define __BIG_ENDIAN 4321 - -#if defined(__LITTLE_ENDIAN__) || defined(__ORDER_LITTLE_ENDIAN__) -#define __BYTE_ORDER __LITTLE_ENDIAN -#else -#define __BYTE_ORDER __BIG_ENDIAN -#endif - -#endif /* __ENDIAN_H__ */ diff --git a/SDKs/linux/usr/include/fcntl.h b/SDKs/linux/usr/include/fcntl.h deleted file mode 100644 index a5f91e3a5..000000000 --- a/SDKs/linux/usr/include/fcntl.h +++ /dev/null @@ -1,17 +0,0 @@ -/* ===-- 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> diff --git a/SDKs/linux/usr/include/limits.h b/SDKs/linux/usr/include/limits.h deleted file mode 100644 index 5495a784f..000000000 --- a/SDKs/linux/usr/include/limits.h +++ /dev/null @@ -1,23 +0,0 @@ -/* ===-- limits.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 __LIMITS_H__ -#define __LIMITS_H__ - -/* This is only here as a landing pad for the include_next from the compiler's - built-in limits.h. */ - -#endif /* __LIMITS_H__ */ diff --git a/SDKs/linux/usr/include/stdio.h b/SDKs/linux/usr/include/stdio.h deleted file mode 100644 index e2161daa4..000000000 --- a/SDKs/linux/usr/include/stdio.h +++ /dev/null @@ -1,44 +0,0 @@ -/* ===-- stdio.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 __STDIO_H__ -#define __STDIO_H__ - -typedef __SIZE_TYPE__ size_t; - -struct _IO_FILE; -typedef struct _IO_FILE FILE; - -extern struct _IO_FILE *stdin; -extern struct _IO_FILE *stdout; -extern struct _IO_FILE *stderr; - -#define SEEK_SET 0 /* set file offset to offset */ -#define SEEK_CUR 1 /* set file offset to current plus offset */ -#define SEEK_END 2 /* set file offset to EOF plus offset */ - -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 int fputc(int, FILE *); -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); -extern long ftell(FILE *); -extern int fseek(FILE *, long, int); - -#endif /* __STDIO_H__ */ diff --git a/SDKs/linux/usr/include/stdlib.h b/SDKs/linux/usr/include/stdlib.h deleted file mode 100644 index 966b29db6..000000000 --- a/SDKs/linux/usr/include/stdlib.h +++ /dev/null @@ -1,36 +0,0 @@ -/* ===-- stdlib.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 __STDLIB_H__ -#define __STDLIB_H__ - -#define NULL ((void *)0) - -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__)) - __attribute__((__nonnull__(1))); - __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__ */ diff --git a/SDKs/linux/usr/include/string.h b/SDKs/linux/usr/include/string.h deleted file mode 100644 index c7da1f57b..000000000 --- a/SDKs/linux/usr/include/string.h +++ /dev/null @@ -1,31 +0,0 @@ -/* ===-- string.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 __STRING_H__ -#define __STRING_H__ - -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 *); -size_t strlen(const char *); -char *strncpy(char *, const char *, size_t); - -#endif /* __STRING_H__ */ diff --git a/SDKs/linux/usr/include/sys/fcntl.h b/SDKs/linux/usr/include/sys/fcntl.h deleted file mode 100644 index 1512bf9b4..000000000 --- a/SDKs/linux/usr/include/sys/fcntl.h +++ /dev/null @@ -1,29 +0,0 @@ -/* ===-- 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_ */ diff --git a/SDKs/linux/usr/include/sys/mman.h b/SDKs/linux/usr/include/sys/mman.h deleted file mode 100644 index bfb7f8bb0..000000000 --- a/SDKs/linux/usr/include/sys/mman.h +++ /dev/null @@ -1,47 +0,0 @@ -/* ===-- limits.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 - -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__)); - -#endif /* __SYS_MMAN_H__ */ diff --git a/SDKs/linux/usr/include/sys/stat.h b/SDKs/linux/usr/include/sys/stat.h deleted file mode 100644 index 0449fddb0..000000000 --- a/SDKs/linux/usr/include/sys/stat.h +++ /dev/null @@ -1,24 +0,0 @@ -/* ===-- stat.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_STAT_H__ -#define __SYS_STAT_H__ - -typedef unsigned int mode_t; - -int mkdir(const char *, mode_t); - -#endif /* __SYS_STAT_H__ */ diff --git a/SDKs/linux/usr/include/sys/types.h b/SDKs/linux/usr/include/sys/types.h deleted file mode 100644 index 10e74bbd0..000000000 --- a/SDKs/linux/usr/include/sys/types.h +++ /dev/null @@ -1,20 +0,0 @@ -/* ===-- stat.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_TYPES_H__ -#define __SYS_TYPES_H__ - -#endif /* __SYS_TYPES_H__ */ diff --git a/SDKs/linux/usr/include/unistd.h b/SDKs/linux/usr/include/unistd.h deleted file mode 100644 index 773b081d4..000000000 --- a/SDKs/linux/usr/include/unistd.h +++ /dev/null @@ -1,26 +0,0 @@ -/* ===-- unistd.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 __UNISTD_H__ -#define __UNISTD_H__ - -enum { - _SC_PAGESIZE = 30 -}; - -extern long int sysconf (int __name) __attribute__ ((__nothrow__)); - -#endif /* __UNISTD_H__ */ diff --git a/cmake/Modules/CompilerRTCompile.cmake b/cmake/Modules/CompilerRTCompile.cmake index de73ccfc5..c883e43aa 100644 --- a/cmake/Modules/CompilerRTCompile.cmake +++ b/cmake/Modules/CompilerRTCompile.cmake @@ -1,5 +1,31 @@ include(LLVMParseArguments) +# On Windows, CMAKE_*_FLAGS are built for MSVC but we use the GCC clang.exe, +# which uses completely different flags. Translate some common flag types, and +# drop the rest. +function(translate_msvc_cflags out_flags msvc_flags) + # Insert an empty string in the list to simplify processing. + set(msvc_flags ";${msvc_flags}") + + # Canonicalize /flag to -flag. + string(REPLACE ";/" ";-" msvc_flags "${msvc_flags}") + + # Make space separated -D and -U flags into joined flags. + string(REGEX REPLACE ";-\([DU]\);" ";-\\1" msvc_flags "${msvc_flags}") + + set(clang_flags "") + foreach(flag ${msvc_flags}) + if ("${flag}" MATCHES "^-[DU]") + # Pass through basic command line macro definitions (-DNDEBUG). + list(APPEND clang_flags "${flag}") + elseif ("${flag}" MATCHES "^-O[2x]") + # Canonicalize normal optimization flags to -O2. + list(APPEND clang_flags "-O2") + endif() + endforeach() + set(${out_flags} "${clang_flags}" PARENT_SCOPE) +endfunction() + # Compile a source into an object file with COMPILER_RT_TEST_COMPILER using # a provided compile flags and dependenices. # clang_compile(<object> <source> @@ -20,13 +46,11 @@ macro(clang_compile object_file source) else() string(REPLACE " " ";" global_flags "${CMAKE_C_FLAGS}") endif() - # On Windows, CMAKE_*_FLAGS are built for MSVC but we use the GCC clang.exe - # which doesn't support flags starting with "/smth". Replace those with - # "-smth" equivalents. - if(MSVC) - string(REGEX REPLACE "^/" "-" global_flags "${global_flags}") - string(REPLACE ";/" ";-" global_flags "${global_flags}") + + if (MSVC) + translate_msvc_cflags(global_flags "${global_flags}") endif() + # Ignore unknown warnings. CMAKE_CXX_FLAGS may contain GCC-specific options # which are not supported by Clang. list(APPEND global_flags -Wno-unknown-warning-option) diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index 9c4c8deea..f52639bdb 100644 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -161,10 +161,11 @@ else() if("${LLVM_NATIVE_ARCH}" STREQUAL "X86") if(NOT MSVC) test_target_arch(x86_64 "" "-m64") + # FIXME: We build runtimes for both i686 and i386, as "clang -m32" may + # target different variant than "$CMAKE_C_COMPILER -m32". This part should + # be gone after we resolve PR14109. test_target_arch(i686 __i686__ "-m32") - if(NOT CAN_TARGET_i686) - test_target_arch(i386 __i386__ "-m32") - endif() + test_target_arch(i386 __i386__ "-m32") else() test_target_arch(i386 "" "") endif() @@ -220,14 +221,14 @@ endfunction() # Architectures supported by compiler-rt libraries. filter_available_targets(SANITIZER_COMMON_SUPPORTED_ARCH x86_64 i386 i686 powerpc64 powerpc64le arm aarch64 mips mips64 mipsel mips64el) -filter_available_targets(ASAN_SUPPORTED_ARCH - x86_64 i386 i686 powerpc64 powerpc64le arm mips mipsel mips64 mips64el) -filter_available_targets(DFSAN_SUPPORTED_ARCH x86_64 mips64 mips64el) -filter_available_targets(LSAN_SUPPORTED_ARCH x86_64 mips64 mips64el) # LSan common files should be available on all architectures supported # by other sanitizers (even if they build into dummy object files). filter_available_targets(LSAN_COMMON_SUPPORTED_ARCH ${SANITIZER_COMMON_SUPPORTED_ARCH}) +filter_available_targets(ASAN_SUPPORTED_ARCH + x86_64 i386 i686 powerpc64 powerpc64le arm mips mipsel mips64 mips64el) +filter_available_targets(DFSAN_SUPPORTED_ARCH x86_64 mips64 mips64el) +filter_available_targets(LSAN_SUPPORTED_ARCH x86_64 mips64 mips64el) filter_available_targets(MSAN_SUPPORTED_ARCH x86_64 mips64 mips64el) filter_available_targets(PROFILE_SUPPORTED_ARCH x86_64 i386 i686 arm mips mips64 mipsel mips64el aarch64 powerpc64 powerpc64le) @@ -276,13 +277,6 @@ else() set(COMPILER_RT_HAS_LSAN FALSE) endif() -if (COMPILER_RT_HAS_SANITIZER_COMMON AND LSAN_COMMON_SUPPORTED_ARCH AND - OS_NAME MATCHES "Darwin|Linux|FreeBSD|Android") - set(COMPILER_RT_HAS_LSAN_COMMON TRUE) -else() - set(COMPILER_RT_HAS_LSAN_COMMON FALSE) -endif() - if (COMPILER_RT_HAS_SANITIZER_COMMON AND MSAN_SUPPORTED_ARCH AND OS_NAME MATCHES "Linux") set(COMPILER_RT_HAS_MSAN TRUE) diff --git a/include/sanitizer/coverage_interface.h b/include/sanitizer/coverage_interface.h index 88a7e4800..404b71e30 100644 --- a/include/sanitizer/coverage_interface.h +++ b/include/sanitizer/coverage_interface.h @@ -39,6 +39,23 @@ extern "C" { // Some of the entries in *data will be zero. uintptr_t __sanitizer_get_coverage_guards(uintptr_t **data); + // The coverage instrumentation may optionally provide imprecise counters. + // Rather than exposing the counter values to the user we instead map + // the counters to a bitset. + // Every counter is associated with 8 bits in the bitset. + // We define 8 value ranges: 1, 2, 3, 4-7, 8-15, 16-31, 32-127, 128+ + // The i-th bit is set to 1 if the counter value is in the i-th range. + // This counter-based coverage implementation is *not* thread-safe. + + // Returns the number of registered coverage counters. + uintptr_t __sanitizer_get_number_of_counters(); + // Updates the counter 'bitset', clears the counters and returns the number of + // new bits in 'bitset'. + // If 'bitset' is nullptr, only clears the counters. + // Otherwise 'bitset' should be at least + // __sanitizer_get_number_of_counters bytes long and 8-aligned. + uintptr_t + __sanitizer_update_counter_bitset_and_clear_counters(uint8_t *bitset); #ifdef __cplusplus } // extern "C" #endif diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 6929e682f..91a7037e3 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -7,6 +7,7 @@ include(SanitizerUtils) if(COMPILER_RT_HAS_SANITIZER_COMMON) add_subdirectory(interception) add_subdirectory(sanitizer_common) + add_subdirectory(lsan) endif() if(COMPILER_RT_HAS_ASAN) @@ -19,10 +20,6 @@ if(COMPILER_RT_HAS_DFSAN) add_subdirectory(dfsan) endif() -if(COMPILER_RT_HAS_LSAN OR COMPILER_RT_HAS_LSAN_COMMON) - add_subdirectory(lsan) -endif() - if(COMPILER_RT_HAS_MSAN) add_subdirectory(msan) endif() diff --git a/lib/asan/Android.mk b/lib/asan/Android.mk index 4314c0278..ccb454570 100644 --- a/lib/asan/Android.mk +++ b/lib/asan/Android.mk @@ -79,6 +79,7 @@ asan_rtl_files := \ ../sanitizer_common/sanitizer_symbolizer_libbacktrace.cc \ ../sanitizer_common/sanitizer_symbolizer_libcdep.cc \ ../sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc \ + ../sanitizer_common/sanitizer_symbolizer_process_libcdep.cc \ ../sanitizer_common/sanitizer_symbolizer_win.cc \ ../sanitizer_common/sanitizer_thread_registry.cc \ ../sanitizer_common/sanitizer_tls_get_addr.cc \ diff --git a/lib/asan/CMakeLists.txt b/lib/asan/CMakeLists.txt index 90cb6f843..8b771fbe6 100644 --- a/lib/asan/CMakeLists.txt +++ b/lib/asan/CMakeLists.txt @@ -106,12 +106,8 @@ else() set(ASAN_COMMON_RUNTIME_OBJECTS $<TARGET_OBJECTS:RTInterception.${arch}> $<TARGET_OBJECTS:RTSanitizerCommon.${arch}> - $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>) - if(NOT WIN32) - # We can't build Leak Sanitizer on Windows yet. - list(APPEND ASAN_COMMON_RUNTIME_OBJECTS - $<TARGET_OBJECTS:RTLSanCommon.${arch}>) - endif() + $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}> + $<TARGET_OBJECTS:RTLSanCommon.${arch}>) add_compiler_rt_runtime(clang_rt.asan-${arch} ${arch} STATIC SOURCES $<TARGET_OBJECTS:RTAsan_preinit.${arch}> diff --git a/lib/asan/asan_globals.cc b/lib/asan/asan_globals.cc index 853a18102..8906d1eed 100644 --- a/lib/asan/asan_globals.cc +++ b/lib/asan/asan_globals.cc @@ -212,20 +212,6 @@ void StopInitOrderChecking() { } } -#if SANITIZER_WINDOWS // Should only be called on Windows. -SANITIZER_INTERFACE_ATTRIBUTE -void UnregisterGlobalsInRange(void *beg, void *end) { - if (!flags()->report_globals) - return; - BlockingMutexLock lock(&mu_for_globals); - for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) { - void *address = (void *)l->g->beg; - if (beg <= address && address < end) - UnregisterGlobal(l->g); - } -} -#endif - } // namespace __asan // ---------------------- Interface ---------------- {{{1 diff --git a/lib/asan/asan_interceptors.cc b/lib/asan/asan_interceptors.cc index df5769692..585181cce 100644 --- a/lib/asan/asan_interceptors.cc +++ b/lib/asan/asan_interceptors.cc @@ -65,7 +65,7 @@ struct AsanInterceptorContext { } \ if (!suppressed) { \ GET_CURRENT_PC_BP_SP; \ - __asan_report_error(pc, bp, sp, __bad, isWrite, __size); \ + __asan_report_error(pc, bp, sp, __bad, isWrite, __size, 0); \ } \ } \ } while (0) @@ -120,17 +120,6 @@ using namespace __asan; // NOLINT DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, uptr) DECLARE_REAL_AND_INTERCEPTOR(void, free, void *) -#if !SANITIZER_MAC -#define ASAN_INTERCEPT_FUNC(name) \ - do { \ - if ((!INTERCEPT_FUNCTION(name) || !REAL(name))) \ - VReport(1, "AddressSanitizer: failed to intercept '" #name "'\n"); \ - } while (0) -#else -// OS X interceptors don't need to be initialized with INTERCEPT_FUNCTION. -#define ASAN_INTERCEPT_FUNC(name) -#endif // SANITIZER_MAC - #define ASAN_INTERCEPTOR_ENTER(ctx, func) \ AsanInterceptorContext _ctx = {#func}; \ ctx = (void *)&_ctx; \ @@ -206,12 +195,6 @@ struct ThreadStartParam { }; static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) { -#if SANITIZER_WINDOWS - // FIXME: this is a bandaid fix for PR22025. - AsanThread *t = (AsanThread*)arg; - SetCurrentThread(t); - return t->ThreadStart(GetTid(), /* signal_thread_is_registered */ nullptr); -#else ThreadStartParam *param = reinterpret_cast<ThreadStartParam *>(arg); AsanThread *t = nullptr; while ((t = reinterpret_cast<AsanThread *>( @@ -219,7 +202,6 @@ static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) { internal_sched_yield(); SetCurrentThread(t); return t->ThreadStart(GetTid(), ¶m->is_registered); -#endif } #if ASAN_INTERCEPT_PTHREAD_CREATE @@ -363,30 +345,6 @@ INTERCEPTOR(void, __cxa_throw, void *a, void *b, void *c) { } #endif -#if SANITIZER_WINDOWS -INTERCEPTOR_WINAPI(void, RaiseException, void *a, void *b, void *c, void *d) { - CHECK(REAL(RaiseException)); - __asan_handle_no_return(); - REAL(RaiseException)(a, b, c, d); -} - -INTERCEPTOR(int, _except_handler3, void *a, void *b, void *c, void *d) { - CHECK(REAL(_except_handler3)); - __asan_handle_no_return(); - return REAL(_except_handler3)(a, b, c, d); -} - -#if ASAN_DYNAMIC -// This handler is named differently in -MT and -MD CRTs. -#define _except_handler4 _except_handler4_common -#endif -INTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) { - CHECK(REAL(_except_handler4)); - __asan_handle_no_return(); - return REAL(_except_handler4)(a, b, c, d); -} -#endif - static inline int CharCmp(unsigned char c1, unsigned char c2) { return (c1 == c2) ? 0 : (c1 < c2) ? -1 : 1; } @@ -813,36 +771,6 @@ INTERCEPTOR(int, fork, void) { } #endif // ASAN_INTERCEPT_FORK -#if SANITIZER_WINDOWS -INTERCEPTOR_WINAPI(DWORD, CreateThread, - void* security, uptr stack_size, - DWORD (__stdcall *start_routine)(void*), void* arg, - DWORD thr_flags, void* tid) { - // Strict init-order checking is thread-hostile. - if (flags()->strict_init_order) - StopInitOrderChecking(); - GET_STACK_TRACE_THREAD; - // FIXME: The CreateThread interceptor is not the same as a pthread_create - // one. This is a bandaid fix for PR22025. - bool detached = false; // FIXME: how can we determine it on Windows? - u32 current_tid = GetCurrentTidOrInvalid(); - AsanThread *t = - AsanThread::Create(start_routine, arg, current_tid, &stack, detached); - return REAL(CreateThread)(security, stack_size, - asan_thread_start, t, thr_flags, tid); -} - -namespace __asan { -void InitializeWindowsInterceptors() { - ASAN_INTERCEPT_FUNC(CreateThread); - ASAN_INTERCEPT_FUNC(RaiseException); - ASAN_INTERCEPT_FUNC(_except_handler3); - ASAN_INTERCEPT_FUNC(_except_handler4); -} - -} // namespace __asan -#endif - // ---------------------- InitializeAsanInterceptors ---------------- {{{1 namespace __asan { void InitializeAsanInterceptors() { @@ -925,10 +853,7 @@ void InitializeAsanInterceptors() { ASAN_INTERCEPT_FUNC(fork); #endif - // Some Windows-specific interceptors. -#if SANITIZER_WINDOWS - InitializeWindowsInterceptors(); -#endif + InitializePlatformInterceptors(); VReport(1, "AddressSanitizer: libc interceptors initialized\n"); } diff --git a/lib/asan/asan_interceptors.h b/lib/asan/asan_interceptors.h index ee3b82aa7..488ada78a 100644 --- a/lib/asan/asan_interceptors.h +++ b/lib/asan/asan_interceptors.h @@ -92,9 +92,21 @@ struct sigaction; DECLARE_REAL(int, sigaction, int signum, const struct sigaction *act, struct sigaction *oldact) +#if !SANITIZER_MAC +#define ASAN_INTERCEPT_FUNC(name) \ + do { \ + if ((!INTERCEPT_FUNCTION(name) || !REAL(name))) \ + VReport(1, "AddressSanitizer: failed to intercept '" #name "'\n"); \ + } while (0) +#else +// OS X interceptors don't need to be initialized with INTERCEPT_FUNCTION. +#define ASAN_INTERCEPT_FUNC(name) +#endif // SANITIZER_MAC + namespace __asan { void InitializeAsanInterceptors(); +void InitializePlatformInterceptors(); #define ENSURE_ASAN_INITED() do { \ CHECK(!asan_init_is_running); \ diff --git a/lib/asan/asan_interface_internal.h b/lib/asan/asan_interface_internal.h index ea7540f6b..8ed4ee367 100644 --- a/lib/asan/asan_interface_internal.h +++ b/lib/asan/asan_interface_internal.h @@ -128,7 +128,7 @@ extern "C" { SANITIZER_INTERFACE_ATTRIBUTE void __asan_report_error(uptr pc, uptr bp, uptr sp, - uptr addr, int is_write, uptr access_size); + uptr addr, int is_write, uptr access_size, u32 exp); SANITIZER_INTERFACE_ATTRIBUTE int __asan_set_error_exit_code(int exit_code); @@ -165,6 +165,21 @@ extern "C" { SANITIZER_INTERFACE_ATTRIBUTE void __asan_loadN(uptr p, uptr size); SANITIZER_INTERFACE_ATTRIBUTE void __asan_storeN(uptr p, uptr size); + SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_load1(uptr p, u32 exp); + SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_load2(uptr p, u32 exp); + SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_load4(uptr p, u32 exp); + SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_load8(uptr p, u32 exp); + SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_load16(uptr p, u32 exp); + SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_store1(uptr p, u32 exp); + SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_store2(uptr p, u32 exp); + SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_store4(uptr p, u32 exp); + SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_store8(uptr p, u32 exp); + SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_store16(uptr p, u32 exp); + SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_loadN(uptr p, uptr size, + u32 exp); + SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_storeN(uptr p, uptr size, + u32 exp); + SANITIZER_INTERFACE_ATTRIBUTE void* __asan_memcpy(void *dst, const void *src, uptr size); SANITIZER_INTERFACE_ATTRIBUTE diff --git a/lib/asan/asan_internal.h b/lib/asan/asan_internal.h index ffd3ff82d..394e46063 100644 --- a/lib/asan/asan_internal.h +++ b/lib/asan/asan_internal.h @@ -62,21 +62,6 @@ namespace __asan { class AsanThread; using __sanitizer::StackTrace; -struct SignalContext { - void *context; - uptr addr; - uptr pc; - uptr sp; - uptr bp; - - SignalContext(void *context, uptr addr, uptr pc, uptr sp, uptr bp) : - context(context), addr(addr), pc(pc), sp(sp), bp(bp) { - } - - // Creates signal context in a platform-specific manner. - static SignalContext Create(void *siginfo, void *context); -}; - void AsanInitFromRtl(); // asan_rtl.cc @@ -90,7 +75,6 @@ void *AsanDoesNotSupportStaticLinkage(); void AsanCheckDynamicRTPrereqs(); void AsanCheckIncompatibleRT(); -void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp); void AsanOnSIGSEGV(int, void *siginfo, void *context); void DisableReexec(); diff --git a/lib/asan/asan_linux.cc b/lib/asan/asan_linux.cc index 8e8bafd47..f4f187f72 100644 --- a/lib/asan/asan_linux.cc +++ b/lib/asan/asan_linux.cc @@ -68,6 +68,8 @@ asan_rt_version_t __asan_rt_version; namespace __asan { +void InitializePlatformInterceptors() {} + void DisableReexec() { // No need to re-exec on Linux. } @@ -152,78 +154,6 @@ void AsanCheckIncompatibleRT() { } #endif // SANITIZER_ANDROID -void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { -#if defined(__arm__) - ucontext_t *ucontext = (ucontext_t*)context; - *pc = ucontext->uc_mcontext.arm_pc; - *bp = ucontext->uc_mcontext.arm_fp; - *sp = ucontext->uc_mcontext.arm_sp; -#elif defined(__aarch64__) - ucontext_t *ucontext = (ucontext_t*)context; - *pc = ucontext->uc_mcontext.pc; - *bp = ucontext->uc_mcontext.regs[29]; - *sp = ucontext->uc_mcontext.sp; -#elif defined(__hppa__) - ucontext_t *ucontext = (ucontext_t*)context; - *pc = ucontext->uc_mcontext.sc_iaoq[0]; - /* GCC uses %r3 whenever a frame pointer is needed. */ - *bp = ucontext->uc_mcontext.sc_gr[3]; - *sp = ucontext->uc_mcontext.sc_gr[30]; -#elif defined(__x86_64__) -# if SANITIZER_FREEBSD - ucontext_t *ucontext = (ucontext_t*)context; - *pc = ucontext->uc_mcontext.mc_rip; - *bp = ucontext->uc_mcontext.mc_rbp; - *sp = ucontext->uc_mcontext.mc_rsp; -# else - ucontext_t *ucontext = (ucontext_t*)context; - *pc = ucontext->uc_mcontext.gregs[REG_RIP]; - *bp = ucontext->uc_mcontext.gregs[REG_RBP]; - *sp = ucontext->uc_mcontext.gregs[REG_RSP]; -# endif -#elif defined(__i386__) -# if SANITIZER_FREEBSD - ucontext_t *ucontext = (ucontext_t*)context; - *pc = ucontext->uc_mcontext.mc_eip; - *bp = ucontext->uc_mcontext.mc_ebp; - *sp = ucontext->uc_mcontext.mc_esp; -# else - ucontext_t *ucontext = (ucontext_t*)context; - *pc = ucontext->uc_mcontext.gregs[REG_EIP]; - *bp = ucontext->uc_mcontext.gregs[REG_EBP]; - *sp = ucontext->uc_mcontext.gregs[REG_ESP]; -# endif -#elif defined(__powerpc__) || defined(__powerpc64__) - ucontext_t *ucontext = (ucontext_t*)context; - *pc = ucontext->uc_mcontext.regs->nip; - *sp = ucontext->uc_mcontext.regs->gpr[PT_R1]; - // The powerpc{,64}-linux ABIs do not specify r31 as the frame - // pointer, but GCC always uses r31 when we need a frame pointer. - *bp = ucontext->uc_mcontext.regs->gpr[PT_R31]; -#elif defined(__sparc__) - ucontext_t *ucontext = (ucontext_t*)context; - uptr *stk_ptr; -# if defined (__arch64__) - *pc = ucontext->uc_mcontext.mc_gregs[MC_PC]; - *sp = ucontext->uc_mcontext.mc_gregs[MC_O6]; - stk_ptr = (uptr *) (*sp + 2047); - *bp = stk_ptr[15]; -# else - *pc = ucontext->uc_mcontext.gregs[REG_PC]; - *sp = ucontext->uc_mcontext.gregs[REG_O6]; - stk_ptr = (uptr *) *sp; - *bp = stk_ptr[15]; -# endif -#elif defined(__mips__) - ucontext_t *ucontext = (ucontext_t*)context; - *pc = ucontext->uc_mcontext.gregs[31]; - *bp = ucontext->uc_mcontext.gregs[30]; - *sp = ucontext->uc_mcontext.gregs[29]; -#else -# error "Unsupported arch" -#endif -} - void AsanPlatformThreadInit() { // Nothing here for now. } diff --git a/lib/asan/asan_mac.cc b/lib/asan/asan_mac.cc index b35368617..b2618d729 100644 --- a/lib/asan/asan_mac.cc +++ b/lib/asan/asan_mac.cc @@ -40,19 +40,7 @@ namespace __asan { -void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { - ucontext_t *ucontext = (ucontext_t*)context; -# if SANITIZER_WORDSIZE == 64 - *pc = ucontext->uc_mcontext->__ss.__rip; - *bp = ucontext->uc_mcontext->__ss.__rbp; - *sp = ucontext->uc_mcontext->__ss.__rsp; -# else - *pc = ucontext->uc_mcontext->__ss.__eip; - *bp = ucontext->uc_mcontext->__ss.__ebp; - *sp = ucontext->uc_mcontext->__ss.__esp; -# endif // SANITIZER_WORDSIZE -} - +void InitializePlatformInterceptors() {} bool PlatformHasDifferentMemcpyAndMemmove() { // On OS X 10.7 memcpy() and memmove() are both resolved diff --git a/lib/asan/asan_poisoning.cc b/lib/asan/asan_poisoning.cc index e2b1f4dc4..569d359aa 100644 --- a/lib/asan/asan_poisoning.cc +++ b/lib/asan/asan_poisoning.cc @@ -112,7 +112,7 @@ void __asan_poison_memory_region(void const volatile *addr, uptr size) { if (!flags()->allow_user_poisoning || size == 0) return; uptr beg_addr = (uptr)addr; uptr end_addr = beg_addr + size; - VPrintf(1, "Trying to poison memory region [%p, %p)\n", (void *)beg_addr, + VPrintf(3, "Trying to poison memory region [%p, %p)\n", (void *)beg_addr, (void *)end_addr); ShadowSegmentEndpoint beg(beg_addr); ShadowSegmentEndpoint end(end_addr); @@ -152,7 +152,7 @@ void __asan_unpoison_memory_region(void const volatile *addr, uptr size) { if (!flags()->allow_user_poisoning || size == 0) return; uptr beg_addr = (uptr)addr; uptr end_addr = beg_addr + size; - VPrintf(1, "Trying to unpoison memory region [%p, %p)\n", (void *)beg_addr, + VPrintf(3, "Trying to unpoison memory region [%p, %p)\n", (void *)beg_addr, (void *)end_addr); ShadowSegmentEndpoint beg(beg_addr); ShadowSegmentEndpoint end(end_addr); @@ -218,7 +218,7 @@ uptr __asan_region_is_poisoned(uptr beg, uptr size) { __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);\ + __asan_report_error(pc, bp, sp, __bad, isWrite, __size, 0);\ } \ } while (false); \ diff --git a/lib/asan/asan_posix.cc b/lib/asan/asan_posix.cc index ad31458df..4652ddee0 100644 --- a/lib/asan/asan_posix.cc +++ b/lib/asan/asan_posix.cc @@ -32,13 +32,6 @@ namespace __asan { -SignalContext SignalContext::Create(void *siginfo, void *context) { - uptr addr = (uptr)((siginfo_t*)siginfo)->si_addr; - uptr pc, sp, bp; - GetPcSpBp(context, &pc, &sp, &bp); - return SignalContext(context, addr, pc, sp, bp); -} - void AsanOnSIGSEGV(int, void *siginfo, void *context) { ScopedDeadlySignal signal_scope(GetCurrentThread()); int code = (int)((siginfo_t*)siginfo)->si_code; diff --git a/lib/asan/asan_report.cc b/lib/asan/asan_report.cc index ad75262b7..c1c340c45 100644 --- a/lib/asan/asan_report.cc +++ b/lib/asan/asan_report.cc @@ -939,9 +939,18 @@ void ReportMacCfReallocUnknown(uptr addr, uptr zone_ptr, const char *zone_name, using namespace __asan; // NOLINT void __asan_report_error(uptr pc, uptr bp, uptr sp, uptr addr, int is_write, - uptr access_size) { + uptr access_size, u32 exp) { ENABLE_FRAME_POINTER; + // Optimization experiments. + // The experiments can be used to evaluate potential optimizations that remove + // instrumentation (assess false negatives). Instead of completely removing + // some instrumentation, compiler can emit special calls into runtime + // (e.g. __asan_report_exp_load1 instead of __asan_report_load1) and pass + // mask of experiments (exp). + // The reaction to a non-zero value of exp is to be defined. + (void)exp; + // Determine the error type. const char *bug_descr = "unknown-crash"; if (AddrIsInMem(addr)) { diff --git a/lib/asan/asan_rtl.cc b/lib/asan/asan_rtl.cc index 9126e71a6..f3466151f 100644 --- a/lib/asan/asan_rtl.cc +++ b/lib/asan/asan_rtl.cc @@ -112,11 +112,15 @@ static void OnLowLevelAllocate(uptr ptr, uptr size) { // -------------------------- Run-time entry ------------------- {{{1 // exported functions #define ASAN_REPORT_ERROR(type, is_write, size) \ -extern "C" NOINLINE INTERFACE_ATTRIBUTE \ -void __asan_report_ ## type ## size(uptr addr); \ -void __asan_report_ ## type ## size(uptr addr) { \ +extern "C" NOINLINE INTERFACE_ATTRIBUTE \ +void __asan_report_ ## type ## size(uptr addr) { \ + GET_CALLER_PC_BP_SP; \ + __asan_report_error(pc, bp, sp, addr, is_write, size, 0); \ +} \ +extern "C" NOINLINE INTERFACE_ATTRIBUTE \ +void __asan_report_exp_ ## type ## size(uptr addr, u32 exp) { \ GET_CALLER_PC_BP_SP; \ - __asan_report_error(pc, bp, sp, addr, is_write, size); \ + __asan_report_error(pc, bp, sp, addr, is_write, size, exp); \ } ASAN_REPORT_ERROR(load, false, 1) @@ -132,18 +136,20 @@ 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(pc, bp, sp, addr, is_write, size, 0); \ +} \ +extern "C" NOINLINE INTERFACE_ATTRIBUTE \ +void __asan_report_exp_ ## type ## _n(uptr addr, uptr size, u32 exp) { \ + GET_CALLER_PC_BP_SP; \ + __asan_report_error(pc, bp, sp, addr, is_write, size, exp); \ } ASAN_REPORT_ERROR_N(load, false) ASAN_REPORT_ERROR_N(store, true) -#define ASAN_MEMORY_ACCESS_CALLBACK(type, is_write, size) \ - extern "C" NOINLINE INTERFACE_ATTRIBUTE void __asan_##type##size(uptr addr); \ - void __asan_##type##size(uptr addr) { \ +#define ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, exp_arg) \ uptr sp = MEM_TO_SHADOW(addr); \ uptr s = size <= SHADOW_GRANULARITY ? *reinterpret_cast<u8 *>(sp) \ : *reinterpret_cast<u16 *>(sp); \ @@ -155,10 +161,19 @@ ASAN_REPORT_ERROR_N(store, true) *__asan_test_only_reported_buggy_pointer = addr; \ } else { \ GET_CALLER_PC_BP_SP; \ - __asan_report_error(pc, bp, sp, addr, is_write, size); \ + __asan_report_error(pc, bp, sp, addr, is_write, size, exp_arg); \ } \ } \ - } \ + } + +#define ASAN_MEMORY_ACCESS_CALLBACK(type, is_write, size) \ + extern "C" NOINLINE INTERFACE_ATTRIBUTE \ + void __asan_##type##size(uptr addr) { \ + ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, 0) \ + } \ + extern "C" NOINLINE INTERFACE_ATTRIBUTE \ + void __asan_exp_##type##size(uptr addr, u32 exp) { \ + ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, exp) \ } ASAN_MEMORY_ACCESS_CALLBACK(load, false, 1) @@ -173,18 +188,38 @@ ASAN_MEMORY_ACCESS_CALLBACK(store, true, 8) ASAN_MEMORY_ACCESS_CALLBACK(store, true, 16) extern "C" -NOINLINE INTERFACE_ATTRIBUTE void __asan_loadN(uptr addr, uptr size) { +NOINLINE INTERFACE_ATTRIBUTE +void __asan_loadN(uptr addr, uptr size) { + if (__asan_region_is_poisoned(addr, size)) { + GET_CALLER_PC_BP_SP; + __asan_report_error(pc, bp, sp, addr, false, size, 0); + } +} + +extern "C" +NOINLINE INTERFACE_ATTRIBUTE +void __asan_exp_loadN(uptr addr, uptr size, u32 exp) { + if (__asan_region_is_poisoned(addr, size)) { + GET_CALLER_PC_BP_SP; + __asan_report_error(pc, bp, sp, addr, false, size, exp); + } +} + +extern "C" +NOINLINE INTERFACE_ATTRIBUTE +void __asan_storeN(uptr addr, uptr size) { if (__asan_region_is_poisoned(addr, size)) { GET_CALLER_PC_BP_SP; - __asan_report_error(pc, bp, sp, addr, false, size); + __asan_report_error(pc, bp, sp, addr, true, size, 0); } } extern "C" -NOINLINE INTERFACE_ATTRIBUTE void __asan_storeN(uptr addr, uptr size) { +NOINLINE INTERFACE_ATTRIBUTE +void __asan_exp_storeN(uptr addr, uptr size, u32 exp) { if (__asan_region_is_poisoned(addr, size)) { GET_CALLER_PC_BP_SP; - __asan_report_error(pc, bp, sp, addr, true, size); + __asan_report_error(pc, bp, sp, addr, true, size, exp); } } @@ -203,26 +238,40 @@ static NOINLINE void force_interface_symbols() { case 3: __asan_report_load4(0); break; case 4: __asan_report_load8(0); break; case 5: __asan_report_load16(0); break; - case 6: __asan_report_store1(0); break; - case 7: __asan_report_store2(0); break; - case 8: __asan_report_store4(0); break; - case 9: __asan_report_store8(0); break; - case 10: __asan_report_store16(0); break; - case 12: __asan_register_globals(0, 0); break; - case 13: __asan_unregister_globals(0, 0); break; - case 14: __asan_set_death_callback(0); break; - case 15: __asan_set_error_report_callback(0); break; - case 16: __asan_handle_no_return(); break; - case 17: __asan_address_is_poisoned(0); break; - case 25: __asan_poison_memory_region(0, 0); break; - case 26: __asan_unpoison_memory_region(0, 0); break; - case 27: __asan_set_error_exit_code(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; - case 34: __asan_region_is_poisoned(0, 0); break; - case 35: __asan_describe_address(0); break; + case 6: __asan_report_load_n(0, 0); break; + case 7: __asan_report_store1(0); break; + case 8: __asan_report_store2(0); break; + case 9: __asan_report_store4(0); break; + case 10: __asan_report_store8(0); break; + case 11: __asan_report_store16(0); break; + case 12: __asan_report_store_n(0, 0); break; + case 13: __asan_report_exp_load1(0, 0); break; + case 14: __asan_report_exp_load2(0, 0); break; + case 15: __asan_report_exp_load4(0, 0); break; + case 16: __asan_report_exp_load8(0, 0); break; + case 17: __asan_report_exp_load16(0, 0); break; + case 18: __asan_report_exp_load_n(0, 0, 0); break; + case 19: __asan_report_exp_store1(0, 0); break; + case 20: __asan_report_exp_store2(0, 0); break; + case 21: __asan_report_exp_store4(0, 0); break; + case 22: __asan_report_exp_store8(0, 0); break; + case 23: __asan_report_exp_store16(0, 0); break; + case 24: __asan_report_exp_store_n(0, 0, 0); break; + case 25: __asan_register_globals(0, 0); break; + case 26: __asan_unregister_globals(0, 0); break; + case 27: __asan_set_death_callback(0); break; + case 28: __asan_set_error_report_callback(0); break; + case 29: __asan_handle_no_return(); break; + case 30: __asan_address_is_poisoned(0); break; + case 31: __asan_poison_memory_region(0, 0); break; + case 32: __asan_unpoison_memory_region(0, 0); break; + case 33: __asan_set_error_exit_code(0); break; + case 34: __asan_before_dynamic_init(0); break; + case 35: __asan_after_dynamic_init(); break; + case 36: __asan_poison_stack_memory(0, 0); break; + case 37: __asan_unpoison_stack_memory(0, 0); break; + case 38: __asan_region_is_poisoned(0, 0); break; + case 39: __asan_describe_address(0); break; } } diff --git a/lib/asan/asan_suppressions.cc b/lib/asan/asan_suppressions.cc index 3f76e20e4..41887b5c8 100644 --- a/lib/asan/asan_suppressions.cc +++ b/lib/asan/asan_suppressions.cc @@ -81,14 +81,10 @@ bool IsStackTraceSuppressed(const StackTrace *stack) { uptr addr = stack->trace[i]; if (suppression_ctx->HasSuppressionType(kInterceptorViaLibrary)) { - const char *module_name; - uptr module_offset; // Match "interceptor_via_lib" suppressions. - if (symbolizer->GetModuleNameAndOffsetForPC(addr, &module_name, - &module_offset) && - suppression_ctx->Match(module_name, kInterceptorViaLibrary, &s)) { - return true; - } + if (const char *module_name = symbolizer->GetModuleNameForPc(addr)) + if (suppression_ctx->Match(module_name, kInterceptorViaLibrary, &s)) + return true; } if (suppression_ctx->HasSuppressionType(kInterceptorViaFunction)) { diff --git a/lib/asan/asan_win.cc b/lib/asan/asan_win.cc index 5b1d0da3a..addb3d40a 100644 --- a/lib/asan/asan_win.cc +++ b/lib/asan/asan_win.cc @@ -22,10 +22,13 @@ #include "asan_interceptors.h" #include "asan_internal.h" #include "asan_report.h" +#include "asan_stack.h" #include "asan_thread.h" #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_mutex.h" +using namespace __asan; // NOLINT + extern "C" { SANITIZER_INTERFACE_ATTRIBUTE int __asan_should_detect_stack_use_after_return() { @@ -33,6 +36,7 @@ int __asan_should_detect_stack_use_after_return() { return __asan_option_detect_stack_use_after_return; } +// -------------------- A workaround for the abscence of weak symbols ----- {{{ // We don't have a direct equivalent of weak symbols when using MSVC, but we can // use the /alternatename directive to tell the linker to default a specific // symbol to a specific value, which works nicely for allocator hooks and @@ -47,11 +51,105 @@ void __asan_default_on_error() {} #pragma comment(linker, "/alternatename:___asan_default_options=___asan_default_default_options") // NOLINT #pragma comment(linker, "/alternatename:___asan_default_suppressions=___asan_default_default_suppressions") // NOLINT #pragma comment(linker, "/alternatename:___asan_on_error=___asan_default_on_error") // NOLINT +// }}} } // extern "C" +// ---------------------- Windows-specific inteceptors ---------------- {{{ +INTERCEPTOR_WINAPI(void, RaiseException, void *a, void *b, void *c, void *d) { + CHECK(REAL(RaiseException)); + __asan_handle_no_return(); + REAL(RaiseException)(a, b, c, d); +} + +INTERCEPTOR(int, _except_handler3, void *a, void *b, void *c, void *d) { + CHECK(REAL(_except_handler3)); + __asan_handle_no_return(); + return REAL(_except_handler3)(a, b, c, d); +} + +#if ASAN_DYNAMIC +// This handler is named differently in -MT and -MD CRTs. +#define _except_handler4 _except_handler4_common +#endif +INTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) { + CHECK(REAL(_except_handler4)); + __asan_handle_no_return(); + return REAL(_except_handler4)(a, b, c, d); +} + +static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) { + AsanThread *t = (AsanThread*)arg; + SetCurrentThread(t); + return t->ThreadStart(GetTid(), /* signal_thread_is_registered */ nullptr); +} + +INTERCEPTOR_WINAPI(DWORD, CreateThread, + void* security, uptr stack_size, + DWORD (__stdcall *start_routine)(void*), void* arg, + DWORD thr_flags, void* tid) { + // Strict init-order checking is thread-hostile. + if (flags()->strict_init_order) + StopInitOrderChecking(); + GET_STACK_TRACE_THREAD; + // FIXME: The CreateThread interceptor is not the same as a pthread_create + // one. This is a bandaid fix for PR22025. + bool detached = false; // FIXME: how can we determine it on Windows? + u32 current_tid = GetCurrentTidOrInvalid(); + AsanThread *t = + AsanThread::Create(start_routine, arg, current_tid, &stack, detached); + return REAL(CreateThread)(security, stack_size, + asan_thread_start, t, thr_flags, tid); +} + +namespace { +BlockingMutex mu_for_thread_tracking(LINKER_INITIALIZED); + +void EnsureWorkerThreadRegistered() { + // FIXME: GetCurrentThread relies on TSD, which might not play well with + // system thread pools. We might want to use something like reference + // counting to zero out GetCurrentThread() underlying storage when the last + // work item finishes? Or can we disable reclaiming of threads in the pool? + BlockingMutexLock l(&mu_for_thread_tracking); + if (__asan::GetCurrentThread()) + return; + + AsanThread *t = AsanThread::Create( + /* start_routine */ nullptr, /* arg */ nullptr, + /* parent_tid */ -1, /* stack */ nullptr, /* detached */ true); + t->Init(); + asanThreadRegistry().StartThread(t->tid(), 0, 0); + SetCurrentThread(t); +} +} // namespace + +INTERCEPTOR_WINAPI(DWORD, NtWaitForWorkViaWorkerFactory, DWORD a, DWORD b) { + // NtWaitForWorkViaWorkerFactory is called from system worker pool threads to + // query work scheduled by BindIoCompletionCallback, QueueUserWorkItem, etc. + // System worker pool threads are created at arbitraty point in time and + // without using CreateThread, so we wrap NtWaitForWorkViaWorkerFactory + // instead and don't register a specific parent_tid/stack. + EnsureWorkerThreadRegistered(); + return REAL(NtWaitForWorkViaWorkerFactory)(a, b); +} + +// }}} + namespace __asan { -// ---------------------- TSD ---------------- {{{1 +void InitializePlatformInterceptors() { + ASAN_INTERCEPT_FUNC(CreateThread); + ASAN_INTERCEPT_FUNC(RaiseException); + ASAN_INTERCEPT_FUNC(_except_handler3); + ASAN_INTERCEPT_FUNC(_except_handler4); + + // NtWaitForWorkViaWorkerFactory is always linked dynamically. + CHECK(::__interception::OverrideFunction( + "NtWaitForWorkViaWorkerFactory", + (uptr)WRAP(NtWaitForWorkViaWorkerFactory), + (uptr *)&REAL(NtWaitForWorkViaWorkerFactory))); +} + +// ---------------------- TSD ---------------- {{{ static bool tsd_key_inited = false; static __declspec(thread) void *fake_tsd = 0; @@ -74,7 +172,9 @@ void AsanTSDSet(void *tsd) { void PlatformTSDDtor(void *tsd) { AsanThread::TSDDtor(tsd); } -// ---------------------- Various stuff ---------------- {{{1 +// }}} + +// ---------------------- Various stuff ---------------- {{{ void DisableReexec() { // No need to re-exec on Windows. } @@ -108,23 +208,6 @@ void AsanOnSIGSEGV(int, void *siginfo, void *context) { static LPTOP_LEVEL_EXCEPTION_FILTER default_seh_handler; -SignalContext SignalContext::Create(void *siginfo, void *context) { - EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD*)siginfo; - CONTEXT *context_record = (CONTEXT*)context; - - uptr pc = (uptr)exception_record->ExceptionAddress; -#ifdef _WIN64 - uptr bp = (uptr)context_record->Rbp; - uptr sp = (uptr)context_record->Rsp; -#else - uptr bp = (uptr)context_record->Ebp; - uptr sp = (uptr)context_record->Esp; -#endif - uptr access_addr = exception_record->ExceptionInformation[1]; - - return SignalContext(context, access_addr, pc, sp, bp); -} - static long WINAPI SEHHandler(EXCEPTION_POINTERS *info) { EXCEPTION_RECORD *exception_record = info->ExceptionRecord; CONTEXT *context = info->ContextRecord; @@ -177,7 +260,7 @@ int __asan_set_seh_filter() { static __declspec(allocate(".CRT$XIZ")) int (*__intercept_seh)() = __asan_set_seh_filter; #endif - +// }}} } // namespace __asan #endif // _WIN32 diff --git a/lib/asan/asan_win_dll_thunk.cc b/lib/asan/asan_win_dll_thunk.cc index 7b9430257..0c363fe29 100644 --- a/lib/asan/asan_win_dll_thunk.cc +++ b/lib/asan/asan_win_dll_thunk.cc @@ -319,6 +319,8 @@ INTERFACE_FUNCTION(__sanitizer_ptr_cmp) INTERFACE_FUNCTION(__sanitizer_ptr_sub) INTERFACE_FUNCTION(__sanitizer_report_error_summary) INTERFACE_FUNCTION(__sanitizer_reset_coverage) +INTERFACE_FUNCTION(__sanitizer_get_number_of_counters) +INTERFACE_FUNCTION(__sanitizer_update_counter_bitset_and_clear_counters) INTERFACE_FUNCTION(__sanitizer_sandbox_on_notify) INTERFACE_FUNCTION(__sanitizer_set_death_callback) INTERFACE_FUNCTION(__sanitizer_set_report_path) diff --git a/lib/asan/asan_win_dynamic_runtime_thunk.cc b/lib/asan/asan_win_dynamic_runtime_thunk.cc index 19456141c..d59f9f576 100644 --- a/lib/asan/asan_win_dynamic_runtime_thunk.cc +++ b/lib/asan/asan_win_dynamic_runtime_thunk.cc @@ -15,7 +15,8 @@ // // This includes: // - forwarding the detect_stack_use_after_return runtime option -// - installing a custom SEH handler +// - working around deficiencies of the MD runtime +// - installing a custom SEH handlerx // //===----------------------------------------------------------------------===// @@ -24,9 +25,13 @@ // simplifies the build procedure. #ifdef ASAN_DYNAMIC_RUNTIME_THUNK #include <windows.h> -#include <psapi.h> -extern "C" { +// First, declare CRT sections we'll be using in this file +#pragma section(".CRT$XID", long, read) // NOLINT +#pragma section(".CRT$XIZ", long, read) // NOLINT +#pragma section(".CRT$XTW", long, read) // NOLINT +#pragma section(".CRT$XTY", long, read) // NOLINT + //////////////////////////////////////////////////////////////////////////////// // Define a copy of __asan_option_detect_stack_use_after_return that should be // used when linking an MD runtime with a set of object files on Windows. @@ -38,82 +43,55 @@ extern "C" { // with a MT or MD runtime and we don't want to use ugly __imp_ names on Windows // just to work around this issue, let's clone the a variable that is // constant after initialization anyways. +extern "C" { __declspec(dllimport) int __asan_should_detect_stack_use_after_return(); int __asan_option_detect_stack_use_after_return = __asan_should_detect_stack_use_after_return(); } //////////////////////////////////////////////////////////////////////////////// -// For some reason, the MD CRT doesn't call the C/C++ terminators as MT does. -// To work around this, for each DLL we schedule a call to -// UnregisterGlobalsInRange atexit() specifying the address range of the DLL -// image to unregister globals in that range. We don't do the same -// for the main module (.exe) as the asan_globals.cc allocator is destroyed -// by the time UnregisterGlobalsInRange is executed. -// See PR22545 for the details. -namespace __asan { -__declspec(dllimport) -void UnregisterGlobalsInRange(void *beg, void *end); -} +// For some reason, the MD CRT doesn't call the C/C++ terminators during on DLL +// unload or on exit. ASan relies on LLVM global_dtors to call +// __asan_unregister_globals on these events, which unfortunately doesn't work +// with the MD runtime, see PR22545 for the details. +// To work around this, for each DLL we schedule a call to UnregisterGlobals +// using atexit() that calls a small subset of C terminators +// where LLVM global_dtors is placed. Fingers crossed, no other C terminators +// are there. +extern "C" void __cdecl _initterm(void *a, void *b); namespace { -void *this_module_base, *this_module_end; +__declspec(allocate(".CRT$XTW")) void* before_global_dtors = 0; +__declspec(allocate(".CRT$XTY")) void* after_global_dtors = 0; void UnregisterGlobals() { - __asan::UnregisterGlobalsInRange(this_module_base, this_module_end); + _initterm(&before_global_dtors, &after_global_dtors); } int ScheduleUnregisterGlobals() { - HMODULE this_module = 0; - // Increments the reference counter of the DLL module, so need to call - // FreeLibrary later. - if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, - (LPCTSTR)&UnregisterGlobals, &this_module)) - return 1; - - // Skip the main module. - if (this_module == GetModuleHandle(0)) - return 0; - - MODULEINFO mi; - bool success = - GetModuleInformation(GetCurrentProcess(), this_module, &mi, sizeof(mi)); - if (!FreeLibrary(this_module)) - return 2; - if (!success) - return 3; - - this_module_base = mi.lpBaseOfDll; - this_module_end = (char*)mi.lpBaseOfDll + mi.SizeOfImage; - return atexit(UnregisterGlobals); } -} // namespace - -/////////////////////////////////////////////////////////////////////////////// -// ASan SEH handling. -extern "C" __declspec(dllimport) int __asan_set_seh_filter(); -static int SetSEHFilter() { return __asan_set_seh_filter(); } -/////////////////////////////////////////////////////////////////////////////// -// We schedule some work at start-up by placing callbacks to our code to the -// list of CRT C initializers. -// -// First, declare sections we'll be using: -#pragma section(".CRT$XID", long, read) // NOLINT -#pragma section(".CRT$XIZ", long, read) // NOLINT - -// We need to call 'atexit(UnregisterGlobals);' after atexit() is initialized -// (.CRT$XIC) but before the C++ constructors (.CRT$XCA). +// We need to call 'atexit(UnregisterGlobals);' as early as possible, but after +// atexit() is initialized (.CRT$XIC). As this is executed before C++ +// initializers (think ctors for globals), UnregisterGlobals gets executed after +// dtors for C++ globals. __declspec(allocate(".CRT$XID")) -static int (*__asan_schedule_unregister_globals)() = ScheduleUnregisterGlobals; +int (*__asan_schedule_unregister_globals)() = ScheduleUnregisterGlobals; +} // namespace + +//////////////////////////////////////////////////////////////////////////////// +// ASan SEH handling. // We need to set the ASan-specific SEH handler at the end of CRT initialization // of each module (see also asan_win.cc). -// +extern "C" { +__declspec(dllimport) int __asan_set_seh_filter(); +static int SetSEHFilter() { return __asan_set_seh_filter(); } + // Unfortunately, putting a pointer to __asan_set_seh_filter into // __asan_intercept_seh gets optimized out, so we have to use an extra function. -extern "C" __declspec(allocate(".CRT$XIZ")) -int (*__asan_seh_interceptor)() = SetSEHFilter; +__declspec(allocate(".CRT$XIZ")) int (*__asan_seh_interceptor)() = SetSEHFilter; +} #endif // ASAN_DYNAMIC_RUNTIME_THUNK diff --git a/lib/asan/scripts/asan_symbolize.py b/lib/asan/scripts/asan_symbolize.py index 59fceaaed..b9d3ad3ad 100755 --- a/lib/asan/scripts/asan_symbolize.py +++ b/lib/asan/scripts/asan_symbolize.py @@ -23,6 +23,7 @@ sysroot_path = None binary_name_filter = None fix_filename_patterns = None logfile = sys.stdin +allow_system_symbolizer = True # FIXME: merge the code that calls fix_filename(). def fix_filename(file_name): @@ -392,6 +393,8 @@ class SymbolizationLoop(object): [BreakpadSymbolizerFactory(binary), self.llvm_symbolizers[binary]]) result = symbolizers[binary].symbolize(addr, binary, offset) if result is None: + if not allow_system_symbolizer: + raise Exception('Failed to launch or use llvm-symbolizer.') # Initialize system symbolizer only if other symbolizers failed. symbolizers[binary].append_symbolizer( SystemSymbolizerFactory(self.system, addr, binary)) diff --git a/lib/asan/tests/asan_asm_test.cc b/lib/asan/tests/asan_asm_test.cc index 1d8b04d61..200de2c13 100644 --- a/lib/asan/tests/asan_asm_test.cc +++ b/lib/asan/tests/asan_asm_test.cc @@ -232,7 +232,7 @@ TEST(AddressSanitizer, asm_flags) { long magic = 0x1234; long r = 0x0; -#if defined(__x86_64__) +#if defined(__x86_64__) && !defined(__ILP32__) __asm__("xorq %%rax, %%rax \n\t" "movq (%[p]), %%rax \n\t" "sete %%al \n\t" @@ -248,7 +248,7 @@ TEST(AddressSanitizer, asm_flags) { : [r] "=r"(r) : [p] "r"(&magic) : "eax", "memory"); -#endif // defined(__x86_64__) +#endif // defined(__x86_64__) && !defined(__ILP32__) ASSERT_EQ(0x1, r); } diff --git a/lib/asan/tests/asan_test.cc b/lib/asan/tests/asan_test.cc index 952b05e21..aa0808054 100644 --- a/lib/asan/tests/asan_test.cc +++ b/lib/asan/tests/asan_test.cc @@ -31,13 +31,13 @@ NOINLINE void free_aaa(void *p) { free_bbb(p); break_optimization(0);} template<typename T> NOINLINE void uaf_test(int size, int off) { - char *p = (char *)malloc_aaa(size); + void *p = malloc_aaa(size); free_aaa(p); for (int i = 1; i < 100; i++) free_aaa(malloc_aaa(i)); fprintf(stderr, "writing %ld byte(s) at %p with offset %d\n", (long)sizeof(T), p, off); - asan_write((T*)(p + off)); + asan_write((T *)((char *)p + off)); } TEST(AddressSanitizer, HasFeatureAddressSanitizerTest) { @@ -436,10 +436,10 @@ TEST(AddressSanitizer, WrongFreeTest) { void DoubleFree() { int *x = (int*)malloc(100 * sizeof(int)); - fprintf(stderr, "DoubleFree: x=%p\n", x); + fprintf(stderr, "DoubleFree: x=%p\n", (void *)x); free(x); free(x); - fprintf(stderr, "should have failed in the second free(%p)\n", x); + fprintf(stderr, "should have failed in the second free(%p)\n", (void *)x); abort(); } @@ -569,7 +569,7 @@ TEST(AddressSanitizer, LongJmpTest) { } #if !defined(_WIN32) // Only basic longjmp is available on Windows. -NOINLINE void BuiltinLongJmpFunc1(jmp_buf buf) { +NOINLINE void UnderscopeLongJmpFunc1(jmp_buf buf) { // create three red zones for these two stack objects. int a; int b; @@ -577,10 +577,10 @@ NOINLINE void BuiltinLongJmpFunc1(jmp_buf buf) { int *A = Ident(&a); int *B = Ident(&b); *A = *B; - __builtin_longjmp((void**)buf, 1); + _longjmp(buf, 1); } -NOINLINE void UnderscopeLongJmpFunc1(jmp_buf buf) { +NOINLINE void SigLongJmpFunc1(sigjmp_buf buf) { // create three red zones for these two stack objects. int a; int b; @@ -588,10 +588,13 @@ NOINLINE void UnderscopeLongJmpFunc1(jmp_buf buf) { int *A = Ident(&a); int *B = Ident(&b); *A = *B; - _longjmp(buf, 1); + siglongjmp(buf, 1); } -NOINLINE void SigLongJmpFunc1(sigjmp_buf buf) { +#if !defined(__ANDROID__) && !defined(__arm__) && \ + !defined(__powerpc64__) && !defined(__powerpc__) && \ + !defined(__aarch64__) +NOINLINE void BuiltinLongJmpFunc1(jmp_buf buf) { // create three red zones for these two stack objects. int a; int b; @@ -599,12 +602,9 @@ NOINLINE void SigLongJmpFunc1(sigjmp_buf buf) { int *A = Ident(&a); int *B = Ident(&b); *A = *B; - siglongjmp(buf, 1); + __builtin_longjmp((void**)buf, 1); } -#if !defined(__ANDROID__) && !defined(__arm__) && \ - !defined(__powerpc64__) && !defined(__powerpc__) && \ - !defined(__aarch64__) // Does not work on Power and ARM: // https://code.google.com/p/address-sanitizer/issues/detail?id=185 TEST(AddressSanitizer, BuiltinLongJmpTest) { @@ -1243,7 +1243,7 @@ TEST(AddressSanitizer, DISABLED_DemoTooMuchMemoryTest) { const size_t kAllocSize = (1 << 28) - 1024; size_t total_size = 0; while (true) { - char *x = (char*)malloc(kAllocSize); + void *x = malloc(kAllocSize); memset(x, 0, kAllocSize); total_size += kAllocSize; fprintf(stderr, "total: %ldM %p\n", (long)total_size >> 20, x); diff --git a/lib/builtins/clear_cache.c b/lib/builtins/clear_cache.c index 8dc0fb1c5..ede7659a0 100644 --- a/lib/builtins/clear_cache.c +++ b/lib/builtins/clear_cache.c @@ -9,11 +9,12 @@ */ #include "int_lib.h" +#include <stddef.h> #if __APPLE__ #include <libkern/OSCacheControl.h> #endif -#if defined(__FreeBSD__) && defined(__arm__) +#if (defined(__FreeBSD__) || defined(__Bitrig__)) && defined(__arm__) #include <sys/types.h> #include <machine/sysarch.h> #endif @@ -25,6 +26,7 @@ #if defined(__mips__) #include <sys/cachectl.h> #include <sys/syscall.h> + #include <unistd.h> #if defined(__ANDROID__) && defined(__LP64__) /* * clear_mips_cache - Invalidates instruction cache for Mips. @@ -89,7 +91,7 @@ void __clear_cache(void *start, void *end) { * so there is nothing to do */ #elif defined(__arm__) && !defined(__APPLE__) - #if defined(__FreeBSD__) || defined(__NetBSD__) + #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__Bitrig__) struct arm_sync_icache_args arg; arg.addr = (uintptr_t)start; @@ -126,6 +128,7 @@ void __clear_cache(void *start, void *end) { #elif defined(__aarch64__) && !defined(__APPLE__) uint64_t xstart = (uint64_t)(uintptr_t) start; uint64_t xend = (uint64_t)(uintptr_t) end; + uint64_t addr; // Get Cache Type Info uint64_t ctr_el0; @@ -136,12 +139,12 @@ void __clear_cache(void *start, void *end) { * uintptr_t in case this runs in an IPL32 environment. */ const size_t dcache_line_size = 4 << ((ctr_el0 >> 16) & 15); - for (uint64_t addr = xstart; addr < xend; addr += dcache_line_size) + for (addr = xstart; addr < xend; addr += dcache_line_size) __asm __volatile("dc cvau, %0" :: "r"(addr)); __asm __volatile("dsb ish"); const size_t icache_line_size = 4 << ((ctr_el0 >> 0) & 15); - for (uint64_t addr = xstart; addr < xend; addr += icache_line_size) + for (addr = xstart; addr < xend; addr += icache_line_size) __asm __volatile("ic ivau, %0" :: "r"(addr)); __asm __volatile("isb sy"); #else diff --git a/lib/builtins/fixdfdi.c b/lib/builtins/fixdfdi.c index 86f9f6ce8..67b124a16 100644 --- a/lib/builtins/fixdfdi.c +++ b/lib/builtins/fixdfdi.c @@ -6,40 +6,17 @@ * Source Licenses. See LICENSE.TXT for details. * * ===----------------------------------------------------------------------=== - * - * This file implements __fixdfdi for the compiler_rt library. - * - * ===----------------------------------------------------------------------=== */ -#include "int_lib.h" - -/* Returns: convert a to a signed long long, rounding toward zero. */ - -/* Assumption: double is a IEEE 64 bit floating point type - * su_int is a 32 bit integral type - * value in double is representable in di_int (no range checking performed) - */ - -/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */ - +#define DOUBLE_PRECISION +#include "fp_lib.h" ARM_EABI_FNALIAS(d2lz, fixdfdi) +typedef di_int fixint_t; +typedef du_int fixuint_t; +#include "fp_fixint_impl.inc" + COMPILER_RT_ABI di_int -__fixdfdi(double a) -{ - double_bits fb; - fb.f = a; - int e = ((fb.u.s.high & 0x7FF00000) >> 20) - 1023; - if (e < 0) - return 0; - di_int s = (si_int)(fb.u.s.high & 0x80000000) >> 31; - dwords r; - r.s.high = (fb.u.s.high & 0x000FFFFF) | 0x00100000; - r.s.low = fb.u.s.low; - if (e > 52) - r.all <<= (e - 52); - else - r.all >>= (52 - e); - return (r.all ^ s) - s; -} +__fixdfdi(fp_t a) { + return __fixint(a); +} diff --git a/lib/builtins/fixdfsi.c b/lib/builtins/fixdfsi.c index 88b2ff5e7..704e65bc4 100644 --- a/lib/builtins/fixdfsi.c +++ b/lib/builtins/fixdfsi.c @@ -1,50 +1,22 @@ -//===-- lib/fixdfsi.c - Double-precision -> integer conversion ----*- C -*-===// -// -// 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 file implements double-precision to integer conversion for the -// compiler-rt library. No range checking is performed; the behavior of this -// conversion is undefined for out of range values in the C standard. -// -//===----------------------------------------------------------------------===// +/* ===-- fixdfsi.c - Implement __fixdfsi -----------------------------------=== + * + * 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. + * + * ===----------------------------------------------------------------------=== + */ #define DOUBLE_PRECISION #include "fp_lib.h" - -#include "int_lib.h" +typedef si_int fixint_t; +typedef su_int fixuint_t; +#include "fp_fixint_impl.inc" ARM_EABI_FNALIAS(d2iz, fixdfsi) -COMPILER_RT_ABI int +COMPILER_RT_ABI si_int __fixdfsi(fp_t a) { - - // Break a into sign, exponent, significand - const rep_t aRep = toRep(a); - const rep_t aAbs = aRep & absMask; - const int sign = aRep & signBit ? -1 : 1; - const int exponent = (aAbs >> significandBits) - exponentBias; - const rep_t significand = (aAbs & significandMask) | implicitBit; - - // If 0 < exponent < significandBits, right shift to get the result. - if ((unsigned int)exponent < significandBits) { - return sign * (significand >> (significandBits - exponent)); - } - - // If exponent is negative, the result is zero. - else if (exponent < 0) { - return 0; - } - - // If significandBits < exponent, left shift to get the result. This shift - // may end up being larger than the type width, which incurs undefined - // behavior, but the conversion itself is undefined in that case, so - // whatever the compiler decides to do is fine. - else { - return sign * (significand << (exponent - significandBits)); - } + return __fixint(a); } diff --git a/lib/builtins/fixdfti.c b/lib/builtins/fixdfti.c index 2c27f4bae..aaf225e74 100644 --- a/lib/builtins/fixdfti.c +++ b/lib/builtins/fixdfti.c @@ -6,40 +6,21 @@ * Source Licenses. See LICENSE.TXT for details. * * ===----------------------------------------------------------------------=== - * - * This file implements __fixdfti for the compiler_rt library. - * - * ===----------------------------------------------------------------------=== */ #include "int_lib.h" #ifdef CRT_HAS_128BIT +#define DOUBLE_PRECISION +#include "fp_lib.h" -/* Returns: convert a to a signed long long, rounding toward zero. */ - -/* Assumption: double is a IEEE 64 bit floating point type - * su_int is a 32 bit integral type - * value in double is representable in ti_int (no range checking performed) - */ - -/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */ +typedef ti_int fixint_t; +typedef tu_int fixuint_t; +#include "fp_fixint_impl.inc" COMPILER_RT_ABI ti_int -__fixdfti(double a) -{ - double_bits fb; - fb.f = a; - int e = ((fb.u.s.high & 0x7FF00000) >> 20) - 1023; - if (e < 0) - return 0; - ti_int s = (si_int)(fb.u.s.high & 0x80000000) >> 31; - ti_int r = 0x0010000000000000uLL | (0x000FFFFFFFFFFFFFuLL & fb.u.all); - if (e > 52) - r <<= (e - 52); - else - r >>= (52 - e); - return (r ^ s) - s; +__fixdfti(fp_t a) { + return __fixint(a); } #endif /* CRT_HAS_128BIT */ diff --git a/lib/builtins/fixsfdi.c b/lib/builtins/fixsfdi.c index 4f6cfdd7a..835ff852d 100644 --- a/lib/builtins/fixsfdi.c +++ b/lib/builtins/fixsfdi.c @@ -1,43 +1,23 @@ /* ===-- fixsfdi.c - Implement __fixsfdi -----------------------------------=== * - * The LLVM Compiler Infrastructure + * 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 file implements __fixsfdi for the compiler_rt library. - * - * ===----------------------------------------------------------------------=== - */ - -#include "int_lib.h" - -/* Returns: convert a to a signed long long, rounding toward zero. */ - -/* Assumption: float is a IEEE 32 bit floating point type - * su_int is a 32 bit integral type - * value in float is representable in di_int (no range checking performed) */ -/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */ +#define SINGLE_PRECISION +#include "fp_lib.h" ARM_EABI_FNALIAS(f2lz, fixsfdi) +typedef di_int fixint_t; +typedef du_int fixuint_t; +#include "fp_fixint_impl.inc" + COMPILER_RT_ABI di_int -__fixsfdi(float a) -{ - float_bits fb; - fb.f = a; - int e = ((fb.u & 0x7F800000) >> 23) - 127; - if (e < 0) - return 0; - di_int s = (si_int)(fb.u & 0x80000000) >> 31; - di_int r = (fb.u & 0x007FFFFF) | 0x00800000; - if (e > 23) - r <<= (e - 23); - else - r >>= (23 - e); - return (r ^ s) - s; +__fixsfdi(fp_t a) { + return __fixint(a); } diff --git a/lib/builtins/fixsfsi.c b/lib/builtins/fixsfsi.c index e3cc42d52..f045536d6 100644 --- a/lib/builtins/fixsfsi.c +++ b/lib/builtins/fixsfsi.c @@ -1,47 +1,22 @@ -//===-- lib/fixsfsi.c - Single-precision -> integer conversion ----*- C -*-===// -// -// 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 file implements single-precision to integer conversion for the -// compiler-rt library. No range checking is performed; the behavior of this -// conversion is undefined for out of range values in the C standard. -// -//===----------------------------------------------------------------------===// +/* ===-- fixsfsi.c - Implement __fixsfsi -----------------------------------=== + * + * 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. + * + * ===----------------------------------------------------------------------=== + */ #define SINGLE_PRECISION #include "fp_lib.h" +typedef si_int fixint_t; +typedef su_int fixuint_t; +#include "fp_fixint_impl.inc" ARM_EABI_FNALIAS(f2iz, fixsfsi) -COMPILER_RT_ABI int +COMPILER_RT_ABI si_int __fixsfsi(fp_t a) { - // Break a into sign, exponent, significand - const rep_t aRep = toRep(a); - const rep_t aAbs = aRep & absMask; - const int sign = aRep & signBit ? -1 : 1; - const int exponent = (aAbs >> significandBits) - exponentBias; - const rep_t significand = (aAbs & significandMask) | implicitBit; - - // If 0 < exponent < significandBits, right shift to get the result. - if ((unsigned int)exponent < significandBits) { - return sign * (significand >> (significandBits - exponent)); - } - - // If exponent is negative, the result is zero. - else if (exponent < 0) { - return 0; - } - - // If significandBits < exponent, left shift to get the result. This shift - // may end up being larger than the type width, which incurs undefined - // behavior, but the conversion itself is undefined in that case, so - // whatever the compiler decides to do is fine. - else { - return sign * (significand << (exponent - significandBits)); - } + return __fixint(a); } diff --git a/lib/builtins/fixsfti.c b/lib/builtins/fixsfti.c index 6a1a1c6d5..3a159b3e1 100644 --- a/lib/builtins/fixsfti.c +++ b/lib/builtins/fixsfti.c @@ -6,40 +6,21 @@ * Source Licenses. See LICENSE.TXT for details. * * ===----------------------------------------------------------------------=== - * - * This file implements __fixsfti for the compiler_rt library. - * - * ===----------------------------------------------------------------------=== */ #include "int_lib.h" #ifdef CRT_HAS_128BIT +#define SINGLE_PRECISION +#include "fp_lib.h" -/* Returns: convert a to a signed long long, rounding toward zero. */ - -/* Assumption: float is a IEEE 32 bit floating point type - * su_int is a 32 bit integral type - * value in float is representable in ti_int (no range checking performed) - */ - -/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */ +typedef ti_int fixint_t; +typedef tu_int fixuint_t; +#include "fp_fixint_impl.inc" COMPILER_RT_ABI ti_int -__fixsfti(float a) -{ - float_bits fb; - fb.f = a; - int e = ((fb.u & 0x7F800000) >> 23) - 127; - if (e < 0) - return 0; - ti_int s = (si_int)(fb.u & 0x80000000) >> 31; - ti_int r = (fb.u & 0x007FFFFF) | 0x00800000; - if (e > 23) - r <<= (e - 23); - else - r >>= (23 - e); - return (r ^ s) - s; +__fixsfti(fp_t a) { + return __fixint(a); } #endif /* CRT_HAS_128BIT */ diff --git a/lib/builtins/fixtfdi.c b/lib/builtins/fixtfdi.c new file mode 100644 index 000000000..bc9dea1f4 --- /dev/null +++ b/lib/builtins/fixtfdi.c @@ -0,0 +1,23 @@ +/* ===-- fixtfdi.c - Implement __fixtfdi -----------------------------------=== + * + * 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. + * + * ===----------------------------------------------------------------------=== + */ + +#define QUAD_PRECISION +#include "fp_lib.h" + +#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT) +typedef di_int fixint_t; +typedef du_int fixuint_t; +#include "fp_fixint_impl.inc" + +COMPILER_RT_ABI di_int +__fixtfdi(fp_t a) { + return __fixint(a); +} +#endif diff --git a/lib/builtins/fixtfsi.c b/lib/builtins/fixtfsi.c new file mode 100644 index 000000000..feb3de885 --- /dev/null +++ b/lib/builtins/fixtfsi.c @@ -0,0 +1,23 @@ +/* ===-- fixtfsi.c - Implement __fixtfsi -----------------------------------=== + * + * 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. + * + * ===----------------------------------------------------------------------=== + */ + +#define QUAD_PRECISION +#include "fp_lib.h" + +#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT) +typedef si_int fixint_t; +typedef su_int fixuint_t; +#include "fp_fixint_impl.inc" + +COMPILER_RT_ABI si_int +__fixtfsi(fp_t a) { + return __fixint(a); +} +#endif diff --git a/lib/builtins/fixtfti.c b/lib/builtins/fixtfti.c new file mode 100644 index 000000000..ee4ada85c --- /dev/null +++ b/lib/builtins/fixtfti.c @@ -0,0 +1,23 @@ +/* ===-- fixtfti.c - Implement __fixtfti -----------------------------------=== + * + * 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. + * + * ===----------------------------------------------------------------------=== + */ + +#define QUAD_PRECISION +#include "fp_lib.h" + +#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT) +typedef ti_int fixint_t; +typedef tu_int fixuint_t; +#include "fp_fixint_impl.inc" + +COMPILER_RT_ABI ti_int +__fixtfti(fp_t a) { + return __fixint(a); +} +#endif diff --git a/lib/builtins/fixunsdfdi.c b/lib/builtins/fixunsdfdi.c index 9e6371390..f4f689e39 100644 --- a/lib/builtins/fixunsdfdi.c +++ b/lib/builtins/fixunsdfdi.c @@ -6,42 +6,16 @@ * Source Licenses. See LICENSE.TXT for details. * * ===----------------------------------------------------------------------=== - * - * This file implements __fixunsdfdi for the compiler_rt library. - * - * ===----------------------------------------------------------------------=== - */ - -#include "int_lib.h" - -/* Returns: convert a to a unsigned long long, rounding toward zero. - * Negative values all become zero. - */ - -/* Assumption: double is a IEEE 64 bit floating point type - * du_int is a 64 bit integral type - * value in double is representable in du_int or is negative - * (no range checking performed) */ -/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */ +#define DOUBLE_PRECISION +#include "fp_lib.h" +typedef du_int fixuint_t; +#include "fp_fixuint_impl.inc" ARM_EABI_FNALIAS(d2ulz, fixunsdfdi) COMPILER_RT_ABI du_int -__fixunsdfdi(double a) -{ - double_bits fb; - fb.f = a; - int e = ((fb.u.s.high & 0x7FF00000) >> 20) - 1023; - if (e < 0 || (fb.u.s.high & 0x80000000)) - return 0; - udwords r; - r.s.high = (fb.u.s.high & 0x000FFFFF) | 0x00100000; - r.s.low = fb.u.s.low; - if (e > 52) - r.all <<= (e - 52); - else - r.all >>= (52 - e); - return r.all; +__fixunsdfdi(fp_t a) { + return __fixuint(a); } diff --git a/lib/builtins/fixunsdfsi.c b/lib/builtins/fixunsdfsi.c index c6a3c755e..232d342d7 100644 --- a/lib/builtins/fixunsdfsi.c +++ b/lib/builtins/fixunsdfsi.c @@ -6,39 +6,16 @@ * Source Licenses. See LICENSE.TXT for details. * * ===----------------------------------------------------------------------=== - * - * This file implements __fixunsdfsi for the compiler_rt library. - * - * ===----------------------------------------------------------------------=== - */ - -#include "int_lib.h" - -/* Returns: convert a to a unsigned int, rounding toward zero. - * Negative values all become zero. - */ - -/* Assumption: double is a IEEE 64 bit floating point type - * su_int is a 32 bit integral type - * value in double is representable in su_int or is negative - * (no range checking performed) */ -/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */ +#define DOUBLE_PRECISION +#include "fp_lib.h" +typedef su_int fixuint_t; +#include "fp_fixuint_impl.inc" ARM_EABI_FNALIAS(d2uiz, fixunsdfsi) COMPILER_RT_ABI su_int -__fixunsdfsi(double a) -{ - double_bits fb; - fb.f = a; - int e = ((fb.u.s.high & 0x7FF00000) >> 20) - 1023; - if (e < 0 || (fb.u.s.high & 0x80000000)) - return 0; - return ( - 0x80000000u | - ((fb.u.s.high & 0x000FFFFF) << 11) | - (fb.u.s.low >> 21) - ) >> (31 - e); +__fixunsdfsi(fp_t a) { + return __fixuint(a); } diff --git a/lib/builtins/fixunsdfti.c b/lib/builtins/fixunsdfti.c index cc6c84ff5..c3d7df97f 100644 --- a/lib/builtins/fixunsdfti.c +++ b/lib/builtins/fixunsdfti.c @@ -6,42 +6,18 @@ * Source Licenses. See LICENSE.TXT for details. * * ===----------------------------------------------------------------------=== - * - * This file implements __fixunsdfti for the compiler_rt library. - * - * ===----------------------------------------------------------------------=== */ #include "int_lib.h" #ifdef CRT_HAS_128BIT - -/* Returns: convert a to a unsigned long long, rounding toward zero. - * Negative values all become zero. - */ - -/* Assumption: double is a IEEE 64 bit floating point type - * tu_int is a 64 bit integral type - * value in double is representable in tu_int or is negative - * (no range checking performed) - */ - -/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */ +#define DOUBLE_PRECISION +#include "fp_lib.h" +typedef tu_int fixuint_t; +#include "fp_fixuint_impl.inc" COMPILER_RT_ABI tu_int -__fixunsdfti(double a) -{ - double_bits fb; - fb.f = a; - int e = ((fb.u.s.high & 0x7FF00000) >> 20) - 1023; - if (e < 0 || (fb.u.s.high & 0x80000000)) - return 0; - tu_int r = 0x0010000000000000uLL | (fb.u.all & 0x000FFFFFFFFFFFFFuLL); - if (e > 52) - r <<= (e - 52); - else - r >>= (52 - e); - return r; +__fixunsdftti(fp_t a) { + return __fixuint(a); } - #endif /* CRT_HAS_128BIT */ diff --git a/lib/builtins/fixunssfdi.c b/lib/builtins/fixunssfdi.c index 69d5952e9..cd21cfd18 100644 --- a/lib/builtins/fixunssfdi.c +++ b/lib/builtins/fixunssfdi.c @@ -6,39 +6,16 @@ * Source Licenses. See LICENSE.TXT for details. * * ===----------------------------------------------------------------------=== - * - * This file implements __fixunssfdi for the compiler_rt library. - * - * ===----------------------------------------------------------------------=== - */ - -#include "int_lib.h" -/* Returns: convert a to a unsigned long long, rounding toward zero. - * Negative values all become zero. - */ - -/* Assumption: float is a IEEE 32 bit floating point type - * du_int is a 64 bit integral type - * value in float is representable in du_int or is negative - * (no range checking performed) */ -/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */ +#define SINGLE_PRECISION +#include "fp_lib.h" +typedef du_int fixuint_t; +#include "fp_fixuint_impl.inc" ARM_EABI_FNALIAS(f2ulz, fixunssfdi) COMPILER_RT_ABI du_int -__fixunssfdi(float a) -{ - float_bits fb; - fb.f = a; - int e = ((fb.u & 0x7F800000) >> 23) - 127; - if (e < 0 || (fb.u & 0x80000000)) - return 0; - du_int r = (fb.u & 0x007FFFFF) | 0x00800000; - if (e > 23) - r <<= (e - 23); - else - r >>= (23 - e); - return r; +__fixunssfdi(fp_t a) { + return __fixuint(a); } diff --git a/lib/builtins/fixunssfsi.c b/lib/builtins/fixunssfsi.c index e034139ea..cc2b05bd8 100644 --- a/lib/builtins/fixunssfsi.c +++ b/lib/builtins/fixunssfsi.c @@ -12,34 +12,14 @@ * ===----------------------------------------------------------------------=== */ -#include "int_lib.h" - -/* Returns: convert a to a unsigned int, rounding toward zero. - * Negative values all become zero. - */ - -/* Assumption: float is a IEEE 32 bit floating point type - * su_int is a 32 bit integral type - * value in float is representable in su_int or is negative - * (no range checking performed) - */ - -/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */ +#define SINGLE_PRECISION +#include "fp_lib.h" +typedef su_int fixuint_t; +#include "fp_fixuint_impl.inc" ARM_EABI_FNALIAS(f2uiz, fixunssfsi) COMPILER_RT_ABI su_int -__fixunssfsi(float a) -{ - float_bits fb; - fb.f = a; - int e = ((fb.u & 0x7F800000) >> 23) - 127; - if (e < 0 || (fb.u & 0x80000000)) - return 0; - su_int r = (fb.u & 0x007FFFFF) | 0x00800000; - if (e > 23) - r <<= (e - 23); - else - r >>= (23 - e); - return r; +__fixunssfsi(fp_t a) { + return __fixuint(a); } diff --git a/lib/builtins/fixunssfti.c b/lib/builtins/fixunssfti.c index 4da9e242a..862d7bd6c 100644 --- a/lib/builtins/fixunssfti.c +++ b/lib/builtins/fixunssfti.c @@ -12,36 +12,15 @@ * ===----------------------------------------------------------------------=== */ -#include "int_lib.h" +#define SINGLE_PRECISION +#include "fp_lib.h" -#ifdef CRT_HAS_128BIT - -/* Returns: convert a to a unsigned long long, rounding toward zero. - * Negative values all become zero. - */ - -/* Assumption: float is a IEEE 32 bit floating point type - * tu_int is a 64 bit integral type - * value in float is representable in tu_int or is negative - * (no range checking performed) - */ - -/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */ +#if defined(CRT_HAS_128BIT) +typedef tu_int fixuint_t; +#include "fp_fixuint_impl.inc" COMPILER_RT_ABI tu_int -__fixunssfti(float a) -{ - float_bits fb; - fb.f = a; - int e = ((fb.u & 0x7F800000) >> 23) - 127; - if (e < 0 || (fb.u & 0x80000000)) - return 0; - tu_int r = (fb.u & 0x007FFFFF) | 0x00800000; - if (e > 23) - r <<= (e - 23); - else - r >>= (23 - e); - return r; +__fixunssfti(fp_t a) { + return __fixuint(a); } - -#endif /* CRT_HAS_128BIT */ +#endif diff --git a/lib/builtins/fixunstfdi.c b/lib/builtins/fixunstfdi.c new file mode 100644 index 000000000..b2995f658 --- /dev/null +++ b/lib/builtins/fixunstfdi.c @@ -0,0 +1,22 @@ +/* ===-- fixunstfdi.c - Implement __fixunstfdi -----------------------------=== + * + * 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. + * + * ===----------------------------------------------------------------------=== + */ + +#define QUAD_PRECISION +#include "fp_lib.h" + +#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT) +typedef du_int fixuint_t; +#include "fp_fixuint_impl.inc" + +COMPILER_RT_ABI du_int +__fixunstfdi(fp_t a) { + return __fixuint(a); +} +#endif diff --git a/lib/builtins/fixunstfsi.c b/lib/builtins/fixunstfsi.c new file mode 100644 index 000000000..b5d3f6a7d --- /dev/null +++ b/lib/builtins/fixunstfsi.c @@ -0,0 +1,22 @@ +/* ===-- fixunstfsi.c - Implement __fixunstfsi -----------------------------=== + * + * 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. + * + * ===----------------------------------------------------------------------=== + */ + +#define QUAD_PRECISION +#include "fp_lib.h" + +#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT) +typedef su_int fixuint_t; +#include "fp_fixuint_impl.inc" + +COMPILER_RT_ABI su_int +__fixunstfsi(fp_t a) { + return __fixuint(a); +} +#endif diff --git a/lib/builtins/fixunstfti.c b/lib/builtins/fixunstfti.c new file mode 100644 index 000000000..22ff9dfc0 --- /dev/null +++ b/lib/builtins/fixunstfti.c @@ -0,0 +1,22 @@ +/* ===-- fixunstfsi.c - Implement __fixunstfsi -----------------------------=== + * + * 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. + * + * ===----------------------------------------------------------------------=== + */ + +#define QUAD_PRECISION +#include "fp_lib.h" + +#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT) +typedef tu_int fixuint_t; +#include "fp_fixuint_impl.inc" + +COMPILER_RT_ABI tu_int +__fixunstfti(fp_t a) { + return __fixuint(a); +} +#endif diff --git a/lib/builtins/fixunsxfdi.c b/lib/builtins/fixunsxfdi.c index 7224d467e..075304e78 100644 --- a/lib/builtins/fixunsxfdi.c +++ b/lib/builtins/fixunsxfdi.c @@ -38,6 +38,8 @@ __fixunsxfdi(long double a) int e = (fb.u.high.s.low & 0x00007FFF) - 16383; if (e < 0 || (fb.u.high.s.low & 0x00008000)) return 0; + if ((unsigned)e > sizeof(du_int) * CHAR_BIT) + return ~(du_int)0; return fb.u.low.all >> (63 - e); } diff --git a/lib/builtins/fixunsxfsi.c b/lib/builtins/fixunsxfsi.c index df0a18e2c..c3c70f743 100644 --- a/lib/builtins/fixunsxfsi.c +++ b/lib/builtins/fixunsxfsi.c @@ -23,7 +23,6 @@ /* Assumption: long double is an intel 80 bit floating point type padded with 6 bytes * su_int is a 32 bit integral type * value in long double is representable in su_int or is negative - * (no range checking performed) */ /* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee | @@ -38,6 +37,8 @@ __fixunsxfsi(long double a) int e = (fb.u.high.s.low & 0x00007FFF) - 16383; if (e < 0 || (fb.u.high.s.low & 0x00008000)) return 0; + if ((unsigned)e > sizeof(su_int) * CHAR_BIT) + return ~(su_int)0; return fb.u.low.s.high >> (31 - e); } diff --git a/lib/builtins/fixunsxfti.c b/lib/builtins/fixunsxfti.c index 42e507304..fb39d00ff 100644 --- a/lib/builtins/fixunsxfti.c +++ b/lib/builtins/fixunsxfti.c @@ -21,9 +21,8 @@ */ /* Assumption: long double is an intel 80 bit floating point type padded with 6 bytes - * tu_int is a 64 bit integral type + * tu_int is a 128 bit integral type * value in long double is representable in tu_int or is negative - * (no range checking performed) */ /* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee | @@ -38,6 +37,8 @@ __fixunsxfti(long double a) int e = (fb.u.high.s.low & 0x00007FFF) - 16383; if (e < 0 || (fb.u.high.s.low & 0x00008000)) return 0; + if ((unsigned)e > sizeof(tu_int) * CHAR_BIT) + return ~(tu_int)0; tu_int r = fb.u.low.all; if (e > 63) r <<= (e - 63); diff --git a/lib/builtins/fixxfdi.c b/lib/builtins/fixxfdi.c index afc79d866..011787f9e 100644 --- a/lib/builtins/fixxfdi.c +++ b/lib/builtins/fixxfdi.c @@ -19,7 +19,7 @@ /* Returns: convert a to a signed long long, rounding toward zero. */ /* Assumption: long double is an intel 80 bit floating point type padded with 6 bytes - * su_int is a 32 bit integral type + * di_int is a 64 bit integral type * value in long double is representable in di_int (no range checking performed) */ @@ -30,11 +30,15 @@ COMPILER_RT_ABI di_int __fixxfdi(long double a) { + const di_int di_max = (di_int)((~(du_int)0) / 2); + const di_int di_min = -di_max - 1; long_double_bits fb; fb.f = a; int e = (fb.u.high.s.low & 0x00007FFF) - 16383; if (e < 0) return 0; + if ((unsigned)e >= sizeof(di_int) * CHAR_BIT) + return a > 0 ? di_max : di_min; di_int s = -(si_int)((fb.u.high.s.low & 0x00008000) >> 15); di_int r = fb.u.low.all; r = (du_int)r >> (63 - e); diff --git a/lib/builtins/fixxfti.c b/lib/builtins/fixxfti.c index 3d0a279b3..968a4f0d5 100644 --- a/lib/builtins/fixxfti.c +++ b/lib/builtins/fixxfti.c @@ -19,8 +19,8 @@ /* Returns: convert a to a signed long long, rounding toward zero. */ /* Assumption: long double is an intel 80 bit floating point type padded with 6 bytes - * su_int is a 32 bit integral type - * value in long double is representable in ti_int (no range checking performed) + * ti_int is a 128 bit integral type + * value in long double is representable in ti_int */ /* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee | @@ -30,6 +30,8 @@ COMPILER_RT_ABI ti_int __fixxfti(long double a) { + const ti_int ti_max = (ti_int)((~(tu_int)0) / 2); + const ti_int ti_min = -ti_max - 1; long_double_bits fb; fb.f = a; int e = (fb.u.high.s.low & 0x00007FFF) - 16383; @@ -37,6 +39,8 @@ __fixxfti(long double a) return 0; ti_int s = -(si_int)((fb.u.high.s.low & 0x00008000) >> 15); ti_int r = fb.u.low.all; + if ((unsigned)e >= sizeof(ti_int) * CHAR_BIT) + return a > 0 ? ti_max : ti_min; if (e > 63) r <<= (e - 63); else diff --git a/lib/builtins/fp_fixint_impl.inc b/lib/builtins/fp_fixint_impl.inc new file mode 100644 index 000000000..035e87ca1 --- /dev/null +++ b/lib/builtins/fp_fixint_impl.inc @@ -0,0 +1,41 @@ +//===-- lib/fixdfsi.c - Double-precision -> integer conversion ----*- C -*-===// +// +// 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 file implements float to integer conversion for the +// compiler-rt library. +// +//===----------------------------------------------------------------------===// + +#include "fp_lib.h" + +static inline fixint_t __fixint(fp_t a) { + const fixint_t fixint_max = (fixint_t)((~(fixuint_t)0) / 2); + const fixint_t fixint_min = -fixint_max - 1; + // Break a into sign, exponent, significand + const rep_t aRep = toRep(a); + const rep_t aAbs = aRep & absMask; + const fixint_t sign = aRep & signBit ? -1 : 1; + const int exponent = (aAbs >> significandBits) - exponentBias; + const rep_t significand = (aAbs & significandMask) | implicitBit; + + // If exponent is negative, the result is zero. + if (exponent < 0) + return 0; + + // If the value is too large for the integer type, saturate. + if ((unsigned)exponent >= sizeof(fixint_t) * CHAR_BIT) + return sign == 1 ? fixint_max : fixint_min; + + // If 0 <= exponent < significandBits, right shift to get the result. + // Otherwise, shift left. + if (exponent < significandBits) + return sign * (significand >> (significandBits - exponent)); + else + return sign * ((fixint_t)significand << (exponent - significandBits)); +} diff --git a/lib/builtins/fp_fixuint_impl.inc b/lib/builtins/fp_fixuint_impl.inc new file mode 100644 index 000000000..5fefab0e2 --- /dev/null +++ b/lib/builtins/fp_fixuint_impl.inc @@ -0,0 +1,39 @@ +//===-- lib/fixdfsi.c - Double-precision -> integer conversion ----*- C -*-===// +// +// 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 file implements float to unsigned integer conversion for the +// compiler-rt library. +// +//===----------------------------------------------------------------------===// + +#include "fp_lib.h" + +static inline fixuint_t __fixuint(fp_t a) { + // Break a into sign, exponent, significand + const rep_t aRep = toRep(a); + const rep_t aAbs = aRep & absMask; + const int sign = aRep & signBit ? -1 : 1; + const int exponent = (aAbs >> significandBits) - exponentBias; + const rep_t significand = (aAbs & significandMask) | implicitBit; + + // If either the value or the exponent is negative, the result is zero. + if (sign == -1 || exponent < 0) + return 0; + + // If the value is too large for the integer type, saturate. + if ((unsigned)exponent > sizeof(fixuint_t) * CHAR_BIT) + return ~(fixuint_t)0; + + // If 0 <= exponent < significandBits, right shift to get the result. + // Otherwise, shift left. + if (exponent < significandBits) + return significand >> (significandBits - exponent); + else + return (fixuint_t)significand << (exponent - significandBits); +} diff --git a/lib/dfsan/dfsan.cc b/lib/dfsan/dfsan.cc index de5b2ce10..5a8da3867 100644 --- a/lib/dfsan/dfsan.cc +++ b/lib/dfsan/dfsan.cc @@ -333,7 +333,7 @@ static void InitializeFlags() { static void dfsan_fini() { if (internal_strcmp(flags().dump_labels_at_exit, "") != 0) { - fd_t fd = OpenFile(flags().dump_labels_at_exit, true /* write */); + fd_t fd = OpenFile(flags().dump_labels_at_exit, WrOnly); if (fd == kInvalidFd) { Report("WARNING: DataFlowSanitizer: unable to open output file %s\n", flags().dump_labels_at_exit); diff --git a/lib/interception/interception.h b/lib/interception/interception.h index 52573258b..9e9aca215 100644 --- a/lib/interception/interception.h +++ b/lib/interception/interception.h @@ -219,7 +219,6 @@ const interpose_substitution substitution_##func_name[] \ namespace __interception { \ FUNC_TYPE(func) PTR_TO_REAL(func); \ } \ - DECLARE_WRAPPER_WINAPI(ret_type, func, __VA_ARGS__) \ extern "C" \ INTERCEPTOR_ATTRIBUTE \ ret_type __stdcall WRAP(func)(__VA_ARGS__) diff --git a/lib/interception/interception_win.cc b/lib/interception/interception_win.cc index cd241c3d2..19cf18494 100644 --- a/lib/interception/interception_win.cc +++ b/lib/interception/interception_win.cc @@ -84,6 +84,7 @@ static size_t RoundUpToInstrBoundary(size_t size, char *code) { cursor += 2; continue; case '\xE9': // E9 XX YY ZZ WW = jmp WWZZYYXX + case '\xB8': // B8 XX YY ZZ WW = mov eax, WWZZYYXX cursor += 5; continue; } @@ -182,10 +183,14 @@ bool OverrideFunction(uptr old_func, uptr new_func, uptr *orig_old_func) { } static const void **InterestingDLLsAvailable() { - const char *InterestingDLLs[] = {"kernel32.dll", - "msvcr110.dll", // VS2012 - "msvcr120.dll", // VS2013 - NULL}; + const char *InterestingDLLs[] = { + "kernel32.dll", + "msvcr110.dll", // VS2012 + "msvcr120.dll", // VS2013 + // NTDLL should go last as it exports some functions that we should override + // in the CRT [presumably only used internally]. + "ntdll.dll", NULL + }; static void *result[ARRAY_SIZE(InterestingDLLs)] = { 0 }; if (!result[0]) { for (size_t i = 0, j = 0; InterestingDLLs[i]; ++i) { diff --git a/lib/lsan/lsan_common.cc b/lib/lsan/lsan_common.cc index a6119af8d..8ac2ae066 100644 --- a/lib/lsan/lsan_common.cc +++ b/lib/lsan/lsan_common.cc @@ -435,13 +435,11 @@ static Suppression *GetSuppressionForAddr(uptr addr) { Suppression *s = nullptr; // Suppress by module name. - const char *module_name; - uptr module_offset; SuppressionContext *suppressions = GetSuppressionContext(); - if (Symbolizer::GetOrInit()->GetModuleNameAndOffsetForPC(addr, &module_name, - &module_offset) && - suppressions->Match(module_name, kSuppressionLeak, &s)) - return s; + if (const char *module_name = + Symbolizer::GetOrInit()->GetModuleNameForPc(addr)) + if (suppressions->Match(module_name, kSuppressionLeak, &s)) + return s; // Suppress by file or function name. SymbolizedStack *frames = Symbolizer::GetOrInit()->SymbolizePC(addr); diff --git a/lib/msan/tests/CMakeLists.txt b/lib/msan/tests/CMakeLists.txt index e008bd329..4bc825481 100644 --- a/lib/msan/tests/CMakeLists.txt +++ b/lib/msan/tests/CMakeLists.txt @@ -33,6 +33,7 @@ set(MSAN_UNITTEST_COMMON_CFLAGS -Wno-deprecated-declarations -Wno-unused-variable -Wno-zero-length-array + -Wno-uninitialized -Werror=sign-compare ) set(MSAN_UNITTEST_INSTRUMENTED_CFLAGS diff --git a/lib/profile/InstrProfilingFile.c b/lib/profile/InstrProfilingFile.c index daa309427..d9acbbeb1 100644 --- a/lib/profile/InstrProfilingFile.c +++ b/lib/profile/InstrProfilingFile.c @@ -8,10 +8,10 @@ \*===----------------------------------------------------------------------===*/ #include "InstrProfiling.h" +#include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <sys/errno.h> #define UNCONST(ptr) ((void *)(uintptr_t)(ptr)) diff --git a/lib/sanitizer_common/CMakeLists.txt b/lib/sanitizer_common/CMakeLists.txt index 6eb6ca8fc..5b32b6ad9 100644 --- a/lib/sanitizer_common/CMakeLists.txt +++ b/lib/sanitizer_common/CMakeLists.txt @@ -27,6 +27,7 @@ set(SANITIZER_SOURCES sanitizer_suppressions.cc sanitizer_symbolizer.cc sanitizer_symbolizer_libbacktrace.cc + sanitizer_symbolizer_mac.cc sanitizer_symbolizer_win.cc sanitizer_tls_get_addr.cc sanitizer_thread_registry.cc @@ -42,6 +43,7 @@ set(SANITIZER_LIBCDEP_SOURCES sanitizer_stoptheworld_linux_libcdep.cc sanitizer_symbolizer_libcdep.cc sanitizer_symbolizer_posix_libcdep.cc + sanitizer_symbolizer_process_libcdep.cc sanitizer_unwind_posix_libcdep.cc) # Explicitly list all sanitizer_common headers. Not all of these are @@ -91,7 +93,10 @@ set(SANITIZER_HEADERS sanitizer_stoptheworld.h sanitizer_suppressions.h sanitizer_symbolizer.h + sanitizer_symbolizer_internal.h sanitizer_symbolizer_libbacktrace.h + sanitizer_symbolizer_mac.h + sanitizer_symbolizer_win.h sanitizer_syscall_generic.inc sanitizer_syscall_linux_x86_64.inc sanitizer_thread_registry.h) @@ -137,12 +142,6 @@ else() DEFS ${SANITIZER_COMMON_DEFINITIONS}) list(APPEND SANITIZER_RUNTIME_LIBRARIES RTSanitizerCommon.${arch} RTSanitizerCommonLibc.${arch}) - add_compiler_rt_runtime(clang_rt.san-${arch} ${arch} STATIC - SOURCES $<TARGET_OBJECTS:RTSanitizerCommon.${arch}> - $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}> - CFLAGS ${SANITIZER_CFLAGS} - DEFS ${SANITIZER_COMMON_DEFINITIONS}) - add_dependencies(sanitizer_common clang_rt.san-${arch}) endforeach() endif() diff --git a/lib/sanitizer_common/sanitizer_common.cc b/lib/sanitizer_common/sanitizer_common.cc index 4be3c7abf..956fc9935 100644 --- a/lib/sanitizer_common/sanitizer_common.cc +++ b/lib/sanitizer_common/sanitizer_common.cc @@ -16,6 +16,8 @@ #include "sanitizer_flags.h" #include "sanitizer_libc.h" #include "sanitizer_placement_new.h" +#include "sanitizer_stacktrace_printer.h" +#include "sanitizer_symbolizer.h" namespace __sanitizer { @@ -56,7 +58,7 @@ void ReportFile::ReopenIfNecessary() { } internal_snprintf(full_path, kMaxPathLength, "%s.%zu", path_prefix, pid); - uptr openrv = OpenFile(full_path, true); + uptr openrv = OpenFile(full_path, WrOnly); if (internal_iserror(openrv)) { const char *ErrorMsgPrefix = "ERROR: Can't open file: "; internal_write(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix)); @@ -142,7 +144,7 @@ uptr ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size, *buff_size = 0; // The files we usually open are not seekable, so try different buffer sizes. for (uptr size = kMinFileLen; size <= max_len; size *= 2) { - uptr openrv = OpenFile(file_name, /*write*/ false); + uptr openrv = OpenFile(file_name, RdOnly); if (internal_iserror(openrv, errno_p)) return 0; fd_t fd = openrv; UnmapOrDie(*buff, *buff_size); @@ -206,12 +208,12 @@ const char *StripPathPrefix(const char *filepath, const char *strip_path_prefix) { if (filepath == 0) return 0; if (strip_path_prefix == 0) return filepath; - const char *pos = internal_strstr(filepath, strip_path_prefix); - if (pos == 0) return filepath; - pos += internal_strlen(strip_path_prefix); - if (pos[0] == '.' && pos[1] == '/') - pos += 2; - return pos; + const char *res = filepath; + if (const char *pos = internal_strstr(filepath, strip_path_prefix)) + res = pos + internal_strlen(strip_path_prefix); + if (res[0] == '.' && res[1] == '/') + res += 2; + return res; } const char *StripModuleName(const char *module) { @@ -230,17 +232,16 @@ void ReportErrorSummary(const char *error_message) { __sanitizer_report_error_summary(buff.data()); } -void ReportErrorSummary(const char *error_type, const char *file, - int line, const char *function) { +#ifndef SANITIZER_GO +void ReportErrorSummary(const char *error_type, const AddressInfo &info) { if (!common_flags()->print_summary) return; InternalScopedString buff(kMaxSummaryLength); - buff.append("%s %s:%d %s", error_type, - file ? StripPathPrefix(file, common_flags()->strip_path_prefix) - : "??", - line, function ? function : "??"); + buff.append("%s ", error_type); + RenderFrame(&buff, "%L %F", 0, info, common_flags()->strip_path_prefix); ReportErrorSummary(buff.data()); } +#endif LoadedModule::LoadedModule(const char *module_name, uptr base_address) { full_name_ = internal_strdup(module_name); diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index ff13ef164..0dfa81593 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -25,6 +25,7 @@ namespace __sanitizer { struct StackTrace; +struct AddressInfo; // Constants. const uptr kWordSize = SANITIZER_WORDSIZE / 8; @@ -186,7 +187,13 @@ extern ReportFile report_file; extern uptr stoptheworld_tracer_pid; extern uptr stoptheworld_tracer_ppid; -uptr OpenFile(const char *filename, bool write); +enum FileAccessMode { + RdOnly, + WrOnly, + RdWr +}; + +uptr OpenFile(const char *filename, FileAccessMode mode); // Opens the file 'file_name" and reads up to 'max_len' bytes. // The resulting buffer is mmaped and stored in '*buff'. // The size of the mmaped region is stored in '*buff_size', @@ -215,6 +222,11 @@ const char *GetEnv(const char *name); bool SetEnv(const char *name, const char *value); const char *GetPwd(); char *FindPathToBinary(const char *name); +bool IsPathSeparator(const char c); +bool IsAbsolutePath(const char *path); + +// Returns the path to the main executable. +uptr ReadBinaryName(/*out*/char *buf, uptr buf_len); u32 GetUid(); void ReExec(); bool StackSizeIsUnlimited(); @@ -288,9 +300,9 @@ const int kMaxSummaryLength = 1024; // and pass it to __sanitizer_report_error_summary. void ReportErrorSummary(const char *error_message); // Same as above, but construct error_message as: -// error_type file:line function -void ReportErrorSummary(const char *error_type, const char *file, - int line, const char *function); +// error_type file:line[:column][ function] +void ReportErrorSummary(const char *error_type, const AddressInfo &info); +// Same as above, but obtains AddressInfo by symbolizing top stack trace frame. void ReportErrorSummary(const char *error_type, StackTrace *trace); // Math @@ -439,11 +451,15 @@ class InternalMmapVectorNoCtor { const T *data() const { return data_; } + T *data() { + return data_; + } uptr capacity() const { return capacity_; } void clear() { size_ = 0; } + bool empty() const { return size() == 0; } private: void Resize(uptr new_capacity) { @@ -532,6 +548,7 @@ uptr InternalBinarySearch(const Container &v, uptr first, uptr last, // executable or a shared object). class LoadedModule { public: + LoadedModule() : full_name_(nullptr), base_address_(0) {} LoadedModule(const char *module_name, uptr base_address); void clear(); void addAddressRange(uptr beg, uptr end, bool executable); @@ -607,6 +624,23 @@ static inline void SanitizerBreakOptimization(void *arg) { #endif } +struct SignalContext { + void *context; + uptr addr; + uptr pc; + uptr sp; + uptr bp; + + SignalContext(void *context, uptr addr, uptr pc, uptr sp, uptr bp) : + context(context), addr(addr), pc(pc), sp(sp), bp(bp) { + } + + // Creates signal context in a platform-specific manner. + static SignalContext Create(void *siginfo, void *context); +}; + +void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp); + } // namespace __sanitizer inline void *operator new(__sanitizer::operator_new_size_type size, diff --git a/lib/sanitizer_common/sanitizer_common_libcdep.cc b/lib/sanitizer_common/sanitizer_common_libcdep.cc index 17ef6897b..9622e60c2 100644 --- a/lib/sanitizer_common/sanitizer_common_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_common_libcdep.cc @@ -44,20 +44,16 @@ void SetSandboxingCallback(void (*f)()) { void ReportErrorSummary(const char *error_type, StackTrace *stack) { if (!common_flags()->print_summary) return; -#if !SANITIZER_GO - if (stack->size > 0 && Symbolizer::GetOrInit()->CanReturnFileLineInfo()) { - // 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]); - SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc); - const AddressInfo &ai = frame->info; - ReportErrorSummary(error_type, ai.file, ai.line, ai.function); - frame->ClearAll(); + if (stack->size == 0) { + ReportErrorSummary(error_type); + return; } -#else - AddressInfo ai; - ReportErrorSummary(error_type, ai.file, ai.line, ai.function); -#endif + // 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]); + SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc); + ReportErrorSummary(error_type, frame->info); + frame->ClearAll(); } static void (*SoftRssLimitExceededCallback)(bool exceeded); diff --git a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc index 49887b1e9..94863c6ef 100644 --- a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc @@ -24,8 +24,12 @@ // and atomically set Guard to -Guard. // - __sanitizer_cov_dump: dump the coverage data to disk. // For every module of the current process that has coverage data -// this will create a file module_name.PID.sancov. The file format is simple: -// it's just a sorted sequence of 4-byte offsets in the module. +// this will create a file module_name.PID.sancov. +// +// The file format is simple: the first 8 bytes is the magic, +// one of 0xC0BFFFFFFFFFFF64 and 0xC0BFFFFFFFFFFF32. The last byte of the +// magic defines the size of the following offsets. +// The rest of the data is the offsets in the module. // // Eventually, this coverage implementation should be obsoleted by a more // powerful general purpose Clang/LLVM coverage instrumentation. @@ -43,6 +47,9 @@ #include "sanitizer_symbolizer.h" #include "sanitizer_flags.h" +static const u64 kMagic64 = 0xC0BFFFFFFFFFFF64ULL; +static const u64 kMagic32 = 0xC0BFFFFFFFFFFF32ULL; + static atomic_uint32_t dump_once_guard; // Ensure that CovDump runs only once. static atomic_uintptr_t coverage_counter; @@ -77,21 +84,32 @@ class CoverageData { uptr cache_size); void DumpCallerCalleePairs(); void DumpTrace(); + void DumpAsBitSet(); + void DumpCounters(); + void DumpOffsets(); + void DumpAll(); ALWAYS_INLINE void TraceBasicBlock(s32 *id); void InitializeGuardArray(s32 *guards); - void InitializeGuards(s32 *guards, uptr n, const char *module_name); + void InitializeGuards(s32 *guards, uptr n, const char *module_name, + uptr caller_pc); + void InitializeCounters(u8 *counters, uptr n); void ReinitializeGuards(); + uptr GetNumberOf8bitCounters(); + uptr Update8bitCounterBitsetAndClearCounters(u8 *bitset); uptr *data(); uptr size(); private: + void DirectOpen(); + void UpdateModuleNameVec(uptr caller_pc, uptr range_beg, uptr range_end); + // Maximal size pc array may ever grow. // We MmapNoReserve this space to ensure that the array is contiguous. - static const uptr kPcArrayMaxSize = FIRST_32_SECOND_64(1 << 24, 1 << 27); + static const uptr kPcArrayMaxSize = FIRST_32_SECOND_64(1 << 26, 1 << 27); // The amount file mapping for the pc array is grown by. static const uptr kPcArrayMmapSize = 64 * 1024; @@ -110,8 +128,22 @@ class CoverageData { // Vector of coverage guard arrays, protected by mu. InternalMmapVectorNoCtor<s32*> guard_array_vec; - // Vector of module (compilation unit) names. - InternalMmapVectorNoCtor<const char*> comp_unit_name_vec; + struct NamedPcRange { + const char *copied_module_name; + uptr beg, end; // elements [beg,end) in pc_array. + }; + + // Vector of module and compilation unit pc ranges. + InternalMmapVectorNoCtor<NamedPcRange> comp_unit_name_vec; + InternalMmapVectorNoCtor<NamedPcRange> module_name_vec; + + struct CounterAndSize { + u8 *counters; + uptr n; + }; + + InternalMmapVectorNoCtor<CounterAndSize> counters_vec; + uptr num_8bit_counters; // Caller-Callee (cc) array, size and current index. static const uptr kCcArrayMaxSize = FIRST_32_SECOND_64(1 << 18, 1 << 24); @@ -133,8 +165,6 @@ class CoverageData { static const uptr kTrPcArrayMaxSize = FIRST_32_SECOND_64(1 << 22, 1 << 27); StaticSpinMutex mu; - - void DirectOpen(); }; static CoverageData coverage_data; @@ -145,9 +175,9 @@ void CoverageData::DirectOpen() { InternalScopedString path(kMaxPathLength); internal_snprintf((char *)path.data(), path.size(), "%s/%zd.sancov.raw", coverage_dir, internal_getpid()); - pc_fd = OpenFile(path.data(), true); + pc_fd = OpenFile(path.data(), RdWr); if (internal_iserror(pc_fd)) { - Report(" Coverage: failed to open %s for writing\n", path.data()); + Report(" Coverage: failed to open %s for reading/writing\n", path.data()); Die(); } @@ -184,6 +214,8 @@ void CoverageData::Enable() { GetMmapGranularity()); tr_event_array_size = kTrEventArrayMaxSize; tr_event_pointer = tr_event_array; + + num_8bit_counters = 0; } void CoverageData::InitializeGuardArray(s32 *guards) { @@ -289,16 +321,70 @@ void CoverageData::Extend(uptr npcs) { atomic_store(&pc_array_size, size, memory_order_release); } +void CoverageData::InitializeCounters(u8 *counters, uptr n) { + if (!counters) return; + CHECK_EQ(reinterpret_cast<uptr>(counters) % 16, 0); + n = RoundUpTo(n, 16); // The compiler must ensure that counters is 16-aligned. + SpinMutexLock l(&mu); + counters_vec.push_back({counters, n}); + num_8bit_counters += n; +} + +void CoverageData::UpdateModuleNameVec(uptr caller_pc, uptr range_beg, + uptr range_end) { + auto sym = Symbolizer::GetOrInit(); + if (!sym) + return; + const char *module_name = sym->GetModuleNameForPc(caller_pc); + if (!module_name) return; + if (module_name_vec.empty() || + internal_strcmp(module_name_vec.back().copied_module_name, module_name)) + module_name_vec.push_back( + {internal_strdup(module_name), range_beg, range_end}); + else + module_name_vec.back().end = range_end; +} + void CoverageData::InitializeGuards(s32 *guards, uptr n, - const char *module_name) { + const char *comp_unit_name, + uptr caller_pc) { // The array 'guards' has n+1 elements, we use the element zero // to store 'n'. CHECK_LT(n, 1 << 30); guards[0] = static_cast<s32>(n); InitializeGuardArray(guards); SpinMutexLock l(&mu); - comp_unit_name_vec.push_back(module_name); + uptr range_end = atomic_load(&pc_array_index, memory_order_relaxed); + uptr range_beg = range_end - n; + comp_unit_name_vec.push_back({comp_unit_name, range_beg, range_end}); guard_array_vec.push_back(guards); + UpdateModuleNameVec(caller_pc, range_beg, range_end); +} + +static const uptr kBundleCounterBits = 16; + +// When coverage_order_pcs==true and SANITIZER_WORDSIZE==64 +// we insert the global counter into the first 16 bits of the PC. +uptr BundlePcAndCounter(uptr pc, uptr counter) { + if (SANITIZER_WORDSIZE != 64 || !common_flags()->coverage_order_pcs) + return pc; + static const uptr kMaxCounter = (1 << kBundleCounterBits) - 1; + if (counter > kMaxCounter) + counter = kMaxCounter; + CHECK_EQ(0, pc >> (SANITIZER_WORDSIZE - kBundleCounterBits)); + return pc | (counter << (SANITIZER_WORDSIZE - kBundleCounterBits)); +} + +uptr UnbundlePc(uptr bundle) { + if (SANITIZER_WORDSIZE != 64 || !common_flags()->coverage_order_pcs) + return bundle; + return (bundle << kBundleCounterBits) >> kBundleCounterBits; +} + +uptr UnbundleCounter(uptr bundle) { + if (SANITIZER_WORDSIZE != 64 || !common_flags()->coverage_order_pcs) + return 0; + return bundle >> (SANITIZER_WORDSIZE - kBundleCounterBits); } // If guard is negative, atomically set it to -guard and store the PC in @@ -316,8 +402,8 @@ void CoverageData::Add(uptr pc, u32 *guard) { return; // May happen after fork when pc_array_index becomes 0. CHECK_LT(idx * sizeof(uptr), atomic_load(&pc_array_size, memory_order_acquire)); - pc_array[idx] = pc; - atomic_fetch_add(&coverage_counter, 1, memory_order_relaxed); + uptr counter = atomic_fetch_add(&coverage_counter, 1, memory_order_relaxed); + pc_array[idx] = BundlePcAndCounter(pc, counter); } // Registers a pair caller=>callee. @@ -354,6 +440,64 @@ void CoverageData::IndirCall(uptr caller, uptr callee, uptr callee_cache[], } } +uptr CoverageData::GetNumberOf8bitCounters() { + return num_8bit_counters; +} + +// Map every 8bit counter to a 8-bit bitset and clear the counter. +uptr CoverageData::Update8bitCounterBitsetAndClearCounters(u8 *bitset) { + uptr num_new_bits = 0; + uptr cur = 0; + // For better speed we map 8 counters to 8 bytes of bitset at once. + static const uptr kBatchSize = 8; + CHECK_EQ(reinterpret_cast<uptr>(bitset) % kBatchSize, 0); + for (uptr i = 0, len = counters_vec.size(); i < len; i++) { + u8 *c = counters_vec[i].counters; + uptr n = counters_vec[i].n; + CHECK_EQ(n % 16, 0); + CHECK_EQ(cur % kBatchSize, 0); + CHECK_EQ(reinterpret_cast<uptr>(c) % kBatchSize, 0); + if (!bitset) { + internal_bzero_aligned16(c, n); + cur += n; + continue; + } + for (uptr j = 0; j < n; j += kBatchSize, cur += kBatchSize) { + CHECK_LT(cur, num_8bit_counters); + u64 *pc64 = reinterpret_cast<u64*>(c + j); + u64 *pb64 = reinterpret_cast<u64*>(bitset + cur); + u64 c64 = *pc64; + u64 old_bits_64 = *pb64; + u64 new_bits_64 = old_bits_64; + if (c64) { + *pc64 = 0; + for (uptr k = 0; k < kBatchSize; k++) { + u64 x = (c64 >> (8 * k)) & 0xff; + if (x) { + u64 bit = 0; + /**/ if (x >= 128) bit = 128; + else if (x >= 32) bit = 64; + else if (x >= 16) bit = 32; + else if (x >= 8) bit = 16; + else if (x >= 4) bit = 8; + else if (x >= 3) bit = 4; + else if (x >= 2) bit = 2; + else if (x >= 1) bit = 1; + u64 mask = bit << (8 * k); + if (!(new_bits_64 & mask)) { + num_new_bits++; + new_bits_64 |= mask; + } + } + } + *pb64 = new_bits_64; + } + } + } + CHECK_EQ(cur, num_8bit_counters); + return num_new_bits; +} + uptr *CoverageData::data() { return pc_array; } @@ -413,23 +557,23 @@ static void CovWritePacked(int pid, const char *module, const void *blob, // If packed = true and name == 0: <pid>.<sancov>.<packed>. // If packed = true and name != 0: <name>.<sancov>.<packed> (name is // user-supplied). -static int CovOpenFile(bool packed, const char *name, - const char *extension = "sancov") { - InternalScopedString path(kMaxPathLength); +static int CovOpenFile(InternalScopedString *path, bool packed, + const char *name, const char *extension = "sancov") { + path->clear(); if (!packed) { CHECK(name); - path.append("%s/%s.%zd.%s", coverage_dir, name, internal_getpid(), + path->append("%s/%s.%zd.%s", coverage_dir, name, internal_getpid(), extension); } else { if (!name) - path.append("%s/%zd.%s.packed", coverage_dir, internal_getpid(), + path->append("%s/%zd.%s.packed", coverage_dir, internal_getpid(), extension); else - path.append("%s/%s.%s.packed", coverage_dir, name, extension); + path->append("%s/%s.%s.packed", coverage_dir, name, extension); } - uptr fd = OpenFile(path.data(), true); + uptr fd = OpenFile(path->data(), WrOnly); if (internal_iserror(fd)) { - Report(" SanitizerCoverage: failed to open %s for writing\n", path.data()); + Report(" SanitizerCoverage: failed to open %s for writing\n", path->data()); return -1; } return fd; @@ -446,24 +590,25 @@ void CoverageData::DumpTrace() { for (uptr i = 0, n = size(); i < n; i++) { const char *module_name = "<unknown>"; uptr module_address = 0; - sym->GetModuleNameAndOffsetForPC(pc_array[i], &module_name, + sym->GetModuleNameAndOffsetForPC(UnbundlePc(pc_array[i]), &module_name, &module_address); out.append("%s 0x%zx\n", module_name, module_address); } - int fd = CovOpenFile(false, "trace-points"); + InternalScopedString path(kMaxPathLength); + int fd = CovOpenFile(&path, false, "trace-points"); if (fd < 0) return; internal_write(fd, out.data(), out.length()); internal_close(fd); - fd = CovOpenFile(false, "trace-compunits"); + fd = CovOpenFile(&path, false, "trace-compunits"); if (fd < 0) return; out.clear(); for (uptr i = 0; i < comp_unit_name_vec.size(); i++) - out.append("%s\n", comp_unit_name_vec[i]); + out.append("%s\n", comp_unit_name_vec[i].copied_module_name); internal_write(fd, out.data(), out.length()); internal_close(fd); - fd = CovOpenFile(false, "trace-events"); + fd = CovOpenFile(&path, false, "trace-events"); if (fd < 0) return; uptr bytes_to_write = max_idx * sizeof(tr_event_array[0]); u8 *event_bytes = reinterpret_cast<u8*>(tr_event_array); @@ -514,7 +659,8 @@ void CoverageData::DumpCallerCalleePairs() { callee_module_address); } } - int fd = CovOpenFile(false, "caller-callee"); + InternalScopedString path(kMaxPathLength); + int fd = CovOpenFile(&path, false, "caller-callee"); if (fd < 0) return; internal_write(fd, out.data(), out.length()); internal_close(fd); @@ -534,86 +680,124 @@ void CoverageData::TraceBasicBlock(s32 *id) { tr_event_pointer++; } -static void CovDumpAsBitSet() { +void CoverageData::DumpCounters() { + if (!common_flags()->coverage_counters) return; + uptr n = coverage_data.GetNumberOf8bitCounters(); + if (!n) return; + InternalScopedBuffer<u8> bitset(n); + coverage_data.Update8bitCounterBitsetAndClearCounters(bitset.data()); + InternalScopedString path(kMaxPathLength); + + for (uptr m = 0; m < module_name_vec.size(); m++) { + auto r = module_name_vec[m]; + CHECK(r.copied_module_name); + CHECK_LE(r.beg, r.end); + CHECK_LE(r.end, size()); + const char *base_name = StripModuleName(r.copied_module_name); + int fd = + CovOpenFile(&path, /* packed */ false, base_name, "counters-sancov"); + if (fd < 0) return; + internal_write(fd, bitset.data() + r.beg, r.end - r.beg); + internal_close(fd); + VReport(1, " CovDump: %zd counters written for '%s'\n", r.end - r.beg, + base_name); + } +} + +void CoverageData::DumpAsBitSet() { if (!common_flags()->coverage_bitset) return; - if (!coverage_data.size()) return; - int fd = CovOpenFile(/* packed */false, "combined", "bitset-sancov"); - if (fd < 0) return; - uptr n = coverage_data.size(); - uptr n_set_bits = 0; - InternalScopedBuffer<char> out(n); - for (uptr i = 0; i < n; i++) { - uptr pc = coverage_data.data()[i]; - out[i] = pc ? '1' : '0'; - if (pc) - n_set_bits++; + if (!size()) return; + InternalScopedBuffer<char> out(size()); + InternalScopedString path(kMaxPathLength); + for (uptr m = 0; m < module_name_vec.size(); m++) { + uptr n_set_bits = 0; + auto r = module_name_vec[m]; + CHECK(r.copied_module_name); + CHECK_LE(r.beg, r.end); + CHECK_LE(r.end, size()); + for (uptr i = r.beg; i < r.end; i++) { + uptr pc = UnbundlePc(pc_array[i]); + out[i] = pc ? '1' : '0'; + if (pc) + n_set_bits++; + } + const char *base_name = StripModuleName(r.copied_module_name); + int fd = CovOpenFile(&path, /* packed */ false, base_name, "bitset-sancov"); + if (fd < 0) return; + internal_write(fd, out.data() + r.beg, r.end - r.beg); + internal_close(fd); + VReport(1, + " CovDump: bitset of %zd bits written for '%s', %zd bits are set\n", + r.end - r.beg, base_name, n_set_bits); } - internal_write(fd, out.data(), n); - internal_close(fd); - VReport(1, " CovDump: bitset of %zd bits written, %zd bits are set\n", n, - n_set_bits); } -// Dump the coverage on disk. -static void CovDump() { - if (!coverage_enabled || common_flags()->coverage_direct) return; -#if !SANITIZER_WINDOWS - if (atomic_fetch_add(&dump_once_guard, 1, memory_order_relaxed)) - return; - CovDumpAsBitSet(); - coverage_data.DumpTrace(); +void CoverageData::DumpOffsets() { + auto sym = Symbolizer::GetOrInit(); if (!common_flags()->coverage_pcs) return; - uptr size = coverage_data.size(); - InternalMmapVector<u32> offsets(size); - uptr *vb = coverage_data.data(); - uptr *ve = vb + size; - SortArray(vb, size); - MemoryMappingLayout proc_maps(/*cache_enabled*/true); - uptr mb, me, off, prot; - InternalScopedString module(kMaxPathLength); + CHECK_NE(sym, nullptr); + InternalMmapVector<uptr> offsets(0); InternalScopedString path(kMaxPathLength); - for (int i = 0; - proc_maps.Next(&mb, &me, &off, module.data(), module.size(), &prot); - i++) { - if ((prot & MemoryMappingLayout::kProtectionExecute) == 0) - continue; - while (vb < ve && *vb < mb) vb++; - if (vb >= ve) break; - if (*vb < me) { - offsets.clear(); - const uptr *old_vb = vb; - CHECK_LE(off, *vb); - for (; vb < ve && *vb < me; vb++) { - uptr diff = *vb - (i ? mb : 0) + off; - CHECK_LE(diff, 0xffffffffU); - offsets.push_back(static_cast<u32>(diff)); - } - const char *module_name = StripModuleName(module.data()); - if (cov_sandboxed) { - if (cov_fd >= 0) { - CovWritePacked(internal_getpid(), module_name, offsets.data(), - offsets.size() * sizeof(u32)); - VReport(1, " CovDump: %zd PCs written to packed file\n", vb - old_vb); - } - } else { - // One file per module per process. - path.clear(); - path.append("%s/%s.%zd.sancov", coverage_dir, module_name, - internal_getpid()); - int fd = CovOpenFile(false /* packed */, module_name); - if (fd > 0) { - internal_write(fd, offsets.data(), offsets.size() * sizeof(u32)); - internal_close(fd); - VReport(1, " CovDump: %s: %zd PCs written\n", path.data(), - vb - old_vb); - } + for (uptr m = 0; m < module_name_vec.size(); m++) { + offsets.clear(); + uptr num_words_for_magic = SANITIZER_WORDSIZE == 64 ? 1 : 2; + for (uptr i = 0; i < num_words_for_magic; i++) + offsets.push_back(0); + auto r = module_name_vec[m]; + CHECK(r.copied_module_name); + CHECK_LE(r.beg, r.end); + CHECK_LE(r.end, size()); + for (uptr i = r.beg; i < r.end; i++) { + uptr pc = UnbundlePc(pc_array[i]); + uptr counter = UnbundleCounter(pc_array[i]); + if (!pc) continue; // Not visited. + const char *unused; + uptr offset = 0; + sym->GetModuleNameAndOffsetForPC(pc, &unused, &offset); + offsets.push_back(BundlePcAndCounter(offset, counter)); + } + + CHECK_GE(offsets.size(), num_words_for_magic); + SortArray(offsets.data(), offsets.size()); + for (uptr i = 0; i < offsets.size(); i++) + offsets[i] = UnbundlePc(offsets[i]); + + uptr num_offsets = offsets.size() - num_words_for_magic; + u64 *magic_p = reinterpret_cast<u64*>(offsets.data()); + CHECK_EQ(*magic_p, 0ULL); + // FIXME: we may want to write 32-bit offsets even in 64-mode + // if all the offsets are small enough. + *magic_p = SANITIZER_WORDSIZE == 64 ? kMagic64 : kMagic32; + + const char *module_name = StripModuleName(r.copied_module_name); + if (cov_sandboxed) { + if (cov_fd >= 0) { + CovWritePacked(internal_getpid(), module_name, offsets.data(), + offsets.size() * sizeof(offsets[0])); + VReport(1, " CovDump: %zd PCs written to packed file\n", num_offsets); } + } else { + // One file per module per process. + int fd = CovOpenFile(&path, false /* packed */, module_name); + if (fd < 0) continue; + internal_write(fd, offsets.data(), offsets.size() * sizeof(offsets[0])); + internal_close(fd); + VReport(1, " CovDump: %s: %zd PCs written\n", path.data(), num_offsets); } } if (cov_fd >= 0) internal_close(cov_fd); - coverage_data.DumpCallerCalleePairs(); -#endif // !SANITIZER_WINDOWS +} + +void CoverageData::DumpAll() { + if (!coverage_enabled || common_flags()->coverage_direct) return; + if (atomic_fetch_add(&dump_once_guard, 1, memory_order_relaxed)) + return; + DumpAsBitSet(); + DumpCounters(); + DumpTrace(); + DumpOffsets(); + DumpCallerCalleePairs(); } void CovPrepareForSandboxing(__sanitizer_sandbox_arguments *args) { @@ -623,15 +807,18 @@ void CovPrepareForSandboxing(__sanitizer_sandbox_arguments *args) { if (!cov_sandboxed) return; cov_fd = args->coverage_fd; cov_max_block_size = args->coverage_max_block_size; - if (cov_fd < 0) + if (cov_fd < 0) { + InternalScopedString path(kMaxPathLength); // Pre-open the file now. The sandbox won't allow us to do it later. - cov_fd = CovOpenFile(true /* packed */, 0); + cov_fd = CovOpenFile(&path, true /* packed */, 0); + } } int MaybeOpenCovFile(const char *name) { CHECK(name); if (!coverage_enabled) return -1; - return CovOpenFile(true /* packed */, name); + InternalScopedString path(kMaxPathLength); + return CovOpenFile(&path, true /* packed */, name); } void CovBeforeFork() { @@ -674,7 +861,8 @@ SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov(u32 *guard) { } SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_with_check(u32 *guard) { atomic_uint32_t *atomic_guard = reinterpret_cast<atomic_uint32_t*>(guard); - if (__sanitizer::atomic_load(atomic_guard, memory_order_relaxed)) + if (static_cast<s32>( + __sanitizer::atomic_load(atomic_guard, memory_order_relaxed)) < 0) __sanitizer_cov(guard); } SANITIZER_INTERFACE_ATTRIBUTE void @@ -687,10 +875,14 @@ SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_init() { coverage_dir = common_flags()->coverage_dir; coverage_data.Init(); } -SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump() { CovDump(); } +SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump() { + coverage_data.DumpAll(); +} SANITIZER_INTERFACE_ATTRIBUTE void -__sanitizer_cov_module_init(s32 *guards, uptr npcs, const char *module_name) { - coverage_data.InitializeGuards(guards, npcs, module_name); +__sanitizer_cov_module_init(s32 *guards, uptr npcs, u8 *counters, + const char *comp_unit_name) { + coverage_data.InitializeGuards(guards, npcs, comp_unit_name, GET_CALLER_PC()); + coverage_data.InitializeCounters(counters, npcs); if (!common_flags()->coverage_direct) return; if (SANITIZER_ANDROID && coverage_enabled) { // dlopen/dlclose interceptors do not work on Android, so we rely on @@ -728,4 +920,14 @@ uptr __sanitizer_get_coverage_guards(uptr **data) { *data = coverage_data.data(); return coverage_data.size(); } + +SANITIZER_INTERFACE_ATTRIBUTE +uptr __sanitizer_get_number_of_counters() { + return coverage_data.GetNumberOf8bitCounters(); +} + +SANITIZER_INTERFACE_ATTRIBUTE +uptr __sanitizer_update_counter_bitset_and_clear_counters(u8 *bitset) { + return coverage_data.Update8bitCounterBitsetAndClearCounters(bitset); +} } // extern "C" diff --git a/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc b/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc index 6b5e91fbc..d3bde4b24 100644 --- a/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc @@ -102,7 +102,7 @@ void CovUpdateMapping(const char *coverage_dir, uptr caller_pc) { "%s/%zd.sancov.map.tmp", coverage_dir, internal_getpid()); CHECK_LE(res, tmp_path.size()); - uptr map_fd = OpenFile(tmp_path.data(), true); + uptr map_fd = OpenFile(tmp_path.data(), WrOnly); if (internal_iserror(map_fd, &err)) { Report(" Coverage: failed to open %s for writing: %d\n", tmp_path.data(), err); diff --git a/lib/sanitizer_common/sanitizer_flags.inc b/lib/sanitizer_common/sanitizer_flags.inc index 58f7f3722..884602f79 100644 --- a/lib/sanitizer_common/sanitizer_flags.inc +++ b/lib/sanitizer_common/sanitizer_flags.inc @@ -111,13 +111,18 @@ COMMON_FLAG( bool, coverage, false, "If set, coverage information will be dumped at program shutdown (if the " "coverage instrumentation was enabled at compile time).") -// On by default, but works only if coverage == true. COMMON_FLAG(bool, coverage_pcs, true, "If set (and if 'coverage' is set too), the coverage information " "will be dumped as a set of PC offsets for every module.") +COMMON_FLAG(bool, coverage_order_pcs, false, + "If true, the PCs will be dumped in the order they've" + " appeared during the execution.") COMMON_FLAG(bool, coverage_bitset, false, "If set (and if 'coverage' is set too), the coverage information " "will also be dumped as a bitset to a separate file.") +COMMON_FLAG(bool, coverage_counters, false, + "If set (and if 'coverage' is set too), the bitmap that corresponds" + " to coverage counters will be dumped.") COMMON_FLAG(bool, coverage_direct, SANITIZER_ANDROID, "If set, coverage information will be dumped directly to a memory " "mapped file. This way data is not lost even if the process is " diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc index 8029181a5..8d2ea4889 100644 --- a/lib/sanitizer_common/sanitizer_linux.cc +++ b/lib/sanitizer_common/sanitizer_linux.cc @@ -57,6 +57,7 @@ #include <sys/syscall.h> #include <sys/time.h> #include <sys/types.h> +#include <ucontext.h> #include <unistd.h> #if SANITIZER_FREEBSD @@ -147,11 +148,6 @@ uptr internal_open(const char *filename, int flags, u32 mode) { #endif } -uptr OpenFile(const char *filename, bool write) { - return internal_open(filename, - write ? O_RDWR | O_CREAT /*| O_CLOEXEC*/ : O_RDONLY, 0660); -} - uptr internal_read(fd_t fd, void *buf, uptr count) { sptr res; HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(read), fd, (uptr)buf, @@ -168,7 +164,8 @@ uptr internal_write(fd_t fd, const void *buf, uptr count) { uptr internal_ftruncate(fd_t fd, uptr size) { sptr res; - HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(ftruncate), fd, size)); + HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(ftruncate), fd, + (OFF_T)size)); return res; } @@ -558,6 +555,7 @@ int internal_fork() { } #if SANITIZER_LINUX +#define SA_RESTORER 0x04000000 // Doesn't set sa_restorer, use with caution (see below). int internal_sigaction_norestorer(int signum, const void *act, void *oldact) { __sanitizer_kernel_sigaction_t k_act, k_oldact; @@ -570,7 +568,8 @@ int internal_sigaction_norestorer(int signum, const void *act, void *oldact) { k_act.sigaction = u_act->sigaction; internal_memcpy(&k_act.sa_mask, &u_act->sa_mask, sizeof(__sanitizer_kernel_sigset_t)); - k_act.sa_flags = u_act->sa_flags; + // Without SA_RESTORER kernel ignores the calls (probably returns EINVAL). + k_act.sa_flags = u_act->sa_flags | SA_RESTORER; // FIXME: most often sa_restorer is unset, however the kernel requires it // to point to a valid signal restorer that calls the rt_sigreturn syscall. // If sa_restorer passed to the kernel is NULL, the program may crash upon @@ -928,6 +927,78 @@ void *internal_start_thread(void (*func)(void *), void *arg) { return 0; } void internal_join_thread(void *th) {} #endif +void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { +#if defined(__arm__) + ucontext_t *ucontext = (ucontext_t*)context; + *pc = ucontext->uc_mcontext.arm_pc; + *bp = ucontext->uc_mcontext.arm_fp; + *sp = ucontext->uc_mcontext.arm_sp; +#elif defined(__aarch64__) + ucontext_t *ucontext = (ucontext_t*)context; + *pc = ucontext->uc_mcontext.pc; + *bp = ucontext->uc_mcontext.regs[29]; + *sp = ucontext->uc_mcontext.sp; +#elif defined(__hppa__) + ucontext_t *ucontext = (ucontext_t*)context; + *pc = ucontext->uc_mcontext.sc_iaoq[0]; + /* GCC uses %r3 whenever a frame pointer is needed. */ + *bp = ucontext->uc_mcontext.sc_gr[3]; + *sp = ucontext->uc_mcontext.sc_gr[30]; +#elif defined(__x86_64__) +# if SANITIZER_FREEBSD + ucontext_t *ucontext = (ucontext_t*)context; + *pc = ucontext->uc_mcontext.mc_rip; + *bp = ucontext->uc_mcontext.mc_rbp; + *sp = ucontext->uc_mcontext.mc_rsp; +# else + ucontext_t *ucontext = (ucontext_t*)context; + *pc = ucontext->uc_mcontext.gregs[REG_RIP]; + *bp = ucontext->uc_mcontext.gregs[REG_RBP]; + *sp = ucontext->uc_mcontext.gregs[REG_RSP]; +# endif +#elif defined(__i386__) +# if SANITIZER_FREEBSD + ucontext_t *ucontext = (ucontext_t*)context; + *pc = ucontext->uc_mcontext.mc_eip; + *bp = ucontext->uc_mcontext.mc_ebp; + *sp = ucontext->uc_mcontext.mc_esp; +# else + ucontext_t *ucontext = (ucontext_t*)context; + *pc = ucontext->uc_mcontext.gregs[REG_EIP]; + *bp = ucontext->uc_mcontext.gregs[REG_EBP]; + *sp = ucontext->uc_mcontext.gregs[REG_ESP]; +# endif +#elif defined(__powerpc__) || defined(__powerpc64__) + ucontext_t *ucontext = (ucontext_t*)context; + *pc = ucontext->uc_mcontext.regs->nip; + *sp = ucontext->uc_mcontext.regs->gpr[PT_R1]; + // The powerpc{,64}-linux ABIs do not specify r31 as the frame + // pointer, but GCC always uses r31 when we need a frame pointer. + *bp = ucontext->uc_mcontext.regs->gpr[PT_R31]; +#elif defined(__sparc__) + ucontext_t *ucontext = (ucontext_t*)context; + uptr *stk_ptr; +# if defined (__arch64__) + *pc = ucontext->uc_mcontext.mc_gregs[MC_PC]; + *sp = ucontext->uc_mcontext.mc_gregs[MC_O6]; + stk_ptr = (uptr *) (*sp + 2047); + *bp = stk_ptr[15]; +# else + *pc = ucontext->uc_mcontext.gregs[REG_PC]; + *sp = ucontext->uc_mcontext.gregs[REG_O6]; + stk_ptr = (uptr *) *sp; + *bp = stk_ptr[15]; +# endif +#elif defined(__mips__) + ucontext_t *ucontext = (ucontext_t*)context; + *pc = ucontext->uc_mcontext.gregs[31]; + *bp = ucontext->uc_mcontext.gregs[30]; + *sp = ucontext->uc_mcontext.gregs[29]; +#else +# error "Unsupported arch" +#endif +} + } // namespace __sanitizer #endif // SANITIZER_FREEBSD || SANITIZER_LINUX diff --git a/lib/sanitizer_common/sanitizer_linux.h b/lib/sanitizer_common/sanitizer_linux.h index b2e603d3a..2ce2025d2 100644 --- a/lib/sanitizer_common/sanitizer_linux.h +++ b/lib/sanitizer_common/sanitizer_linux.h @@ -80,8 +80,6 @@ uptr ThreadSelfOffset(); // information). bool LibraryNameIs(const char *full_name, const char *base_name); -// Read the name of the current binary from /proc/self/exe. -uptr ReadBinaryName(/*out*/char *buf, uptr buf_len); // Cache the value of /proc/self/exe. void CacheBinaryName(); diff --git a/lib/sanitizer_common/sanitizer_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_linux_libcdep.cc index c71b6257e..1c099d862 100644 --- a/lib/sanitizer_common/sanitizer_linux_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_linux_libcdep.cc @@ -488,7 +488,7 @@ static uptr GetRSSFromGetrusage() { uptr GetRSS() { if (!common_flags()->can_use_proc_maps_statm) return GetRSSFromGetrusage(); - uptr fd = OpenFile("/proc/self/statm", false); + uptr fd = OpenFile("/proc/self/statm", RdOnly); if ((sptr)fd < 0) return GetRSSFromGetrusage(); char buf[64]; diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc index 39a5c7e8d..91a5b7d93 100644 --- a/lib/sanitizer_common/sanitizer_mac.cc +++ b/lib/sanitizer_common/sanitizer_mac.cc @@ -31,9 +31,11 @@ #include <crt_externs.h> // for _NSGetEnviron #include <fcntl.h> +#include <mach-o/dyld.h> #include <pthread.h> #include <sched.h> #include <signal.h> +#include <stdlib.h> #include <sys/mman.h> #include <sys/resource.h> #include <sys/stat.h> @@ -69,11 +71,6 @@ uptr internal_open(const char *filename, int flags, u32 mode) { return open(filename, flags, mode); } -uptr OpenFile(const char *filename, bool write) { - return internal_open(filename, - write ? O_WRONLY | O_CREAT : O_RDONLY, 0660); -} - uptr internal_read(fd_t fd, void *buf, uptr count) { return read(fd, buf, count); } @@ -204,6 +201,21 @@ const char *GetEnv(const char *name) { return 0; } +uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { + CHECK_LE(kMaxPathLength, buf_len); + + // On OS X the executable path is saved to the stack by dyld. Reading it + // from there is much faster than calling dladdr, especially for large + // binaries with symbols. + InternalScopedString exe_path(kMaxPathLength); + uint32_t size = exe_path.size(); + if (_NSGetExecutablePath(exe_path.data(), &size) == 0 && + realpath(exe_path.data(), buf) != 0) { + return internal_strlen(buf); + } + return 0; +} + void ReExec() { UNIMPLEMENTED(); } @@ -328,6 +340,19 @@ uptr GetRSS() { void *internal_start_thread(void (*func)(void *arg), void *arg) { return 0; } void internal_join_thread(void *th) { } +void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { + ucontext_t *ucontext = (ucontext_t*)context; +# if SANITIZER_WORDSIZE == 64 + *pc = ucontext->uc_mcontext->__ss.__rip; + *bp = ucontext->uc_mcontext->__ss.__rbp; + *sp = ucontext->uc_mcontext->__ss.__rsp; +# else + *pc = ucontext->uc_mcontext->__ss.__eip; + *bp = ucontext->uc_mcontext->__ss.__ebp; + *sp = ucontext->uc_mcontext->__ss.__esp; +# endif // SANITIZER_WORDSIZE +} + } // namespace __sanitizer #endif // SANITIZER_MAC diff --git a/lib/sanitizer_common/sanitizer_posix.cc b/lib/sanitizer_common/sanitizer_posix.cc index 5bc41c258..5e01212c2 100644 --- a/lib/sanitizer_common/sanitizer_posix.cc +++ b/lib/sanitizer_common/sanitizer_posix.cc @@ -20,6 +20,8 @@ #include "sanitizer_procmaps.h" #include "sanitizer_stacktrace.h" +#include <fcntl.h> +#include <signal.h> #include <sys/mman.h> #if SANITIZER_LINUX @@ -47,7 +49,7 @@ uptr GetMmapGranularity() { #if SANITIZER_WORDSIZE == 32 // Take care of unusable kernel area in top gigabyte. static uptr GetKernelAreaSize() { -#if SANITIZER_LINUX +#if SANITIZER_LINUX && !SANITIZER_X32 const uptr gbyte = 1UL << 30; // Firstly check if there are writable segments @@ -79,7 +81,7 @@ static uptr GetKernelAreaSize() { return gbyte; #else return 0; -#endif // SANITIZER_LINUX +#endif // SANITIZER_LINUX && !SANITIZER_X32 } #endif // SANITIZER_WORDSIZE == 32 @@ -203,8 +205,18 @@ void *Mprotect(uptr fixed_addr, uptr size) { MAP_NORESERVE, -1, 0); } +uptr OpenFile(const char *filename, FileAccessMode mode) { + int flags; + switch (mode) { + case RdOnly: flags = O_RDONLY; break; + case WrOnly: flags = O_WRONLY | O_CREAT; break; + case RdWr: flags = O_RDWR | O_CREAT; break; + } + return internal_open(filename, flags, 0660); +} + void *MapFileToMemory(const char *file_name, uptr *buff_size) { - uptr openrv = OpenFile(file_name, false); + uptr openrv = OpenFile(file_name, RdOnly); CHECK(!internal_iserror(openrv)); fd_t fd = openrv; uptr fsize = internal_filesize(fd); @@ -219,9 +231,10 @@ void *MapWritableFileToMemory(void *addr, uptr size, uptr fd, uptr offset) { uptr flags = MAP_SHARED; if (addr) flags |= MAP_FIXED; uptr p = internal_mmap(addr, size, PROT_READ | PROT_WRITE, flags, fd, offset); - if (internal_iserror(p)) { - Printf("could not map writable file (%zd, %zu, %zu): %zd\n", fd, offset, - size, p); + int mmap_errno = 0; + if (internal_iserror(p, &mmap_errno)) { + Printf("could not map writable file (%zd, %zu, %zu): %zd, errno: %d\n", + fd, offset, size, p, mmap_errno); return 0; } return (void *)p; @@ -293,6 +306,14 @@ char *FindPathToBinary(const char *name) { return 0; } +bool IsPathSeparator(const char c) { + return c == '/'; +} + +bool IsAbsolutePath(const char *path) { + return path != nullptr && IsPathSeparator(path[0]); +} + void ReportFile::Write(const char *buffer, uptr length) { SpinMutexLock l(mu); static const char *kWriteError = @@ -319,6 +340,13 @@ bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end) { return false; } +SignalContext SignalContext::Create(void *siginfo, void *context) { + uptr addr = (uptr)((siginfo_t*)siginfo)->si_addr; + uptr pc, sp, bp; + GetPcSpBp(context, &pc, &sp, &bp); + return SignalContext(context, addr, pc, sp, bp); +} + } // namespace __sanitizer #endif // SANITIZER_POSIX diff --git a/lib/sanitizer_common/sanitizer_stoptheworld.h b/lib/sanitizer_common/sanitizer_stoptheworld.h index a32646708..aa6f5d833 100644 --- a/lib/sanitizer_common/sanitizer_stoptheworld.h +++ b/lib/sanitizer_common/sanitizer_stoptheworld.h @@ -59,7 +59,8 @@ typedef void (*StopTheWorldCallback)( // Suspend all threads in the current process and run the callback on the list // of suspended threads. This function will resume the threads before returning. -// The callback should not call any libc functions. +// The callback should not call any libc functions. The callback must not call +// exit() nor _exit() and instead return to the caller. // This function should NOT be called from multiple threads simultaneously. void StopTheWorld(StopTheWorldCallback callback, void *argument); diff --git a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc index ad20e3955..64e1c7974 100644 --- a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc @@ -19,6 +19,7 @@ #include "sanitizer_stoptheworld.h" #include "sanitizer_platform_limits_posix.h" +#include "sanitizer_atomic.h" #include <errno.h> #include <sched.h> // for CLONE_* definitions @@ -70,11 +71,25 @@ COMPILER_CHECK(sizeof(SuspendedThreadID) == sizeof(pid_t)); namespace __sanitizer { + +// Structure for passing arguments into the tracer thread. +struct TracerThreadArgument { + StopTheWorldCallback callback; + void *callback_argument; + // The tracer thread waits on this mutex while the parent finishes its + // preparations. + BlockingMutex mutex; + // Tracer thread signals its completion by setting done. + atomic_uintptr_t done; + uptr parent_pid; +}; + // This class handles thread suspending/unsuspending in the tracer thread. class ThreadSuspender { public: - explicit ThreadSuspender(pid_t pid) - : pid_(pid) { + explicit ThreadSuspender(pid_t pid, TracerThreadArgument *arg) + : arg(arg) + , pid_(pid) { CHECK_GE(pid, 0); } bool SuspendAllThreads(); @@ -83,6 +98,7 @@ class ThreadSuspender { SuspendedThreadsList &suspended_threads_list() { return suspended_threads_list_; } + TracerThreadArgument *arg; private: SuspendedThreadsList suspended_threads_list_; pid_t pid_; @@ -103,7 +119,7 @@ bool ThreadSuspender::SuspendThread(SuspendedThreadID tid) { VReport(1, "Could not attach to thread %d (errno %d).\n", tid, pterrno); return false; } else { - VReport(1, "Attached to thread %d.\n", tid); + VReport(2, "Attached to thread %d.\n", tid); // The thread is not guaranteed to stop before ptrace returns, so we must // wait on it. Note: if the thread receives a signal concurrently, // we can get notification about the signal before notification about stop. @@ -143,7 +159,7 @@ void ThreadSuspender::ResumeAllThreads() { int pterrno; if (!internal_iserror(internal_ptrace(PTRACE_DETACH, tid, NULL, NULL), &pterrno)) { - VReport(1, "Detached from thread %d.\n", tid); + VReport(2, "Detached from thread %d.\n", tid); } else { // Either the thread is dead, or we are already detached. // The latter case is possible, for instance, if this function was called @@ -188,25 +204,23 @@ static ThreadSuspender *thread_suspender_instance = NULL; static const int kSyncSignals[] = { SIGABRT, SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGXCPU, SIGXFSZ }; -// Structure for passing arguments into the tracer thread. -struct TracerThreadArgument { - StopTheWorldCallback callback; - void *callback_argument; - // The tracer thread waits on this mutex while the parent finishes its - // preparations. - BlockingMutex mutex; - uptr parent_pid; -}; - static DieCallbackType old_die_callback; // Signal handler to wake up suspended threads when the tracer thread dies. -static void TracerThreadSignalHandler(int signum, void *siginfo, void *) { - if (thread_suspender_instance != NULL) { +static void TracerThreadSignalHandler(int signum, void *siginfo, void *uctx) { + SignalContext ctx = SignalContext::Create(siginfo, uctx); + VPrintf(1, "Tracer caught signal %d: addr=0x%zx pc=0x%zx sp=0x%zx\n", + signum, ctx.addr, ctx.pc, ctx.sp); + ThreadSuspender *inst = thread_suspender_instance; + if (inst != NULL) { if (signum == SIGABRT) - thread_suspender_instance->KillAllThreads(); + inst->KillAllThreads(); else - thread_suspender_instance->ResumeAllThreads(); + inst->ResumeAllThreads(); + SetDieCallback(old_die_callback); + old_die_callback = NULL; + thread_suspender_instance = NULL; + atomic_store(&inst->arg->done, 1, memory_order_relaxed); } internal__exit((signum == SIGABRT) ? 1 : 2); } @@ -218,10 +232,15 @@ static void TracerThreadDieCallback() { // point. So we correctly handle calls to Die() from within the callback, but // not those that happen before or after the callback. Hopefully there aren't // a lot of opportunities for that to happen... - if (thread_suspender_instance) - thread_suspender_instance->KillAllThreads(); + ThreadSuspender *inst = thread_suspender_instance; + if (inst != NULL && stoptheworld_tracer_pid == internal_getpid()) { + inst->KillAllThreads(); + thread_suspender_instance = NULL; + } if (old_die_callback) old_die_callback(); + SetDieCallback(old_die_callback); + old_die_callback = NULL; } // Size of alternative stack for signal handlers in the tracer thread. @@ -244,7 +263,7 @@ static int TracerThread(void* argument) { old_die_callback = GetDieCallback(); SetDieCallback(TracerThreadDieCallback); - ThreadSuspender thread_suspender(internal_getppid()); + ThreadSuspender thread_suspender(internal_getppid(), tracer_thread_argument); // Global pointer for the signal handler. thread_suspender_instance = &thread_suspender; @@ -276,11 +295,9 @@ static int TracerThread(void* argument) { thread_suspender.ResumeAllThreads(); exit_code = 0; } - // Note, this is a bad race. If TracerThreadDieCallback is already started - // in another thread and observed that thread_suspender_instance != 0, - // it can call KillAllThreads on the destroyed variable. SetDieCallback(old_die_callback); thread_suspender_instance = NULL; + atomic_store(&tracer_thread_argument->done, 1, memory_order_relaxed); return exit_code; } @@ -354,6 +371,7 @@ void StopTheWorld(StopTheWorldCallback callback, void *argument) { tracer_thread_argument.callback = callback; tracer_thread_argument.callback_argument = argument; tracer_thread_argument.parent_pid = internal_getpid(); + atomic_store(&tracer_thread_argument.done, 0, memory_order_relaxed); const uptr kTracerStackSize = 2 * 1024 * 1024; ScopedStackSpaceWithGuard tracer_stack(kTracerStackSize); // Block the execution of TracerThread until after we have set ptrace @@ -402,14 +420,27 @@ void StopTheWorld(StopTheWorldCallback callback, void *argument) { #endif // Allow the tracer thread to start. tracer_thread_argument.mutex.Unlock(); - // Since errno is shared between this thread and the tracer thread, we - // must avoid using errno while the tracer thread is running. - // At this point, any signal will either be blocked or kill us, so waitpid - // should never return (and set errno) while the tracer thread is alive. - uptr waitpid_status = internal_waitpid(tracer_pid, NULL, __WALL); - if (internal_iserror(waitpid_status, &local_errno)) + // NOTE: errno is shared between this thread and the tracer thread. + // internal_waitpid() may call syscall() which can access/spoil errno, + // so we can't call it now. Instead we for the tracer thread to finish using + // the spin loop below. Man page for sched_yield() says "In the Linux + // implementation, sched_yield() always succeeds", so let's hope it does not + // spoil errno. Note that this spin loop runs only for brief periods before + // the tracer thread has suspended us and when it starts unblocking threads. + while (atomic_load(&tracer_thread_argument.done, memory_order_relaxed) == 0) + sched_yield(); + // Now the tracer thread is about to exit and does not touch errno, + // wait for it. + for (;;) { + uptr waitpid_status = internal_waitpid(tracer_pid, NULL, __WALL); + if (!internal_iserror(waitpid_status, &local_errno)) + break; + if (local_errno == EINTR) + continue; VReport(1, "Waiting on the tracer thread failed (errno %d).\n", local_errno); + break; + } } } diff --git a/lib/sanitizer_common/sanitizer_suppressions.cc b/lib/sanitizer_common/sanitizer_suppressions.cc index 2b697e955..8009b4d6a 100644 --- a/lib/sanitizer_common/sanitizer_suppressions.cc +++ b/lib/sanitizer_common/sanitizer_suppressions.cc @@ -30,18 +30,50 @@ SuppressionContext::SuppressionContext(const char *suppression_types[], internal_memset(has_suppression_type_, 0, suppression_types_num_); } +static bool GetPathAssumingFileIsRelativeToExec(const char *file_path, + /*out*/char *new_file_path, + uptr new_file_path_size) { + InternalScopedString exec(kMaxPathLength); + if (ReadBinaryName(exec.data(), exec.size())) { + const char *file_name_pos = StripModuleName(exec.data()); + uptr path_to_exec_len = file_name_pos - exec.data(); + internal_strncat(new_file_path, exec.data(), + Min(path_to_exec_len, new_file_path_size - 1)); + internal_strncat(new_file_path, file_path, + new_file_path_size - internal_strlen(new_file_path) - 1); + return true; + } + return false; +} + void SuppressionContext::ParseFromFile(const char *filename) { if (filename[0] == '\0') return; + + // If we cannot find the file, check if its location is relative to + // the location of the executable. + InternalScopedString new_file_path(kMaxPathLength); + if (!FileExists(filename) && !IsAbsolutePath(filename) && + GetPathAssumingFileIsRelativeToExec(filename, new_file_path.data(), + new_file_path.size())) { + filename = new_file_path.data(); + } + + // Read the file. char *file_contents; uptr buffer_size; - uptr contents_size = ReadFileToBuffer(filename, &file_contents, &buffer_size, - 1 << 26 /* max_len */); + const uptr max_len = 1 << 26; + uptr contents_size = + ReadFileToBuffer(filename, &file_contents, &buffer_size, max_len); + VPrintf(1, "%s: reading suppressions file at %s\n", + SanitizerToolName, filename); + if (contents_size == 0) { Printf("%s: failed to read suppressions file '%s'\n", SanitizerToolName, filename); Die(); } + Parse(file_contents); } diff --git a/lib/sanitizer_common/sanitizer_symbolizer.cc b/lib/sanitizer_common/sanitizer_symbolizer.cc index 135720ed5..df7661ab6 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer.cc +++ b/lib/sanitizer_common/sanitizer_symbolizer.cc @@ -16,7 +16,7 @@ #include "sanitizer_internal_defs.h" #include "sanitizer_libc.h" #include "sanitizer_placement_new.h" -#include "sanitizer_symbolizer.h" +#include "sanitizer_symbolizer_internal.h" namespace __sanitizer { @@ -33,9 +33,7 @@ void AddressInfo::Clear() { function_offset = kUnknown; } -void AddressInfo::FillAddressAndModuleInfo(uptr addr, const char *mod_name, - uptr mod_offset) { - address = addr; +void AddressInfo::FillModuleInfo(const char *mod_name, uptr mod_offset) { module = internal_strdup(mod_name); module_offset = mod_offset; } @@ -70,13 +68,6 @@ Symbolizer *Symbolizer::symbolizer_; StaticSpinMutex Symbolizer::init_mu_; LowLevelAllocator Symbolizer::symbolizer_allocator_; -Symbolizer *Symbolizer::Disable() { - CHECK_EQ(0, symbolizer_); - // Initialize a dummy symbolizer. - symbolizer_ = new(symbolizer_allocator_) Symbolizer; - return symbolizer_; -} - void Symbolizer::AddHooks(Symbolizer::StartSymbolizationHook start_hook, Symbolizer::EndSymbolizationHook end_hook) { CHECK(start_hook_ == 0 && end_hook_ == 0); @@ -84,7 +75,8 @@ void Symbolizer::AddHooks(Symbolizer::StartSymbolizationHook start_hook, end_hook_ = end_hook; } -Symbolizer::Symbolizer() : start_hook_(0), end_hook_(0) {} +Symbolizer::Symbolizer(IntrusiveList<SymbolizerTool> tools) + : tools_(tools), start_hook_(0), end_hook_(0) {} Symbolizer::SymbolizerScope::SymbolizerScope(const Symbolizer *sym) : sym_(sym) { @@ -97,4 +89,76 @@ Symbolizer::SymbolizerScope::~SymbolizerScope() { sym_->end_hook_(); } +SymbolizedStack *Symbolizer::SymbolizePC(uptr addr) { + BlockingMutexLock l(&mu_); + const char *module_name; + uptr module_offset; + SymbolizedStack *res = SymbolizedStack::New(addr); + if (!PlatformFindModuleNameAndOffsetForAddress(addr, &module_name, + &module_offset)) + return res; + // Always fill data about module name and offset. + res->info.FillModuleInfo(module_name, module_offset); + for (auto iter = Iterator(&tools_); iter.hasNext();) { + auto *tool = iter.next(); + SymbolizerScope sym_scope(this); + if (tool->SymbolizePC(addr, res)) { + return res; + } + } + return res; +} + +bool Symbolizer::SymbolizeData(uptr addr, DataInfo *info) { + BlockingMutexLock l(&mu_); + const char *module_name; + uptr module_offset; + if (!PlatformFindModuleNameAndOffsetForAddress(addr, &module_name, + &module_offset)) + return false; + info->Clear(); + info->module = internal_strdup(module_name); + info->module_offset = module_offset; + for (auto iter = Iterator(&tools_); iter.hasNext();) { + auto *tool = iter.next(); + SymbolizerScope sym_scope(this); + if (tool->SymbolizeData(addr, info)) { + return true; + } + } + return true; +} + +bool Symbolizer::GetModuleNameAndOffsetForPC(uptr pc, const char **module_name, + uptr *module_address) { + BlockingMutexLock l(&mu_); + return PlatformFindModuleNameAndOffsetForAddress(pc, module_name, + module_address); +} + +void Symbolizer::Flush() { + BlockingMutexLock l(&mu_); + for (auto iter = Iterator(&tools_); iter.hasNext();) { + auto *tool = iter.next(); + SymbolizerScope sym_scope(this); + tool->Flush(); + } +} + +const char *Symbolizer::Demangle(const char *name) { + BlockingMutexLock l(&mu_); + for (auto iter = Iterator(&tools_); iter.hasNext();) { + auto *tool = iter.next(); + SymbolizerScope sym_scope(this); + if (const char *demangled = tool->Demangle(name)) + return demangled; + } + return PlatformDemangle(name); +} + +void Symbolizer::PrepareForSandboxing() { + BlockingMutexLock l(&mu_); + PlatformPrepareForSandboxing(); +} + } // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_symbolizer.h b/lib/sanitizer_common/sanitizer_symbolizer.h index 3a807744d..225da70de 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer.h +++ b/lib/sanitizer_common/sanitizer_symbolizer.h @@ -43,8 +43,7 @@ struct AddressInfo { AddressInfo(); // Deletes all strings and resets all fields. void Clear(); - void FillAddressAndModuleInfo(uptr addr, const char *mod_name, - uptr mod_offset); + void FillModuleInfo(const char *mod_name, uptr mod_offset); }; // Linked list of symbolized frames (each frame is described by AddressInfo). @@ -74,6 +73,8 @@ struct DataInfo { void Clear(); }; +class SymbolizerTool; + class Symbolizer { public: /// Initialize and return platform-specific implementation of symbolizer @@ -81,26 +82,22 @@ class Symbolizer { static Symbolizer *GetOrInit(); // Returns a list of symbolized frames for a given address (containing // all inlined functions, if necessary). - virtual SymbolizedStack *SymbolizePC(uptr address) { - return SymbolizedStack::New(address); - } - virtual bool SymbolizeData(uptr address, DataInfo *info) { - return false; - } - virtual bool GetModuleNameAndOffsetForPC(uptr pc, const char **module_name, - uptr *module_address) { - return false; - } - virtual bool CanReturnFileLineInfo() { - return false; + SymbolizedStack *SymbolizePC(uptr address); + bool SymbolizeData(uptr address, DataInfo *info); + bool GetModuleNameAndOffsetForPC(uptr pc, const char **module_name, + uptr *module_address); + const char *GetModuleNameForPc(uptr pc) { + const char *module_name = 0; + uptr unused; + if (GetModuleNameAndOffsetForPC(pc, &module_name, &unused)) + return module_name; + return nullptr; } // Release internal caches (if any). - virtual void Flush() {} + void Flush(); // Attempts to demangle the provided C++ mangled name. - virtual const char *Demangle(const char *name) { - return name; - } - virtual void PrepareForSandboxing() {} + const char *Demangle(const char *name); + void PrepareForSandboxing(); // Allow user to install hooks that would be called before/after Symbolizer // does the actual file/line info fetching. Specific sanitizers may need this @@ -115,14 +112,28 @@ class Symbolizer { private: /// Platform-specific function for creating a Symbolizer object. static Symbolizer *PlatformInit(); - /// Initialize the symbolizer in a disabled state. Not thread safe. - static Symbolizer *Disable(); + + virtual bool PlatformFindModuleNameAndOffsetForAddress( + uptr address, const char **module_name, uptr *module_offset) { + UNIMPLEMENTED(); + } + // Platform-specific default demangler, must not return nullptr. + virtual const char *PlatformDemangle(const char *name) { UNIMPLEMENTED(); } + virtual void PlatformPrepareForSandboxing() { UNIMPLEMENTED(); } static Symbolizer *symbolizer_; static StaticSpinMutex init_mu_; + // Mutex locked from public methods of |Symbolizer|, so that the internals + // (including individual symbolizer tools and platform-specific methods) are + // always synchronized. + BlockingMutex mu_; + + typedef IntrusiveList<SymbolizerTool>::Iterator Iterator; + IntrusiveList<SymbolizerTool> tools_; + protected: - Symbolizer(); + explicit Symbolizer(IntrusiveList<SymbolizerTool> tools); static LowLevelAllocator symbolizer_allocator_; @@ -137,61 +148,6 @@ class Symbolizer { }; }; -class ExternalSymbolizerInterface { - public: - // Can't declare pure virtual functions in sanitizer runtimes: - // __cxa_pure_virtual might be unavailable. - virtual char *SendCommand(bool is_data, const char *module_name, - uptr module_offset) { - UNIMPLEMENTED(); - } -}; - -// SymbolizerProcess encapsulates communication between the tool and -// external symbolizer program, running in a different subprocess. -// SymbolizerProcess may not be used from two threads simultaneously. -class SymbolizerProcess : public ExternalSymbolizerInterface { - public: - explicit SymbolizerProcess(const char *path); - char *SendCommand(bool is_data, const char *module_name, - uptr module_offset) override; - - private: - bool Restart(); - char *SendCommandImpl(bool is_data, const char *module_name, - uptr module_offset); - bool ReadFromSymbolizer(char *buffer, uptr max_length); - bool WriteToSymbolizer(const char *buffer, uptr length); - bool StartSymbolizerSubprocess(); - - virtual bool RenderInputCommand(char *buffer, uptr max_length, bool is_data, - const char *module_name, - uptr module_offset) const { - UNIMPLEMENTED(); - } - - virtual bool ReachedEndOfOutput(const char *buffer, uptr length) const { - UNIMPLEMENTED(); - } - - virtual void ExecuteWithDefaultArgs(const char *path_to_binary) const { - UNIMPLEMENTED(); - } - - const char *path_; - int input_fd_; - int output_fd_; - - static const uptr kBufferSize = 16 * 1024; - char buffer_[kBufferSize]; - - static const uptr kMaxTimesRestarted = 5; - static const int kSymbolizerStartupTimeMillis = 10; - uptr times_restarted_; - bool failed_to_start_; - bool reported_invalid_path_; -}; - } // namespace __sanitizer #endif // SANITIZER_SYMBOLIZER_H diff --git a/lib/sanitizer_common/sanitizer_symbolizer_internal.h b/lib/sanitizer_common/sanitizer_symbolizer_internal.h new file mode 100644 index 000000000..66ae809ed --- /dev/null +++ b/lib/sanitizer_common/sanitizer_symbolizer_internal.h @@ -0,0 +1,109 @@ +//===-- sanitizer_symbolizer_internal.h -------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Header for internal classes and functions to be used by implementations of +// symbolizers. +// +//===----------------------------------------------------------------------===// +#ifndef SANITIZER_SYMBOLIZER_INTERNAL_H +#define SANITIZER_SYMBOLIZER_INTERNAL_H + +#include "sanitizer_symbolizer.h" + +namespace __sanitizer { + +// Parsing helpers, 'str' is searched for delimiter(s) and a string or uptr +// is extracted. When extracting a string, a newly allocated (using +// InternalAlloc) and null-terminataed buffer is returned. They return a pointer +// to the next characted after the found delimiter. +const char *ExtractToken(const char *str, const char *delims, char **result); +const char *ExtractInt(const char *str, const char *delims, int *result); +const char *ExtractUptr(const char *str, const char *delims, uptr *result); +const char *ExtractTokenUpToDelimiter(const char *str, const char *delimiter, + char **result); + +const char *DemangleCXXABI(const char *name); + +// SymbolizerTool is an interface that is implemented by individual "tools" +// that can perform symbolication (external llvm-symbolizer, libbacktrace, +// Windows DbgHelp symbolizer, etc.). +class SymbolizerTool { + public: + // The main |Symbolizer| class implements a "fallback chain" of symbolizer + // tools. In a request to symbolize an address, if one tool returns false, + // the next tool in the chain will be tried. + SymbolizerTool *next; + + SymbolizerTool() : next(nullptr) { } + + // Can't declare pure virtual functions in sanitizer runtimes: + // __cxa_pure_virtual might be unavailable. + + // The |stack| parameter is inout. It is pre-filled with the address, + // module base and module offset values and is to be used to construct + // other stack frames. + virtual bool SymbolizePC(uptr addr, SymbolizedStack *stack) { + UNIMPLEMENTED(); + } + + // The |info| parameter is inout. It is pre-filled with the module base + // and module offset values. + virtual bool SymbolizeData(uptr addr, DataInfo *info) { + UNIMPLEMENTED(); + } + + virtual void Flush() {} + + // Return nullptr to fallback to the default platform-specific demangler. + virtual const char *Demangle(const char *name) { + return nullptr; + } +}; + +// SymbolizerProcess encapsulates communication between the tool and +// external symbolizer program, running in a different subprocess. +// SymbolizerProcess may not be used from two threads simultaneously. +class SymbolizerProcess { + public: + explicit SymbolizerProcess(const char *path, bool use_forkpty = false); + const char *SendCommand(const char *command); + + private: + bool Restart(); + const char *SendCommandImpl(const char *command); + bool ReadFromSymbolizer(char *buffer, uptr max_length); + bool WriteToSymbolizer(const char *buffer, uptr length); + bool StartSymbolizerSubprocess(); + + virtual bool ReachedEndOfOutput(const char *buffer, uptr length) const { + UNIMPLEMENTED(); + } + + virtual void ExecuteWithDefaultArgs(const char *path_to_binary) const { + UNIMPLEMENTED(); + } + + const char *path_; + int input_fd_; + int output_fd_; + + static const uptr kBufferSize = 16 * 1024; + char buffer_[kBufferSize]; + + static const uptr kMaxTimesRestarted = 5; + static const int kSymbolizerStartupTimeMillis = 10; + uptr times_restarted_; + bool failed_to_start_; + bool reported_invalid_path_; + bool use_forkpty_; +}; + +} // namespace __sanitizer + +#endif // SANITIZER_SYMBOLIZER_INTERNAL_H diff --git a/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc b/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc index 9317a78ee..57354668b 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc +++ b/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc @@ -33,6 +33,8 @@ namespace __sanitizer { +static char *DemangleAlloc(const char *name, bool always_alloc); + #if SANITIZER_LIBBACKTRACE namespace { @@ -86,17 +88,20 @@ char *CplusV3Demangle(const char *name) { struct SymbolizeCodeCallbackArg { SymbolizedStack *first; SymbolizedStack *last; - const char *module_name; - uptr module_offset; - - void append(SymbolizedStack *f) { - if (last != nullptr) { - last->next = f; - last = f; - } else { - first = f; - last = f; + uptr frames_symbolized; + + AddressInfo *get_new_frame(uintptr_t addr) { + CHECK(last); + if (frames_symbolized > 0) { + SymbolizedStack *cur = SymbolizedStack::New(addr); + AddressInfo *info = &cur->info; + info->FillModuleInfo(first->info.module, first->info.module_offset); + last->next = cur; + last = cur; } + CHECK_EQ(addr, first->info.address); + CHECK_EQ(addr, last->info.address); + return &last->info; } }; @@ -106,15 +111,12 @@ static int SymbolizeCodePCInfoCallback(void *vdata, uintptr_t addr, const char *function) { SymbolizeCodeCallbackArg *cdata = (SymbolizeCodeCallbackArg *)vdata; if (function) { - SymbolizedStack *cur = SymbolizedStack::New(addr); - cdata->append(cur); - AddressInfo *info = &cur->info; - info->FillAddressAndModuleInfo(addr, cdata->module_name, - cdata->module_offset); - info->function = LibbacktraceSymbolizer::Demangle(function, true); + AddressInfo *info = cdata->get_new_frame(addr); + info->function = DemangleAlloc(function, /*always_alloc*/ true); if (filename) info->file = internal_strdup(filename); info->line = lineno; + cdata->frames_symbolized++; } return 0; } @@ -123,12 +125,9 @@ static void SymbolizeCodeCallback(void *vdata, uintptr_t addr, const char *symname, uintptr_t, uintptr_t) { SymbolizeCodeCallbackArg *cdata = (SymbolizeCodeCallbackArg *)vdata; if (symname) { - SymbolizedStack *cur = SymbolizedStack::New(addr); - cdata->append(cur); - AddressInfo *info = &cur->info; - info->FillAddressAndModuleInfo(addr, cdata->module_name, - cdata->module_offset); - info->function = LibbacktraceSymbolizer::Demangle(symname, true); + AddressInfo *info = cdata->get_new_frame(addr); + info->function = DemangleAlloc(symname, /*always_alloc*/ true); + cdata->frames_symbolized++; } } @@ -136,7 +135,7 @@ static void SymbolizeDataCallback(void *vdata, uintptr_t, const char *symname, uintptr_t symval, uintptr_t symsize) { DataInfo *info = (DataInfo *)vdata; if (symname && symval) { - info->name = LibbacktraceSymbolizer::Demangle(symname, true); + info->name = DemangleAlloc(symname, /*always_alloc*/ true); info->start = symval; info->size = symsize; } @@ -156,21 +155,18 @@ LibbacktraceSymbolizer *LibbacktraceSymbolizer::get(LowLevelAllocator *alloc) { return new(*alloc) LibbacktraceSymbolizer(state); } -SymbolizedStack *LibbacktraceSymbolizer::SymbolizeCode(uptr addr, - const char *module_name, - uptr module_offset) { +bool LibbacktraceSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) { SymbolizeCodeCallbackArg data; - data.first = nullptr; - data.last = nullptr; - data.module_name = module_name; - data.module_offset = module_offset; + data.first = stack; + data.last = stack; + data.frames_symbolized = 0; backtrace_pcinfo((backtrace_state *)state_, addr, SymbolizeCodePCInfoCallback, ErrorCallback, &data); - if (data.first) - return data.first; + if (data.frames_symbolized > 0) + return true; backtrace_syminfo((backtrace_state *)state_, addr, SymbolizeCodeCallback, ErrorCallback, &data); - return data.first; + return (data.frames_symbolized > 0); } bool LibbacktraceSymbolizer::SymbolizeData(uptr addr, DataInfo *info) { @@ -185,11 +181,9 @@ LibbacktraceSymbolizer *LibbacktraceSymbolizer::get(LowLevelAllocator *alloc) { return 0; } -SymbolizedStack *LibbacktraceSymbolizer::SymbolizeCode(uptr addr, - const char *module_name, - uptr module_offset) { +bool LibbacktraceSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) { (void)state_; - return nullptr; + return false; } bool LibbacktraceSymbolizer::SymbolizeData(uptr addr, DataInfo *info) { @@ -198,7 +192,7 @@ bool LibbacktraceSymbolizer::SymbolizeData(uptr addr, DataInfo *info) { #endif // SANITIZER_LIBBACKTRACE -char *LibbacktraceSymbolizer::Demangle(const char *name, bool always_alloc) { +static char *DemangleAlloc(const char *name, bool always_alloc) { #if SANITIZER_LIBBACKTRACE && SANITIZER_CP_DEMANGLE if (char *demangled = CplusV3Demangle(name)) return demangled; @@ -208,4 +202,8 @@ char *LibbacktraceSymbolizer::Demangle(const char *name, bool always_alloc) { return 0; } +const char *LibbacktraceSymbolizer::Demangle(const char *name) { + return DemangleAlloc(name, /*always_alloc*/ false); +} + } // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.h b/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.h index 1ff005042..00b465a72 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.h +++ b/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.h @@ -16,7 +16,7 @@ #include "sanitizer_platform.h" #include "sanitizer_common.h" -#include "sanitizer_symbolizer.h" +#include "sanitizer_symbolizer_internal.h" #ifndef SANITIZER_LIBBACKTRACE # define SANITIZER_LIBBACKTRACE 0 @@ -28,17 +28,16 @@ namespace __sanitizer { -class LibbacktraceSymbolizer { +class LibbacktraceSymbolizer : public SymbolizerTool { public: static LibbacktraceSymbolizer *get(LowLevelAllocator *alloc); - SymbolizedStack *SymbolizeCode(uptr addr, const char *module_name, - uptr module_offset); + bool SymbolizePC(uptr addr, SymbolizedStack *stack) override; - bool SymbolizeData(uptr addr, DataInfo *info); + bool SymbolizeData(uptr addr, DataInfo *info) override; // May return NULL if demangling failed. - static char *Demangle(const char *name, bool always_alloc = false); + const char *Demangle(const char *name) override; private: explicit LibbacktraceSymbolizer(void *state) : state_(state) {} diff --git a/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc index 63c9356a5..f1e2289c8 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc @@ -11,18 +11,62 @@ // run-time libraries. //===----------------------------------------------------------------------===// +#include "sanitizer_allocator_internal.h" #include "sanitizer_internal_defs.h" -#include "sanitizer_symbolizer.h" +#include "sanitizer_symbolizer_internal.h" namespace __sanitizer { +const char *ExtractToken(const char *str, const char *delims, char **result) { + uptr prefix_len = internal_strcspn(str, delims); + *result = (char*)InternalAlloc(prefix_len + 1); + internal_memcpy(*result, str, prefix_len); + (*result)[prefix_len] = '\0'; + const char *prefix_end = str + prefix_len; + if (*prefix_end != '\0') prefix_end++; + return prefix_end; +} + +const char *ExtractInt(const char *str, const char *delims, int *result) { + char *buff; + const char *ret = ExtractToken(str, delims, &buff); + if (buff != 0) { + *result = (int)internal_atoll(buff); + } + InternalFree(buff); + return ret; +} + +const char *ExtractUptr(const char *str, const char *delims, uptr *result) { + char *buff; + const char *ret = ExtractToken(str, delims, &buff); + if (buff != 0) { + *result = (uptr)internal_atoll(buff); + } + InternalFree(buff); + return ret; +} + +const char *ExtractTokenUpToDelimiter(const char *str, const char *delimiter, + char **result) { + const char *found_delimiter = internal_strstr(str, delimiter); + uptr prefix_len = + found_delimiter ? found_delimiter - str : internal_strlen(str); + *result = (char *)InternalAlloc(prefix_len + 1); + internal_memcpy(*result, str, prefix_len); + (*result)[prefix_len] = '\0'; + const char *prefix_end = str + prefix_len; + if (*prefix_end != '\0') prefix_end += internal_strlen(delimiter); + return prefix_end; +} + Symbolizer *Symbolizer::GetOrInit() { SpinMutexLock l(&init_mu_); if (symbolizer_) return symbolizer_; - if ((symbolizer_ = PlatformInit())) - return symbolizer_; - return Disable(); + symbolizer_ = PlatformInit(); + CHECK(symbolizer_); + return symbolizer_; } } // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_symbolizer_mac.cc b/lib/sanitizer_common/sanitizer_symbolizer_mac.cc new file mode 100644 index 000000000..c2397ef98 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_symbolizer_mac.cc @@ -0,0 +1,151 @@ +//===-- sanitizer_symbolizer_mac.cc ---------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is shared between various sanitizers' runtime libraries. +// +// Implementation of Mac-specific "atos" symbolizer. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_MAC + +#include "sanitizer_allocator_internal.h" +#include "sanitizer_mac.h" +#include "sanitizer_symbolizer_mac.h" + +namespace __sanitizer { + +#include <dlfcn.h> +#include <errno.h> +#include <stdlib.h> +#include <sys/wait.h> +#include <unistd.h> +#include <util.h> + +bool DlAddrSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) { + Dl_info info; + int result = dladdr((const void *)addr, &info); + if (!result) return false; + const char *demangled = DemangleCXXABI(info.dli_sname); + stack->info.function = internal_strdup(demangled); + return true; +} + +bool DlAddrSymbolizer::SymbolizeData(uptr addr, DataInfo *info) { + return false; +} + +class AtosSymbolizerProcess : public SymbolizerProcess { + public: + explicit AtosSymbolizerProcess(const char *path, pid_t parent_pid) + : SymbolizerProcess(path, /*use_forkpty*/ true), + parent_pid_(parent_pid) {} + + private: + bool ReachedEndOfOutput(const char *buffer, uptr length) const override { + return (length >= 1 && buffer[length - 1] == '\n'); + } + + void ExecuteWithDefaultArgs(const char *path_to_binary) const override { + // The `atos` binary has some issues with DYLD_ROOT_PATH on i386. + unsetenv("DYLD_ROOT_PATH"); + + char pid_str[16]; + internal_snprintf(pid_str, sizeof(pid_str), "%d", parent_pid_); + if (GetMacosVersion() == MACOS_VERSION_MAVERICKS) { + // On Mavericks atos prints a deprecation warning which we suppress by + // passing -d. The warning isn't present on other OSX versions, even the + // newer ones. + execl(path_to_binary, path_to_binary, "-p", pid_str, "-d", (char *)0); + } else { + execl(path_to_binary, path_to_binary, "-p", pid_str, (char *)0); + } + } + + pid_t parent_pid_; +}; + +static const char *kAtosErrorMessages[] = { + "atos cannot examine process", + "unable to get permission to examine process", + "An admin user name and password is required", + "could not load inserted library", + "architecture mismatch between analysis process", +}; + +static bool IsAtosErrorMessage(const char *str) { + for (uptr i = 0; i < ARRAY_SIZE(kAtosErrorMessages); i++) { + if (internal_strstr(str, kAtosErrorMessages[i])) { + return true; + } + } + return false; +} + +static bool ParseCommandOutput(const char *str, SymbolizedStack *res) { + // Trim ending newlines. + char *trim; + ExtractTokenUpToDelimiter(str, "\n", &trim); + + // The line from `atos` is in one of these formats: + // myfunction (in library.dylib) (sourcefile.c:17) + // myfunction (in library.dylib) + 0x1fe + // 0xdeadbeef (in library.dylib) + 0x1fe + // 0xdeadbeef (in library.dylib) + // 0xdeadbeef + + if (IsAtosErrorMessage(trim)) { + Report("atos returned an error: %s\n", trim); + InternalFree(trim); + return false; + } + + const char *rest = trim; + char *function_name; + rest = ExtractTokenUpToDelimiter(rest, " (in ", &function_name); + if (internal_strncmp(function_name, "0x", 2) != 0) + res->info.function = function_name; + else + InternalFree(function_name); + rest = ExtractTokenUpToDelimiter(rest, ") ", &res->info.module); + + if (rest[0] == '(') { + rest++; + rest = ExtractTokenUpToDelimiter(rest, ":", &res->info.file); + char *extracted_line_number; + rest = ExtractTokenUpToDelimiter(rest, ")", &extracted_line_number); + res->info.line = internal_atoll(extracted_line_number); + InternalFree(extracted_line_number); + } + + InternalFree(trim); + return true; +} + +AtosSymbolizer::AtosSymbolizer(const char *path, LowLevelAllocator *allocator) + : process_(new(*allocator) AtosSymbolizerProcess(path, getpid())) {} + +bool AtosSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) { + if (!process_) return false; + char command[32]; + internal_snprintf(command, sizeof(command), "0x%zx\n", addr); + const char *buf = process_->SendCommand(command); + if (!buf) return false; + if (!ParseCommandOutput(buf, stack)) { + process_ = nullptr; + return false; + } + return true; +} + +bool AtosSymbolizer::SymbolizeData(uptr addr, DataInfo *info) { return false; } + +} // namespace __sanitizer + +#endif // SANITIZER_MAC diff --git a/lib/sanitizer_common/sanitizer_symbolizer_mac.h b/lib/sanitizer_common/sanitizer_symbolizer_mac.h new file mode 100644 index 000000000..068644de3 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_symbolizer_mac.h @@ -0,0 +1,48 @@ +//===-- sanitizer_symbolizer_mac.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 shared between various sanitizers' runtime libraries. +// +// Header for Mac-specific "atos" symbolizer. +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_SYMBOLIZER_MAC_H +#define SANITIZER_SYMBOLIZER_MAC_H + +#include "sanitizer_platform.h" +#if SANITIZER_MAC + +#include "sanitizer_symbolizer_internal.h" + +namespace __sanitizer { + +class DlAddrSymbolizer : public SymbolizerTool { + public: + bool SymbolizePC(uptr addr, SymbolizedStack *stack) override; + bool SymbolizeData(uptr addr, DataInfo *info) override; +}; + +class AtosSymbolizerProcess; + +class AtosSymbolizer : public SymbolizerTool { + public: + explicit AtosSymbolizer(const char *path, LowLevelAllocator *allocator); + + bool SymbolizePC(uptr addr, SymbolizedStack *stack) override; + bool SymbolizeData(uptr addr, DataInfo *info) override; + + private: + AtosSymbolizerProcess *process_; +}; + +} // namespace __sanitizer + +#endif // SANITIZER_MAC + +#endif // SANITIZER_SYMBOLIZER_MAC_H diff --git a/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc index deb3429b0..189b0abd8 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc @@ -21,12 +21,10 @@ #include "sanitizer_linux.h" #include "sanitizer_placement_new.h" #include "sanitizer_procmaps.h" -#include "sanitizer_symbolizer.h" +#include "sanitizer_symbolizer_internal.h" #include "sanitizer_symbolizer_libbacktrace.h" +#include "sanitizer_symbolizer_mac.h" -#include <errno.h> -#include <stdlib.h> -#include <sys/wait.h> #include <unistd.h> // C++ demangling function, as required by Itanium C++ ABI. This is weak, @@ -41,7 +39,7 @@ namespace __cxxabiv1 { namespace __sanitizer { // Attempts to demangle the name via __cxa_demangle from __cxxabiv1. -static const char *DemangleCXXABI(const char *name) { +const char *DemangleCXXABI(const char *name) { // FIXME: __cxa_demangle aggressively insists on allocating memory. // There's not much we can do about that, short of providing our // own demangler (libc++abi's implementation could be adapted so that @@ -55,217 +53,6 @@ static const char *DemangleCXXABI(const char *name) { return name; } -// Extracts the prefix of "str" that consists of any characters not -// present in "delims" string, and copies this prefix to "result", allocating -// space for it. -// Returns a pointer to "str" after skipping extracted prefix and first -// delimiter char. -static const char *ExtractToken(const char *str, const char *delims, - char **result) { - uptr prefix_len = internal_strcspn(str, delims); - *result = (char*)InternalAlloc(prefix_len + 1); - internal_memcpy(*result, str, prefix_len); - (*result)[prefix_len] = '\0'; - const char *prefix_end = str + prefix_len; - if (*prefix_end != '\0') prefix_end++; - return prefix_end; -} - -// Same as ExtractToken, but converts extracted token to integer. -static const char *ExtractInt(const char *str, const char *delims, - int *result) { - char *buff; - const char *ret = ExtractToken(str, delims, &buff); - if (buff != 0) { - *result = (int)internal_atoll(buff); - } - InternalFree(buff); - return ret; -} - -static const char *ExtractUptr(const char *str, const char *delims, - uptr *result) { - char *buff; - const char *ret = ExtractToken(str, delims, &buff); - if (buff != 0) { - *result = (uptr)internal_atoll(buff); - } - InternalFree(buff); - return ret; -} - -SymbolizerProcess::SymbolizerProcess(const char *path) - : path_(path), - input_fd_(kInvalidFd), - output_fd_(kInvalidFd), - times_restarted_(0), - failed_to_start_(false), - reported_invalid_path_(false) { - CHECK(path_); - CHECK_NE(path_[0], '\0'); -} - -char *SymbolizerProcess::SendCommand(bool is_data, const char *module_name, - uptr module_offset) { - for (; times_restarted_ < kMaxTimesRestarted; times_restarted_++) { - // Start or restart symbolizer if we failed to send command to it. - if (char *res = SendCommandImpl(is_data, module_name, module_offset)) - return res; - Restart(); - } - if (!failed_to_start_) { - Report("WARNING: Failed to use and restart external symbolizer!\n"); - failed_to_start_ = true; - } - return 0; -} - -bool SymbolizerProcess::Restart() { - if (input_fd_ != kInvalidFd) - internal_close(input_fd_); - if (output_fd_ != kInvalidFd) - internal_close(output_fd_); - return StartSymbolizerSubprocess(); -} - -char *SymbolizerProcess::SendCommandImpl(bool is_data, const char *module_name, - uptr module_offset) { - if (input_fd_ == kInvalidFd || output_fd_ == kInvalidFd) - return 0; - CHECK(module_name); - if (!RenderInputCommand(buffer_, kBufferSize, is_data, module_name, - module_offset)) - return 0; - if (!WriteToSymbolizer(buffer_, internal_strlen(buffer_))) - return 0; - if (!ReadFromSymbolizer(buffer_, kBufferSize)) - return 0; - return buffer_; -} - -bool SymbolizerProcess::ReadFromSymbolizer(char *buffer, uptr max_length) { - if (max_length == 0) - return true; - uptr read_len = 0; - while (true) { - uptr just_read = internal_read(input_fd_, buffer + read_len, - max_length - read_len - 1); - // We can't read 0 bytes, as we don't expect external symbolizer to close - // its stdout. - if (just_read == 0 || just_read == (uptr)-1) { - Report("WARNING: Can't read from symbolizer at fd %d\n", input_fd_); - return false; - } - read_len += just_read; - if (ReachedEndOfOutput(buffer, read_len)) - break; - } - buffer[read_len] = '\0'; - return true; -} - -bool SymbolizerProcess::WriteToSymbolizer(const char *buffer, uptr length) { - if (length == 0) - return true; - uptr write_len = internal_write(output_fd_, buffer, length); - if (write_len == 0 || write_len == (uptr)-1) { - Report("WARNING: Can't write to symbolizer at fd %d\n", output_fd_); - return false; - } - return true; -} - -bool SymbolizerProcess::StartSymbolizerSubprocess() { - if (!FileExists(path_)) { - if (!reported_invalid_path_) { - Report("WARNING: invalid path to external symbolizer!\n"); - reported_invalid_path_ = true; - } - return false; - } - - int *infd = NULL; - int *outfd = NULL; - // The client program may close its stdin and/or stdout and/or stderr - // thus allowing socketpair to reuse file descriptors 0, 1 or 2. - // In this case the communication between the forked processes may be - // broken if either the parent or the child tries to close or duplicate - // these descriptors. The loop below produces two pairs of file - // descriptors, each greater than 2 (stderr). - int sock_pair[5][2]; - for (int i = 0; i < 5; i++) { - if (pipe(sock_pair[i]) == -1) { - for (int j = 0; j < i; j++) { - internal_close(sock_pair[j][0]); - internal_close(sock_pair[j][1]); - } - Report("WARNING: Can't create a socket pair to start " - "external symbolizer (errno: %d)\n", errno); - return false; - } else if (sock_pair[i][0] > 2 && sock_pair[i][1] > 2) { - if (infd == NULL) { - infd = sock_pair[i]; - } else { - outfd = sock_pair[i]; - for (int j = 0; j < i; j++) { - if (sock_pair[j] == infd) continue; - internal_close(sock_pair[j][0]); - internal_close(sock_pair[j][1]); - } - break; - } - } - } - CHECK(infd); - CHECK(outfd); - - // Real fork() may call user callbacks registered with pthread_atfork(). - int pid = internal_fork(); - if (pid == -1) { - // Fork() failed. - internal_close(infd[0]); - internal_close(infd[1]); - internal_close(outfd[0]); - internal_close(outfd[1]); - Report("WARNING: failed to fork external symbolizer " - " (errno: %d)\n", errno); - return false; - } else if (pid == 0) { - // Child subprocess. - internal_close(STDOUT_FILENO); - internal_close(STDIN_FILENO); - internal_dup2(outfd[0], STDIN_FILENO); - internal_dup2(infd[1], STDOUT_FILENO); - internal_close(outfd[0]); - internal_close(outfd[1]); - internal_close(infd[0]); - internal_close(infd[1]); - for (int fd = sysconf(_SC_OPEN_MAX); fd > 2; fd--) - internal_close(fd); - ExecuteWithDefaultArgs(path_); - internal__exit(1); - } - - // Continue execution in parent process. - internal_close(outfd[0]); - internal_close(infd[1]); - input_fd_ = infd[0]; - output_fd_ = outfd[1]; - - // Check that symbolizer subprocess started successfully. - int pid_status; - SleepForMillis(kSymbolizerStartupTimeMillis); - int exited_pid = waitpid(pid, &pid_status, WNOHANG); - if (exited_pid != 0) { - // Either waitpid failed, or child has already exited. - Report("WARNING: external symbolizer didn't start up correctly!\n"); - return false; - } - - return true; -} - - // Parses one or more two-line strings in the following format: // <function_name> // <file_name>:<line_number>[:<column_number>] @@ -288,8 +75,7 @@ static void ParseSymbolizePCOutput(const char *str, SymbolizedStack *res) { top_frame = false; } else { cur = SymbolizedStack::New(res->info.address); - cur->info.FillAddressAndModuleInfo(res->info.address, res->info.module, - res->info.module_offset); + cur->info.FillModuleInfo(res->info.module, res->info.module_offset); last->next = cur; last = cur; } @@ -343,13 +129,6 @@ class LLVMSymbolizerProcess : public SymbolizerProcess { explicit LLVMSymbolizerProcess(const char *path) : SymbolizerProcess(path) {} private: - bool RenderInputCommand(char *buffer, uptr max_length, bool is_data, - const char *module_name, uptr module_offset) const { - internal_snprintf(buffer, max_length, "%s\"%s\" 0x%zx\n", - is_data ? "DATA " : "", module_name, module_offset); - return true; - } - bool ReachedEndOfOutput(const char *buffer, uptr length) const { // Empty line marks the end of llvm-symbolizer output. return length >= 2 && buffer[length - 1] == '\n' && @@ -377,6 +156,44 @@ class LLVMSymbolizerProcess : public SymbolizerProcess { } }; +class LLVMSymbolizer : public SymbolizerTool { + public: + explicit LLVMSymbolizer(const char *path, LowLevelAllocator *allocator) + : symbolizer_process_(new(*allocator) LLVMSymbolizerProcess(path)) {} + + bool SymbolizePC(uptr addr, SymbolizedStack *stack) override { + if (const char *buf = SendCommand(/*is_data*/ false, stack->info.module, + stack->info.module_offset)) { + ParseSymbolizePCOutput(buf, stack); + return true; + } + return false; + } + + bool SymbolizeData(uptr addr, DataInfo *info) override { + if (const char *buf = + SendCommand(/*is_data*/ true, info->module, info->module_offset)) { + ParseSymbolizeDataOutput(buf, info); + info->start += (addr - info->module_offset); // Add the base address. + return true; + } + return false; + } + + private: + const char *SendCommand(bool is_data, const char *module_name, + uptr module_offset) { + CHECK(module_name); + internal_snprintf(buffer_, kBufferSize, "%s\"%s\" 0x%zx\n", + is_data ? "DATA " : "", module_name, module_offset); + return symbolizer_process_->SendCommand(buffer_); + } + + LLVMSymbolizerProcess *symbolizer_process_; + static const uptr kBufferSize = 16 * 1024; + char buffer_[kBufferSize]; +}; + class Addr2LineProcess : public SymbolizerProcess { public: Addr2LineProcess(const char *path, const char *module_name) @@ -385,15 +202,6 @@ class Addr2LineProcess : public SymbolizerProcess { const char *module_name() const { return module_name_; } private: - bool RenderInputCommand(char *buffer, uptr max_length, bool is_data, - const char *module_name, uptr module_offset) const { - if (is_data) - return false; - CHECK_EQ(0, internal_strcmp(module_name, module_name_)); - internal_snprintf(buffer, max_length, "0x%zx\n", module_offset); - return true; - } - bool ReachedEndOfOutput(const char *buffer, uptr length) const { // Output should consist of two lines. int num_lines = 0; @@ -413,16 +221,28 @@ class Addr2LineProcess : public SymbolizerProcess { const char *module_name_; // Owned, leaked. }; -class Addr2LinePool : public ExternalSymbolizerInterface { +class Addr2LinePool : public SymbolizerTool { public: explicit Addr2LinePool(const char *addr2line_path, LowLevelAllocator *allocator) : addr2line_path_(addr2line_path), allocator_(allocator), addr2line_pool_(16) {} - char *SendCommand(bool is_data, const char *module_name, uptr module_offset) { - if (is_data) - return 0; + bool SymbolizePC(uptr addr, SymbolizedStack *stack) override { + if (const char *buf = + SendCommand(stack->info.module, stack->info.module_offset)) { + ParseSymbolizePCOutput(buf, stack); + return true; + } + return false; + } + + bool SymbolizeData(uptr addr, DataInfo *info) override { + return false; + } + + private: + const char *SendCommand(const char *module_name, uptr module_offset) { Addr2LineProcess *addr2line = 0; for (uptr i = 0; i < addr2line_pool_.size(); ++i) { if (0 == @@ -436,10 +256,13 @@ class Addr2LinePool : public ExternalSymbolizerInterface { new(*allocator_) Addr2LineProcess(addr2line_path_, module_name); addr2line_pool_.push_back(addr2line); } - return addr2line->SendCommand(is_data, module_name, module_offset); + CHECK_EQ(0, internal_strcmp(module_name, addr2line->module_name())); + char buffer_[kBufferSize]; + internal_snprintf(buffer_, kBufferSize, "0x%zx\n", module_offset); + return addr2line->SendCommand(buffer_); } - private: + static const uptr kBufferSize = 32; const char *addr2line_path_; LowLevelAllocator *allocator_; InternalMmapVector<Addr2LineProcess*> addr2line_pool_; @@ -460,10 +283,8 @@ int __sanitizer_symbolize_demangle(const char *Name, char *Buffer, int MaxLength); } // extern "C" -class InternalSymbolizer { +class InternalSymbolizer : public SymbolizerTool { public: - typedef bool (*SanitizerSymbolizeFn)(const char*, u64, char*, int); - static InternalSymbolizer *get(LowLevelAllocator *alloc) { if (__sanitizer_symbolize_code != 0 && __sanitizer_symbolize_data != 0) { @@ -472,20 +293,29 @@ class InternalSymbolizer { return 0; } - char *SendCommand(bool is_data, const char *module_name, uptr module_offset) { - SanitizerSymbolizeFn symbolize_fn = is_data ? __sanitizer_symbolize_data - : __sanitizer_symbolize_code; - if (symbolize_fn(module_name, module_offset, buffer_, kBufferSize)) - return buffer_; - return 0; + bool SymbolizePC(uptr addr, SymbolizedStack *stack) override { + bool result = __sanitizer_symbolize_code( + stack->info.module, stack->info.module_offset, buffer_, kBufferSize); + if (result) ParseSymbolizePCOutput(buffer_, stack); + return result; + } + + bool SymbolizeData(uptr addr, DataInfo *info) override { + bool result = __sanitizer_symbolize_data(info->module, info->module_offset, + buffer_, kBufferSize); + if (result) { + ParseSymbolizeDataOutput(buffer_, info); + info->start += (addr - info->module_offset); // Add the base address. + } + return result; } - void Flush() { + void Flush() override { if (__sanitizer_symbolize_flush) __sanitizer_symbolize_flush(); } - const char *Demangle(const char *name) { + const char *Demangle(const char *name) override { if (__sanitizer_symbolize_demangle) { for (uptr res_length = 1024; res_length <= InternalSizeClassMap::kMaxSize;) { @@ -512,146 +342,35 @@ class InternalSymbolizer { }; #else // SANITIZER_SUPPORTS_WEAK_HOOKS -class InternalSymbolizer { +class InternalSymbolizer : public SymbolizerTool { public: static InternalSymbolizer *get(LowLevelAllocator *alloc) { return 0; } - char *SendCommand(bool is_data, const char *module_name, uptr module_offset) { - return 0; - } - void Flush() { } - const char *Demangle(const char *name) { return name; } }; #endif // SANITIZER_SUPPORTS_WEAK_HOOKS class POSIXSymbolizer : public Symbolizer { public: - POSIXSymbolizer(ExternalSymbolizerInterface *external_symbolizer, - InternalSymbolizer *internal_symbolizer, - LibbacktraceSymbolizer *libbacktrace_symbolizer) - : Symbolizer(), - external_symbolizer_(external_symbolizer), - internal_symbolizer_(internal_symbolizer), - libbacktrace_symbolizer_(libbacktrace_symbolizer) {} - - SymbolizedStack *SymbolizePC(uptr addr) override { - BlockingMutexLock l(&mu_); - const char *module_name; - uptr module_offset; - if (!FindModuleNameAndOffsetForAddress(addr, &module_name, &module_offset)) - return SymbolizedStack::New(addr); - // First, try to use libbacktrace symbolizer (if it's available). - if (libbacktrace_symbolizer_ != 0) { - mu_.CheckLocked(); - if (SymbolizedStack *res = libbacktrace_symbolizer_->SymbolizeCode( - addr, module_name, module_offset)) - return res; - } - // Always fill data about module name and offset. - SymbolizedStack *res = SymbolizedStack::New(addr); - res->info.FillAddressAndModuleInfo(addr, module_name, module_offset); - - const char *str = SendCommand(false, module_name, module_offset); - if (str == 0) { - // Symbolizer was not initialized or failed. - return res; - } - - ParseSymbolizePCOutput(str, res); - return res; - } - - bool SymbolizeData(uptr addr, DataInfo *info) override { - BlockingMutexLock l(&mu_); - LoadedModule *module = FindModuleForAddress(addr); - if (module == 0) - return false; - const char *module_name = module->full_name(); - uptr module_offset = addr - module->base_address(); - info->Clear(); - info->module = internal_strdup(module_name); - info->module_offset = module_offset; - // First, try to use libbacktrace symbolizer (if it's available). - if (libbacktrace_symbolizer_ != 0) { - mu_.CheckLocked(); - if (libbacktrace_symbolizer_->SymbolizeData(addr, info)) - return true; - } - const char *str = SendCommand(true, module_name, module_offset); - if (str == 0) - return true; - ParseSymbolizeDataOutput(str, info); - info->start += module->base_address(); - return true; - } - - bool GetModuleNameAndOffsetForPC(uptr pc, const char **module_name, - uptr *module_address) override { - BlockingMutexLock l(&mu_); - return FindModuleNameAndOffsetForAddress(pc, module_name, module_address); - } - - bool CanReturnFileLineInfo() override { - return internal_symbolizer_ != 0 || external_symbolizer_ != 0 || - libbacktrace_symbolizer_ != 0; - } - - void Flush() override { - BlockingMutexLock l(&mu_); - if (internal_symbolizer_ != 0) { - SymbolizerScope sym_scope(this); - internal_symbolizer_->Flush(); - } - } + explicit POSIXSymbolizer(IntrusiveList<SymbolizerTool> tools) + : Symbolizer(tools), n_modules_(0), modules_fresh_(false) {} - const char *Demangle(const char *name) override { - BlockingMutexLock l(&mu_); - // Run hooks even if we don't use internal symbolizer, as cxxabi - // demangle may call system functions. - SymbolizerScope sym_scope(this); - // Try to use libbacktrace demangler (if available). - if (libbacktrace_symbolizer_ != 0) { - if (const char *demangled = libbacktrace_symbolizer_->Demangle(name)) - return demangled; - } - if (internal_symbolizer_ != 0) - return internal_symbolizer_->Demangle(name); + private: + const char *PlatformDemangle(const char *name) override { return DemangleCXXABI(name); } - void PrepareForSandboxing() override { + void PlatformPrepareForSandboxing() override { #if SANITIZER_LINUX && !SANITIZER_ANDROID - BlockingMutexLock l(&mu_); // Cache /proc/self/exe on Linux. CacheBinaryName(); #endif } - private: - char *SendCommand(bool is_data, const char *module_name, uptr module_offset) { - mu_.CheckLocked(); - // First, try to use internal symbolizer. - if (internal_symbolizer_) { - SymbolizerScope sym_scope(this); - return internal_symbolizer_->SendCommand(is_data, module_name, - module_offset); - } - // Otherwise, fall back to external symbolizer. - if (external_symbolizer_) { - SymbolizerScope sym_scope(this); - return external_symbolizer_->SendCommand(is_data, module_name, - module_offset); - } - return 0; - } - LoadedModule *FindModuleForAddress(uptr address) { - mu_.CheckLocked(); bool modules_were_reloaded = false; - if (modules_ == 0 || !modules_fresh_) { - modules_ = (LoadedModule*)(symbolizer_allocator_.Allocate( - kMaxNumberOfModuleContexts * sizeof(LoadedModule))); - CHECK(modules_); + if (!modules_fresh_) { + for (uptr i = 0; i < n_modules_; i++) + modules_[i].clear(); n_modules_ = GetListOfModules(modules_, kMaxNumberOfModuleContexts, /* filter */ 0); CHECK_GT(n_modules_, 0); @@ -675,9 +394,9 @@ class POSIXSymbolizer : public Symbolizer { return 0; } - bool FindModuleNameAndOffsetForAddress(uptr address, const char **module_name, - uptr *module_offset) { - mu_.CheckLocked(); + bool PlatformFindModuleNameAndOffsetForAddress(uptr address, + const char **module_name, + uptr *module_offset) override { LoadedModule *module = FindModuleForAddress(address); if (module == 0) return false; @@ -688,53 +407,94 @@ class POSIXSymbolizer : public Symbolizer { // 16K loaded modules should be enough for everyone. static const uptr kMaxNumberOfModuleContexts = 1 << 14; - LoadedModule *modules_; // Array of module descriptions is leaked. + LoadedModule modules_[kMaxNumberOfModuleContexts]; uptr n_modules_; // If stale, need to reload the modules before looking up addresses. bool modules_fresh_; - BlockingMutex mu_; - - ExternalSymbolizerInterface *external_symbolizer_; // Leaked. - InternalSymbolizer *const internal_symbolizer_; // Leaked. - LibbacktraceSymbolizer *libbacktrace_symbolizer_; // Leaked. }; -Symbolizer *Symbolizer::PlatformInit() { +static SymbolizerTool *ChooseExternalSymbolizer(LowLevelAllocator *allocator) { + const char *path = common_flags()->external_symbolizer_path; + const char *binary_name = path ? StripModuleName(path) : ""; + if (path && path[0] == '\0') { + VReport(2, "External symbolizer is explicitly disabled.\n"); + return nullptr; + } else if (!internal_strcmp(binary_name, "llvm-symbolizer")) { + VReport(2, "Using llvm-symbolizer at user-specified path: %s\n", path); + return new(*allocator) LLVMSymbolizer(path, allocator); + } else if (!internal_strcmp(binary_name, "atos")) { +#if SANITIZER_MAC + VReport(2, "Using atos at user-specified path: %s\n", path); + return new(*allocator) AtosSymbolizer(path, allocator); +#else // SANITIZER_MAC + Report("ERROR: Using `atos` is only supported on Darwin.\n"); + Die(); +#endif // SANITIZER_MAC + } else if (!internal_strcmp(binary_name, "addr2line")) { + VReport(2, "Using addr2line at user-specified path: %s\n", path); + return new(*allocator) Addr2LinePool(path, allocator); + } else if (path) { + Report("ERROR: External symbolizer path is set to '%s' which isn't " + "a known symbolizer. Please set the path to the llvm-symbolizer " + "binary or other known tool.\n", path); + Die(); + } + + // Otherwise symbolizer program is unknown, let's search $PATH + CHECK(path == nullptr); + if (const char *found_path = FindPathToBinary("llvm-symbolizer")) { + VReport(2, "Using llvm-symbolizer found at: %s\n", found_path); + return new(*allocator) LLVMSymbolizer(found_path, allocator); + } +#if SANITIZER_MAC + if (const char *found_path = FindPathToBinary("atos")) { + VReport(2, "Using atos found at: %s\n", found_path); + return new(*allocator) AtosSymbolizer(found_path, allocator); + } +#endif // SANITIZER_MAC + if (common_flags()->allow_addr2line) { + if (const char *found_path = FindPathToBinary("addr2line")) { + VReport(2, "Using addr2line found at: %s\n", found_path); + return new(*allocator) Addr2LinePool(found_path, allocator); + } + } + return nullptr; +} + +static void ChooseSymbolizerTools(IntrusiveList<SymbolizerTool> *list, + LowLevelAllocator *allocator) { if (!common_flags()->symbolize) { - return new(symbolizer_allocator_) POSIXSymbolizer(0, 0, 0); + VReport(2, "Symbolizer is disabled.\n"); + return; } - InternalSymbolizer* internal_symbolizer = - InternalSymbolizer::get(&symbolizer_allocator_); - ExternalSymbolizerInterface *external_symbolizer = 0; - LibbacktraceSymbolizer *libbacktrace_symbolizer = 0; - - if (!internal_symbolizer) { - libbacktrace_symbolizer = - LibbacktraceSymbolizer::get(&symbolizer_allocator_); - if (!libbacktrace_symbolizer) { - const char *path_to_external = common_flags()->external_symbolizer_path; - if (path_to_external && path_to_external[0] == '\0') { - // External symbolizer is explicitly disabled. Do nothing. - } else { - // Find path to llvm-symbolizer if it's not provided. - if (!path_to_external) - path_to_external = FindPathToBinary("llvm-symbolizer"); - if (path_to_external) { - external_symbolizer = new(symbolizer_allocator_) - LLVMSymbolizerProcess(path_to_external); - } else if (common_flags()->allow_addr2line) { - // If llvm-symbolizer is not found, try to use addr2line. - if (const char *addr2line_path = FindPathToBinary("addr2line")) { - external_symbolizer = new(symbolizer_allocator_) - Addr2LinePool(addr2line_path, &symbolizer_allocator_); - } - } - } - } + if (SymbolizerTool *tool = InternalSymbolizer::get(allocator)) { + VReport(2, "Using internal symbolizer.\n"); + list->push_back(tool); + return; + } + if (SymbolizerTool *tool = LibbacktraceSymbolizer::get(allocator)) { + VReport(2, "Using libbacktrace symbolizer.\n"); + list->push_back(tool); + return; } - return new(symbolizer_allocator_) POSIXSymbolizer( - external_symbolizer, internal_symbolizer, libbacktrace_symbolizer); + if (SymbolizerTool *tool = ChooseExternalSymbolizer(allocator)) { + list->push_back(tool); + } else { + VReport(2, "No internal or external symbolizer found.\n"); + } + +#if SANITIZER_MAC + VReport(2, "Using dladdr symbolizer.\n"); + list->push_back(new(*allocator) DlAddrSymbolizer()); +#endif // SANITIZER_MAC +} + +Symbolizer *Symbolizer::PlatformInit() { + IntrusiveList<SymbolizerTool> list; + list.clear(); + ChooseSymbolizerTools(&list, &symbolizer_allocator_); + return new(symbolizer_allocator_) POSIXSymbolizer(list); } } // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_symbolizer_process_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_process_libcdep.cc new file mode 100644 index 000000000..98d16e04e --- /dev/null +++ b/lib/sanitizer_common/sanitizer_symbolizer_process_libcdep.cc @@ -0,0 +1,228 @@ +//===-- sanitizer_symbolizer_process_libcdep.cc ---------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Implementation of SymbolizerProcess used by external symbolizers. +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_POSIX +#include "sanitizer_symbolizer_internal.h" + +#include <errno.h> +#include <stdlib.h> +#include <sys/wait.h> +#include <unistd.h> + +#if SANITIZER_MAC +#include <util.h> // for forkpty() +#endif // SANITIZER_MAC + +namespace __sanitizer { + +SymbolizerProcess::SymbolizerProcess(const char *path, bool use_forkpty) + : path_(path), + input_fd_(kInvalidFd), + output_fd_(kInvalidFd), + times_restarted_(0), + failed_to_start_(false), + reported_invalid_path_(false), + use_forkpty_(use_forkpty) { + CHECK(path_); + CHECK_NE(path_[0], '\0'); +} + +const char *SymbolizerProcess::SendCommand(const char *command) { + for (; times_restarted_ < kMaxTimesRestarted; times_restarted_++) { + // Start or restart symbolizer if we failed to send command to it. + if (const char *res = SendCommandImpl(command)) + return res; + Restart(); + } + if (!failed_to_start_) { + Report("WARNING: Failed to use and restart external symbolizer!\n"); + failed_to_start_ = true; + } + return 0; +} + +bool SymbolizerProcess::Restart() { + if (input_fd_ != kInvalidFd) + internal_close(input_fd_); + if (output_fd_ != kInvalidFd) + internal_close(output_fd_); + return StartSymbolizerSubprocess(); +} + +const char *SymbolizerProcess::SendCommandImpl(const char *command) { + if (input_fd_ == kInvalidFd || output_fd_ == kInvalidFd) + return 0; + if (!WriteToSymbolizer(command, internal_strlen(command))) + return 0; + if (!ReadFromSymbolizer(buffer_, kBufferSize)) + return 0; + return buffer_; +} + +bool SymbolizerProcess::ReadFromSymbolizer(char *buffer, uptr max_length) { + if (max_length == 0) + return true; + uptr read_len = 0; + while (true) { + uptr just_read = internal_read(input_fd_, buffer + read_len, + max_length - read_len - 1); + // We can't read 0 bytes, as we don't expect external symbolizer to close + // its stdout. + if (just_read == 0 || just_read == (uptr)-1) { + Report("WARNING: Can't read from symbolizer at fd %d\n", input_fd_); + return false; + } + read_len += just_read; + if (ReachedEndOfOutput(buffer, read_len)) + break; + } + buffer[read_len] = '\0'; + return true; +} + +bool SymbolizerProcess::WriteToSymbolizer(const char *buffer, uptr length) { + if (length == 0) + return true; + uptr write_len = internal_write(output_fd_, buffer, length); + if (write_len == 0 || write_len == (uptr)-1) { + Report("WARNING: Can't write to symbolizer at fd %d\n", output_fd_); + return false; + } + return true; +} + +bool SymbolizerProcess::StartSymbolizerSubprocess() { + if (!FileExists(path_)) { + if (!reported_invalid_path_) { + Report("WARNING: invalid path to external symbolizer!\n"); + reported_invalid_path_ = true; + } + return false; + } + + int pid; + if (use_forkpty_) { +#if SANITIZER_MAC + fd_t fd = kInvalidFd; + // Use forkpty to disable buffering in the new terminal. + pid = forkpty(&fd, 0, 0, 0); + if (pid == -1) { + // forkpty() failed. + Report("WARNING: failed to fork external symbolizer (errno: %d)\n", + errno); + return false; + } else if (pid == 0) { + // Child subprocess. + ExecuteWithDefaultArgs(path_); + internal__exit(1); + } + + // Continue execution in parent process. + input_fd_ = output_fd_ = fd; + + // Disable echo in the new terminal, disable CR. + struct termios termflags; + tcgetattr(fd, &termflags); + termflags.c_oflag &= ~ONLCR; + termflags.c_lflag &= ~ECHO; + tcsetattr(fd, TCSANOW, &termflags); +#else // SANITIZER_MAC + UNIMPLEMENTED(); +#endif // SANITIZER_MAC + } else { + int *infd = NULL; + int *outfd = NULL; + // The client program may close its stdin and/or stdout and/or stderr + // thus allowing socketpair to reuse file descriptors 0, 1 or 2. + // In this case the communication between the forked processes may be + // broken if either the parent or the child tries to close or duplicate + // these descriptors. The loop below produces two pairs of file + // descriptors, each greater than 2 (stderr). + int sock_pair[5][2]; + for (int i = 0; i < 5; i++) { + if (pipe(sock_pair[i]) == -1) { + for (int j = 0; j < i; j++) { + internal_close(sock_pair[j][0]); + internal_close(sock_pair[j][1]); + } + Report("WARNING: Can't create a socket pair to start " + "external symbolizer (errno: %d)\n", errno); + return false; + } else if (sock_pair[i][0] > 2 && sock_pair[i][1] > 2) { + if (infd == NULL) { + infd = sock_pair[i]; + } else { + outfd = sock_pair[i]; + for (int j = 0; j < i; j++) { + if (sock_pair[j] == infd) continue; + internal_close(sock_pair[j][0]); + internal_close(sock_pair[j][1]); + } + break; + } + } + } + CHECK(infd); + CHECK(outfd); + + // Real fork() may call user callbacks registered with pthread_atfork(). + pid = internal_fork(); + if (pid == -1) { + // Fork() failed. + internal_close(infd[0]); + internal_close(infd[1]); + internal_close(outfd[0]); + internal_close(outfd[1]); + Report("WARNING: failed to fork external symbolizer " + " (errno: %d)\n", errno); + return false; + } else if (pid == 0) { + // Child subprocess. + internal_close(STDOUT_FILENO); + internal_close(STDIN_FILENO); + internal_dup2(outfd[0], STDIN_FILENO); + internal_dup2(infd[1], STDOUT_FILENO); + internal_close(outfd[0]); + internal_close(outfd[1]); + internal_close(infd[0]); + internal_close(infd[1]); + for (int fd = sysconf(_SC_OPEN_MAX); fd > 2; fd--) + internal_close(fd); + ExecuteWithDefaultArgs(path_); + internal__exit(1); + } + + // Continue execution in parent process. + internal_close(outfd[0]); + internal_close(infd[1]); + input_fd_ = infd[0]; + output_fd_ = outfd[1]; + } + + // Check that symbolizer subprocess started successfully. + int pid_status; + SleepForMillis(kSymbolizerStartupTimeMillis); + int exited_pid = waitpid(pid, &pid_status, WNOHANG); + if (exited_pid != 0) { + // Either waitpid failed, or child has already exited. + Report("WARNING: external symbolizer didn't start up correctly!\n"); + return false; + } + + return true; +} + +} // namespace __sanitizer + +#endif // SANITIZER_POSIX diff --git a/lib/sanitizer_common/sanitizer_symbolizer_win.cc b/lib/sanitizer_common/sanitizer_symbolizer_win.cc index ed96a3a89..67ed4b325 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer_win.cc +++ b/lib/sanitizer_common/sanitizer_symbolizer_win.cc @@ -18,139 +18,153 @@ #include <dbghelp.h> #pragma comment(lib, "dbghelp.lib") -#include "sanitizer_symbolizer.h" +#include "sanitizer_symbolizer_win.h" +#include "sanitizer_symbolizer_internal.h" namespace __sanitizer { -class WinSymbolizer : public Symbolizer { - public: - WinSymbolizer() : initialized_(false) {} - - SymbolizedStack *SymbolizePC(uptr addr) override { - SymbolizedStack *frame = SymbolizedStack::New(addr); - - BlockingMutexLock l(&dbghelp_mu_); - InitializeIfNeeded(); - - // See http://msdn.microsoft.com/en-us/library/ms680578(VS.85).aspx - char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(CHAR)]; - PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer; - symbol->SizeOfStruct = sizeof(SYMBOL_INFO); - symbol->MaxNameLen = MAX_SYM_NAME; - DWORD64 offset = 0; - BOOL got_objname = SymFromAddr(GetCurrentProcess(), - (DWORD64)addr, &offset, symbol); - if (!got_objname) - return frame; - - DWORD unused; - IMAGEHLP_LINE64 line_info; - line_info.SizeOfStruct = sizeof(IMAGEHLP_LINE64); - BOOL got_fileline = SymGetLineFromAddr64(GetCurrentProcess(), (DWORD64)addr, - &unused, &line_info); - frame->info.function = internal_strdup(symbol->Name); - frame->info.function_offset = (uptr)offset; - if (got_fileline) { - frame->info.file = internal_strdup(line_info.FileName); - frame->info.line = line_info.LineNumber; - } - - IMAGEHLP_MODULE64 mod_info; - internal_memset(&mod_info, 0, sizeof(mod_info)); - mod_info.SizeOfStruct = sizeof(mod_info); - if (SymGetModuleInfo64(GetCurrentProcess(), addr, &mod_info)) - frame->info.FillAddressAndModuleInfo(addr, mod_info.ImageName, - addr - (uptr)mod_info.BaseOfImage); - return frame; - } +namespace { - bool CanReturnFileLineInfo() override { - return true; +bool is_dbghelp_initialized = false; + +bool TrySymInitialize() { + SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME | SYMOPT_LOAD_LINES); + return SymInitialize(GetCurrentProcess(), 0, TRUE); + // FIXME: We don't call SymCleanup() on exit yet - should we? +} + +// Initializes DbgHelp library, if it's not yet initialized. Calls to this +// function should be synchronized with respect to other calls to DbgHelp API +// (e.g. from WinSymbolizerTool). +void InitializeDbgHelpIfNeeded() { + if (is_dbghelp_initialized) + return; + if (!TrySymInitialize()) { + // OK, maybe the client app has called SymInitialize already. + // That's a bit unfortunate for us as all the DbgHelp functions are + // single-threaded and we can't coordinate with the app. + // FIXME: Can we stop the other threads at this point? + // Anyways, we have to reconfigure stuff to make sure that SymInitialize + // has all the appropriate options set. + // Cross our fingers and reinitialize DbgHelp. + Report("*** WARNING: Failed to initialize DbgHelp! ***\n"); + Report("*** Most likely this means that the app is already ***\n"); + Report("*** using DbgHelp, possibly with incompatible flags. ***\n"); + Report("*** Due to technical reasons, symbolization might crash ***\n"); + Report("*** or produce wrong results. ***\n"); + SymCleanup(GetCurrentProcess()); + TrySymInitialize(); + } + is_dbghelp_initialized = true; + + // When an executable is run from a location different from the one where it + // was originally built, we may not see the nearby PDB files. + // To work around this, let's append the directory of the main module + // to the symbol search path. All the failures below are not fatal. + const size_t kSymPathSize = 2048; + static wchar_t path_buffer[kSymPathSize + 1 + MAX_PATH]; + if (!SymGetSearchPathW(GetCurrentProcess(), path_buffer, kSymPathSize)) { + Report("*** WARNING: Failed to SymGetSearchPathW ***\n"); + return; + } + size_t sz = wcslen(path_buffer); + if (sz) { + CHECK_EQ(0, wcscat_s(path_buffer, L";")); + sz++; } + DWORD res = GetModuleFileNameW(NULL, path_buffer + sz, MAX_PATH); + if (res == 0 || res == MAX_PATH) { + Report("*** WARNING: Failed to getting the EXE directory ***\n"); + return; + } + // Write the zero character in place of the last backslash to get the + // directory of the main module at the end of path_buffer. + wchar_t *last_bslash = wcsrchr(path_buffer + sz, L'\\'); + CHECK_NE(last_bslash, 0); + *last_bslash = L'\0'; + if (!SymSetSearchPathW(GetCurrentProcess(), path_buffer)) { + Report("*** WARNING: Failed to SymSetSearchPathW\n"); + return; + } +} - const char *Demangle(const char *name) override { - CHECK(initialized_); - static char demangle_buffer[1000]; - if (name[0] == '\01' && - UnDecorateSymbolName(name + 1, demangle_buffer, sizeof(demangle_buffer), - UNDNAME_NAME_ONLY)) - return demangle_buffer; - else - return name; +} // namespace + +bool WinSymbolizerTool::SymbolizePC(uptr addr, SymbolizedStack *frame) { + InitializeDbgHelpIfNeeded(); + + // See http://msdn.microsoft.com/en-us/library/ms680578(VS.85).aspx + char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(CHAR)]; + PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer; + symbol->SizeOfStruct = sizeof(SYMBOL_INFO); + symbol->MaxNameLen = MAX_SYM_NAME; + DWORD64 offset = 0; + BOOL got_objname = SymFromAddr(GetCurrentProcess(), + (DWORD64)addr, &offset, symbol); + if (!got_objname) + return false; + + DWORD unused; + IMAGEHLP_LINE64 line_info; + line_info.SizeOfStruct = sizeof(IMAGEHLP_LINE64); + BOOL got_fileline = SymGetLineFromAddr64(GetCurrentProcess(), (DWORD64)addr, + &unused, &line_info); + frame->info.function = internal_strdup(symbol->Name); + frame->info.function_offset = (uptr)offset; + if (got_fileline) { + frame->info.file = internal_strdup(line_info.FileName); + frame->info.line = line_info.LineNumber; } + return true; +} - // FIXME: Implement GetModuleNameAndOffsetForPC(). +const char *WinSymbolizerTool::Demangle(const char *name) { + CHECK(is_dbghelp_initialized); + static char demangle_buffer[1000]; + if (name[0] == '\01' && + UnDecorateSymbolName(name + 1, demangle_buffer, sizeof(demangle_buffer), + UNDNAME_NAME_ONLY)) + return demangle_buffer; + else + return name; +} - private: - void InitializeIfNeeded() { - if (initialized_) - return; - if (!TrySymInitialize()) { - // OK, maybe the client app has called SymInitialize already. - // That's a bit unfortunate for us as all the DbgHelp functions are - // single-threaded and we can't coordinate with the app. - // FIXME: Can we stop the other threads at this point? - // Anyways, we have to reconfigure stuff to make sure that SymInitialize - // has all the appropriate options set. - // Cross our fingers and reinitialize DbgHelp. - Report("*** WARNING: Failed to initialize DbgHelp! ***\n"); - Report("*** Most likely this means that the app is already ***\n"); - Report("*** using DbgHelp, possibly with incompatible flags. ***\n"); - Report("*** Due to technical reasons, symbolization might crash ***\n"); - Report("*** or produce wrong results. ***\n"); - SymCleanup(GetCurrentProcess()); - TrySymInitialize(); - } - initialized_ = true; - - // When an executable is run from a location different from the one where it - // was originally built, we may not see the nearby PDB files. - // To work around this, let's append the directory of the main module - // to the symbol search path. All the failures below are not fatal. - const size_t kSymPathSize = 2048; - static wchar_t path_buffer[kSymPathSize + 1 + MAX_PATH]; - if (!SymGetSearchPathW(GetCurrentProcess(), path_buffer, kSymPathSize)) { - Report("*** WARNING: Failed to SymGetSearchPathW ***\n"); - return; - } - size_t sz = wcslen(path_buffer); - if (sz) { - CHECK_EQ(0, wcscat_s(path_buffer, L";")); - sz++; - } - DWORD res = GetModuleFileNameW(NULL, path_buffer + sz, MAX_PATH); - if (res == 0 || res == MAX_PATH) { - Report("*** WARNING: Failed to getting the EXE directory ***\n"); - return; - } - // Write the zero character in place of the last backslash to get the - // directory of the main module at the end of path_buffer. - wchar_t *last_bslash = wcsrchr(path_buffer + sz, L'\\'); - CHECK_NE(last_bslash, 0); - *last_bslash = L'\0'; - if (!SymSetSearchPathW(GetCurrentProcess(), path_buffer)) { - Report("*** WARNING: Failed to SymSetSearchPathW\n"); - return; - } - } +bool FindModuleNameAndOffsetForAddress(uptr addr, const char **module_name, + uptr *module_offset) { + InitializeDbgHelpIfNeeded(); - bool TrySymInitialize() { - SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME | SYMOPT_LOAD_LINES); - return SymInitialize(GetCurrentProcess(), 0, TRUE); - // FIXME: We don't call SymCleanup() on exit yet - should we? + IMAGEHLP_MODULE64 mod_info; + internal_memset(&mod_info, 0, sizeof(mod_info)); + mod_info.SizeOfStruct = sizeof(mod_info); + if (SymGetModuleInfo64(GetCurrentProcess(), addr, &mod_info)) { + *module_name = mod_info.ImageName; + *module_offset = addr - (uptr)mod_info.BaseOfImage; + return true; } + return false; +} - // All DbgHelp functions are single threaded, so we should use a mutex to - // serialize accesses. - BlockingMutex dbghelp_mu_; - bool initialized_; +// TODO(kuba.brecka): To be merged with POSIXSymbolizer. +class WinSymbolizer : public Symbolizer { + public: + explicit WinSymbolizer(IntrusiveList<SymbolizerTool> tools) + : Symbolizer(tools) {} + + private: + bool PlatformFindModuleNameAndOffsetForAddress( + uptr addr, const char **module_name, uptr *module_offset) override { + return ::FindModuleNameAndOffsetForAddress(addr, module_name, + module_offset); + } + const char *PlatformDemangle(const char *name) override { return name; } + void PlatformPrepareForSandboxing() override { } }; Symbolizer *Symbolizer::PlatformInit() { - static bool called_once = false; - CHECK(!called_once && "Shouldn't create more than one symbolizer"); - called_once = true; - return new(symbolizer_allocator_) WinSymbolizer(); + IntrusiveList<SymbolizerTool> list; + list.clear(); + list.push_back(new(symbolizer_allocator_) WinSymbolizerTool()); + return new(symbolizer_allocator_) WinSymbolizer(list); } } // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_symbolizer_win.h b/lib/sanitizer_common/sanitizer_symbolizer_win.h new file mode 100644 index 000000000..72ac5e5ee --- /dev/null +++ b/lib/sanitizer_common/sanitizer_symbolizer_win.h @@ -0,0 +1,31 @@ +//===-- sanitizer_symbolizer_win.h ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Header file for the Windows symbolizer tool. +// +//===----------------------------------------------------------------------===// +#ifndef SANITIZER_SYMBOLIZER_WIN_H +#define SANITIZER_SYMBOLIZER_WIN_H + +#include "sanitizer_symbolizer_internal.h" + +namespace __sanitizer { + +class WinSymbolizerTool : public SymbolizerTool { + public: + bool SymbolizePC(uptr addr, SymbolizedStack *stack) override; + bool SymbolizeData(uptr addr, DataInfo *info) override { + return false; + } + const char *Demangle(const char *name) override; +}; + +} // namespace __sanitizer + +#endif // SANITIZER_SYMBOLIZER_WIN_H diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index 335cecabe..3ec90842c 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -313,6 +313,19 @@ char *FindPathToBinary(const char *name) { return 0; } +uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { + // Nothing here for now. + return 0; +} + +bool IsPathSeparator(const char c) { + return c == '\\' || c == '/'; +} + +bool IsAbsolutePath(const char *path) { + UNIMPLEMENTED(); +} + void SleepForSeconds(int seconds) { Sleep(seconds * 1000); } @@ -368,7 +381,7 @@ uptr internal_open(const char *filename, int flags, u32 mode) { UNIMPLEMENTED(); } -uptr OpenFile(const char *filename, bool write) { +uptr OpenFile(const char *filename, FileAccessMode mode) { UNIMPLEMENTED(); } @@ -618,6 +631,23 @@ bool IsAccessibleMemoryRange(uptr beg, uptr size) { return true; } +SignalContext SignalContext::Create(void *siginfo, void *context) { + EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD*)siginfo; + CONTEXT *context_record = (CONTEXT*)context; + + uptr pc = (uptr)exception_record->ExceptionAddress; +#ifdef _WIN64 + uptr bp = (uptr)context_record->Rbp; + uptr sp = (uptr)context_record->Rsp; +#else + uptr bp = (uptr)context_record->Ebp; + uptr sp = (uptr)context_record->Esp; +#endif + uptr access_addr = exception_record->ExceptionInformation[1]; + + return SignalContext(context, access_addr, pc, sp, bp); +} + } // namespace __sanitizer #endif // _WIN32 diff --git a/lib/sanitizer_common/scripts/check_lint.sh b/lib/sanitizer_common/scripts/check_lint.sh index 7ed05d735..9108a81e2 100755 --- a/lib/sanitizer_common/scripts/check_lint.sh +++ b/lib/sanitizer_common/scripts/check_lint.sh @@ -17,7 +17,6 @@ fi # Filters # TODO: remove some of these filters -LLVM_LINT_FILTER=-,+whitespace COMMON_LINT_FILTER=-build/include,-build/header_guard,-legal/copyright,-whitespace/comments,-readability/casting,\ -build/namespaces ASAN_RTL_LINT_FILTER=${COMMON_LINT_FILTER},-runtime/int @@ -60,9 +59,6 @@ run_lint() { ${LITLINT} "$@" 2>>$ERROR_LOG } -run_lint ${LLVM_LINT_FILTER} --filter=${LLVM_LINT_FILTER} \ - lib/Transforms/Instrumentation/*Sanitizer.cpp & - if [ "${COMPILER_RT}" = "" ]; then COMPILER_RT=projects/compiler-rt fi diff --git a/lib/sanitizer_common/scripts/sancov.py b/lib/sanitizer_common/scripts/sancov.py index 566116eb2..53180d09b 100755 --- a/lib/sanitizer_common/scripts/sancov.py +++ b/lib/sanitizer_common/scripts/sancov.py @@ -9,35 +9,77 @@ import sys import bisect import os.path -prog_name = ""; +prog_name = "" def Usage(): print >> sys.stderr, "Usage: \n" + \ - " " + prog_name + " merge file1 [file2 ...] > output\n" \ - " " + prog_name + " print file1 [file2 ...]\n" \ - " " + prog_name + " unpack file1 [file2 ...]\n" \ - " " + prog_name + " rawunpack file1 [file2 ...]\n" + " " + prog_name + " [32|64] merge file1 [file2 ...] > output\n" \ + " " + prog_name + " [32|64] print file1 [file2 ...]\n" \ + " " + prog_name + " [32|64] unpack file1 [file2 ...]\n" \ + " " + prog_name + " [32|64] rawunpack file1 [file2 ...]\n" exit(1) +def CheckBits(bits): + if bits != 32 and bits != 64: + raise Exception("Wrong bitness: %d" % bits) + +def TypeCodeForBits(bits): + CheckBits(bits) + return 'L' if bits == 64 else 'I' + +kMagic32SecondHalf = 0xFFFFFF32; +kMagic64SecondHalf = 0xFFFFFF64; +kMagicFirstHalf = 0xC0BFFFFF; + +def MagicForBits(bits): + CheckBits(bits) + if sys.byteorder == 'little': + return [kMagic64SecondHalf if bits == 64 else kMagic32SecondHalf, kMagicFirstHalf] + else: + return [kMagicFirstHalf, kMagic64SecondHalf if bits == 64 else kMagic32SecondHalf] + +def ReadMagicAndReturnBitness(f, path): + magic_bytes = f.read(8) + magic_words = struct.unpack('II', magic_bytes); + bits = 0 + idx = 1 if sys.byteorder == 'little' else 0 + if magic_words[idx] == kMagicFirstHalf: + if magic_words[1-idx] == kMagic64SecondHalf: + bits = 64 + elif magic_words[1-idx] == kMagic32SecondHalf: + bits = 32 + if bits == 0: + raise Exception('Bad magic word in %s' % path) + return bits + def ReadOneFile(path): with open(path, mode="rb") as f: f.seek(0, 2) size = f.tell() f.seek(0, 0) - s = set(array.array('I', f.read(size))) - print >>sys.stderr, "%s: read %d PCs from %s" % (prog_name, size / 4, path) + if size < 8: + raise Exception('File %s is short (< 8 bytes)' % path) + bits = ReadMagicAndReturnBitness(f, path) + size -= 8 + s = array.array(TypeCodeForBits(bits), f.read(size)) + print >>sys.stderr, "%s: read %d %d-bit PCs from %s" % (prog_name, size * 8 / bits, bits, path) return s def Merge(files): s = set() for f in files: - s = s.union(ReadOneFile(f)) + s = s.union(set(ReadOneFile(f))) print >> sys.stderr, "%s: %d files merged; %d PCs total" % \ (prog_name, len(files), len(s)) return sorted(s) def PrintFiles(files): - s = Merge(files) + if len(files) > 1: + s = Merge(files) + else: # If there is just on file, print the PCs in order. + s = ReadOneFile(files[0]) + print >> sys.stderr, "%s: 1 file merged; %d PCs total" % \ + (prog_name, len(s)) for i in s: print "0x%x" % i @@ -45,7 +87,11 @@ def MergeAndPrint(files): if sys.stdout.isatty(): Usage() s = Merge(files) - a = array.array('I', s) + bits = 32 + if max(s) > 0xFFFFFFFF: + bits = 64 + array.array('I', MagicForBits(bits)).tofile(sys.stdout) + a = array.array(TypeCodeForBits(bits), s) a.tofile(sys.stdout) @@ -82,6 +128,8 @@ def UnpackOneRawFile(path, map_path): with open(map_path, mode="rt") as f_map: print >> sys.stderr, "%s: reading map %s" % (prog_name, map_path) bits = int(f_map.readline()) + if bits != 32 and bits != 64: + raise Exception('Wrong bits size in the map') for line in f_map: parts = line.rstrip().split() mem_map.append((int(parts[0], 16), @@ -97,11 +145,7 @@ def UnpackOneRawFile(path, map_path): f.seek(0, 2) size = f.tell() f.seek(0, 0) - if bits == 64: - typecode = 'L' - else: - typecode = 'I' - pcs = array.array(typecode, f.read(size)) + pcs = array.array(TypeCodeForBits(bits), f.read(size)) mem_map_pcs = [[] for i in range(0, len(mem_map))] for pc in pcs: @@ -119,9 +163,10 @@ def UnpackOneRawFile(path, map_path): assert path.endswith('.sancov.raw') dst_path = module_path + '.' + os.path.basename(path)[:-4] print >> sys.stderr, "%s: writing %d PCs to %s" % (prog_name, len(pc_list), dst_path) - arr = array.array('I') + arr = array.array(TypeCodeForBits(bits)) arr.fromlist(sorted(pc_list)) with open(dst_path, 'ab') as f2: + array.array('I', MagicForBits(bits)).tofile(f2) arr.tofile(f2) def RawUnpack(files): @@ -135,6 +180,7 @@ if __name__ == '__main__': prog_name = sys.argv[0] if len(sys.argv) <= 2: Usage(); + if sys.argv[1] == "print": PrintFiles(sys.argv[2:]) elif sys.argv[1] == "merge": diff --git a/lib/sanitizer_common/tests/CMakeLists.txt b/lib/sanitizer_common/tests/CMakeLists.txt index 75008db3b..b062c5a02 100644 --- a/lib/sanitizer_common/tests/CMakeLists.txt +++ b/lib/sanitizer_common/tests/CMakeLists.txt @@ -28,6 +28,7 @@ set(SANITIZER_UNITTESTS sanitizer_stacktrace_test.cc sanitizer_stoptheworld_test.cc sanitizer_suppressions_test.cc + sanitizer_symbolizer_test.cc sanitizer_test_main.cc sanitizer_thread_registry_test.cc) diff --git a/lib/sanitizer_common/tests/sanitizer_libc_test.cc b/lib/sanitizer_common/tests/sanitizer_libc_test.cc index 8712d2c1b..279f6fed9 100644 --- a/lib/sanitizer_common/tests/sanitizer_libc_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_libc_test.cc @@ -78,14 +78,14 @@ TEST(SanitizerCommon, FileOps) { char tmpfile[128]; temp_file_name(tmpfile, sizeof(tmpfile), "sanitizer_common.fileops.tmp."); - uptr openrv = OpenFile(tmpfile, true); + uptr openrv = OpenFile(tmpfile, WrOnly); EXPECT_FALSE(internal_iserror(openrv)); fd_t fd = openrv; EXPECT_EQ(len1, internal_write(fd, str1, len1)); EXPECT_EQ(len2, internal_write(fd, str2, len2)); internal_close(fd); - openrv = OpenFile(tmpfile, false); + openrv = OpenFile(tmpfile, RdOnly); EXPECT_FALSE(internal_iserror(openrv)); fd = openrv; uptr fsize = internal_filesize(fd); @@ -134,7 +134,7 @@ TEST(SanitizerCommon, InternalMmapWithOffset) { char tmpfile[128]; temp_file_name(tmpfile, sizeof(tmpfile), "sanitizer_common.internalmmapwithoffset.tmp."); - uptr res = OpenFile(tmpfile, true); + uptr res = OpenFile(tmpfile, RdWr); ASSERT_FALSE(internal_iserror(res)); fd_t fd = res; diff --git a/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc b/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc index ac820c25a..a8bd7261e 100644 --- a/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc @@ -30,11 +30,11 @@ class FastUnwindTest : public ::testing::Test { } void *mapping; - uptr *fake_stack; + uhwptr *fake_stack; const uptr fake_stack_size = 10; - uptr start_pc; - uptr fake_top; - uptr fake_bottom; + uhwptr start_pc; + uhwptr fake_top; + uhwptr fake_bottom; BufferedStackTrace trace; }; @@ -48,7 +48,7 @@ void FastUnwindTest::SetUp() { Mprotect((uptr)mapping, ps); // Unwinder may peek 1 word down from the starting FP. - fake_stack = (uptr *)((uptr)mapping + ps + sizeof(uptr)); + fake_stack = (uhwptr *)((uptr)mapping + ps + sizeof(uhwptr)); // Fill an array of pointers with fake fp+retaddr pairs. Frame pointers have // even indices. @@ -57,12 +57,12 @@ void FastUnwindTest::SetUp() { fake_stack[i+1] = PC(i + 1); // retaddr } // Mark the last fp point back up to terminate the stack trace. - fake_stack[RoundDownTo(fake_stack_size - 1, 2)] = (uptr)&fake_stack[0]; + fake_stack[RoundDownTo(fake_stack_size - 1, 2)] = (uhwptr)&fake_stack[0]; // Top is two slots past the end because FastUnwindStack subtracts two. - fake_top = (uptr)&fake_stack[fake_stack_size + 2]; + fake_top = (uhwptr)&fake_stack[fake_stack_size + 2]; // Bottom is one slot before the start because FastUnwindStack uses >. - fake_bottom = (uptr)mapping; + fake_bottom = (uhwptr)mapping; start_pc = PC(0); } @@ -85,7 +85,7 @@ TEST_F(FastUnwindTest, Basic) { // From: http://code.google.com/p/address-sanitizer/issues/detail?id=162 TEST_F(FastUnwindTest, FramePointerLoop) { // Make one fp point to itself. - fake_stack[4] = (uptr)&fake_stack[4]; + fake_stack[4] = (uhwptr)&fake_stack[4]; if (!TryFastUnwind(kStackTraceMax)) return; // Should get all on-stack retaddrs up to the 4th slot and start_pc. @@ -114,7 +114,7 @@ TEST_F(FastUnwindTest, OneFrameStackTrace) { return; EXPECT_EQ(1U, trace.size); EXPECT_EQ(start_pc, trace.trace[0]); - EXPECT_EQ((uptr)&fake_stack[0], trace.top_frame_bp); + EXPECT_EQ((uhwptr)&fake_stack[0], trace.top_frame_bp); } TEST_F(FastUnwindTest, ZeroFramesStackTrace) { @@ -127,7 +127,7 @@ TEST_F(FastUnwindTest, ZeroFramesStackTrace) { TEST_F(FastUnwindTest, FPBelowPrevFP) { // The next FP points to unreadable memory inside the stack limits, but below // current FP. - fake_stack[0] = (uptr)&fake_stack[-50]; + fake_stack[0] = (uhwptr)&fake_stack[-50]; fake_stack[1] = PC(1); if (!TryFastUnwind(3)) return; diff --git a/lib/sanitizer_common/tests/sanitizer_stoptheworld_test.cc b/lib/sanitizer_common/tests/sanitizer_stoptheworld_test.cc index b6786ba8b..802af392c 100644 --- a/lib/sanitizer_common/tests/sanitizer_stoptheworld_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_stoptheworld_test.cc @@ -189,6 +189,16 @@ TEST(StopTheWorld, SuspendThreadsAdvanced) { pthread_mutex_destroy(&advanced_incrementer_thread_exit_mutex); } +static void SegvCallback(const SuspendedThreadsList &suspended_threads_list, + void *argument) { + *(volatile int*)0x1234 = 0; +} + +TEST(StopTheWorld, SegvInCallback) { + // Test that tracer thread catches SIGSEGV. + StopTheWorld(&SegvCallback, NULL); +} + } // namespace __sanitizer #endif // SANITIZER_LINUX && defined(__x86_64__) diff --git a/lib/sanitizer_common/tests/sanitizer_symbolizer_test.cc b/lib/sanitizer_common/tests/sanitizer_symbolizer_test.cc new file mode 100644 index 000000000..429ac591e --- /dev/null +++ b/lib/sanitizer_common/tests/sanitizer_symbolizer_test.cc @@ -0,0 +1,58 @@ +//===-- sanitizer_symbolizer_test.cc --------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Tests for sanitizer_symbolizer.h and sanitizer_symbolizer_internal.h +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_common/sanitizer_allocator_internal.h" +#include "sanitizer_common/sanitizer_symbolizer_internal.h" +#include "gtest/gtest.h" + +namespace __sanitizer { + +TEST(Symbolizer, ExtractToken) { + char *token; + const char *rest; + + rest = ExtractToken("a;b;c", ";", &token); + EXPECT_STREQ("a", token); + EXPECT_STREQ("b;c", rest); + InternalFree(token); + + rest = ExtractToken("aaa-bbb.ccc", ";.-*", &token); + EXPECT_STREQ("aaa", token); + EXPECT_STREQ("bbb.ccc", rest); + InternalFree(token); +} + +TEST(Symbolizer, ExtractInt) { + int token; + const char *rest = ExtractInt("123,456;789", ";,", &token); + EXPECT_EQ(123, token); + EXPECT_STREQ("456;789", rest); +} + +TEST(Symbolizer, ExtractUptr) { + uptr token; + const char *rest = ExtractUptr("123,456;789", ";,", &token); + EXPECT_EQ(123U, token); + EXPECT_STREQ("456;789", rest); +} + +TEST(Symbolizer, ExtractTokenUpToDelimiter) { + char *token; + const char *rest = + ExtractTokenUpToDelimiter("aaa-+-bbb-+-ccc", "-+-", &token); + EXPECT_STREQ("aaa", token); + EXPECT_STREQ("bbb-+-ccc", rest); + InternalFree(token); +} + +} // namespace __sanitizer diff --git a/lib/tsan/Makefile.old b/lib/tsan/Makefile.old index 9e0693fa0..fbdb9ddad 100644 --- a/lib/tsan/Makefile.old +++ b/lib/tsan/Makefile.old @@ -11,7 +11,9 @@ ifeq ($(DEBUG), 0) CXXFLAGS += -O3 endif ifeq ($(CXX), $(CLANG)++) - CXXFLAGS+= -Wno-unused-private-field -Wno-static-in-inline -Wgnu + CXXFLAGS += -Wno-unused-private-field -Wno-static-in-inline -Wgnu +else + CXXFLAGS += -Wno-maybe-uninitialized endif LIBTSAN=rtl/libtsan.a diff --git a/lib/tsan/rtl/Makefile.old b/lib/tsan/rtl/Makefile.old index 150b37634..627e03bdc 100644 --- a/lib/tsan/rtl/Makefile.old +++ b/lib/tsan/rtl/Makefile.old @@ -15,6 +15,7 @@ CXXFLAGS+=$(CFLAGS) ifeq ($(DEBUG), 0) CXXFLAGS+=-fomit-frame-pointer ifeq ($(CXX), g++) + CXXFLAGS+=-Wno-maybe-uninitialized CXXFLAGS+=-Wframe-larger-than=512 endif # CXX=g++ endif # DEBUG=0 diff --git a/lib/tsan/rtl/tsan_interceptors.cc b/lib/tsan/rtl/tsan_interceptors.cc index 31ff7d56a..c45bcdc1c 100644 --- a/lib/tsan/rtl/tsan_interceptors.cc +++ b/lib/tsan/rtl/tsan_interceptors.cc @@ -145,7 +145,10 @@ struct sigaction_t { const sighandler_t SIG_DFL = (sighandler_t)0; const sighandler_t SIG_IGN = (sighandler_t)1; const sighandler_t SIG_ERR = (sighandler_t)-1; -#ifdef __mips__ +#if SANITIZER_FREEBSD +const int SA_SIGINFO = 0x40; +const int SIG_SETMASK = 3; +#elif defined(__mips__) const int SA_SIGINFO = 8; const int SIG_SETMASK = 3; #else @@ -167,7 +170,7 @@ struct SignalDesc { ucontext_t ctx; }; -struct SignalContext { +struct ThreadSignalContext { int int_signal_send; atomic_uintptr_t in_blocking_func; atomic_uintptr_t have_pending_signals; @@ -194,10 +197,10 @@ void InitializeLibIgnore() { } // namespace __tsan -static SignalContext *SigCtx(ThreadState *thr) { - SignalContext *ctx = (SignalContext*)thr->signal_ctx; +static ThreadSignalContext *SigCtx(ThreadState *thr) { + ThreadSignalContext *ctx = (ThreadSignalContext*)thr->signal_ctx; if (ctx == 0 && !thr->is_dead) { - ctx = (SignalContext*)MmapOrDie(sizeof(*ctx), "SignalContext"); + ctx = (ThreadSignalContext*)MmapOrDie(sizeof(*ctx), "ThreadSignalContext"); MemoryResetRange(thr, (uptr)&SigCtx, (uptr)ctx, sizeof(*ctx)); thr->signal_ctx = ctx; } @@ -298,7 +301,7 @@ struct BlockingCall { } ThreadState *thr; - SignalContext *ctx; + ThreadSignalContext *ctx; }; TSAN_INTERCEPTOR(unsigned, sleep, unsigned sec) { @@ -410,7 +413,7 @@ static void JmpBufGarbageCollect(ThreadState *thr, uptr sp) { } static void SetJmp(ThreadState *thr, uptr sp, uptr mangled_sp) { - if (thr->shadow_stack_pos == 0) // called from libc guts during bootstrap + if (!thr->is_inited) // called from libc guts during bootstrap return; // Cleanup old bufs. JmpBufGarbageCollect(thr, sp); @@ -419,7 +422,7 @@ static void SetJmp(ThreadState *thr, uptr sp, uptr mangled_sp) { buf->sp = sp; buf->mangled_sp = mangled_sp; buf->shadow_stack_pos = thr->shadow_stack_pos; - SignalContext *sctx = SigCtx(thr); + ThreadSignalContext *sctx = SigCtx(thr); buf->int_signal_send = sctx ? sctx->int_signal_send : 0; buf->in_blocking_func = sctx ? atomic_load(&sctx->in_blocking_func, memory_order_relaxed) : @@ -442,7 +445,7 @@ static void LongJmp(ThreadState *thr, uptr *env) { // Unwind the stack. while (thr->shadow_stack_pos > buf->shadow_stack_pos) FuncExit(thr); - SignalContext *sctx = SigCtx(thr); + ThreadSignalContext *sctx = SigCtx(thr); if (sctx) { sctx->int_signal_send = buf->int_signal_send; atomic_store(&sctx->in_blocking_func, buf->in_blocking_func, @@ -666,9 +669,12 @@ TSAN_INTERCEPTOR(void*, memset, void *dst, int v, uptr size) { } TSAN_INTERCEPTOR(void*, memcpy, void *dst, const void *src, uptr size) { - SCOPED_TSAN_INTERCEPTOR(memcpy, dst, src, size); - MemoryAccessRange(thr, pc, (uptr)dst, size, true); - MemoryAccessRange(thr, pc, (uptr)src, size, false); + // On FreeBSD we get here from libthr internals on thread initialization. + if (cur_thread()->is_inited) { + SCOPED_TSAN_INTERCEPTOR(memcpy, dst, src, size); + MemoryAccessRange(thr, pc, (uptr)dst, size, true); + MemoryAccessRange(thr, pc, (uptr)src, size, false); + } return internal_memcpy(dst, src, size); } @@ -797,6 +803,7 @@ TSAN_INTERCEPTOR(void*, mmap64, void *addr, long_t sz, int prot, TSAN_INTERCEPTOR(int, munmap, void *addr, long_t sz) { SCOPED_TSAN_INTERCEPTOR(munmap, addr, sz); DontNeedShadowFor((uptr)addr, sz); + ctx->metamap.ResetRange(thr, pc, (uptr)addr, (uptr)sz); int res = REAL(munmap)(addr, sz); return res; } @@ -878,7 +885,7 @@ static void thread_finalize(void *v) { { ThreadState *thr = cur_thread(); ThreadFinish(thr); - SignalContext *sctx = thr->signal_ctx; + ThreadSignalContext *sctx = thr->signal_ctx; if (sctx) { thr->signal_ctx = 0; UnmapOrDie(sctx, sizeof(*sctx)); @@ -1940,7 +1947,7 @@ static void CallUserSignalHandler(ThreadState *thr, bool sync, bool acquire, } void ProcessPendingSignals(ThreadState *thr) { - SignalContext *sctx = SigCtx(thr); + ThreadSignalContext *sctx = SigCtx(thr); if (sctx == 0 || atomic_load(&sctx->have_pending_signals, memory_order_relaxed) == 0) return; @@ -1948,8 +1955,8 @@ void ProcessPendingSignals(ThreadState *thr) { atomic_fetch_add(&thr->in_signal_handler, 1, memory_order_relaxed); // These are too big for stack. static THREADLOCAL __sanitizer_sigset_t emptyset, oldset; - REAL(sigfillset)(&emptyset); - pthread_sigmask(SIG_SETMASK, &emptyset, &oldset); + CHECK_EQ(0, REAL(sigfillset)(&emptyset)); + CHECK_EQ(0, pthread_sigmask(SIG_SETMASK, &emptyset, &oldset)); for (int sig = 0; sig < kSigCount; sig++) { SignalDesc *signal = &sctx->pending_signals[sig]; if (signal->armed) { @@ -1958,13 +1965,13 @@ void ProcessPendingSignals(ThreadState *thr) { &signal->siginfo, &signal->ctx); } } - pthread_sigmask(SIG_SETMASK, &oldset, 0); + CHECK_EQ(0, pthread_sigmask(SIG_SETMASK, &oldset, 0)); atomic_fetch_add(&thr->in_signal_handler, -1, memory_order_relaxed); } } // namespace __tsan -static bool is_sync_signal(SignalContext *sctx, int sig) { +static bool is_sync_signal(ThreadSignalContext *sctx, int sig) { return sig == SIGSEGV || sig == SIGBUS || sig == SIGILL || sig == SIGABRT || sig == SIGFPE || sig == SIGPIPE || sig == SIGSYS || // If we are sending signal to ourselves, we must process it now. @@ -1974,7 +1981,7 @@ static bool is_sync_signal(SignalContext *sctx, int sig) { void ALWAYS_INLINE rtl_generic_sighandler(bool sigact, int sig, my_siginfo_t *info, void *ctx) { ThreadState *thr = cur_thread(); - SignalContext *sctx = SigCtx(thr); + ThreadSignalContext *sctx = SigCtx(thr); if (sig < 0 || sig >= kSigCount) { VPrintf(1, "ThreadSanitizer: ignoring signal %d\n", sig); return; @@ -2083,7 +2090,7 @@ TSAN_INTERCEPTOR(int, sigsuspend, const __sanitizer_sigset_t *mask) { TSAN_INTERCEPTOR(int, raise, int sig) { SCOPED_TSAN_INTERCEPTOR(raise, sig); - SignalContext *sctx = SigCtx(thr); + ThreadSignalContext *sctx = SigCtx(thr); CHECK_NE(sctx, 0); int prev = sctx->int_signal_send; sctx->int_signal_send = sig; @@ -2095,7 +2102,7 @@ TSAN_INTERCEPTOR(int, raise, int sig) { TSAN_INTERCEPTOR(int, kill, int pid, int sig) { SCOPED_TSAN_INTERCEPTOR(kill, pid, sig); - SignalContext *sctx = SigCtx(thr); + ThreadSignalContext *sctx = SigCtx(thr); CHECK_NE(sctx, 0); int prev = sctx->int_signal_send; if (pid == (int)internal_getpid()) { @@ -2111,7 +2118,7 @@ TSAN_INTERCEPTOR(int, kill, int pid, int sig) { TSAN_INTERCEPTOR(int, pthread_kill, void *tid, int sig) { SCOPED_TSAN_INTERCEPTOR(pthread_kill, tid, sig); - SignalContext *sctx = SigCtx(thr); + ThreadSignalContext *sctx = SigCtx(thr); CHECK_NE(sctx, 0); int prev = sctx->int_signal_send; if (tid == pthread_self()) { diff --git a/lib/tsan/rtl/tsan_report.cc b/lib/tsan/rtl/tsan_report.cc index 7e69cb4ec..18bad146b 100644 --- a/lib/tsan/rtl/tsan_report.cc +++ b/lib/tsan/rtl/tsan_report.cc @@ -335,10 +335,8 @@ void PrintReport(const ReportDesc *rep) { Printf(" And %d more similar thread leaks.\n\n", rep->count - 1); if (ReportStack *stack = ChooseSummaryStack(rep)) { - if (SymbolizedStack *frame = SkipTsanInternalFrames(stack->frames)) { - const AddressInfo &info = frame->info; - ReportErrorSummary(rep_typ_str, info.file, info.line, info.function); - } + if (SymbolizedStack *frame = SkipTsanInternalFrames(stack->frames)) + ReportErrorSummary(rep_typ_str, frame->info); } Printf("==================\n"); diff --git a/lib/tsan/rtl/tsan_rtl.cc b/lib/tsan/rtl/tsan_rtl.cc index b76f3e05d..1c64caf1c 100644 --- a/lib/tsan/rtl/tsan_rtl.cc +++ b/lib/tsan/rtl/tsan_rtl.cc @@ -153,7 +153,7 @@ static void BackgroundThread(void *arg) { } else { InternalScopedString filename(kMaxPathLength); filename.append("%s.%d", flags()->profile_memory, (int)internal_getpid()); - uptr openrv = OpenFile(filename.data(), true); + uptr openrv = OpenFile(filename.data(), WrOnly); if (internal_iserror(openrv)) { Printf("ThreadSanitizer: failed to open memory profile file '%s'\n", &filename[0]); @@ -461,7 +461,7 @@ void GrowShadowStack(ThreadState *thr) { #endif u32 CurrentStackId(ThreadState *thr, uptr pc) { - if (thr->shadow_stack_pos == 0) // May happen during bootstrap. + if (!thr->is_inited) // May happen during bootstrap. return 0; if (pc != 0) { #ifndef SANITIZER_GO diff --git a/lib/tsan/rtl/tsan_rtl.h b/lib/tsan/rtl/tsan_rtl.h index 7a60e5c55..d32688ee6 100644 --- a/lib/tsan/rtl/tsan_rtl.h +++ b/lib/tsan/rtl/tsan_rtl.h @@ -313,7 +313,7 @@ class Shadow : public FastState { } }; -struct SignalContext; +struct ThreadSignalContext; struct JmpBuf { uptr sp; @@ -371,6 +371,7 @@ struct ThreadState { const int unique_id; bool in_symbolizer; bool in_ignored_lib; + bool is_inited; bool is_dead; bool is_freeing; bool is_vptr_access; @@ -387,7 +388,7 @@ struct ThreadState { DDLogicalThread *dd_lt; atomic_uintptr_t in_signal_handler; - SignalContext *signal_ctx; + ThreadSignalContext *signal_ctx; DenseSlabAllocCache block_cache; DenseSlabAllocCache sync_cache; diff --git a/lib/tsan/rtl/tsan_rtl_thread.cc b/lib/tsan/rtl/tsan_rtl_thread.cc index 8ed1fbf2e..66c78cfdd 100644 --- a/lib/tsan/rtl/tsan_rtl_thread.cc +++ b/lib/tsan/rtl/tsan_rtl_thread.cc @@ -120,6 +120,7 @@ void ThreadContext::OnStarted(void *arg) { AcquireImpl(thr, 0, &sync); StatInc(thr, StatSyncAcquire); sync.Reset(&thr->clock_cache); + thr->is_inited = true; DPrintf("#%d: ThreadStart epoch=%zu stk_addr=%zx stk_size=%zx " "tls_addr=%zx tls_size=%zx\n", tid, (uptr)epoch0, args->stk_addr, args->stk_size, diff --git a/lib/tsan/rtl/tsan_suppressions.cc b/lib/tsan/rtl/tsan_suppressions.cc index 5413f04af..731572980 100644 --- a/lib/tsan/rtl/tsan_suppressions.cc +++ b/lib/tsan/rtl/tsan_suppressions.cc @@ -21,6 +21,7 @@ #include "tsan_mman.h" #include "tsan_platform.h" +#ifndef SANITIZER_GO // Suppressions for true/false positives in standard libraries. static const char *const std_suppressions = // Libstdc++ 4.4 has data races in std::string. @@ -33,7 +34,6 @@ static const char *const std_suppressions = "race:std::_Sp_counted_ptr_inplace<std::thread::_Impl\n"; // Can be overriden in frontend. -#ifndef SANITIZER_GO extern "C" const char *WEAK __tsan_default_suppressions() { return 0; } diff --git a/lib/tsan/rtl/tsan_sync.cc b/lib/tsan/rtl/tsan_sync.cc index 1041073be..49c4d15e5 100644 --- a/lib/tsan/rtl/tsan_sync.cc +++ b/lib/tsan/rtl/tsan_sync.cc @@ -80,7 +80,8 @@ uptr MetaMap::FreeBlock(ThreadState *thr, uptr pc, uptr p) { return sz; } -void MetaMap::FreeRange(ThreadState *thr, uptr pc, uptr p, uptr sz) { +bool MetaMap::FreeRange(ThreadState *thr, uptr pc, uptr p, uptr sz) { + bool has_something = false; u32 *meta = MemToMeta(p); u32 *end = MemToMeta(p + sz); if (end == meta) @@ -91,6 +92,7 @@ void MetaMap::FreeRange(ThreadState *thr, uptr pc, uptr p, uptr sz) { for (;;) { if (idx == 0) break; + has_something = true; if (idx & kFlagBlock) { block_alloc_.Free(&thr->block_cache, idx & ~kFlagMask); break; @@ -106,6 +108,64 @@ void MetaMap::FreeRange(ThreadState *thr, uptr pc, uptr p, uptr sz) { } } } + return has_something; +} + +// ResetRange removes all meta objects from the range. +// It is called for large mmap-ed regions. The function is best-effort wrt +// freeing of meta objects, because we don't want to page in the whole range +// which can be huge. The function probes pages one-by-one until it finds a page +// without meta objects, at this point it stops freeing meta objects. Because +// thread stacks grow top-down, we do the same starting from end as well. +void MetaMap::ResetRange(ThreadState *thr, uptr pc, uptr p, uptr sz) { + const uptr kMetaRatio = kMetaShadowCell / kMetaShadowSize; + const uptr kPageSize = GetPageSizeCached() * kMetaRatio; + if (sz <= 4 * kPageSize) { + // If the range is small, just do the normal free procedure. + FreeRange(thr, pc, p, sz); + return; + } + // First, round both ends of the range to page size. + uptr diff = RoundUp(p, kPageSize) - p; + if (diff != 0) { + FreeRange(thr, pc, p, diff); + p += diff; + sz -= diff; + } + diff = p + sz - RoundDown(p + sz, kPageSize); + if (diff != 0) { + FreeRange(thr, pc, p + sz - diff, diff); + sz -= diff; + } + // Now we must have a non-empty page-aligned range. + CHECK_GT(sz, 0); + CHECK_EQ(p, RoundUp(p, kPageSize)); + CHECK_EQ(sz, RoundUp(sz, kPageSize)); + const uptr p0 = p; + const uptr sz0 = sz; + // Probe start of the range. + while (sz > 0) { + bool has_something = FreeRange(thr, pc, p, kPageSize); + p += kPageSize; + sz -= kPageSize; + if (!has_something) + break; + } + // Probe end of the range. + while (sz > 0) { + bool has_something = FreeRange(thr, pc, p - kPageSize, kPageSize); + sz -= kPageSize; + if (!has_something) + break; + } + // Finally, page out the whole range (including the parts that we've just + // freed). Note: we can't simply madvise, because we need to leave a zeroed + // range (otherwise __tsan_java_move can crash if it encounters a left-over + // meta objects in java heap). + uptr metap = (uptr)MemToMeta(p0); + uptr metasz = sz0 / kMetaRatio; + UnmapOrDie((void*)metap, metasz); + MmapFixedNoReserve(metap, metasz); } MBlock* MetaMap::GetBlock(uptr p) { diff --git a/lib/tsan/rtl/tsan_sync.h b/lib/tsan/rtl/tsan_sync.h index 574810d8a..2d12cdff8 100644 --- a/lib/tsan/rtl/tsan_sync.h +++ b/lib/tsan/rtl/tsan_sync.h @@ -73,7 +73,8 @@ class MetaMap { void AllocBlock(ThreadState *thr, uptr pc, uptr p, uptr sz); uptr FreeBlock(ThreadState *thr, uptr pc, uptr p); - void FreeRange(ThreadState *thr, uptr pc, uptr p, uptr sz); + bool FreeRange(ThreadState *thr, uptr pc, uptr p, uptr sz); + void ResetRange(ThreadState *thr, uptr pc, uptr p, uptr sz); MBlock* GetBlock(uptr p); SyncVar* GetOrCreateAndLock(ThreadState *thr, uptr pc, diff --git a/lib/ubsan/CMakeLists.txt b/lib/ubsan/CMakeLists.txt index 668327296..a8b3f61ef 100644 --- a/lib/ubsan/CMakeLists.txt +++ b/lib/ubsan/CMakeLists.txt @@ -22,34 +22,61 @@ set(UBSAN_CXXFLAGS ${SANITIZER_COMMON_CFLAGS}) add_custom_target(ubsan) if(APPLE) - # Build universal binary on APPLE. - add_compiler_rt_osx_static_runtime(clang_rt.ubsan_osx - ARCH ${UBSAN_SUPPORTED_ARCH} - SOURCES ${UBSAN_SOURCES} ${UBSAN_CXX_SOURCES} - $<TARGET_OBJECTS:RTSanitizerCommon.osx> - CFLAGS ${UBSAN_CXXFLAGS}) - add_dependencies(ubsan clang_rt.ubsan_osx) + foreach(os ${SANITIZER_COMMON_SUPPORTED_DARWIN_OS}) + add_compiler_rt_darwin_object_library(RTUbsan ${os} + ARCH ${UBSAN_SUPPORTED_ARCH} + SOURCES ${UBSAN_SOURCES} ${UBSAN_CXX_SOURCES} + CFLAGS ${UBSAN_CXXFLAGS}) + + add_compiler_rt_darwin_dynamic_runtime(clang_rt.ubsan_${os}_dynamic ${os} + ARCH ${UBSAN_SUPPORTED_ARCH} + SOURCES $<TARGET_OBJECTS:RTUbsan.${os}> + $<TARGET_OBJECTS:RTSanitizerCommon.${os}> + LINKFLAGS -lc++abi) + + add_dependencies(ubsan clang_rt.ubsan_${os}_dynamic) + endforeach() else() # Build separate libraries for each target. foreach(arch ${UBSAN_SUPPORTED_ARCH}) - # Main UBSan runtime. + add_compiler_rt_object_library(RTUbsan ${arch} + SOURCES ${UBSAN_SOURCES} CFLAGS ${UBSAN_CFLAGS}) + # C++-specific parts of UBSan runtime. Requires a C++ ABI library. + add_compiler_rt_object_library(RTUbsan_cxx ${arch} + SOURCES ${UBSAN_CXX_SOURCES} CFLAGS ${UBSAN_CXXFLAGS}) + + # Standalone UBSan runtimes. + add_compiler_rt_runtime(clang_rt.ubsan_standalone-${arch} ${arch} STATIC + SOURCES $<TARGET_OBJECTS:RTSanitizerCommon.${arch}> + $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}> + $<TARGET_OBJECTS:RTUbsan.${arch}> + CFLAGS ${UBSAN_CFLAGS}) + add_compiler_rt_runtime(clang_rt.ubsan_standalone_cxx-${arch} ${arch} STATIC + SOURCES $<TARGET_OBJECTS:RTUbsan_cxx.${arch}> + CFLAGS ${UBSAN_CXXFLAGS}) + # UBSan runtimes used when another sanitizer is available. add_compiler_rt_runtime(clang_rt.ubsan-${arch} ${arch} STATIC - SOURCES ${UBSAN_SOURCES} + SOURCES $<TARGET_OBJECTS:RTUbsan.${arch}> CFLAGS ${UBSAN_CFLAGS}) - # C++-specific parts of UBSan runtime. Requires a C++ ABI library. add_compiler_rt_runtime(clang_rt.ubsan_cxx-${arch} ${arch} STATIC - SOURCES ${UBSAN_CXX_SOURCES} + SOURCES $<TARGET_OBJECTS:RTUbsan_cxx.${arch}> CFLAGS ${UBSAN_CXXFLAGS}) + add_dependencies(ubsan - clang_rt.san-${arch} clang_rt.ubsan-${arch} - clang_rt.ubsan_cxx-${arch}) + clang_rt.ubsan_cxx-${arch} + clang_rt.ubsan_standalone-${arch} + clang_rt.ubsan_standalone_cxx-${arch}) if (UNIX AND NOT ${arch} MATCHES "i386|i686") add_sanitizer_rt_symbols(clang_rt.ubsan-${arch} ubsan.syms.extra) add_sanitizer_rt_symbols(clang_rt.ubsan_cxx-${arch} ubsan.syms.extra) + add_sanitizer_rt_symbols(clang_rt.ubsan_standalone-${arch} ubsan.syms.extra) + add_sanitizer_rt_symbols(clang_rt.ubsan_standalone_cxx-${arch} ubsan.syms.extra) add_dependencies(ubsan clang_rt.ubsan-${arch}-symbols - clang_rt.ubsan_cxx-${arch}-symbols) + clang_rt.ubsan_cxx-${arch}-symbols + clang_rt.ubsan_standalone-${arch}-symbols + clang_rt.ubsan_standalone_cxx-${arch}-symbols) endif() endforeach() endif() diff --git a/lib/ubsan/ubsan_diag.cc b/lib/ubsan/ubsan_diag.cc index 4f2a2a9f3..2314fb6ed 100644 --- a/lib/ubsan/ubsan_diag.cc +++ b/lib/ubsan/ubsan_diag.cc @@ -11,6 +11,8 @@ // //===----------------------------------------------------------------------===// +#include "ubsan_platform.h" +#if CAN_SANITIZE_UB #include "ubsan_diag.h" #include "ubsan_init.h" #include "ubsan_flags.h" @@ -49,8 +51,13 @@ static void MaybeReportErrorSummary(Location Loc) { if (Loc.isSourceLocation()) { SourceLocation SLoc = Loc.getSourceLocation(); if (!SLoc.isInvalid()) { - ReportErrorSummary("undefined-behavior", SLoc.getFilename(), - SLoc.getLine(), ""); + AddressInfo AI; + AI.file = internal_strdup(SLoc.getFilename()); + AI.line = SLoc.getLine(); + AI.column = SLoc.getColumn(); + AI.function = internal_strdup(""); // Avoid printing ?? as function name. + ReportErrorSummary("undefined-behavior", AI); + AI.Clear(); return; } } @@ -356,3 +363,5 @@ bool __ubsan::IsVptrCheckSuppressed(const char *TypeName) { Suppression *s; return suppression_ctx->Match(TypeName, kVptrCheck, &s); } + +#endif // CAN_SANITIZE_UB diff --git a/lib/ubsan/ubsan_flags.cc b/lib/ubsan/ubsan_flags.cc index 0dbffc9b1..49ada8a26 100644 --- a/lib/ubsan/ubsan_flags.cc +++ b/lib/ubsan/ubsan_flags.cc @@ -11,6 +11,8 @@ // //===----------------------------------------------------------------------===// +#include "ubsan_platform.h" +#if CAN_SANITIZE_UB #include "ubsan_flags.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_flags.h" @@ -77,3 +79,5 @@ SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE const char *__ubsan_default_options() { return ""; } } // extern "C" #endif + +#endif // CAN_SANITIZE_UB diff --git a/lib/ubsan/ubsan_handlers.cc b/lib/ubsan/ubsan_handlers.cc index 78e7508f7..a65b2f5e3 100644 --- a/lib/ubsan/ubsan_handlers.cc +++ b/lib/ubsan/ubsan_handlers.cc @@ -11,6 +11,8 @@ // //===----------------------------------------------------------------------===// +#include "ubsan_platform.h" +#if CAN_SANITIZE_UB #include "ubsan_handlers.h" #include "ubsan_diag.h" @@ -419,3 +421,5 @@ void __ubsan::__ubsan_handle_nonnull_arg_abort(NonNullArgData *Data) { handleNonNullArg(Data, Opts); Die(); } + +#endif // CAN_SANITIZE_UB diff --git a/lib/ubsan/ubsan_handlers_cxx.cc b/lib/ubsan/ubsan_handlers_cxx.cc index 4718e6eac..b3cda32a9 100644 --- a/lib/ubsan/ubsan_handlers_cxx.cc +++ b/lib/ubsan/ubsan_handlers_cxx.cc @@ -13,6 +13,8 @@ // //===----------------------------------------------------------------------===// +#include "ubsan_platform.h" +#if CAN_SANITIZE_UB #include "ubsan_handlers_cxx.h" #include "ubsan_diag.h" #include "ubsan_type_hash.h" @@ -79,3 +81,5 @@ void __ubsan::__ubsan_handle_dynamic_type_cache_miss_abort( GET_REPORT_OPTIONS(true); HandleDynamicTypeCacheMiss(Data, Pointer, Hash, Opts); } + +#endif // CAN_SANITIZE_UB diff --git a/lib/ubsan/ubsan_init.cc b/lib/ubsan/ubsan_init.cc index 219273d51..952726977 100644 --- a/lib/ubsan/ubsan_init.cc +++ b/lib/ubsan/ubsan_init.cc @@ -11,6 +11,8 @@ // //===----------------------------------------------------------------------===// +#include "ubsan_platform.h" +#if CAN_SANITIZE_UB #include "ubsan_diag.h" #include "ubsan_init.h" #include "ubsan_flags.h" @@ -61,3 +63,5 @@ class UbsanInitializer { }; static UbsanInitializer ubsan_initializer; #endif // SANITIZER_CAN_USE_PREINIT_ARRAY + +#endif // CAN_SANITIZE_UB diff --git a/lib/ubsan/ubsan_platform.h b/lib/ubsan/ubsan_platform.h new file mode 100644 index 000000000..efb7974d4 --- /dev/null +++ b/lib/ubsan/ubsan_platform.h @@ -0,0 +1,26 @@ +//===-- ubsan_platform.h ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Defines the platforms which UBSan is supported at. +// +//===----------------------------------------------------------------------===// +#ifndef UBSAN_PLATFORM_H +#define UBSAN_PLATFORM_H + +// Other platforms should be easy to add, and probably work as-is. +#if (defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__)) && \ + (defined(__x86_64__) || defined(__i386__) || defined(__arm__) || \ + defined(__aarch64__) || defined(__mips__)) +# define CAN_SANITIZE_UB 1 +#else +# define CAN_SANITIZE_UB 0 +# error "UBSan not supported for this platform!" +#endif + +#endif diff --git a/lib/ubsan/ubsan_type_hash.cc b/lib/ubsan/ubsan_type_hash.cc index a388bcc6d..c85d68dfd 100644 --- a/lib/ubsan/ubsan_type_hash.cc +++ b/lib/ubsan/ubsan_type_hash.cc @@ -13,6 +13,8 @@ // //===----------------------------------------------------------------------===// +#include "ubsan_platform.h" +#if CAN_SANITIZE_UB #include "ubsan_type_hash.h" #include "sanitizer_common/sanitizer_common.h" @@ -248,3 +250,5 @@ __ubsan::DynamicTypeInfo __ubsan::getDynamicTypeInfo(void *Object) { return DynamicTypeInfo(Vtable->TypeInfo->__type_name, -Vtable->Offset, ObjectType ? ObjectType->__type_name : "<unknown>"); } + +#endif // CAN_SANITIZE_UB diff --git a/lib/ubsan/ubsan_value.cc b/lib/ubsan/ubsan_value.cc index ab74720f6..ea91d63bb 100644 --- a/lib/ubsan/ubsan_value.cc +++ b/lib/ubsan/ubsan_value.cc @@ -12,6 +12,8 @@ // //===----------------------------------------------------------------------===// +#include "ubsan_platform.h" +#if CAN_SANITIZE_UB #include "ubsan_value.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_libc.h" @@ -100,3 +102,5 @@ FloatMax Value::getFloatValue() const { } UNREACHABLE("unexpected floating point bit width"); } + +#endif // CAN_SANITIZE_UB diff --git a/lib/ubsan/ubsan_value.h b/lib/ubsan/ubsan_value.h index a68108440..72eee1555 100644 --- a/lib/ubsan/ubsan_value.h +++ b/lib/ubsan/ubsan_value.h @@ -14,12 +14,6 @@ #ifndef UBSAN_VALUE_H #define UBSAN_VALUE_H -// For now, only support Linux, FreeBSD and Darwin. Other platforms should -// be easy to add, and probably work as-is. -#if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__APPLE__) -#error "UBSan not supported for this platform!" -#endif - #include "sanitizer_common/sanitizer_atomic.h" #include "sanitizer_common/sanitizer_common.h" @@ -32,7 +26,6 @@ __extension__ typedef unsigned __int128 u128; #define HAVE_INT128_T 0 #endif - namespace __ubsan { /// \brief Largest integer types we support. diff --git a/make/platform/clang_darwin.mk b/make/platform/clang_darwin.mk index 4f71c0b46..b0e88021e 100644 --- a/make/platform/clang_darwin.mk +++ b/make/platform/clang_darwin.mk @@ -119,8 +119,11 @@ UniversalArchs.asan_osx_dynamic := $(call CheckArches,i386 x86_64 x86_64h,asan_o Configs += asan_iossim_dynamic UniversalArchs.asan_iossim_dynamic := $(call CheckArches,i386 x86_64,asan_iossim_dynamic,$(IOSSIM_SDK)) -Configs += ubsan_osx -UniversalArchs.ubsan_osx := $(call CheckArches,i386 x86_64 x86_64h,ubsan_osx,$(OSX_SDK)) +Configs += ubsan_osx_dynamic +UniversalArchs.ubsan_osx_dynamic := $(call CheckArches,i386 x86_64 x86_64h,ubsan_osx_dynamic,$(OSX_SDK)) + +Configs += ubsan_iossim_dynamic +UniversalArchs.ubsan_iossim_dynamic := $(call CheckArches,i386 x86_64,ubsan_iossim_dynamic,$(IOSSIM_SDK)) # Darwin 10.6 has a bug in cctools that makes it unable to use ranlib on our ARM # object files. If we are on that platform, strip out all ARM archs. We still @@ -172,26 +175,31 @@ IOSSIM_DEPLOYMENT_ARGS += -isysroot $(IOSSIM_SDK) CFLAGS.eprintf := $(CFLAGS) $(OSX_DEPLOYMENT_ARGS) CFLAGS.10.4 := $(CFLAGS) $(OSX_DEPLOYMENT_ARGS) +SANITIZER_MACOSX_DEPLOYMENT_ARGS := -mmacosx-version-min=10.7 +SANITIZER_IOSSIM_DEPLOYMENT_ARGS := -mios-simulator-version-min=7.0 \ + -isysroot $(IOSSIM_SDK) +SANITIZER_CFLAGS := -fno-builtin -gline-tables-only -stdlib=libc++ + CFLAGS.asan_osx_dynamic := \ - $(CFLAGS) -mmacosx-version-min=10.7 \ - -stdlib=libc++ \ - -isysroot $(OSX_SDK) \ - -fno-builtin \ - -gline-tables-only \ + $(CFLAGS) $(SANITIZER_MACOSX_DEPLOYMENT_ARGS) \ + $(SANITIZER_CFLAGS) \ -DMAC_INTERPOSE_FUNCTIONS=1 \ -DASAN_DYNAMIC=1 CFLAGS.asan_iossim_dynamic := \ - $(CFLAGS) -mios-simulator-version-min=7.0 \ - -isysroot $(IOSSIM_SDK) \ - -fno-builtin \ - -gline-tables-only \ + $(CFLAGS) $(SANITIZER_IOSSIM_DEPLOYMENT_ARGS) \ + $(SANITIZER_CFLAGS) \ -DMAC_INTERPOSE_FUNCTIONS=1 \ -DASAN_DYNAMIC=1 -CFLAGS.ubsan_osx := $(CFLAGS) -mmacosx-version-min=10.6 \ - -isysroot $(OSX_SDK) \ - -fno-builtin +CFLAGS.ubsan_osx_dynamic := \ + $(CFLAGS) $(SANITIZER_MACOSX_DEPLOYMENT_ARGS) \ + $(SANITIZER_CFLAGS) + +CFLAGS.ubsan_iossim_dynamic := \ + $(CFLAGS) $(SANITIZER_IOSSIM_DEPLOYMENT_ARGS) \ + $(SANITIZER_CFLAGS) + CFLAGS.ios.i386 := $(CFLAGS) $(IOSSIM_DEPLOYMENT_ARGS) CFLAGS.ios.x86_64 := $(CFLAGS) $(IOSSIM_DEPLOYMENT_ARGS) @@ -222,19 +230,30 @@ CFLAGS.profile_ios.armv7k := $(CFLAGS) $(IOS_DEPLOYMENT_ARGS) CFLAGS.profile_ios.armv7s := $(CFLAGS) $(IOS_DEPLOYMENT_ARGS) CFLAGS.profile_ios.arm64 := $(CFLAGS) $(IOS6_DEPLOYMENT_ARGS) -# Configure the asan_osx_dynamic library to be built shared. +SANITIZER_LDFLAGS := -stdlib=libc++ -lc++ + SHARED_LIBRARY.asan_osx_dynamic := 1 -LDFLAGS.asan_osx_dynamic := -lc++ -undefined dynamic_lookup -install_name @rpath/libclang_rt.asan_osx_dynamic.dylib \ - -mmacosx-version-min=10.7 \ - -isysroot $(OSX_SDK) +LDFLAGS.asan_osx_dynamic := $(SANITIZER_LDFLAGS) -install_name @rpath/libclang_rt.asan_osx_dynamic.dylib \ + $(SANITIZER_MACOSX_DEPLOYMENT_ARGS) -# Configure the asan_iossim_dynamic library to be built shared. SHARED_LIBRARY.asan_iossim_dynamic := 1 -# configure+make uses Clang, so we're using isysroot instead of --sysroot -# or -Wl,-syslibroot. -LDFLAGS.asan_iossim_dynamic := -undefined dynamic_lookup -install_name @rpath/libclang_rt.asan_iossim_dynamic.dylib \ - -Wl,-ios_simulator_version_min,7.0.0 \ - -mios-simulator-version-min=7.0 -isysroot $(IOSSIM_SDK) +LDFLAGS.asan_iossim_dynamic := $(SANITIZER_LDFLAGS) -install_name @rpath/libclang_rt.asan_iossim_dynamic.dylib \ + -Wl,-ios_simulator_version_min,7.0.0 $(SANITIZER_IOSSIM_DEPLOYMENT_ARGS) + +SHARED_LIBRARY.ubsan_osx_dynamic := 1 +LDFLAGS.ubsan_osx_dynamic := $(SANITIZER_LDFLAGS) -lc++abi -install_name @rpath/libclang_rt.ubsan_osx_dynamic.dylib \ + $(SANITIZER_MACOSX_DEPLOYMENT_ARGS) + +SHARED_LIBRARY.ubsan_iossim_dynamic := 1 +LDFLAGS.ubsan_iossim_dynamic := $(SANITIZER_LDFLAGS) -lc++abi -install_name @rpath/libclang_rt.ubsan_iossim_dynamic.dylib \ + -Wl,-ios_simulator_version_min,7.0.0 $(SANITIZER_IOSSIM_DEPLOYMENT_ARGS) + +ifneq ($(OSX_SDK),) +CFLAGS.asan_osx_dynamic += -isysroot $(OSX_SDK) +LDFLAGS.asan_osx_dynamic += -isysroot $(OSX_SDK) +CFLAGS.ubsan_osx_dynamic += -isysroot $(OSX_SDK) +LDFLAGS.ubsan_osx_dynamic += -isysroot $(OSX_SDK) +endif FUNCTIONS.eprintf := eprintf FUNCTIONS.10.4 := eprintf floatundidf floatundisf floatundixf @@ -256,15 +275,18 @@ FUNCTIONS.profile_ios := $(FUNCTIONS.profile_osx) FUNCTIONS.asan_osx_dynamic := $(AsanFunctions) $(AsanCXXFunctions) \ $(InterceptionFunctions) \ $(SanitizerCommonFunctions) \ - $(AsanDynamicFunctions) + $(AsanDynamicFunctions) FUNCTIONS.asan_iossim_dynamic := $(AsanFunctions) $(AsanCXXFunctions) \ $(InterceptionFunctions) \ $(SanitizerCommonFunctions) \ - $(AsanDynamicFunctions) + $(AsanDynamicFunctions) + +FUNCTIONS.ubsan_osx_dynamic := $(UbsanFunctions) $(UbsanCXXFunctions) \ + $(SanitizerCommonFunctions) -FUNCTIONS.ubsan_osx := $(UbsanFunctions) $(UbsanCXXFunctions) \ - $(SanitizerCommonFunctions) +FUNCTIONS.ubsan_iossim_dynamic := $(UbsanFunctions) $(UbsanCXXFunctions) \ + $(SanitizerCommonFunctions) CCKEXT_PROFILE_FUNCTIONS := \ InstrProfiling \ diff --git a/make/platform/clang_linux.mk b/make/platform/clang_linux.mk index cb023f3db..4585cd969 100644 --- a/make/platform/clang_linux.mk +++ b/make/platform/clang_linux.mk @@ -74,12 +74,6 @@ CFLAGS.builtins-x86_64 := $(CFLAGS) -m64 CFLAGS.profile-i386 := $(CFLAGS) -m32 CFLAGS.profile-x86_64 := $(CFLAGS) -m64 -# Use our stub SDK as the sysroot to support more portable building. For now we -# just do this for the core module, because the stub SDK doesn't have -# enough support to build the profile runtime. -CFLAGS.builtins-i386 += --sysroot=$(ProjSrcRoot)/SDKs/linux -CFLAGS.builtins-x86_64 += --sysroot=$(ProjSrcRoot)/SDKs/linux - FUNCTIONS.builtins-i386 := $(CommonFunctions) $(ArchFunctions.i386) FUNCTIONS.builtins-x86_64 := $(CommonFunctions) $(ArchFunctions.x86_64) FUNCTIONS.profile-i386 := GCDAProfiling InstrProfiling InstrProfilingBuffer \ diff --git a/test/asan/CMakeLists.txt b/test/asan/CMakeLists.txt index e1b812646..08c168988 100644 --- a/test/asan/CMakeLists.txt +++ b/test/asan/CMakeLists.txt @@ -5,9 +5,9 @@ set(ASAN_DYNAMIC_TESTSUITES) macro(get_bits_for_arch arch bits) if (${arch} MATCHES "i386|i686|arm|mips|mipsel") - set(bits 32) + set(${bits} 32) elseif (${arch} MATCHES "x86_64|powerpc64|powerpc64le|aarch64|mips64|mips64el") - set(bits 64) + set(${bits} 64) else() message(FATAL_ERROR "Unknown target architecture: ${arch}") endif() diff --git a/test/asan/TestCases/Darwin/atos-symbolizer.cc b/test/asan/TestCases/Darwin/atos-symbolizer.cc new file mode 100644 index 000000000..a4df3a2e5 --- /dev/null +++ b/test/asan/TestCases/Darwin/atos-symbolizer.cc @@ -0,0 +1,28 @@ +// Check that the `atos` symbolizer works. + +// RUN: %clangxx_asan -O0 %s -o %t +// RUN: ASAN_OPTIONS=verbosity=2 ASAN_SYMBOLIZER_PATH=$(which atos) not %run %t 2>&1 | FileCheck %s + +// Check that when having a DYLD_ROOT_PATH set, the symbolizer still works. +// RUN: DYLD_ROOT_PATH="/" ASAN_OPTIONS=verbosity=2 ASAN_SYMBOLIZER_PATH=$(which atos) \ +// RUN: not %run %t 2>&1 | FileCheck %s + +#include <stdlib.h> +#include <string.h> +int main(int argc, char **argv) { + char *x = (char*)malloc(10 * sizeof(char)); + memset(x, 0, 10); + int res = x[argc]; + free(x); + free(x + argc - 1); // BOOM + // CHECK: AddressSanitizer: attempting double-free{{.*}}in thread T0 + // CHECK: Using atos at user-specified path: + // CHECK: #0 0x{{.*}} in {{.*}}free + // CHECK: #1 0x{{.*}} in main {{.*}}atos-symbolizer.cc:[[@LINE-4]] + // CHECK: freed by thread T0 here: + // CHECK: #0 0x{{.*}} in {{.*}}free + // CHECK: #1 0x{{.*}} in main {{.*}}atos-symbolizer.cc:[[@LINE-8]] + // CHECK: allocated by thread T0 here: + // CHECK: atos-symbolizer.cc:[[@LINE-13]] + return res; +} diff --git a/test/asan/TestCases/Darwin/dladdr-demangling.cc b/test/asan/TestCases/Darwin/dladdr-demangling.cc new file mode 100644 index 000000000..494007f51 --- /dev/null +++ b/test/asan/TestCases/Darwin/dladdr-demangling.cc @@ -0,0 +1,33 @@ +// In a non-forking sandbox, we fallback to dladdr(). Test that we provide +// properly demangled C++ names in that case. + +// RUN: %clangxx_asan -O0 %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s +// RUN: ASAN_OPTIONS=verbosity=2 not %run sandbox-exec -p '(version 1)(allow default)(deny process-fork)' %t 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-DLADDR + +#include <stdlib.h> + +class MyClass { + public: + int my_function(int n) { + char *x = (char*)malloc(n * sizeof(char)); + free(x); + return x[5]; + // CHECK: {{.*ERROR: AddressSanitizer: heap-use-after-free on address}} + // CHECK: {{READ of size 1 at 0x.* thread T0}} + // CHECK-DLADDR: Using dladdr symbolizer + // CHECK-DLADDR: failed to fork external symbolizer + // CHECK: {{ #0 0x.* in MyClass::my_function\(int\)}} + // CHECK: {{freed by thread T0 here:}} + // CHECK: {{ #0 0x.* in wrap_free}} + // CHECK: {{ #1 0x.* in MyClass::my_function\(int\)}} + // CHECK: {{previously allocated by thread T0 here:}} + // CHECK: {{ #0 0x.* in wrap_malloc}} + // CHECK: {{ #1 0x.* in MyClass::my_function\(int\)}} + } +}; + +int main() { + MyClass o; + return o.my_function(10); +} diff --git a/test/asan/TestCases/Darwin/interface_symbols_darwin.c b/test/asan/TestCases/Darwin/interface_symbols_darwin.c index a75044d49..bd9bbee84 100644 --- a/test/asan/TestCases/Darwin/interface_symbols_darwin.c +++ b/test/asan/TestCases/Darwin/interface_symbols_darwin.c @@ -29,6 +29,18 @@ // RUN: echo __asan_report_store16 >> %t.interface // RUN: echo __asan_report_load_n >> %t.interface // RUN: echo __asan_report_store_n >> %t.interface +// RUN: echo __asan_report_exp_load1 >> %t.interface +// RUN: echo __asan_report_exp_load2 >> %t.interface +// RUN: echo __asan_report_exp_load4 >> %t.interface +// RUN: echo __asan_report_exp_load8 >> %t.interface +// RUN: echo __asan_report_exp_load16 >> %t.interface +// RUN: echo __asan_report_exp_store1 >> %t.interface +// RUN: echo __asan_report_exp_store2 >> %t.interface +// RUN: echo __asan_report_exp_store4 >> %t.interface +// RUN: echo __asan_report_exp_store8 >> %t.interface +// RUN: echo __asan_report_exp_store16 >> %t.interface +// RUN: echo __asan_report_exp_load_n >> %t.interface +// RUN: echo __asan_report_exp_store_n >> %t.interface // RUN: echo __asan_get_current_fake_stack >> %t.interface // RUN: echo __asan_addr_is_in_fake_stack >> %t.interface // RUN: echo __asan_mz_calloc >> %t.interface diff --git a/test/asan/TestCases/Darwin/sandbox-symbolizer.cc b/test/asan/TestCases/Darwin/sandbox-symbolizer.cc new file mode 100644 index 000000000..431337187 --- /dev/null +++ b/test/asan/TestCases/Darwin/sandbox-symbolizer.cc @@ -0,0 +1,29 @@ +// In a non-forking sandbox, we can't spawn an external symbolizer, but dladdr() +// should still work and provide function names. No line numbers though. +// Second, `atos` symbolizer can't inspect a process that has an inaccessible +// task port, in which case we should again fallback to dladdr gracefully. + +// RUN: %clangxx_asan -O0 %s -o %t +// RUN: not %run sandbox-exec -p '(version 1)(allow default)(deny process-fork)' %t 2>&1 | FileCheck %s +// RUN: not %run sandbox-exec -p '(version 1)(allow default)(deny mach-priv-task-port)' %t 2>&1 | FileCheck %s +// RUN: ASAN_SYMBOLIZER_PATH="" not %run sandbox-exec -p '(version 1)(allow default)(deny mach-priv-task-port)' %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O3 %s -o %t +// RUN: not %run sandbox-exec -p '(version 1)(allow default)(deny process-fork)' %t 2>&1 | FileCheck %s +// RUN: not %run sandbox-exec -p '(version 1)(allow default)(deny mach-priv-task-port)' %t 2>&1 | FileCheck %s +// RUN: ASAN_SYMBOLIZER_PATH="" not %run sandbox-exec -p '(version 1)(allow default)(deny mach-priv-task-port)' %t 2>&1 | FileCheck %s + +#include <stdlib.h> +int main() { + char *x = (char*)malloc(10 * sizeof(char)); + free(x); + return x[5]; + // CHECK: {{.*ERROR: AddressSanitizer: heap-use-after-free on address}} + // CHECK: {{READ of size 1 at 0x.* thread T0}} + // CHECK: {{ #0 0x.* in main}} + // CHECK: {{freed by thread T0 here:}} + // CHECK: {{ #0 0x.* in wrap_free}} + // CHECK: {{ #1 0x.* in main}} + // CHECK: {{previously allocated by thread T0 here:}} + // CHECK: {{ #0 0x.* in wrap_malloc}} + // CHECK: {{ #1 0x.* in main}} +} diff --git a/test/asan/TestCases/Darwin/suppressions-sandbox.cc b/test/asan/TestCases/Darwin/suppressions-sandbox.cc new file mode 100644 index 000000000..59fe47510 --- /dev/null +++ b/test/asan/TestCases/Darwin/suppressions-sandbox.cc @@ -0,0 +1,26 @@ +// Check that without suppressions, we catch the issue. +// RUN: %clangxx_asan -O0 %s -o %t -framework Foundation +// RUN: not %run %t 2>&1 | FileCheck --check-prefix=CHECK-CRASH %s + +// Check that suppressing a function name works within a no-fork sandbox +// RUN: echo "interceptor_via_fun:CFStringCreateWithBytes" > %t.supp +// RUN: ASAN_OPTIONS=suppressions=%t.supp \ +// RUN: sandbox-exec -p '(version 1)(allow default)(deny process-fork)' \ +// RUN: %run %t 2>&1 | FileCheck --check-prefix=CHECK-IGNORE %s + +#include <CoreFoundation/CoreFoundation.h> + +int main() { + char *a = (char *)malloc(6); + strcpy(a, "hello"); + CFStringRef str = + CFStringCreateWithBytes(kCFAllocatorDefault, (unsigned char *)a, 10, + kCFStringEncodingUTF8, FALSE); // BOOM + fprintf(stderr, "Ignored.\n"); + free(a); +} + +// CHECK-CRASH: AddressSanitizer: heap-buffer-overflow +// CHECK-CRASH-NOT: Ignored. +// CHECK-IGNORE-NOT: AddressSanitizer: heap-buffer-overflow +// CHECK-IGNORE: Ignored. diff --git a/test/asan/TestCases/Linux/coverage-module-unloaded.cc b/test/asan/TestCases/Linux/coverage-module-unloaded.cc index f8d9c57f8..573fc4664 100644 --- a/test/asan/TestCases/Linux/coverage-module-unloaded.cc +++ b/test/asan/TestCases/Linux/coverage-module-unloaded.cc @@ -50,7 +50,7 @@ int main(int argc, char **argv) { // CHECK: PID: [[PID:[0-9]+]] // CHECK: [[PID]].sancov: 1 PCs written -// CHECK: .so.[[PID]] -// If we get coverage for both DSOs, it means the module wasn't unloaded and -// this test is useless. -// CHECK-NOT: .so.[[PID]] +// CHECK: test_1.so.[[PID]] +// CHECK: test_2.so.[[PID]] +// Even though we've unloaded one of the libs we still dump the coverage file +// for that lib (although the data will be inaccurate, it at all useful) diff --git a/test/asan/TestCases/Linux/coverage-sandboxing.cc b/test/asan/TestCases/Linux/coverage-sandboxing.cc index 1a72c6bb9..15bada886 100644 --- a/test/asan/TestCases/Linux/coverage-sandboxing.cc +++ b/test/asan/TestCases/Linux/coverage-sandboxing.cc @@ -78,8 +78,8 @@ int main(int argc, char **argv) { #endif // CHECK-vanilla: PID: [[PID:[0-9]+]] -// CHECK-vanilla: [[PID]].sancov: 1 PCs written // CHECK-vanilla: .so.[[PID]].sancov: 258 PCs written +// CHECK-vanilla: [[PID]].sancov: 1 PCs written // CHECK-sandbox: PID: [[PID:[0-9]+]] // CHECK-sandbox: 258 PCs written to packed file diff --git a/test/asan/TestCases/Linux/coverage.cc b/test/asan/TestCases/Linux/coverage.cc index 06fe1a295..1ad19e66c 100644 --- a/test/asan/TestCases/Linux/coverage.cc +++ b/test/asan/TestCases/Linux/coverage.cc @@ -1,11 +1,18 @@ // RUN: %clangxx_asan -fsanitize-coverage=1 -DSHARED %s -shared -o %T/libcoverage_test.so -fPIC // RUN: %clangxx_asan -fsanitize-coverage=1 %s -o %t -Wl,-R,\$ORIGIN -L%T -lcoverage_test // RUN: export ASAN_OPTIONS=coverage=1:verbosity=1 -// RUN: mkdir -p %T/coverage && cd %T/coverage +// RUN: rm -rf %T/coverage && mkdir -p %T/coverage && cd %T/coverage // RUN: %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-main +// RUN: %sancov print coverage.*sancov 2>&1 | FileCheck %s --check-prefix=CHECK-SANCOV1 // RUN: %run %t foo 2>&1 | FileCheck %s --check-prefix=CHECK-foo +// RUN: %sancov print coverage.*sancov 2>&1 | FileCheck %s --check-prefix=CHECK-SANCOV2 // RUN: %run %t bar 2>&1 | FileCheck %s --check-prefix=CHECK-bar +// RUN: %sancov print coverage.*sancov 2>&1 | FileCheck %s --check-prefix=CHECK-SANCOV2 // RUN: %run %t foo bar 2>&1 | FileCheck %s --check-prefix=CHECK-foo-bar +// RUN: %sancov print coverage.*sancov 2>&1 | FileCheck %s --check-prefix=CHECK-SANCOV2 +// RUN: %sancov print libcoverage_test.*sancov 2>&1 | FileCheck %s --check-prefix=CHECK-SANCOV1 +// RUN: %sancov merge coverage.*sancov > merged-cov +// RUN: %sancov print merged-cov 2>&1 | FileCheck %s --check-prefix=CHECK-SANCOV2 // RUN: not %run %t foo bar 4 2>&1 | FileCheck %s --check-prefix=CHECK-report // RUN: not %run %t foo bar 4 5 2>&1 | FileCheck %s --check-prefix=CHECK-segv // RUN: cd .. && rm coverage -r @@ -57,15 +64,18 @@ int main(int argc, char **argv) { // CHECK-foo-NOT: .so.[[PID]] // // CHECK-bar: PID: [[PID:[0-9]+]] -// CHECK-bar: [[PID]].sancov: 1 PCs written // CHECK-bar: .so.[[PID]].sancov: 1 PCs written +// CHECK-bar: [[PID]].sancov: 1 PCs written // // CHECK-foo-bar: PID: [[PID:[0-9]+]] -// CHECK-foo-bar: [[PID]].sancov: 2 PCs written // CHECK-foo-bar: so.[[PID]].sancov: 1 PCs written +// CHECK-foo-bar: [[PID]].sancov: 2 PCs written // // CHECK-report: AddressSanitizer: global-buffer-overflow // CHECK-report: PCs written // // CHECK-segv: AddressSanitizer: SEGV // CHECK-segv: PCs written +// +// CHECK-SANCOV1: 1 PCs total +// CHECK-SANCOV2: 2 PCs total diff --git a/test/asan/TestCases/Linux/interface_symbols_linux.c b/test/asan/TestCases/Linux/interface_symbols_linux.c index a616732ff..bec501b84 100644 --- a/test/asan/TestCases/Linux/interface_symbols_linux.c +++ b/test/asan/TestCases/Linux/interface_symbols_linux.c @@ -24,6 +24,18 @@ // RUN: echo __asan_report_store16 >> %t.interface // RUN: echo __asan_report_load_n >> %t.interface // RUN: echo __asan_report_store_n >> %t.interface +// RUN: echo __asan_report_exp_load1 >> %t.interface +// RUN: echo __asan_report_exp_load2 >> %t.interface +// RUN: echo __asan_report_exp_load4 >> %t.interface +// RUN: echo __asan_report_exp_load8 >> %t.interface +// RUN: echo __asan_report_exp_load16 >> %t.interface +// RUN: echo __asan_report_exp_store1 >> %t.interface +// RUN: echo __asan_report_exp_store2 >> %t.interface +// RUN: echo __asan_report_exp_store4 >> %t.interface +// RUN: echo __asan_report_exp_store8 >> %t.interface +// RUN: echo __asan_report_exp_store16 >> %t.interface +// RUN: echo __asan_report_exp_load_n >> %t.interface +// RUN: echo __asan_report_exp_store_n >> %t.interface // RUN: echo __asan_get_current_fake_stack >> %t.interface // RUN: echo __asan_addr_is_in_fake_stack >> %t.interface // RUN: cat %t.interface | sort -u | diff %t.symbols - diff --git a/test/asan/TestCases/Linux/leak_check_segv.cc b/test/asan/TestCases/Linux/leak_check_segv.cc new file mode 100644 index 000000000..8160d5fe5 --- /dev/null +++ b/test/asan/TestCases/Linux/leak_check_segv.cc @@ -0,0 +1,23 @@ +// Test that SIGSEGV during leak checking does not crash the process. +// RUN: %clangxx_asan -O1 %s -o %t && LSAN_OPTIONS="verbosity=1" not %run %t 2>&1 +// REQUIRES: leak-detection +#include <stdlib.h> +#include <stdio.h> +#include <sys/mman.h> +#include <sanitizer/lsan_interface.h> + +char data[10 * 1024 * 1024]; + +int main() { + void *p = malloc(10 * 1024 * 1024); + // surprise-surprise! + mprotect((void*)(((unsigned long)p + 4095) & ~4095), 16 * 1024, PROT_NONE); + mprotect((void*)(((unsigned long)data + 4095) & ~4095), 16 * 1024, PROT_NONE); + __lsan_do_leak_check(); + fprintf(stderr, "DONE\n"); +} + +// CHECK: Tracer caught signal 11 +// CHECK: LeakSanitizer has encountered a fatal error +// CHECK-NOT: DONE + diff --git a/test/asan/TestCases/Linux/nohugepage_test.cc b/test/asan/TestCases/Linux/nohugepage_test.cc index b549f3bc2..337b95dc0 100644 --- a/test/asan/TestCases/Linux/nohugepage_test.cc +++ b/test/asan/TestCases/Linux/nohugepage_test.cc @@ -22,15 +22,31 @@ #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> +#include <errno.h> #include <sanitizer/asan_interface.h> -char FileContents[1 << 14]; +char FileContents[1 << 16]; void FileToString(const char *path) { FileContents[0] = 0; int fd = open(path, 0); if (fd < 0) return; - ssize_t res = read(fd, FileContents, sizeof(FileContents) - 1); + char *p = FileContents; + ssize_t size = sizeof(FileContents) - 1; + ssize_t res = 0; + do { + ssize_t got = read (fd, p, size); + if (got == 0) + break; + else if (got > 0) + { + p += got; + res += got; + size -= got; + } + else if (errno != EINTR) + break; + } while (size > 0 && res < sizeof(FileContents)); if (res >= 0) FileContents[res] = 0; } diff --git a/test/asan/TestCases/Linux/ptrace.cc b/test/asan/TestCases/Linux/ptrace.cc index 7e5acb64c..6840ebe28 100644 --- a/test/asan/TestCases/Linux/ptrace.cc +++ b/test/asan/TestCases/Linux/ptrace.cc @@ -31,8 +31,8 @@ int main(void) { // CHECK: AddressSanitizer: stack-buffer-overflow // CHECK: {{.*ptrace.cc:}}[[@LINE-2]] assert(!res); -#if __WORDSIZE == 64 - printf("%zx\n", regs.rip); +#ifdef __x86_64__ + printf("%lx\n", (unsigned long)regs.rip); #else printf("%lx\n", regs.eip); #endif @@ -42,7 +42,7 @@ int main(void) { assert(!res); printf("%lx\n", (unsigned long)fpregs.cwd); -#if __WORDSIZE == 32 +#ifndef __x86_64__ user_fpxregs_struct fpxregs; res = ptrace(PTRACE_GETFPXREGS, pid, NULL, &fpxregs); assert(!res); diff --git a/test/asan/TestCases/Linux/signal_during_stop_the_world.cc b/test/asan/TestCases/Linux/signal_during_stop_the_world.cc new file mode 100644 index 000000000..b1a41fe20 --- /dev/null +++ b/test/asan/TestCases/Linux/signal_during_stop_the_world.cc @@ -0,0 +1,60 @@ +// Test StopTheWorld behavior during signal storm. +// Historically StopTheWorld crashed because did not handle EINTR properly. +// The test is somewhat convoluted, but that's what caused crashes previously. + +// RUN: %clangxx_asan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s + +#include <stdio.h> +#include <stdlib.h> +#include <signal.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/prctl.h> +#include <sys/wait.h> +#include <time.h> +#include <pthread.h> +#include <sanitizer/lsan_interface.h> + +static void handler(int signo); +static void *thr(void *arg); + +int main() { + struct sigaction act = {}; + act.sa_handler = handler; + sigaction(SIGPROF, &act, 0); + + pid_t pid = fork(); + if (pid < 0) { + fprintf(stderr, "failed to fork\n"); + exit(1); + } + if (pid == 0) { + // Child constantly sends signals to parent to cause spurious return from + // waitpid in StopTheWorld. + prctl(PR_SET_PDEATHSIG, SIGTERM, 0, 0, 0); + pid_t parent = getppid(); + for (;;) { + // There is no strong reason for these two particular signals, + // but at least one of them ought to unblock waitpid. + kill(parent, SIGCHLD); + kill(parent, SIGPROF); + } + } + usleep(10000); // Let the child start. + __lsan_do_leak_check(); + // Kill and join the child. + kill(pid, SIGTERM); + waitpid(pid, 0, 0); + sleep(1); // If the tracer thread still runs, give it time to crash. + fprintf(stderr, "DONE\n"); +// CHECK: DONE +} + +static void handler(int signo) { +} + +static void *thr(void *arg) { + for (;;) + sleep(1); + return 0; +} diff --git a/test/asan/TestCases/Linux/sized_delete_test.cc b/test/asan/TestCases/Linux/sized_delete_test.cc index 1ce610f1b..140164464 100644 --- a/test/asan/TestCases/Linux/sized_delete_test.cc +++ b/test/asan/TestCases/Linux/sized_delete_test.cc @@ -1,4 +1,4 @@ -// RUN: %clangxx_asan -Xclang -fdefine-sized-deallocation -Xclang -fsized-deallocation -O0 %s -o %t +// RUN: %clangxx_asan -fsized-deallocation -O0 %s -o %t // RUN: not %run %t scalar 2>&1 | FileCheck %s -check-prefix=SCALAR // RUN: ASAN_OPTIONS=new_delete_type_mismatch=1 not %run %t scalar 2>&1 | FileCheck %s -check-prefix=SCALAR // RUN: not %run %t array 2>&1 | FileCheck %s -check-prefix=ARRAY @@ -6,9 +6,10 @@ // RUN: ASAN_OPTIONS=new_delete_type_mismatch=0 %run %t scalar // RUN: ASAN_OPTIONS=new_delete_type_mismatch=0 %run %t array +// FIXME: the following two lines are not true after r232788. // Sized-delete is implemented with a weak delete() definition. // Weak symbols are kind of broken on Android. -// XFAIL: android, asan-dynamic-runtime +// XFAIL: android #include <new> #include <stdio.h> diff --git a/test/asan/TestCases/Linux/coverage-direct.cc b/test/asan/TestCases/Posix/coverage-direct.cc index 45222fa1a..45222fa1a 100644 --- a/test/asan/TestCases/Linux/coverage-direct.cc +++ b/test/asan/TestCases/Posix/coverage-direct.cc diff --git a/test/asan/TestCases/Linux/coverage-fork.cc b/test/asan/TestCases/Posix/coverage-fork.cc index 38c200942..38c200942 100644 --- a/test/asan/TestCases/Linux/coverage-fork.cc +++ b/test/asan/TestCases/Posix/coverage-fork.cc diff --git a/test/asan/TestCases/log_path_fork_test.cc.disabled b/test/asan/TestCases/Posix/log_path_fork_test.cc.disabled index cfe90dfb5..cfe90dfb5 100644 --- a/test/asan/TestCases/log_path_fork_test.cc.disabled +++ b/test/asan/TestCases/Posix/log_path_fork_test.cc.disabled diff --git a/test/asan/TestCases/Posix/start-deactivated.cc b/test/asan/TestCases/Posix/start-deactivated.cc index d7e0dfc98..2eb02dff6 100644 --- a/test/asan/TestCases/Posix/start-deactivated.cc +++ b/test/asan/TestCases/Posix/start-deactivated.cc @@ -19,7 +19,6 @@ // RUN: ASAN_ACTIVATION_OPTIONS=help=1,handle_segv=0,verbosity=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-UNSUPPORTED // XFAIL: arm-linux-gnueabi -// XFAIL: armv7l-unknown-linux-gnueabihf #if !defined(SHARED_LIB) #include <assert.h> diff --git a/test/asan/TestCases/Windows/bind_io_completion_callback.cc b/test/asan/TestCases/Windows/bind_io_completion_callback.cc new file mode 100644 index 000000000..c062a799f --- /dev/null +++ b/test/asan/TestCases/Windows/bind_io_completion_callback.cc @@ -0,0 +1,70 @@ +// Make sure we can throw exceptions from work items executed via +// BindIoCompletionCallback. +// +// Clang doesn't support exceptions on Windows yet, so for the time being we +// build this program in two parts: the code with exceptions is built with CL, +// the rest is built with Clang. This represents the typical scenario when we +// build a large project using "clang-cl -fallback -fsanitize=address". +// +// RUN: cl -c %s -Fo%t.obj +// RUN: %clangxx_asan -o %t.exe %s %t.obj +// RUN: %run %t.exe 2>&1 | FileCheck %s + +#include <windows.h> +#include <stdio.h> + +void ThrowAndCatch(); + +#if !defined(__clang__) +__declspec(noinline) +void Throw() { + fprintf(stderr, "Throw\n"); +// CHECK: Throw + throw 1; +} + +void ThrowAndCatch() { + int local; + try { + Throw(); + } catch(...) { + fprintf(stderr, "Catch\n"); +// CHECK: Catch + } +} +#else + +char buffer[65536]; +HANDLE done; +OVERLAPPED ov; + +void CALLBACK completion_callback(DWORD error, DWORD bytesRead, + LPOVERLAPPED pov) { + ThrowAndCatch(); + SetEvent(done); +} + +int main(int argc, char **argv) { + done = CreateEvent(0, false, false, "job is done"); + if (!done) + return 1; + HANDLE file = CreateFile( + argv[0], GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, + NULL); + if (!file) + return 2; + if (!BindIoCompletionCallback(file, completion_callback, 0)) + return 3; + + if (!ReadFile(file, buffer, sizeof(buffer), NULL, &ov) && + GetLastError() != ERROR_IO_PENDING) + return 4; + + if (WAIT_OBJECT_0 != WaitForSingleObject(done, INFINITE)) + return 5; + fprintf(stderr, "Done!\n"); +// CHECK: Done! +} +#endif diff --git a/test/asan/TestCases/Windows/dll_noreturn.cc b/test/asan/TestCases/Windows/dll_noreturn.cc index 6ec907251..79f923ecc 100644 --- a/test/asan/TestCases/Windows/dll_noreturn.cc +++ b/test/asan/TestCases/Windows/dll_noreturn.cc @@ -9,7 +9,7 @@ void noreturn_f() { char buffer[42]; buffer[subscript] = 42; _exit(1); -// CHECK: AddressSanitizer: stack-buffer-overflow on address [[ADDR:0x[0-9a-f]+]] +// CHECK: AddressSanitizer: stack-buffer-underflow on address [[ADDR:0x[0-9a-f]+]] // CHECK: WRITE of size 1 at [[ADDR]] thread T0 // CHECK-NEXT: noreturn_f {{.*}}dll_noreturn.cc:[[@LINE-4]] // CHECK-NEXT: test_function {{.*}}dll_noreturn.cc diff --git a/test/asan/TestCases/Windows/dll_report_globals_symbolization_at_startup.cc b/test/asan/TestCases/Windows/dll_report_globals_symbolization_at_startup.cc new file mode 100644 index 000000000..fbdb1c145 --- /dev/null +++ b/test/asan/TestCases/Windows/dll_report_globals_symbolization_at_startup.cc @@ -0,0 +1,40 @@ +// RUN: %clang_cl_asan -LD -O0 -DDLL %s -Fe%t.dll +// RUN: %clang_cl_asan -O0 -DEXE %s %t.lib -Fe%te.exe +// RUN: env ASAN_OPTIONS=report_globals=2 %run %te.exe 2>&1 | FileCheck %s + +// FIXME: Currently, the MT runtime build crashes on startup due to dbghelp.dll +// initialization failure. +// REQUIRES: asan-dynamic-runtime + +#include <windows.h> +#include <stdio.h> + +extern "C" { +#if defined(EXE) +__declspec(dllimport) int foo_from_dll(); + +// CHECK: in DLL(reason=1) +int main(int argc, char **argv) { + foo_from_dll(); +// CHECK: hello! + printf("hello!\n"); + fflush(0); +// CHECK: in DLL(reason=0) +} +#elif defined(DLL) +// This global is registered at startup. +int x[42]; + +__declspec(dllexport) int foo_from_dll() { + return x[2]; +} + +BOOL WINAPI DllMain(HMODULE, DWORD reason, LPVOID) { + printf("in DLL(reason=%d)\n", (int)reason); + fflush(0); + return TRUE; +} +#else +# error oops! +#endif +} diff --git a/test/asan/TestCases/Windows/dll_thread_stack_array_left_oob.cc b/test/asan/TestCases/Windows/dll_thread_stack_array_left_oob.cc index 8f5362341..04d3e2ec5 100644 --- a/test/asan/TestCases/Windows/dll_thread_stack_array_left_oob.cc +++ b/test/asan/TestCases/Windows/dll_thread_stack_array_left_oob.cc @@ -9,7 +9,7 @@ DWORD WINAPI thread_proc(void *context) { int subscript = -1; char stack_buffer[42]; stack_buffer[subscript] = 42; -// CHECK: AddressSanitizer: stack-buffer-overflow on address [[ADDR:0x[0-9a-f]+]] +// CHECK: AddressSanitizer: stack-buffer-underflow on address [[ADDR:0x[0-9a-f]+]] // CHECK: WRITE of size 1 at [[ADDR]] thread T1 // CHECK-NEXT: thread_proc {{.*}}dll_thread_stack_array_left_oob.cc:[[@LINE-3]] // diff --git a/test/asan/TestCases/Windows/queue_user_work_item.cc b/test/asan/TestCases/Windows/queue_user_work_item.cc new file mode 100644 index 000000000..d99ea6fc2 --- /dev/null +++ b/test/asan/TestCases/Windows/queue_user_work_item.cc @@ -0,0 +1,55 @@ +// Make sure we can throw exceptions from work items executed via +// QueueUserWorkItem. +// +// Clang doesn't support exceptions on Windows yet, so for the time being we +// build this program in two parts: the code with exceptions is built with CL, +// the rest is built with Clang. This represents the typical scenario when we +// build a large project using "clang-cl -fallback -fsanitize=address". +// +// RUN: cl -c %s -Fo%t.obj +// RUN: %clangxx_asan -o %t.exe %s %t.obj +// RUN: %run %t.exe 2>&1 | FileCheck %s + +#include <windows.h> +#include <stdio.h> + +void ThrowAndCatch(); + +#if !defined(__clang__) +__declspec(noinline) +void Throw() { + fprintf(stderr, "Throw\n"); +// CHECK: Throw + throw 1; +} + +void ThrowAndCatch() { + int local; + try { + Throw(); + } catch(...) { + fprintf(stderr, "Catch\n"); +// CHECK: Catch + } +} +#else + +HANDLE done; + +DWORD CALLBACK work_item(LPVOID) { + ThrowAndCatch(); + SetEvent(done); + return 0; +} + +int main(int argc, char **argv) { + done = CreateEvent(0, false, false, "job is done"); + if (!done) + return 1; + QueueUserWorkItem(&work_item, nullptr, 0); + if (WAIT_OBJECT_0 != WaitForSingleObject(done, INFINITE)) + return 2; + fprintf(stderr, "Done!\n"); +// CHECK: Done! +} +#endif diff --git a/test/asan/TestCases/Windows/queue_user_work_item_report.cc b/test/asan/TestCases/Windows/queue_user_work_item_report.cc new file mode 100644 index 000000000..a57e1e767 --- /dev/null +++ b/test/asan/TestCases/Windows/queue_user_work_item_report.cc @@ -0,0 +1,29 @@ +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: not %run %t 2>&1 | FileCheck %s + +#include <windows.h> + +HANDLE done; + +DWORD CALLBACK work_item(LPVOID) { + int subscript = -1; + volatile char stack_buffer[42]; + stack_buffer[subscript] = 42; +// CHECK: AddressSanitizer: stack-buffer-underflow on address [[ADDR:0x[0-9a-f]+]] +// CHECK: WRITE of size 1 at [[ADDR]] thread T1 +// CHECK: {{#0 .* work_item .*queue_user_work_item_report.cc}}:[[@LINE-3]] +// CHECK: Address [[ADDR]] is located in stack of thread T1 at offset {{.*}} in frame +// CHECK: work_item + SetEvent(done); + return 0; +} + +int main(int argc, char **argv) { + done = CreateEvent(0, false, false, "job is done"); + if (!done) + return 1; +// CHECK-NOT: Thread T1 created + QueueUserWorkItem(&work_item, nullptr, 0); + if (WAIT_OBJECT_0 != WaitForSingleObject(done, INFINITE)) + return 2; +} diff --git a/test/asan/TestCases/Windows/report_globals_reload_dll.cc b/test/asan/TestCases/Windows/report_globals_reload_dll.cc new file mode 100644 index 000000000..8b050975a --- /dev/null +++ b/test/asan/TestCases/Windows/report_globals_reload_dll.cc @@ -0,0 +1,51 @@ +// Make sure we can handle reloading the same DLL multiple times. +// RUN: %clang_cl_asan -LD -O0 -DDLL %s -Fe%t.dll +// RUN: %clang_cl_asan -O0 -DEXE %s -Fe%te.exe +// RUN: env ASAN_OPTIONS=report_globals=1 %run %te.exe %t.dll 2>&1 | FileCheck %s + +#include <windows.h> +#include <stdio.h> +#include <string.h> + +extern "C" { +#if defined(EXE) +int main(int argc, char **argv) { + if (argc != 2) { + printf("Usage: %s [client].dll\n", argv[0]); + return 101; + } + const char *dll_name = argv[1]; + +// CHECK: time to load DLL + printf("time to load DLL\n"); + fflush(0); + +// CHECK: in DLL(reason=1) +// CHECK: in DLL(reason=0) +// CHECK: in DLL(reason=1) +// CHECK: in DLL(reason=0) +// CHECK: in DLL(reason=1) +// CHECK: in DLL(reason=0) + for (int i = 0; i < 30; ++i) { + HMODULE dll = LoadLibrary(dll_name); + if (dll == NULL) + return 3; + + if (!FreeLibrary(dll)) + return 4; + } + +// CHECK: All OK! + printf("All OK!\n"); + fflush(0); +} +#elif defined(DLL) +BOOL WINAPI DllMain(HMODULE, DWORD reason, LPVOID) { + printf("in DLL(reason=%d)\n", (int)reason); + fflush(0); + return TRUE; +} +#else +# error oops! +#endif +} diff --git a/test/asan/TestCases/Windows/globals_multiple_dlls.cc b/test/asan/TestCases/Windows/report_globals_vs_freelibrary.cc index 634e57827..72bf36ad0 100644 --- a/test/asan/TestCases/Windows/globals_multiple_dlls.cc +++ b/test/asan/TestCases/Windows/report_globals_vs_freelibrary.cc @@ -1,7 +1,3 @@ -// Make sure everything works even if the main module doesn't have any stack -// variables, thus doesn't explicitly reference any symbol exported by the -// runtime thunk. -// // RUN: %clang_cl_asan -LD -O0 -DDLL %s -Fe%t.dll // RUN: %clang_cl_asan -O0 -DEXE %s -Fe%te.exe // RUN: env ASAN_OPTIONS=report_globals=2 %run %te.exe %t.dll 2>&1 | FileCheck %s diff --git a/test/asan/TestCases/Windows/stack_array_left_oob.cc b/test/asan/TestCases/Windows/stack_array_left_oob.cc index 040d855b4..845a1f332 100644 --- a/test/asan/TestCases/Windows/stack_array_left_oob.cc +++ b/test/asan/TestCases/Windows/stack_array_left_oob.cc @@ -7,7 +7,7 @@ int main() { int subscript = -1; char buffer[42]; buffer[subscript] = 42; -// CHECK: AddressSanitizer: stack-buffer-overflow on address [[ADDR:0x[0-9a-f]+]] +// CHECK: AddressSanitizer: stack-buffer-underflow on address [[ADDR:0x[0-9a-f]+]] // CHECK: WRITE of size 1 at [[ADDR]] thread T0 // CHECK-NEXT: {{#0 .* main .*stack_array_left_oob.cc}}:[[@LINE-3]] // CHECK: Address [[ADDR]] is located in stack of thread T0 at offset [[OFFSET:.*]] in frame diff --git a/test/asan/TestCases/Windows/thread_stack_array_left_oob.cc b/test/asan/TestCases/Windows/thread_stack_array_left_oob.cc index 17b9b1bf8..63cb8ae1f 100644 --- a/test/asan/TestCases/Windows/thread_stack_array_left_oob.cc +++ b/test/asan/TestCases/Windows/thread_stack_array_left_oob.cc @@ -7,7 +7,7 @@ DWORD WINAPI thread_proc(void *) { int subscript = -1; volatile char stack_buffer[42]; stack_buffer[subscript] = 42; -// CHECK: AddressSanitizer: stack-buffer-overflow on address [[ADDR:0x[0-9a-f]+]] +// CHECK: AddressSanitizer: stack-buffer-underflow on address [[ADDR:0x[0-9a-f]+]] // CHECK: WRITE of size 1 at [[ADDR]] thread T1 // CHECK: {{#0 .* thread_proc .*thread_stack_array_left_oob.cc}}:[[@LINE-3]] // CHECK: Address [[ADDR]] is located in stack of thread T1 at offset {{.*}} in frame diff --git a/test/asan/TestCases/closed-fds.cc b/test/asan/TestCases/closed-fds.cc new file mode 100644 index 000000000..604bf8bcf --- /dev/null +++ b/test/asan/TestCases/closed-fds.cc @@ -0,0 +1,30 @@ +// Check that when the program closed its std(in|out|err), running the external +// symbolizer still works. + +// RUN: rm -f %t.log.* +// RUN: %clangxx_asan -O0 %s -o %t 2>&1 && ASAN_OPTIONS=log_path=%t.log:verbosity=2 not %run %t 2>&1 +// RUN: FileCheck %s --check-prefix=CHECK-FILE < %t.log.* + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +int main(int argc, char **argv) { + int result = fprintf(stderr, "Closing streams.\n"); + assert(result > 0); + close(STDIN_FILENO); + close(STDOUT_FILENO); + close(STDERR_FILENO); + result = fprintf(stderr, "Can you hear me now?\n"); + assert(result < 0); + char *x = (char *)malloc(10 * sizeof(char)); + free(x); + x[argc] = 'X'; // BOOM + // CHECK-FILE: {{.*ERROR: AddressSanitizer: heap-use-after-free on address}} + // CHECK-FILE: {{0x.* at pc 0x.* bp 0x.* sp 0x.*}} + // CHECK-FILE: {{WRITE of size 1 at 0x.* thread T0}} + // CHECK-FILE: {{ #0 0x.* in main .*closed-fds.cc:}}[[@LINE-4]] + return 0; +} diff --git a/test/asan/TestCases/Linux/coverage-and-lsan.cc b/test/asan/TestCases/coverage-and-lsan.cc index 4cb8e2af3..4cb8e2af3 100644 --- a/test/asan/TestCases/Linux/coverage-and-lsan.cc +++ b/test/asan/TestCases/coverage-and-lsan.cc diff --git a/test/asan/TestCases/Linux/coverage-caller-callee-total-count.cc b/test/asan/TestCases/coverage-caller-callee-total-count.cc index 7598f6bc7..7598f6bc7 100644 --- a/test/asan/TestCases/Linux/coverage-caller-callee-total-count.cc +++ b/test/asan/TestCases/coverage-caller-callee-total-count.cc diff --git a/test/asan/TestCases/Linux/coverage-caller-callee.cc b/test/asan/TestCases/coverage-caller-callee.cc index cd318962b..cd318962b 100644 --- a/test/asan/TestCases/Linux/coverage-caller-callee.cc +++ b/test/asan/TestCases/coverage-caller-callee.cc diff --git a/test/asan/TestCases/Linux/coverage-disabled.cc b/test/asan/TestCases/coverage-disabled.cc index cb33542a5..cb33542a5 100644 --- a/test/asan/TestCases/Linux/coverage-disabled.cc +++ b/test/asan/TestCases/coverage-disabled.cc diff --git a/test/asan/TestCases/Linux/coverage-levels.cc b/test/asan/TestCases/coverage-levels.cc index cc196c5a9..63bed650b 100644 --- a/test/asan/TestCases/Linux/coverage-levels.cc +++ b/test/asan/TestCases/coverage-levels.cc @@ -6,6 +6,10 @@ // RUN: ASAN_OPTIONS=coverage=1:coverage_bitset=1:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 // RUN: %clangxx_asan -O1 -fsanitize-coverage=3 %s -o %t // RUN: ASAN_OPTIONS=coverage=1:coverage_bitset=1:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK3 +// RUN: %clangxx_asan -O1 -fsanitize-coverage=3 -mllvm -sanitizer-coverage-block-threshold=0 %s -o %t +// RUN: ASAN_OPTIONS=coverage=1:coverage_bitset=1:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK3 +// RUN: %clangxx_asan -O1 -fsanitize-coverage=3 -mllvm -sanitizer-coverage-8bit-counters=1 %s -o %t +// RUN: ASAN_OPTIONS=coverage=1:coverage_counters=1:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK_COUNTERS // RUN: ASAN_OPTIONS=coverage=1:coverage_bitset=0:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK3_NOBITSET // RUN: ASAN_OPTIONS=coverage=1:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK3_NOBITSET @@ -19,11 +23,12 @@ int main(int argc, char **argv) { sink = 0; } -// CHECK1: CovDump: bitset of 1 bits written, 1 bits are set +// CHECK1: CovDump: bitset of 1 bits written for '{{.*}}', 1 bits are set // CHECK1: 1 PCs written -// CHECK2: CovDump: bitset of 3 bits written, 2 bits are set +// CHECK2: CovDump: bitset of 3 bits written for '{{.*}}', 2 bits are set // CHECK2: 2 PCs written -// CHECK3: CovDump: bitset of 4 bits written, 3 bits are set +// CHECK3: CovDump: bitset of 4 bits written for '{{.*}}', 3 bits are set // CHECK3: 3 PCs written // CHECK3_NOBITSET-NOT: bitset of // CHECK3_NOPCS-NOT: PCs written +// CHECK_COUNTERS: CovDump: 4 counters written for diff --git a/test/asan/TestCases/Linux/coverage-maybe-open-file.cc b/test/asan/TestCases/coverage-maybe-open-file.cc index 4580de411..ca3f92e80 100644 --- a/test/asan/TestCases/Linux/coverage-maybe-open-file.cc +++ b/test/asan/TestCases/coverage-maybe-open-file.cc @@ -15,6 +15,7 @@ #include <sanitizer/coverage_interface.h> +// FIXME: the code below might not work on Windows. int main(int argc, char **argv) { int fd = __sanitizer_maybe_open_cov_file("test"); if (fd > 0) { diff --git a/test/asan/TestCases/coverage-order-pcs.cc b/test/asan/TestCases/coverage-order-pcs.cc new file mode 100644 index 000000000..076fe1b92 --- /dev/null +++ b/test/asan/TestCases/coverage-order-pcs.cc @@ -0,0 +1,56 @@ +// Test coverage_order_pcs=1 flag which orders the PCs by their appearance. +// RUN: DIR=%T/coverage-order-pcs +// RUN: rm -rf $DIR +// RUN: mkdir $DIR +// RUN: %clangxx_asan -fsanitize-coverage=1 %s -o %t +// RUN: ASAN_OPTIONS=coverage_dir=$DIR:coverage=1:coverage_order_pcs=0 %run %t +// RUN: mv $DIR/*sancov $DIR/A + +// RUN: ASAN_OPTIONS=coverage_dir=$DIR:coverage=1:coverage_order_pcs=0 %run %t 1 +// RUN: mv $DIR/*sancov $DIR/B + +// RUN: ASAN_OPTIONS=coverage_dir=$DIR:coverage=1:coverage_order_pcs=1 %run %t +// RUN: mv $DIR/*sancov $DIR/C + +// RUN: ASAN_OPTIONS=coverage_dir=$DIR:coverage=1:coverage_order_pcs=1 %run %t 1 +// RUN: mv $DIR/*sancov $DIR/D +// +// RUN: (%sancov print $DIR/A; %sancov print $DIR/B; %sancov print $DIR/C; %sancov print $DIR/D) | FileCheck %s +// +// RUN: rm -rf $DIR +// Ordering works only in 64-bit mode for now. +// REQUIRES: asan-64-bits +#include <stdio.h> + +void foo() { fprintf(stderr, "FOO\n"); } +void bar() { fprintf(stderr, "BAR\n"); } + +int main(int argc, char **argv) { + if (argc == 2) { + foo(); + bar(); + } else { + bar(); + foo(); + } +} + +// Run A: no ordering +// CHECK: [[FOO:0x[0-9a-f]*]] +// CHECK-NEXT: [[BAR:0x[0-9a-f]*]] +// CHECK-NEXT: [[MAIN:0x[0-9a-f]*]] +// +// Run B: still no ordering +// CHECK-NEXT: [[FOO]] +// CHECK-NEXT: [[BAR]] +// CHECK-NEXT: [[MAIN]] +// +// Run C: MAIN, BAR, FOO +// CHECK-NEXT: [[MAIN]] +// CHECK-NEXT: [[BAR]] +// CHECK-NEXT: [[FOO]] +// +// Run D: MAIN, FOO, BAR +// CHECK-NEXT: [[MAIN]] +// CHECK-NEXT: [[FOO]] +// CHECK-NEXT: [[BAR]] diff --git a/test/asan/TestCases/Linux/coverage-reset.cc b/test/asan/TestCases/coverage-reset.cc index d3d35e21b..d3d35e21b 100644 --- a/test/asan/TestCases/Linux/coverage-reset.cc +++ b/test/asan/TestCases/coverage-reset.cc diff --git a/test/asan/TestCases/Linux/coverage-tracing.cc b/test/asan/TestCases/coverage-tracing.cc index 49dbb5e95..49dbb5e95 100644 --- a/test/asan/TestCases/Linux/coverage-tracing.cc +++ b/test/asan/TestCases/coverage-tracing.cc diff --git a/test/asan/TestCases/debug_stacks.cc b/test/asan/TestCases/debug_stacks.cc index 57bb54650..15af76dc4 100644 --- a/test/asan/TestCases/debug_stacks.cc +++ b/test/asan/TestCases/debug_stacks.cc @@ -2,6 +2,9 @@ // malloc and free stacks. // RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s +// FIXME: Figure out why allocation/free stack traces may be too short on ARM. +// REQUIRES: stable-runtime + #include <sanitizer/asan_interface.h> #include <stdio.h> #include <stdlib.h> diff --git a/test/asan/TestCases/heap-overflow-large.cc b/test/asan/TestCases/heap-overflow-large.cc index eb2fcc322..566b1158a 100644 --- a/test/asan/TestCases/heap-overflow-large.cc +++ b/test/asan/TestCases/heap-overflow-large.cc @@ -15,9 +15,9 @@ int main(int argc, char *argv[]) { int *x = new int[5]; memset(x, 0, sizeof(x[0]) * 5); int index = atoi(argv[1]); - int res = x[index]; + unsigned res = x[index]; // CHECK: main // CHECK-NOT: CHECK failed delete[] x; - return res ? res : 1; + return (res % 10) + 1; } diff --git a/test/asan/TestCases/print_summary.cc b/test/asan/TestCases/print_summary.cc index 79411c529..12dfa2612 100644 --- a/test/asan/TestCases/print_summary.cc +++ b/test/asan/TestCases/print_summary.cc @@ -1,14 +1,16 @@ // RUN: %clangxx_asan -O0 %s -o %t -// RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=YES -// RUN: env ASAN_OPTIONS=print_summary=false not %run %t 2>&1 | FileCheck %s --check-prefix=NO +// RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=SOURCE +// RUN: env ASAN_OPTIONS=symbolize=false not %run %t 2>&1 | FileCheck %s --check-prefix=MODULE +// RUN: env ASAN_OPTIONS=print_summary=false not %run %t 2>&1 | FileCheck %s --check-prefix=MISSING int main() { char *x = new char[20]; delete[] x; return x[0]; - // YES: ERROR: AddressSanitizer: heap-use-after-free - // YES: SUMMARY: AddressSanitizer: heap-use-after-free - // NO: ERROR: AddressSanitizer: heap-use-after-free - // NO-NOT: SUMMARY: AddressSanitizer: heap-use-after-free + // SOURCE: ERROR: AddressSanitizer: heap-use-after-free + // SOURCE: SUMMARY: AddressSanitizer: heap-use-after-free {{.*}}print_summary.cc:[[@LINE-2]]{{.*}} main + // MODULE: ERROR: AddressSanitizer: heap-use-after-free + // MODULE: SUMMARY: AddressSanitizer: heap-use-after-free ({{.*}}+0x{{.*}}) + // MISSING: ERROR: AddressSanitizer: heap-use-after-free + // MISSING-NOT: SUMMARY } - diff --git a/test/asan/TestCases/strip_path_prefix.c b/test/asan/TestCases/strip_path_prefix.c index 4556e9031..c441eac92 100644 --- a/test/asan/TestCases/strip_path_prefix.c +++ b/test/asan/TestCases/strip_path_prefix.c @@ -1,5 +1,5 @@ // RUN: %clang_asan -O2 %s -o %t -// RUN: env ASAN_OPTIONS="strip_path_prefix='/'" not %run %t 2>&1 | FileCheck %s +// RUN: env ASAN_OPTIONS="strip_path_prefix='%S/'" not %run %t 2>&1 | FileCheck %s #include <stdlib.h> int main() { @@ -8,5 +8,5 @@ int main() { return x[5]; // Check that paths in error report don't start with slash. // CHECK: heap-use-after-free - // CHECK-NOT: #0 0x{{.*}} ({{[/].*}}) + // CHECK: #0 0x{{.*}} in main strip_path_prefix.c:[[@LINE-3]] } diff --git a/test/asan/TestCases/suppressions-exec-relative-location.cc b/test/asan/TestCases/suppressions-exec-relative-location.cc new file mode 100644 index 000000000..cc69b7a6e --- /dev/null +++ b/test/asan/TestCases/suppressions-exec-relative-location.cc @@ -0,0 +1,47 @@ +// Check that without suppressions, we catch the issue. +// RUN: %clangxx_asan -O0 %s -o %t +// RUN: not %run %t 2>&1 | FileCheck --check-prefix=CHECK-CRASH %s + +// If the executable is started from a different location, we should still +// find the suppression file located relative to the location of the executable. +// RUN: rm -rf %T/suppressions-exec-relative-location +// RUN: mkdir -p %T/suppressions-exec-relative-location +// RUN: %clangxx_asan -O0 %s -o %T/suppressions-exec-relative-location/exec +// RUN: echo "interceptor_via_fun:crash_function" > \ +// RUN: %T/suppressions-exec-relative-location/supp.txt +// RUN: ASAN_OPTIONS="suppressions=supp.txt" \ +// RUN: %run %T/suppressions-exec-relative-location/exec 2>&1 | \ +// RUN: FileCheck --check-prefix=CHECK-IGNORE %s +// RUN: rm -rf %T/suppressions-exec-relative-location + +// If the wrong absolute path is given, we don't try to construct +// a relative path with it. +// RUN: ASAN_OPTIONS="suppressions='/absolute/path'" not %run %t 2>&1 | \ +// RUN: FileCheck --check-prefix=CHECK-WRONG-FILE-NAME %s + +// Test that we reject directory as filename. +// RUN: ASAN_OPTIONS="suppressions='folder/only/'" not %run %t 2>&1 | \ +// RUN: FileCheck --check-prefix=CHECK-WRONG-FILE-NAME %s + +// XFAIL: android +// XFAIL: win32 + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +void crash_function() { + char *a = (char *)malloc(6); + free(a); + size_t len = strlen(a); // BOOM + fprintf(stderr, "strlen ignored, len = %zu\n", len); +} + +int main() { + crash_function(); +} + +// CHECK-CRASH: AddressSanitizer: heap-use-after-free +// CHECK-IGNORE-NOT: AddressSanitizer: heap-buffer-overflow +// CHECK-IGNORE: ignored +// CHECK-WRONG-FILE-NAME: failed to read suppressions file diff --git a/test/builtins/Unit/divtc3_test.c b/test/builtins/Unit/divtc3_test.c index 7bb74d755..50918d68f 100644 --- a/test/builtins/Unit/divtc3_test.c +++ b/test/builtins/Unit/divtc3_test.c @@ -11,12 +11,13 @@ // //===----------------------------------------------------------------------===// +#include <stdio.h> + #if _ARCH_PPC #include "int_lib.h" #include <math.h> #include <complex.h> -#include <stdio.h> // Returns: the quotient of (a + ib) / (c + id) diff --git a/test/builtins/Unit/fixtfsi_test.c b/test/builtins/Unit/fixtfsi_test.c new file mode 100644 index 000000000..45ad0d243 --- /dev/null +++ b/test/builtins/Unit/fixtfsi_test.c @@ -0,0 +1,65 @@ +//===--------------- fixtfsi_test.c - Test __fixtfsi ----------------------===// +// +// 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 file tests __fixtfsi for the compiler_rt library. +// +//===----------------------------------------------------------------------===// + +#include <stdio.h> + +#if __LDBL_MANT_DIG__ == 113 + +#include "fp_test.h" + +int __fixtfsi(long double a); + +int test__fixtfsi(long double a, int expected) +{ + int x = __fixtfsi(a); + int ret = (x != expected); + + if (ret){ + printf("error in test__fixtfsi(%.20Lf) = %d, " + "expected %d\n", a, x, expected); + } + return ret; +} + +char assumption_1[sizeof(long double) * CHAR_BIT == 128] = {0}; + +#endif + +int main() +{ +#if __LDBL_MANT_DIG__ == 113 + if (test__fixtfsi(makeInf128(), 0x7fffffff)) + return 1; + if (test__fixtfsi(0, 0x0)) + return 1; + if (test__fixtfsi(0x1.23456789abcdefp+5, 0x24)) + return 1; + if (test__fixtfsi(0x1.23456789abcdefp-3, 0x0)) + return 1; + if (test__fixtfsi(0x1.23456789abcdefp+20, 0x123456)) + return 1; + if (test__fixtfsi(0x1.23456789abcdefp+40, 0x7fffffff)) + return 1; + if (test__fixtfsi(0x1.23456789abcdefp+256, 0x7fffffff)) + return 1; + if (test__fixtfsi(-0x1.23456789abcdefp+20, 0xffedcbaa)) + return 1; + if (test__fixtfsi(-0x1.23456789abcdefp+40, 0x80000001)) + return 1; + +#else + printf("skipped\n"); + +#endif + return 0; +} diff --git a/test/builtins/Unit/fixunstfdi_test.c b/test/builtins/Unit/fixunstfdi_test.c index d0a5db7a9..a5a946050 100644 --- a/test/builtins/Unit/fixunstfdi_test.c +++ b/test/builtins/Unit/fixunstfdi_test.c @@ -11,10 +11,11 @@ // //===----------------------------------------------------------------------===// +#include <stdio.h> + #if _ARCH_PPC #include "int_lib.h" -#include <stdio.h> // Returns: convert a to a unsigned long long, rounding toward zero. // Negative values all become zero. diff --git a/test/builtins/Unit/fixunstfsi_test.c b/test/builtins/Unit/fixunstfsi_test.c new file mode 100644 index 000000000..4bf8fdec6 --- /dev/null +++ b/test/builtins/Unit/fixunstfsi_test.c @@ -0,0 +1,64 @@ +//===--------------- fixunstfsi_test.c - Test __fixunstfsi ----------------===// +// +// 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 file tests __fixunstfsi for the compiler_rt library. +// +//===----------------------------------------------------------------------===// + +#include <stdio.h> + +#if __LDBL_MANT_DIG__ == 113 + +#include "fp_test.h" + +unsigned int __fixunstfsi(long double a); + +int test__fixunstfsi(long double a, unsigned int expected) +{ + unsigned int x = __fixunstfsi(a); + int ret = (x != expected); + + if (ret) + { + printf("error in test__fixunstfsi(%.20Lf) = %u, " + "expected %u\n", a, x, expected); + } + return ret; +} + +char assumption_1[sizeof(long double) * CHAR_BIT == 128] = {0}; + +#endif + +int main() +{ +#if __LDBL_MANT_DIG__ == 113 + if (test__fixunstfsi(makeInf128(), UINT32_C(0xffffffff))) + return 1; + if (test__fixunstfsi(0, UINT32_C(0x0))) + return 1; + if (test__fixunstfsi(0x1.23456789abcdefp+5, UINT32_C(0x24))) + return 1; + if (test__fixunstfsi(0x1.23456789abcdefp-3, UINT32_C(0x0))) + return 1; + if (test__fixunstfsi(0x1.23456789abcdefp+20, UINT32_C(0x123456))) + return 1; + if (test__fixunstfsi(0x1.23456789abcdefp+40, UINT32_C(0xffffffff))) + return 1; + if (test__fixunstfsi(0x1.23456789abcdefp+256, UINT32_C(0xffffffff))) + return 1; + if (test__fixunstfsi(-0x1.23456789abcdefp+3, UINT32_C(0x0))) + return 1; + +#else + printf("skipped\n"); + +#endif + return 0; +} diff --git a/test/builtins/Unit/multc3_test.c b/test/builtins/Unit/multc3_test.c index f8c66c0e4..8d3480157 100644 --- a/test/builtins/Unit/multc3_test.c +++ b/test/builtins/Unit/multc3_test.c @@ -11,12 +11,13 @@ // //===----------------------------------------------------------------------===// +#include <stdio.h> + #if _ARCH_PPC #include "int_lib.h" #include <math.h> #include <complex.h> -#include <stdio.h> // Returns: the product of a + ib and c + id diff --git a/test/builtins/Unit/powitf2_test.c b/test/builtins/Unit/powitf2_test.c index 817cb1130..dfe758837 100644 --- a/test/builtins/Unit/powitf2_test.c +++ b/test/builtins/Unit/powitf2_test.c @@ -11,10 +11,11 @@ // //===----------------------------------------------------------------------===// +#include <stdio.h> + #if _ARCH_PPC #include "int_lib.h" -#include <stdio.h> #include <math.h> // Returns: a ^ b diff --git a/test/cfi/CMakeLists.txt b/test/cfi/CMakeLists.txt index 5750bd8a4..625e3ff11 100644 --- a/test/cfi/CMakeLists.txt +++ b/test/cfi/CMakeLists.txt @@ -15,6 +15,11 @@ if(NOT COMPILER_RT_STANDALONE_BUILD) LLVMgold ) endif() + if(APPLE) + list(APPEND CFI_TEST_DEPS + LTO + ) + endif() endif() add_lit_testsuite(check-cfi "Running the cfi regression tests" diff --git a/test/cfi/bad-cast.cpp b/test/cfi/bad-cast.cpp new file mode 100644 index 000000000..39d8a351b --- /dev/null +++ b/test/cfi/bad-cast.cpp @@ -0,0 +1,136 @@ +// RUN: %clangxx_cfi -o %t %s +// RUN: not --crash %t a 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: not --crash %t b 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: not --crash %t c 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %t d 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %t e 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %t f 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: not --crash %t g 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %t h 2>&1 | FileCheck --check-prefix=PASS %s + +// RUN: %clangxx_cfi -DB32 -o %t %s +// RUN: not --crash %t a 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: not --crash %t b 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: not --crash %t c 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %t d 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %t e 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %t f 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: not --crash %t g 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %t h 2>&1 | FileCheck --check-prefix=PASS %s + +// RUN: %clangxx_cfi -DB64 -o %t %s +// RUN: not --crash %t a 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: not --crash %t b 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: not --crash %t c 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %t d 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %t e 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %t f 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: not --crash %t g 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %t h 2>&1 | FileCheck --check-prefix=PASS %s + +// RUN: %clangxx_cfi -DBM -o %t %s +// RUN: not --crash %t a 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: not --crash %t b 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: not --crash %t c 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %t d 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %t e 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %t f 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: not --crash %t g 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %t h 2>&1 | FileCheck --check-prefix=PASS %s + +// RUN: %clangxx_cfi -fsanitize=cfi-cast-strict -o %t %s +// RUN: not --crash %t a 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: not --crash %t b 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: not --crash %t c 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: not --crash %t d 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: not --crash %t e 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: not --crash %t f 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: not --crash %t g 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: not --crash %t h 2>&1 | FileCheck --check-prefix=FAIL %s + +// RUN: %clangxx -o %t %s +// RUN: %t a 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %t b 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %t c 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %t d 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %t e 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %t f 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %t g 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %t h 2>&1 | FileCheck --check-prefix=PASS %s + +// Tests that the CFI enforcement detects bad casts. + +#include <stdio.h> +#include <utility> +#include "utils.h" + +struct A { + virtual void f(); +}; + +void A::f() {} + +struct B : A { + virtual void f(); +}; + +void B::f() {} + +struct C : A { +}; + +int main(int argc, char **argv) { +#ifdef B32 + break_optimization(new Deriver<B, 0>); +#endif + +#ifdef B64 + break_optimization(new Deriver<B, 0>); + break_optimization(new Deriver<B, 1>); +#endif + +#ifdef BM + break_optimization(new Deriver<B, 0>); + break_optimization(new Deriver<B, 1>); + break_optimization(new Deriver<B, 2>); +#endif + + B *b = new B; + break_optimization(b); + + // FAIL: 1 + // PASS: 1 + fprintf(stderr, "1\n"); + + A a; + switch (argv[1][0]) { + case 'a': + static_cast<B *>(&a); // UB + break; + case 'b': + static_cast<B &>(a); // UB + break; + case 'c': + static_cast<B &&>(a); // UB + break; + case 'd': + static_cast<C *>(&a); // UB, strict only + break; + case 'e': + static_cast<C &>(a); // UB, strict only + break; + case 'f': + static_cast<C &&>(a); // UB, strict only + break; + case 'g': + static_cast<B *>(static_cast<void *>(&a)); // Non-UB bad cast + break; + case 'h': + static_cast<C *>(static_cast<void *>(&a)); // Non-UB bad cast, strict only + break; + } + + // FAIL-NOT: 2 + // PASS: 2 + fprintf(stderr, "2\n"); +} diff --git a/test/cfi/sibling.cpp b/test/cfi/sibling.cpp new file mode 100644 index 000000000..c8b95e9de --- /dev/null +++ b/test/cfi/sibling.cpp @@ -0,0 +1,67 @@ +// XFAIL: * + +// RUN: %clangxx_cfi -o %t %s +// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s + +// RUN: %clangxx_cfi -DB32 -o %t %s +// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s + +// RUN: %clangxx_cfi -DB64 -o %t %s +// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s + +// RUN: %clangxx_cfi -DBM -o %t %s +// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s + +// RUN: %clangxx -o %t %s +// RUN: %t 2>&1 | FileCheck --check-prefix=NCFI %s + +// Tests that the CFI enforcement distinguishes betwen non-overriding siblings. +// XFAILed as not implemented yet. + +#include <stdio.h> +#include "utils.h" + +struct A { + virtual void f(); +}; + +void A::f() {} + +struct B : A { + virtual void f(); +}; + +void B::f() {} + +struct C : A { +}; + +int main() { +#ifdef B32 + break_optimization(new Deriver<B, 0>); +#endif + +#ifdef B64 + break_optimization(new Deriver<B, 0>); + break_optimization(new Deriver<B, 1>); +#endif + +#ifdef BM + break_optimization(new Deriver<B, 0>); + break_optimization(new Deriver<B, 1>); + break_optimization(new Deriver<B, 2>); +#endif + + B *b = new B; + break_optimization(b); + + // CFI: 1 + // NCFI: 1 + fprintf(stderr, "1\n"); + + ((C *)b)->f(); // UB here + + // CFI-NOT: 2 + // NCFI: 2 + fprintf(stderr, "2\n"); +} diff --git a/test/dfsan/basic.c b/test/dfsan/basic.c index 6582727e5..990fd1161 100644 --- a/test/dfsan/basic.c +++ b/test/dfsan/basic.c @@ -1,5 +1,5 @@ -// RUN: %clang_dfsan -m64 %s -o %t && %run %t -// RUN: %clang_dfsan -mllvm -dfsan-args-abi -m64 %s -o %t && %run %t +// RUN: %clang_dfsan %s -o %t && %run %t +// RUN: %clang_dfsan -mllvm -dfsan-args-abi %s -o %t && %run %t // Tests that labels are propagated through loads and stores. diff --git a/test/dfsan/custom.cc b/test/dfsan/custom.cc index d7bb3e307..bdd7cf511 100644 --- a/test/dfsan/custom.cc +++ b/test/dfsan/custom.cc @@ -1,7 +1,7 @@ -// RUN: %clang_dfsan -m64 %s -o %t && DFSAN_OPTIONS="strict_data_dependencies=0" %run %t -// RUN: %clang_dfsan -mllvm -dfsan-args-abi -m64 %s -o %t && DFSAN_OPTIONS="strict_data_dependencies=0" %run %t -// RUN: %clang_dfsan -DSTRICT_DATA_DEPENDENCIES -m64 %s -o %t && %run %t -// RUN: %clang_dfsan -DSTRICT_DATA_DEPENDENCIES -mllvm -dfsan-args-abi -m64 %s -o %t && %run %t +// RUN: %clang_dfsan %s -o %t && DFSAN_OPTIONS="strict_data_dependencies=0" %run %t +// RUN: %clang_dfsan -mllvm -dfsan-args-abi %s -o %t && DFSAN_OPTIONS="strict_data_dependencies=0" %run %t +// RUN: %clang_dfsan -DSTRICT_DATA_DEPENDENCIES %s -o %t && %run %t +// RUN: %clang_dfsan -DSTRICT_DATA_DEPENDENCIES -mllvm -dfsan-args-abi %s -o %t && %run %t // Tests custom implementations of various glibc functions. diff --git a/test/dfsan/dump_labels.c b/test/dfsan/dump_labels.c index 67801af18..3bbc1e2c0 100644 --- a/test/dfsan/dump_labels.c +++ b/test/dfsan/dump_labels.c @@ -1,4 +1,4 @@ -// RUN: %clang_dfsan -m64 %s -o %t +// RUN: %clang_dfsan %s -o %t // RUN: DFSAN_OPTIONS=dump_labels_at_exit=/dev/stdout %run %t 2>&1 | FileCheck %s // RUN: DFSAN_OPTIONS=dump_labels_at_exit=/dev/stdout not %run %t c 2>&1 | FileCheck %s --check-prefix=CHECK-OOL // RUN: DFSAN_OPTIONS=dump_labels_at_exit=/dev/stdout not %run %t u 2>&1 | FileCheck %s --check-prefix=CHECK-OOL diff --git a/test/dfsan/flags.c b/test/dfsan/flags.c index 79069b96f..914f54f42 100644 --- a/test/dfsan/flags.c +++ b/test/dfsan/flags.c @@ -1,6 +1,6 @@ -// RUN: %clang_dfsan -m64 %s -fsanitize-blacklist=%S/Inputs/flags_abilist.txt -mllvm -dfsan-debug-nonzero-labels -o %t && %run %t 2>&1 | FileCheck %s -// RUN: %clang_dfsan -m64 %s -fsanitize-blacklist=%S/Inputs/flags_abilist.txt -mllvm -dfsan-debug-nonzero-labels -o %t && DFSAN_OPTIONS=warn_unimplemented=0 %run %t 2>&1 | count 0 -// RUN: %clang_dfsan -m64 %s -fsanitize-blacklist=%S/Inputs/flags_abilist.txt -mllvm -dfsan-debug-nonzero-labels -o %t && DFSAN_OPTIONS=warn_nonzero_labels=1 %run %t 2>&1 | FileCheck --check-prefix=CHECK-NONZERO %s +// RUN: %clang_dfsan %s -fsanitize-blacklist=%S/Inputs/flags_abilist.txt -mllvm -dfsan-debug-nonzero-labels -o %t && %run %t 2>&1 | FileCheck %s +// RUN: %clang_dfsan %s -fsanitize-blacklist=%S/Inputs/flags_abilist.txt -mllvm -dfsan-debug-nonzero-labels -o %t && DFSAN_OPTIONS=warn_unimplemented=0 %run %t 2>&1 | count 0 +// RUN: %clang_dfsan %s -fsanitize-blacklist=%S/Inputs/flags_abilist.txt -mllvm -dfsan-debug-nonzero-labels -o %t && DFSAN_OPTIONS=warn_nonzero_labels=1 %run %t 2>&1 | FileCheck --check-prefix=CHECK-NONZERO %s // Tests that flags work correctly. diff --git a/test/dfsan/fncall.c b/test/dfsan/fncall.c index e780f3145..458fba66d 100644 --- a/test/dfsan/fncall.c +++ b/test/dfsan/fncall.c @@ -1,5 +1,5 @@ -// RUN: %clang_dfsan -m64 %s -o %t && %run %t -// RUN: %clang_dfsan -mllvm -dfsan-args-abi -m64 %s -o %t && %run %t +// RUN: %clang_dfsan %s -o %t && %run %t +// RUN: %clang_dfsan -mllvm -dfsan-args-abi %s -o %t && %run %t // Tests that labels are propagated through function calls. diff --git a/test/dfsan/label_count.c b/test/dfsan/label_count.c index a4b608701..b42ce5824 100644 --- a/test/dfsan/label_count.c +++ b/test/dfsan/label_count.c @@ -1,11 +1,11 @@ -// RUN: %clang_dfsan -DLIB -m64 -c %s -o %t.lib.o && \ -// RUN: %clang_dfsan -m64 -c %s -o %t.o && \ -// RUN: %clang_dfsan -m64 %t.lib.o %t.o -o %t.bin && \ +// RUN: %clang_dfsan -DLIB -c %s -o %t.lib.o && \ +// RUN: %clang_dfsan -c %s -o %t.o && \ +// RUN: %clang_dfsan %t.lib.o %t.o -o %t.bin && \ // RUN: %run %t.bin -// RUN: %clang_dfsan -mllvm -dfsan-args-abi -m64 -DLIB -c %s -o %t.lib.o && \ -// RUN: %clang_dfsan -mllvm -dfsan-args-abi -m64 -c %s -o %t.o && \ -// RUN: %clang_dfsan -mllvm -dfsan-args-abi -m64 %t.o %t.lib.o -o %t.bin && \ +// RUN: %clang_dfsan -mllvm -dfsan-args-abi -DLIB -c %s -o %t.lib.o && \ +// RUN: %clang_dfsan -mllvm -dfsan-args-abi -c %s -o %t.o && \ +// RUN: %clang_dfsan -mllvm -dfsan-args-abi %t.o %t.lib.o -o %t.bin && \ // RUN: %run %t.bin #include <sanitizer/dfsan_interface.h> diff --git a/test/dfsan/lit.cfg b/test/dfsan/lit.cfg index d4adb9a51..e4d4e8f57 100644 --- a/test/dfsan/lit.cfg +++ b/test/dfsan/lit.cfg @@ -9,7 +9,7 @@ config.name = 'DataFlowSanitizer' config.test_source_root = os.path.dirname(__file__) # Setup default compiler flags used with -fsanitize=dataflow option. -clang_dfsan_cflags = ["-fsanitize=dataflow"] +clang_dfsan_cflags = ["-fsanitize=dataflow", "-m64"] clang_dfsan_cxxflags = config.cxx_mode_flags + clang_dfsan_cflags def build_invocation(compile_flags): diff --git a/test/dfsan/propagate.c b/test/dfsan/propagate.c index 733538cb1..c30a087d6 100644 --- a/test/dfsan/propagate.c +++ b/test/dfsan/propagate.c @@ -1,5 +1,5 @@ -// RUN: %clang_dfsan -m64 %s -o %t && %run %t -// RUN: %clang_dfsan -mllvm -dfsan-args-abi -m64 %s -o %t && %run %t +// RUN: %clang_dfsan %s -o %t && %run %t +// RUN: %clang_dfsan -mllvm -dfsan-args-abi %s -o %t && %run %t // Tests that labels are propagated through computation and that union labels // are properly created. diff --git a/test/dfsan/vararg.c b/test/dfsan/vararg.c index 2227ba715..f51e39c71 100644 --- a/test/dfsan/vararg.c +++ b/test/dfsan/vararg.c @@ -1,7 +1,7 @@ -// RUN: %clang_dfsan -m64 %s -o %t +// RUN: %clang_dfsan %s -o %t // RUN: not %run %t 2>&1 | FileCheck %s // RUN: %run %t foo -// RUN: %clang_dfsan -mllvm -dfsan-args-abi -m64 %s -o %t +// RUN: %clang_dfsan -mllvm -dfsan-args-abi %s -o %t // RUN: not %run %t 2>&1 | FileCheck %s // RUN: %run %t foo diff --git a/test/dfsan/write_callback.c b/test/dfsan/write_callback.c index bb35f3250..3ba027a0a 100644 --- a/test/dfsan/write_callback.c +++ b/test/dfsan/write_callback.c @@ -1,5 +1,5 @@ -// RUN: %clang_dfsan -m64 %s -o %t && %run %t | FileCheck %s -// RUN: %clang_dfsan -mllvm -dfsan-args-abi -m64 %s -o %t && %run %t | FileCheck %s +// RUN: %clang_dfsan %s -o %t && %run %t | FileCheck %s +// RUN: %clang_dfsan -mllvm -dfsan-args-abi %s -o %t && %run %t | FileCheck %s // Tests that the custom implementation of write() does writes with or without // a callback set using dfsan_set_write_callback(). diff --git a/test/msan/Linux/getresid.cc b/test/msan/Linux/getresid.cc index 385351dfd..f3c0914b5 100644 --- a/test/msan/Linux/getresid.cc +++ b/test/msan/Linux/getresid.cc @@ -1,6 +1,6 @@ -// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t %p 2>&1 -// RUN: %clangxx_msan -m64 -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t %p 2>&1 -// RUN: %clangxx_msan -m64 -O3 %s -o %t && %run %t %p 2>&1 +// RUN: %clangxx_msan -O0 %s -o %t && %run %t %p 2>&1 +// RUN: %clangxx_msan -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t %p 2>&1 +// RUN: %clangxx_msan -O3 %s -o %t && %run %t %p 2>&1 #include <assert.h> #include <unistd.h> diff --git a/test/msan/Linux/glob.cc b/test/msan/Linux/glob.cc index 8604e4d76..1481861a0 100644 --- a/test/msan/Linux/glob.cc +++ b/test/msan/Linux/glob.cc @@ -1,6 +1,6 @@ -// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t %p 2>&1 | FileCheck %s -// RUN: %clangxx_msan -m64 -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t %p 2>&1 | FileCheck %s -// RUN: %clangxx_msan -m64 -O3 %s -o %t && %run %t %p 2>&1 | FileCheck %s +// RUN: %clangxx_msan -O0 %s -o %t && %run %t %p 2>&1 | FileCheck %s +// RUN: %clangxx_msan -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t %p 2>&1 | FileCheck %s +// RUN: %clangxx_msan -O3 %s -o %t && %run %t %p 2>&1 | FileCheck %s #include <assert.h> #include <glob.h> diff --git a/test/msan/Linux/glob_altdirfunc.cc b/test/msan/Linux/glob_altdirfunc.cc index 2c02e735e..cb7fe09cb 100644 --- a/test/msan/Linux/glob_altdirfunc.cc +++ b/test/msan/Linux/glob_altdirfunc.cc @@ -1,6 +1,6 @@ -// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t %p 2>&1 | FileCheck %s -// RUN: %clangxx_msan -m64 -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t %p 2>&1 | FileCheck %s -// RUN: %clangxx_msan -m64 -O3 %s -o %t && %run %t %p 2>&1 | FileCheck %s +// RUN: %clangxx_msan -O0 %s -o %t && %run %t %p 2>&1 | FileCheck %s +// RUN: %clangxx_msan -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t %p 2>&1 | FileCheck %s +// RUN: %clangxx_msan -O3 %s -o %t && %run %t %p 2>&1 | FileCheck %s #include <assert.h> #include <glob.h> diff --git a/test/msan/Linux/glob_nomatch.cc b/test/msan/Linux/glob_nomatch.cc index bc35c30d6..fa132c813 100644 --- a/test/msan/Linux/glob_nomatch.cc +++ b/test/msan/Linux/glob_nomatch.cc @@ -1,5 +1,5 @@ -// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t %p -// RUN: %clangxx_msan -m64 -O3 %s -o %t && %run %t %p +// RUN: %clangxx_msan -O0 %s -o %t && %run %t %p +// RUN: %clangxx_msan -O3 %s -o %t && %run %t %p #include <assert.h> #include <glob.h> diff --git a/test/msan/Linux/sunrpc.cc b/test/msan/Linux/sunrpc.cc index 78645a7dc..c92ad632c 100644 --- a/test/msan/Linux/sunrpc.cc +++ b/test/msan/Linux/sunrpc.cc @@ -1,14 +1,14 @@ -// RUN: %clangxx_msan -m64 -g -O0 -DTYPE=int -DFN=xdr_int %s -o %t && \ +// RUN: %clangxx_msan -g -O0 -DTYPE=int -DFN=xdr_int %s -o %t && \ // RUN: %run %t 2>&1 -// RUN: %clangxx_msan -m64 -g -O0 -DTYPE=int -DFN=xdr_int -DUNINIT=1 %s -o %t && \ +// RUN: %clangxx_msan -g -O0 -DTYPE=int -DFN=xdr_int -DUNINIT=1 %s -o %t && \ // RUN: not %run %t 2>&1 | FileCheck %s -// RUN: %clangxx_msan -m64 -g -O0 -DTYPE=double -DFN=xdr_double %s -o %t && \ +// RUN: %clangxx_msan -g -O0 -DTYPE=double -DFN=xdr_double %s -o %t && \ // RUN: %run %t 2>&1 -// RUN: %clangxx_msan -m64 -g -O0 -DTYPE=double -DFN=xdr_double -DUNINIT=1 %s -o %t && \ +// RUN: %clangxx_msan -g -O0 -DTYPE=double -DFN=xdr_double -DUNINIT=1 %s -o %t && \ // RUN: not %run %t 2>&1 | FileCheck %s -// RUN: %clangxx_msan -m64 -g -O0 -DTYPE=u_quad_t -DFN=xdr_u_longlong_t %s -o %t && \ +// RUN: %clangxx_msan -g -O0 -DTYPE=u_quad_t -DFN=xdr_u_longlong_t %s -o %t && \ // RUN: %run %t 2>&1 -// RUN: %clangxx_msan -m64 -g -O0 -DTYPE=u_quad_t -DFN=xdr_u_longlong_t -DUNINIT=1 %s -o %t && \ +// RUN: %clangxx_msan -g -O0 -DTYPE=u_quad_t -DFN=xdr_u_longlong_t -DUNINIT=1 %s -o %t && \ // RUN: not %run %t 2>&1 | FileCheck %s #include <assert.h> diff --git a/test/msan/Linux/sunrpc_bytes.cc b/test/msan/Linux/sunrpc_bytes.cc index f0c35746f..477637af2 100644 --- a/test/msan/Linux/sunrpc_bytes.cc +++ b/test/msan/Linux/sunrpc_bytes.cc @@ -1,6 +1,6 @@ -// RUN: %clangxx_msan -m64 -g -O0 %s -o %t && \ +// RUN: %clangxx_msan -g -O0 %s -o %t && \ // RUN: %run %t 2>&1 -// RUN: %clangxx_msan -m64 -g -O0 -DUNINIT=1 %s -o %t && \ +// RUN: %clangxx_msan -g -O0 -DUNINIT=1 %s -o %t && \ // RUN: not %run %t 2>&1 | FileCheck %s #include <assert.h> diff --git a/test/msan/Linux/sunrpc_string.cc b/test/msan/Linux/sunrpc_string.cc index 3f44a96d1..350222f5c 100644 --- a/test/msan/Linux/sunrpc_string.cc +++ b/test/msan/Linux/sunrpc_string.cc @@ -1,6 +1,6 @@ -// RUN: %clangxx_msan -m64 -g -O0 %s -o %t && \ +// RUN: %clangxx_msan -g -O0 %s -o %t && \ // RUN: %run %t 2>&1 -// RUN: %clangxx_msan -m64 -g -O0 -DUNINIT=1 %s -o %t && \ +// RUN: %clangxx_msan -g -O0 -DUNINIT=1 %s -o %t && \ // RUN: not %run %t 2>&1 | FileCheck %s #include <assert.h> diff --git a/test/msan/Linux/syscalls.cc b/test/msan/Linux/syscalls.cc index 4dd97e745..78dba3663 100644 --- a/test/msan/Linux/syscalls.cc +++ b/test/msan/Linux/syscalls.cc @@ -1,5 +1,5 @@ -// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t 2>&1 -// RUN: %clangxx_msan -m64 -O3 %s -o %t && %run %t 2>&1 +// RUN: %clangxx_msan -O0 %s -o %t && %run %t 2>&1 +// RUN: %clangxx_msan -O3 %s -o %t && %run %t 2>&1 #include <assert.h> #include <errno.h> diff --git a/test/msan/Linux/tcgetattr.cc b/test/msan/Linux/tcgetattr.cc index e1425b84f..454b7fd15 100644 --- a/test/msan/Linux/tcgetattr.cc +++ b/test/msan/Linux/tcgetattr.cc @@ -1,4 +1,4 @@ -// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t %p +// RUN: %clangxx_msan -O0 %s -o %t && %run %t %p #include <assert.h> #include <glob.h> diff --git a/test/msan/Linux/xattr.cc b/test/msan/Linux/xattr.cc index 1beba117d..86cc2cd47 100644 --- a/test/msan/Linux/xattr.cc +++ b/test/msan/Linux/xattr.cc @@ -1,6 +1,6 @@ -// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t %p 2>&1 -// RUN: %clangxx_msan -m64 -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t %p 2>&1 -// RUN: %clangxx_msan -m64 -O3 %s -o %t && %run %t %p 2>&1 +// RUN: %clangxx_msan -O0 %s -o %t && %run %t %p 2>&1 +// RUN: %clangxx_msan -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t %p 2>&1 +// RUN: %clangxx_msan -O3 %s -o %t && %run %t %p 2>&1 #include <argz.h> #include <assert.h> diff --git a/test/msan/backtrace.cc b/test/msan/backtrace.cc index 473e0ae8f..b6cfcbed4 100644 --- a/test/msan/backtrace.cc +++ b/test/msan/backtrace.cc @@ -1,4 +1,4 @@ -// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t +// RUN: %clangxx_msan -O0 %s -o %t && %run %t #include <assert.h> #include <execinfo.h> diff --git a/test/msan/c-strdup.c b/test/msan/c-strdup.c index 059300e42..b1e02b914 100644 --- a/test/msan/c-strdup.c +++ b/test/msan/c-strdup.c @@ -1,7 +1,7 @@ -// RUN: %clang_msan -m64 -O0 %s -o %t && %run %t >%t.out 2>&1 -// RUN: %clang_msan -m64 -O1 %s -o %t && %run %t >%t.out 2>&1 -// RUN: %clang_msan -m64 -O2 %s -o %t && %run %t >%t.out 2>&1 -// RUN: %clang_msan -m64 -O3 %s -o %t && %run %t >%t.out 2>&1 +// RUN: %clang_msan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: %clang_msan -O1 %s -o %t && %run %t >%t.out 2>&1 +// RUN: %clang_msan -O2 %s -o %t && %run %t >%t.out 2>&1 +// RUN: %clang_msan -O3 %s -o %t && %run %t >%t.out 2>&1 // Test that strdup in C programs is intercepted. // GLibC headers translate strdup to __strdup at -O1 and higher. diff --git a/test/msan/chained_origin.cc b/test/msan/chained_origin.cc index 336bbd852..ae72c10b6 100644 --- a/test/msan/chained_origin.cc +++ b/test/msan/chained_origin.cc @@ -1,17 +1,17 @@ -// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -m64 -O3 %s -o %t && \ +// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -O3 %s -o %t && \ // RUN: not %run %t >%t.out 2>&1 // RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-STACK < %t.out -// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -DHEAP=1 -m64 -O3 %s -o %t && \ +// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -DHEAP=1 -O3 %s -o %t && \ // RUN: not %run %t >%t.out 2>&1 // RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-HEAP < %t.out -// RUN: %clangxx_msan -mllvm -msan-instrumentation-with-call-threshold=0 -fsanitize-memory-track-origins=2 -m64 -O3 %s -o %t && \ +// RUN: %clangxx_msan -mllvm -msan-instrumentation-with-call-threshold=0 -fsanitize-memory-track-origins=2 -O3 %s -o %t && \ // RUN: not %run %t >%t.out 2>&1 // RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-STACK < %t.out -// RUN: %clangxx_msan -mllvm -msan-instrumentation-with-call-threshold=0 -fsanitize-memory-track-origins=2 -DHEAP=1 -m64 -O3 %s -o %t && \ +// RUN: %clangxx_msan -mllvm -msan-instrumentation-with-call-threshold=0 -fsanitize-memory-track-origins=2 -DHEAP=1 -O3 %s -o %t && \ // RUN: not %run %t >%t.out 2>&1 // RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-HEAP < %t.out diff --git a/test/msan/chained_origin_empty_stack.cc b/test/msan/chained_origin_empty_stack.cc index 36727e3d7..f1ed66b75 100644 --- a/test/msan/chained_origin_empty_stack.cc +++ b/test/msan/chained_origin_empty_stack.cc @@ -1,4 +1,4 @@ -// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -m64 -O3 %s -o %t && \ +// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -O3 %s -o %t && \ // RUN: MSAN_OPTIONS=store_context_size=1 not %run %t 2>&1 | FileCheck %s // Test that stack trace for the intermediate store is not empty. diff --git a/test/msan/chained_origin_limits.cc b/test/msan/chained_origin_limits.cc index 0cc57f32a..90fd09a86 100644 --- a/test/msan/chained_origin_limits.cc +++ b/test/msan/chained_origin_limits.cc @@ -1,7 +1,7 @@ // This test program creates a very large number of unique histories. // Heap origin. -// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -m64 -O3 %s -o %t +// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -O3 %s -o %t // RUN: MSAN_OPTIONS=origin_history_size=7 not %run %t >%t.out 2>&1 // RUN: FileCheck %s --check-prefix=CHECK7 < %t.out @@ -16,7 +16,7 @@ // RUN: FileCheck %s --check-prefix=CHECK7 < %t.out // Stack origin. -// RUN: %clangxx_msan -DSTACK -fsanitize-memory-track-origins=2 -m64 -O3 %s -o %t +// RUN: %clangxx_msan -DSTACK -fsanitize-memory-track-origins=2 -O3 %s -o %t // RUN: MSAN_OPTIONS=origin_history_size=7 not %run %t >%t.out 2>&1 // RUN: FileCheck %s --check-prefix=CHECK7 < %t.out @@ -32,7 +32,7 @@ // Heap origin, with calls. -// RUN: %clangxx_msan -mllvm -msan-instrumentation-with-call-threshold=0 -fsanitize-memory-track-origins=2 -m64 -O3 %s -o %t +// RUN: %clangxx_msan -mllvm -msan-instrumentation-with-call-threshold=0 -fsanitize-memory-track-origins=2 -O3 %s -o %t // RUN: MSAN_OPTIONS=origin_history_size=7 not %run %t >%t.out 2>&1 // RUN: FileCheck %s --check-prefix=CHECK7 < %t.out @@ -48,7 +48,7 @@ // Stack origin, with calls. -// RUN: %clangxx_msan -DSTACK -mllvm -msan-instrumentation-with-call-threshold=0 -fsanitize-memory-track-origins=2 -m64 -O3 %s -o %t +// RUN: %clangxx_msan -DSTACK -mllvm -msan-instrumentation-with-call-threshold=0 -fsanitize-memory-track-origins=2 -O3 %s -o %t // RUN: MSAN_OPTIONS=origin_history_size=7 not %run %t >%t.out 2>&1 // RUN: FileCheck %s --check-prefix=CHECK7 < %t.out diff --git a/test/msan/chained_origin_memcpy.cc b/test/msan/chained_origin_memcpy.cc index f4c2f7fca..3fe0b77a0 100644 --- a/test/msan/chained_origin_memcpy.cc +++ b/test/msan/chained_origin_memcpy.cc @@ -1,17 +1,17 @@ -// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -m64 -DOFFSET=0 -O3 %s -o %t && \ +// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -DOFFSET=0 -O3 %s -o %t && \ // RUN: not %run %t >%t.out 2>&1 // RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-Z1 < %t.out -// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -DOFFSET=10 -m64 -O3 %s -o %t && \ +// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -DOFFSET=10 -O3 %s -o %t && \ // RUN: not %run %t >%t.out 2>&1 // RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-Z2 < %t.out -// RUN: %clangxx_msan -mllvm -msan-instrumentation-with-call-threshold=0 -fsanitize-memory-track-origins=2 -m64 -DOFFSET=0 -O3 %s -o %t && \ +// RUN: %clangxx_msan -mllvm -msan-instrumentation-with-call-threshold=0 -fsanitize-memory-track-origins=2 -DOFFSET=0 -O3 %s -o %t && \ // RUN: not %run %t >%t.out 2>&1 // RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-Z1 < %t.out -// RUN: %clangxx_msan -mllvm -msan-instrumentation-with-call-threshold=0 -fsanitize-memory-track-origins=2 -DOFFSET=10 -m64 -O3 %s -o %t && \ +// RUN: %clangxx_msan -mllvm -msan-instrumentation-with-call-threshold=0 -fsanitize-memory-track-origins=2 -DOFFSET=10 -O3 %s -o %t && \ // RUN: not %run %t >%t.out 2>&1 // RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-Z2 < %t.out diff --git a/test/msan/chained_origin_with_signals.cc b/test/msan/chained_origin_with_signals.cc index 2841e34a1..43dbdcca7 100644 --- a/test/msan/chained_origin_with_signals.cc +++ b/test/msan/chained_origin_with_signals.cc @@ -2,11 +2,11 @@ // This is, in fact, undesired behavior caused by our chained origins // implementation being not async-signal-safe. -// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -m64 -O3 %s -o %t && \ +// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -O3 %s -o %t && \ // RUN: not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out -// RUN: %clangxx_msan -mllvm -msan-instrumentation-with-call-threshold=0 -fsanitize-memory-track-origins=2 -m64 -O3 %s -o %t && \ +// RUN: %clangxx_msan -mllvm -msan-instrumentation-with-call-threshold=0 -fsanitize-memory-track-origins=2 -O3 %s -o %t && \ // RUN: not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out diff --git a/test/msan/check_mem_is_initialized.cc b/test/msan/check_mem_is_initialized.cc index 7d2328810..e1d3b117e 100644 --- a/test/msan/check_mem_is_initialized.cc +++ b/test/msan/check_mem_is_initialized.cc @@ -1,19 +1,19 @@ -// RUN: %clangxx_msan -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -O0 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out -// RUN: %clangxx_msan -m64 -O1 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -O1 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out -// RUN: %clangxx_msan -m64 -O2 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -O2 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out -// RUN: %clangxx_msan -m64 -O3 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -O3 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out -// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -fsanitize-memory-track-origins -O0 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out -// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O1 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -fsanitize-memory-track-origins -O1 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out -// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O2 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -fsanitize-memory-track-origins -O2 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out -// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O3 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -fsanitize-memory-track-origins -O3 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out #include <sanitizer/msan_interface.h> diff --git a/test/msan/cxa_atexit.cc b/test/msan/cxa_atexit.cc index 0aa36ecee..70384b9c9 100644 --- a/test/msan/cxa_atexit.cc +++ b/test/msan/cxa_atexit.cc @@ -1,4 +1,4 @@ -// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t %p +// RUN: %clangxx_msan -O0 %s -o %t && %run %t %p // PR17377: C++ module destructors get stale argument shadow. diff --git a/test/msan/death-callback.cc b/test/msan/death-callback.cc index 6d0488339..08cf2911b 100644 --- a/test/msan/death-callback.cc +++ b/test/msan/death-callback.cc @@ -1,10 +1,10 @@ -// RUN: %clangxx_msan -m64 -DERROR %s -o %t && not %run %t 2>&1 | \ +// RUN: %clangxx_msan -DERROR %s -o %t && not %run %t 2>&1 | \ // RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NOCB -// RUN: %clangxx_msan -m64 -DERROR -DMSANCB_SET %s -o %t && not %run %t 2>&1 | \ +// RUN: %clangxx_msan -DERROR -DMSANCB_SET %s -o %t && not %run %t 2>&1 | \ // RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-CB -// RUN: %clangxx_msan -m64 -DERROR -DMSANCB_SET -DMSANCB_CLEAR %s -o %t && not %run %t 2>&1 | \ +// RUN: %clangxx_msan -DERROR -DMSANCB_SET -DMSANCB_CLEAR %s -o %t && not %run %t 2>&1 | \ // RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NOCB -// RUN: %clangxx_msan -m64 -DMSANCB_SET %s -o %t && %run %t 2>&1 | \ +// RUN: %clangxx_msan -DMSANCB_SET %s -o %t && %run %t 2>&1 | \ // RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NOCB #include <sanitizer/msan_interface.h> diff --git a/test/msan/dlerror.cc b/test/msan/dlerror.cc index 2c726d360..d5510b65c 100644 --- a/test/msan/dlerror.cc +++ b/test/msan/dlerror.cc @@ -1,4 +1,4 @@ -// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t +// RUN: %clangxx_msan -O0 %s -o %t && %run %t #include <assert.h> #include <dlfcn.h> diff --git a/test/msan/dso-origin.cc b/test/msan/dso-origin.cc index ba008c007..7f6244984 100644 --- a/test/msan/dso-origin.cc +++ b/test/msan/dso-origin.cc @@ -1,7 +1,7 @@ // Build a library with origin tracking and an executable w/o origin tracking. // Test that origin tracking is enabled at runtime. -// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %s -DBUILD_SO -fPIC -shared -o %t-so.so -// RUN: %clangxx_msan -m64 -O0 %s %t-so.so -o %t && not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_msan -fsanitize-memory-track-origins -O0 %s -DBUILD_SO -fPIC -shared -o %t-so.so +// RUN: %clangxx_msan -O0 %s %t-so.so -o %t && not %run %t 2>&1 | FileCheck %s #ifdef BUILD_SO diff --git a/test/msan/dtls_test.c b/test/msan/dtls_test.c index cb88ede2f..4036f71a7 100644 --- a/test/msan/dtls_test.c +++ b/test/msan/dtls_test.c @@ -1,5 +1,5 @@ -/* RUN: %clang_msan -g -m64 %s -o %t - RUN: %clang_msan -g -m64 %s -DBUILD_SO -fPIC -o %t-so.so -shared +/* RUN: %clang_msan -g %s -o %t + RUN: %clang_msan -g %s -DBUILD_SO -fPIC -o %t-so.so -shared RUN: %run %t 2>&1 Regression test for a bug in msan/glibc integration, diff --git a/test/msan/errno.cc b/test/msan/errno.cc index 8af8eb5ee..6ed0fd410 100644 --- a/test/msan/errno.cc +++ b/test/msan/errno.cc @@ -1,4 +1,4 @@ -// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t +// RUN: %clangxx_msan -O0 %s -o %t && %run %t #include <assert.h> #include <errno.h> diff --git a/test/msan/fork.cc b/test/msan/fork.cc index 10de8a937..78a62d549 100644 --- a/test/msan/fork.cc +++ b/test/msan/fork.cc @@ -2,7 +2,7 @@ // Run a number of threads that create new chained origins, then fork // and verify that origin reads do not deadlock in the child process. -// RUN: %clangxx_msan -std=c++11 -fsanitize-memory-track-origins=2 -g -m64 -O3 %s -o %t +// RUN: %clangxx_msan -std=c++11 -fsanitize-memory-track-origins=2 -g -O3 %s -o %t // RUN: MSAN_OPTIONS=store_context_size=1000,origin_history_size=0,origin_history_per_stack_limit=0 %run %t |& FileCheck %s // Fun fact: if test output is redirected to a file (as opposed to diff --git a/test/msan/ftime.cc b/test/msan/ftime.cc index 2d0935d18..5ed9358f0 100644 --- a/test/msan/ftime.cc +++ b/test/msan/ftime.cc @@ -1,4 +1,4 @@ -// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t +// RUN: %clangxx_msan -O0 -g %s -o %t && %run %t #include <assert.h> #include <sys/timeb.h> diff --git a/test/msan/getaddrinfo-positive.cc b/test/msan/getaddrinfo-positive.cc index 7658cd504..45c1b604d 100644 --- a/test/msan/getaddrinfo-positive.cc +++ b/test/msan/getaddrinfo-positive.cc @@ -1,6 +1,6 @@ -// RUN: %clangxx_msan -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -O0 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out -// RUN: %clangxx_msan -m64 -O3 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -O3 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out #include <sys/types.h> diff --git a/test/msan/getaddrinfo.cc b/test/msan/getaddrinfo.cc index abab8bd78..c9dcf3ecb 100644 --- a/test/msan/getaddrinfo.cc +++ b/test/msan/getaddrinfo.cc @@ -1,4 +1,4 @@ -// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t +// RUN: %clangxx_msan -O0 %s -o %t && %run %t #include <sys/types.h> #include <sys/socket.h> diff --git a/test/msan/getc_unlocked.c b/test/msan/getc_unlocked.c index 7df958ad6..8468fed5c 100644 --- a/test/msan/getc_unlocked.c +++ b/test/msan/getc_unlocked.c @@ -1,12 +1,12 @@ -// RUN: %clangxx_msan -DGETC -m64 -O0 -g -xc++ %s -o %t && %run %t -// RUN: %clangxx_msan -DGETC -m64 -O3 -g -xc++ %s -o %t && %run %t -// RUN: %clang_msan -DGETC -m64 -O0 -g %s -o %t && %run %t -// RUN: %clang_msan -DGETC -m64 -O3 -g %s -o %t && %run %t +// RUN: %clangxx_msan -DGETC -O0 -g -xc++ %s -o %t && %run %t +// RUN: %clangxx_msan -DGETC -O3 -g -xc++ %s -o %t && %run %t +// RUN: %clang_msan -DGETC -O0 -g %s -o %t && %run %t +// RUN: %clang_msan -DGETC -O3 -g %s -o %t && %run %t -// RUN: %clangxx_msan -DGETCHAR -m64 -O0 -g -xc++ %s -o %t && %run %t -// RUN: %clangxx_msan -DGETCHAR -m64 -O3 -g -xc++ %s -o %t && %run %t -// RUN: %clang_msan -DGETCHAR -m64 -O0 -g %s -o %t && %run %t -// RUN: %clang_msan -DGETCHAR -m64 -O3 -g %s -o %t && %run %t +// RUN: %clangxx_msan -DGETCHAR -O0 -g -xc++ %s -o %t && %run %t +// RUN: %clangxx_msan -DGETCHAR -O3 -g -xc++ %s -o %t && %run %t +// RUN: %clang_msan -DGETCHAR -O0 -g %s -o %t && %run %t +// RUN: %clang_msan -DGETCHAR -O3 -g %s -o %t && %run %t #include <assert.h> #include <stdio.h> diff --git a/test/msan/heap-origin.cc b/test/msan/heap-origin.cc index 0920001be..4f170f0d7 100644 --- a/test/msan/heap-origin.cc +++ b/test/msan/heap-origin.cc @@ -1,19 +1,19 @@ -// RUN: %clangxx_msan -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -O0 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out -// RUN: %clangxx_msan -m64 -O1 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -O1 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out -// RUN: %clangxx_msan -m64 -O2 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -O2 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out -// RUN: %clangxx_msan -m64 -O3 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -O3 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out -// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -fsanitize-memory-track-origins -O0 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out -// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O1 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -fsanitize-memory-track-origins -O1 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out -// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O2 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -fsanitize-memory-track-origins -O2 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out -// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O3 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -fsanitize-memory-track-origins -O3 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out #include <stdlib.h> diff --git a/test/msan/iconv.cc b/test/msan/iconv.cc index ea6958b79..c4f253479 100644 --- a/test/msan/iconv.cc +++ b/test/msan/iconv.cc @@ -1,5 +1,5 @@ -// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t -// RUN: %clangxx_msan -m64 -O0 -g -DPOSITIVE %s -o %t && not %run %t |& FileCheck %s +// RUN: %clangxx_msan -O0 -g %s -o %t && %run %t +// RUN: %clangxx_msan -O0 -g -DPOSITIVE %s -o %t && not %run %t |& FileCheck %s #include <assert.h> #include <iconv.h> diff --git a/test/msan/if_indextoname.cc b/test/msan/if_indextoname.cc index b74aec16c..7f7dea7d5 100644 --- a/test/msan/if_indextoname.cc +++ b/test/msan/if_indextoname.cc @@ -1,6 +1,6 @@ -// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t 2>&1 -// RUN: %clangxx_msan -m64 -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t 2>&1 -// RUN: %clangxx_msan -m64 -O3 %s -o %t && %run %t 2>&1 +// RUN: %clangxx_msan -O0 %s -o %t && %run %t 2>&1 +// RUN: %clangxx_msan -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t 2>&1 +// RUN: %clangxx_msan -O3 %s -o %t && %run %t 2>&1 #include <assert.h> #include <errno.h> diff --git a/test/msan/ifaddrs.cc b/test/msan/ifaddrs.cc index 6a0db3a5b..568e6615b 100644 --- a/test/msan/ifaddrs.cc +++ b/test/msan/ifaddrs.cc @@ -1,6 +1,6 @@ -// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t %p 2>&1 -// RUN: %clangxx_msan -m64 -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t %p 2>&1 -// RUN: %clangxx_msan -m64 -O3 %s -o %t && %run %t %p 2>&1 +// RUN: %clangxx_msan -O0 %s -o %t && %run %t %p 2>&1 +// RUN: %clangxx_msan -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t %p 2>&1 +// RUN: %clangxx_msan -O3 %s -o %t && %run %t %p 2>&1 #include <assert.h> #include <errno.h> diff --git a/test/msan/initgroups.cc b/test/msan/initgroups.cc index 94f6cd825..d11fd582a 100644 --- a/test/msan/initgroups.cc +++ b/test/msan/initgroups.cc @@ -1,4 +1,4 @@ -// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t +// RUN: %clangxx_msan -O0 %s -o %t && %run %t #include <sys/types.h> #include <grp.h> diff --git a/test/msan/insertvalue_origin.cc b/test/msan/insertvalue_origin.cc index 545debffa..a0c70023f 100644 --- a/test/msan/insertvalue_origin.cc +++ b/test/msan/insertvalue_origin.cc @@ -1,6 +1,6 @@ -// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -fsanitize-memory-track-origins -O0 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out && FileCheck %s < %t.out -// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O3 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -fsanitize-memory-track-origins -O3 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out && FileCheck %s < %t.out // Test origin propagation through insertvalue IR instruction. diff --git a/test/msan/ioctl.cc b/test/msan/ioctl.cc index caa5c274f..e21ef636c 100644 --- a/test/msan/ioctl.cc +++ b/test/msan/ioctl.cc @@ -1,5 +1,5 @@ -// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t -// RUN: %clangxx_msan -m64 -O3 -g %s -o %t && %run %t +// RUN: %clangxx_msan -O0 -g %s -o %t && %run %t +// RUN: %clangxx_msan -O3 -g %s -o %t && %run %t #include <assert.h> #include <stdlib.h> diff --git a/test/msan/ioctl_custom.cc b/test/msan/ioctl_custom.cc index 7c7fde4bd..6df22d75e 100644 --- a/test/msan/ioctl_custom.cc +++ b/test/msan/ioctl_custom.cc @@ -1,8 +1,8 @@ -// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t -// RUN: %clangxx_msan -m64 -O3 -g %s -o %t && %run %t +// RUN: %clangxx_msan -O0 -g %s -o %t && %run %t +// RUN: %clangxx_msan -O3 -g %s -o %t && %run %t -// RUN: %clangxx_msan -DPOSITIVE -m64 -O0 -g %s -o %t && not %run %t 2>&1 | FileCheck %s -// RUN: %clangxx_msan -DPOSITIVE -m64 -O3 -g %s -o %t && not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_msan -DPOSITIVE -O0 -g %s -o %t && not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_msan -DPOSITIVE -O3 -g %s -o %t && not %run %t 2>&1 | FileCheck %s #include <assert.h> #include <stdlib.h> diff --git a/test/msan/ioctl_sound.cc b/test/msan/ioctl_sound.cc index ed896f761..fb36c52f2 100644 --- a/test/msan/ioctl_sound.cc +++ b/test/msan/ioctl_sound.cc @@ -1,5 +1,5 @@ -// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t -// RUN: %clangxx_msan -m64 -O3 -g %s -o %t && %run %t +// RUN: %clangxx_msan -O0 -g %s -o %t && %run %t +// RUN: %clangxx_msan -O3 -g %s -o %t && %run %t #include <assert.h> #include <fcntl.h> diff --git a/test/msan/keep-going-dso.cc b/test/msan/keep-going-dso.cc index 7975306c5..f32a513ea 100644 --- a/test/msan/keep-going-dso.cc +++ b/test/msan/keep-going-dso.cc @@ -1,15 +1,15 @@ -// RUN: %clangxx_msan -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -O0 %s -o %t && not %run %t >%t.out 2>&1 // FileCheck --check-prefix=CHECK-KEEP-GOING %s <%t.out -// RUN: %clangxx_msan -m64 -O0 %s -o %t && MSAN_OPTIONS=keep_going=0 not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -O0 %s -o %t && MSAN_OPTIONS=keep_going=0 not %run %t >%t.out 2>&1 // FileCheck %s <%t.out -// RUN: %clangxx_msan -m64 -O0 %s -o %t && MSAN_OPTIONS=keep_going=1 not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -O0 %s -o %t && MSAN_OPTIONS=keep_going=1 not %run %t >%t.out 2>&1 // FileCheck --check-prefix=CHECK-KEEP-GOING %s <%t.out -// RUN: %clangxx_msan -m64 -mllvm -msan-keep-going=1 -O0 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -mllvm -msan-keep-going=1 -O0 %s -o %t && not %run %t >%t.out 2>&1 // FileCheck --check-prefix=CHECK-KEEP-GOING %s <%t.out -// RUN: %clangxx_msan -m64 -mllvm -msan-keep-going=1 -O0 %s -o %t && MSAN_OPTIONS=keep_going=0 not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -mllvm -msan-keep-going=1 -O0 %s -o %t && MSAN_OPTIONS=keep_going=0 not %run %t >%t.out 2>&1 // FileCheck %s <%t.out -// RUN: %clangxx_msan -m64 -mllvm -msan-keep-going=1 -O0 %s -o %t && MSAN_OPTIONS=keep_going=1 not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -mllvm -msan-keep-going=1 -O0 %s -o %t && MSAN_OPTIONS=keep_going=1 not %run %t >%t.out 2>&1 // FileCheck --check-prefix=CHECK-KEEP-GOING %s <%t.out // Test how -mllvm -msan-keep-going and MSAN_OPTIONS=keep_going affect reports diff --git a/test/msan/keep-going.cc b/test/msan/keep-going.cc index 6426574a9..577297563 100644 --- a/test/msan/keep-going.cc +++ b/test/msan/keep-going.cc @@ -1,19 +1,19 @@ -// RUN: %clangxx_msan -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -O0 %s -o %t && not %run %t >%t.out 2>&1 // FileCheck %s <%t.out -// RUN: %clangxx_msan -m64 -O0 %s -o %t && MSAN_OPTIONS=keep_going=0 not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -O0 %s -o %t && MSAN_OPTIONS=keep_going=0 not %run %t >%t.out 2>&1 // FileCheck %s <%t.out -// RUN: %clangxx_msan -m64 -O0 %s -o %t && MSAN_OPTIONS=keep_going=1 not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -O0 %s -o %t && MSAN_OPTIONS=keep_going=1 not %run %t >%t.out 2>&1 // FileCheck %s <%t.out -// RUN: %clangxx_msan -m64 -mllvm -msan-keep-going=1 -O0 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -mllvm -msan-keep-going=1 -O0 %s -o %t && not %run %t >%t.out 2>&1 // FileCheck --check-prefix=CHECK-KEEP-GOING %s <%t.out -// RUN: %clangxx_msan -m64 -mllvm -msan-keep-going=1 -O0 %s -o %t && MSAN_OPTIONS=keep_going=0 not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -mllvm -msan-keep-going=1 -O0 %s -o %t && MSAN_OPTIONS=keep_going=0 not %run %t >%t.out 2>&1 // FileCheck %s <%t.out -// RUN: %clangxx_msan -m64 -mllvm -msan-keep-going=1 -O0 %s -o %t && MSAN_OPTIONS=keep_going=1 not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -mllvm -msan-keep-going=1 -O0 %s -o %t && MSAN_OPTIONS=keep_going=1 not %run %t >%t.out 2>&1 // FileCheck --check-prefix=CHECK-KEEP-GOING %s <%t.out -// RUN: %clangxx_msan -m64 -mllvm -msan-keep-going=1 -O0 %s -o %t && MSAN_OPTIONS=halt_on_error=1 not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -mllvm -msan-keep-going=1 -O0 %s -o %t && MSAN_OPTIONS=halt_on_error=1 not %run %t >%t.out 2>&1 // FileCheck %s <%t.out -// RUN: %clangxx_msan -m64 -mllvm -msan-keep-going=1 -O0 %s -o %t && MSAN_OPTIONS=halt_on_error=0 not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -mllvm -msan-keep-going=1 -O0 %s -o %t && MSAN_OPTIONS=halt_on_error=0 not %run %t >%t.out 2>&1 // FileCheck --check-prefix=CHECK-KEEP-GOING %s <%t.out // Test behaviour of -mllvm -msan-keep-going and MSAN_OPTIONS=keep_going. diff --git a/test/msan/mallinfo.cc b/test/msan/mallinfo.cc index 3f3086830..3c3692969 100644 --- a/test/msan/mallinfo.cc +++ b/test/msan/mallinfo.cc @@ -1,4 +1,4 @@ -// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t +// RUN: %clangxx_msan -O0 -g %s -o %t && %run %t #include <assert.h> #include <malloc.h> diff --git a/test/msan/mktime.cc b/test/msan/mktime.cc index c419057c3..997fb0ddb 100644 --- a/test/msan/mktime.cc +++ b/test/msan/mktime.cc @@ -1,5 +1,5 @@ -// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t -// RUN: %clangxx_msan -m64 -O0 -g -DUNINIT %s -o %t && not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_msan -O0 -g %s -o %t && %run %t +// RUN: %clangxx_msan -O0 -g -DUNINIT %s -o %t && not %run %t 2>&1 | FileCheck %s #include <assert.h> #include <time.h> diff --git a/test/msan/mmap_below_shadow.cc b/test/msan/mmap_below_shadow.cc index 0b982d589..2b507d024 100644 --- a/test/msan/mmap_below_shadow.cc +++ b/test/msan/mmap_below_shadow.cc @@ -3,10 +3,10 @@ // Without MAP_FIXED, we ignore the address hint and map somewhere in // application range. -// RUN: %clangxx_msan -m64 -O0 -DFIXED=0 %s -o %t && %run %t -// RUN: %clangxx_msan -m64 -O0 -DFIXED=1 %s -o %t && %run %t -// RUN: %clangxx_msan -m64 -O0 -DFIXED=0 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t -// RUN: %clangxx_msan -m64 -O0 -DFIXED=1 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t +// RUN: %clangxx_msan -O0 -DFIXED=0 %s -o %t && %run %t +// RUN: %clangxx_msan -O0 -DFIXED=1 %s -o %t && %run %t +// RUN: %clangxx_msan -O0 -DFIXED=0 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t +// RUN: %clangxx_msan -O0 -DFIXED=1 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t #include <assert.h> #include <errno.h> diff --git a/test/msan/msan_check_mem_is_initialized.cc b/test/msan/msan_check_mem_is_initialized.cc index 33558cd2f..599cf2d7d 100644 --- a/test/msan/msan_check_mem_is_initialized.cc +++ b/test/msan/msan_check_mem_is_initialized.cc @@ -1,9 +1,9 @@ -// RUN: %clangxx_msan -m64 -O0 -g -DPOSITIVE %s -o %t +// RUN: %clangxx_msan -O0 -g -DPOSITIVE %s -o %t // RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK // RUN: MSAN_OPTIONS=verbosity=1 not %run %t 2>&1 | \ // RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-VERBOSE -// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t +// RUN: %clangxx_msan -O0 -g %s -o %t && %run %t #include <sanitizer/msan_interface.h> diff --git a/test/msan/msan_dump_shadow.cc b/test/msan/msan_dump_shadow.cc index 08371e306..543fa7013 100644 --- a/test/msan/msan_dump_shadow.cc +++ b/test/msan/msan_dump_shadow.cc @@ -1,10 +1,10 @@ -// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -O0 -g %s -o %t && %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out -// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 -g %s -o %t && %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -fsanitize-memory-track-origins -O0 -g %s -o %t && %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out -// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -m64 -O0 -g %s -o %t && %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -O0 -g %s -o %t && %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out #include <sanitizer/msan_interface.h> diff --git a/test/msan/msan_print_shadow.cc b/test/msan/msan_print_shadow.cc index f4894596a..9668be2c2 100644 --- a/test/msan/msan_print_shadow.cc +++ b/test/msan/msan_print_shadow.cc @@ -1,10 +1,10 @@ -// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -O0 -g %s -o %t && %run %t >%t.out 2>&1 // RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NO-ORIGINS < %t.out -// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 -g %s -o %t && %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -fsanitize-memory-track-origins -O0 -g %s -o %t && %run %t >%t.out 2>&1 // RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-ORIGINS < %t.out -// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -m64 -O0 -g %s -o %t && %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -O0 -g %s -o %t && %run %t >%t.out 2>&1 // RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-ORIGINS --check-prefix=CHECK-ORIGINS-2 < %t.out #include <sanitizer/msan_interface.h> diff --git a/test/msan/msan_print_shadow2.cc b/test/msan/msan_print_shadow2.cc index 343ee9e5c..5095081c9 100644 --- a/test/msan/msan_print_shadow2.cc +++ b/test/msan/msan_print_shadow2.cc @@ -1,10 +1,10 @@ -// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -O0 -g %s -o %t && %run %t >%t.out 2>&1 // RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NO-ORIGINS < %t.out -// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 -g %s -o %t && %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -fsanitize-memory-track-origins -O0 -g %s -o %t && %run %t >%t.out 2>&1 // RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-ORIGINS < %t.out -// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -m64 -O0 -g %s -o %t && %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -O0 -g %s -o %t && %run %t >%t.out 2>&1 // RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-ORIGINS < %t.out #include <sanitizer/msan_interface.h> diff --git a/test/msan/msan_print_shadow3.cc b/test/msan/msan_print_shadow3.cc index c605ef188..b29f3222d 100644 --- a/test/msan/msan_print_shadow3.cc +++ b/test/msan/msan_print_shadow3.cc @@ -1,4 +1,4 @@ -// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -O0 -g %s -o %t && %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out #include <stdint.h> diff --git a/test/msan/mul_by_const.cc b/test/msan/mul_by_const.cc index a975bb921..8240fdbed 100644 --- a/test/msan/mul_by_const.cc +++ b/test/msan/mul_by_const.cc @@ -1,4 +1,4 @@ -// RUN: %clangxx_msan -m64 -O2 %s -o %t && %run %t +// RUN: %clangxx_msan -O2 %s -o %t && %run %t #include <sanitizer/msan_interface.h> diff --git a/test/msan/no_sanitize_memory.cc b/test/msan/no_sanitize_memory.cc index c5643816c..5c53ee4f3 100644 --- a/test/msan/no_sanitize_memory.cc +++ b/test/msan/no_sanitize_memory.cc @@ -1,12 +1,12 @@ -// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t >%t.out 2>&1 -// RUN: %clangxx_msan -m64 -O1 %s -o %t && %run %t >%t.out 2>&1 -// RUN: %clangxx_msan -m64 -O2 %s -o %t && %run %t >%t.out 2>&1 -// RUN: %clangxx_msan -m64 -O3 %s -o %t && %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -O1 %s -o %t && %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -O2 %s -o %t && %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -O3 %s -o %t && %run %t >%t.out 2>&1 -// RUN: %clangxx_msan -m64 -O0 %s -o %t -DCHECK_IN_F && %run %t >%t.out 2>&1 -// RUN: %clangxx_msan -m64 -O1 %s -o %t -DCHECK_IN_F && %run %t >%t.out 2>&1 -// RUN: %clangxx_msan -m64 -O2 %s -o %t -DCHECK_IN_F && %run %t >%t.out 2>&1 -// RUN: %clangxx_msan -m64 -O3 %s -o %t -DCHECK_IN_F && %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -O0 %s -o %t -DCHECK_IN_F && %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -O1 %s -o %t -DCHECK_IN_F && %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -O2 %s -o %t -DCHECK_IN_F && %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -O3 %s -o %t -DCHECK_IN_F && %run %t >%t.out 2>&1 // Test that (no_sanitize_memory) functions // * don't check shadow values (-DCHECK_IN_F) diff --git a/test/msan/no_sanitize_memory_prop.cc b/test/msan/no_sanitize_memory_prop.cc index 4275ebbf7..bfd4194dd 100644 --- a/test/msan/no_sanitize_memory_prop.cc +++ b/test/msan/no_sanitize_memory_prop.cc @@ -1,7 +1,7 @@ -// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t >%t.out 2>&1 -// RUN: %clangxx_msan -m64 -O1 %s -o %t && %run %t >%t.out 2>&1 -// RUN: %clangxx_msan -m64 -O2 %s -o %t && %run %t >%t.out 2>&1 -// RUN: %clangxx_msan -m64 -O3 %s -o %t && %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -O1 %s -o %t && %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -O2 %s -o %t && %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -O3 %s -o %t && %run %t >%t.out 2>&1 // Test that (no_sanitize_memory) functions DO NOT propagate shadow. diff --git a/test/msan/obstack.cc b/test/msan/obstack.cc index 222f43b83..f1f53be4c 100644 --- a/test/msan/obstack.cc +++ b/test/msan/obstack.cc @@ -1,5 +1,5 @@ -// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t -// RUN: %clangxx_msan -m64 -O0 -g -DPOSITIVE %s -o %t && not %run %t |& FileCheck %s +// RUN: %clangxx_msan -O0 -g %s -o %t && %run %t +// RUN: %clangxx_msan -O0 -g -DPOSITIVE %s -o %t && not %run %t |& FileCheck %s #include <obstack.h> #include <sanitizer/msan_interface.h> diff --git a/test/msan/origin-store-long.cc b/test/msan/origin-store-long.cc index a7c2b7a7d..5c9fe04b7 100644 --- a/test/msan/origin-store-long.cc +++ b/test/msan/origin-store-long.cc @@ -1,7 +1,7 @@ // Check that 8-byte store updates origin for the full store range. -// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -fsanitize-memory-track-origins -O0 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out && FileCheck %s < %t.out -// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O2 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -fsanitize-memory-track-origins -O2 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out && FileCheck %s < %t.out #include <sanitizer/msan_interface.h> diff --git a/test/msan/param_tls_limit.cc b/test/msan/param_tls_limit.cc index 869afc935..982ae1ebd 100644 --- a/test/msan/param_tls_limit.cc +++ b/test/msan/param_tls_limit.cc @@ -1,9 +1,9 @@ // ParamTLS has limited size. Everything that does not fit is considered fully // initialized. -// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t -// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %s -o %t && %run %t -// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -m64 -O0 %s -o %t && %run %t +// RUN: %clangxx_msan -O0 %s -o %t && %run %t +// RUN: %clangxx_msan -fsanitize-memory-track-origins -O0 %s -o %t && %run %t +// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -O0 %s -o %t && %run %t #include <sanitizer/msan_interface.h> #include <assert.h> diff --git a/test/msan/print_stats.cc b/test/msan/print_stats.cc index 74943835b..39af50417 100644 --- a/test/msan/print_stats.cc +++ b/test/msan/print_stats.cc @@ -1,4 +1,4 @@ -// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -m64 -g %s -o %t +// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -g %s -o %t // RUN: %run %t 2>&1 | \ // RUN: FileCheck --check-prefix=CHECK --check-prefix=CHECK-NOSTATS %s // RUN: MSAN_OPTIONS=print_stats=1 %run %t 2>&1 | \ @@ -6,13 +6,13 @@ // RUN: MSAN_OPTIONS=print_stats=1,atexit=1 %run %t 2>&1 | \ // RUN: FileCheck --check-prefix=CHECK --check-prefix=CHECK-STATS %s -// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -m64 -g -DPOSITIVE=1 %s -o %t +// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -g -DPOSITIVE=1 %s -o %t // RUN: not %run %t 2>&1 | \ // RUN: FileCheck --check-prefix=CHECK --check-prefix=CHECK-NOSTATS %s // RUN: MSAN_OPTIONS=print_stats=1 not %run %t 2>&1 | \ // RUN: FileCheck --check-prefix=CHECK --check-prefix=CHECK-STATS %s -// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -m64 -g -DPOSITIVE=1 -mllvm -msan-keep-going=1 %s -o %t +// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -g -DPOSITIVE=1 -mllvm -msan-keep-going=1 %s -o %t // RUN: not %run %t 2>&1 | \ // RUN: FileCheck --check-prefix=CHECK --check-prefix=CHECK-NOSTATS --check-prefix=CHECK-KEEPGOING %s // RUN: MSAN_OPTIONS=print_stats=1 not %run %t 2>&1 | \ diff --git a/test/msan/pthread_getattr_np_deadlock.cc b/test/msan/pthread_getattr_np_deadlock.cc index 07f19cb61..0f5228085 100644 --- a/test/msan/pthread_getattr_np_deadlock.cc +++ b/test/msan/pthread_getattr_np_deadlock.cc @@ -1,4 +1,4 @@ -// RUN: %clangxx_msan -m64 -fsanitize-memory-track-origins -O0 %s -o %t && %run %t +// RUN: %clangxx_msan -fsanitize-memory-track-origins -O0 %s -o %t && %run %t // Regression test for a deadlock in pthread_getattr_np diff --git a/test/msan/rand_r.cc b/test/msan/rand_r.cc index d6bdb1dea..f40cf9f96 100644 --- a/test/msan/rand_r.cc +++ b/test/msan/rand_r.cc @@ -1,5 +1,5 @@ -// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t -// RUN: %clangxx_msan -m64 -O0 -g -DUNINIT %s -o %t && not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_msan -O0 -g %s -o %t && %run %t +// RUN: %clangxx_msan -O0 -g -DUNINIT %s -o %t && not %run %t 2>&1 | FileCheck %s #include <assert.h> #include <stdio.h> diff --git a/test/msan/readdir64.cc b/test/msan/readdir64.cc index 4f00d1838..e77ada6ac 100644 --- a/test/msan/readdir64.cc +++ b/test/msan/readdir64.cc @@ -1,12 +1,12 @@ -// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t -// RUN: %clangxx_msan -m64 -O1 %s -o %t && %run %t -// RUN: %clangxx_msan -m64 -O2 %s -o %t && %run %t -// RUN: %clangxx_msan -m64 -O3 %s -o %t && %run %t +// RUN: %clangxx_msan -O0 %s -o %t && %run %t +// RUN: %clangxx_msan -O1 %s -o %t && %run %t +// RUN: %clangxx_msan -O2 %s -o %t && %run %t +// RUN: %clangxx_msan -O3 %s -o %t && %run %t -// RUN: %clangxx_msan -m64 -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t -// RUN: %clangxx_msan -m64 -O1 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t -// RUN: %clangxx_msan -m64 -O2 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t -// RUN: %clangxx_msan -m64 -O3 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t +// RUN: %clangxx_msan -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t +// RUN: %clangxx_msan -O1 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t +// RUN: %clangxx_msan -O2 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t +// RUN: %clangxx_msan -O3 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t // Test that readdir64 is intercepted as well as readdir. diff --git a/test/msan/realloc-large-origin.cc b/test/msan/realloc-large-origin.cc index de39394cb..ce25ad8c4 100644 --- a/test/msan/realloc-large-origin.cc +++ b/test/msan/realloc-large-origin.cc @@ -1,6 +1,6 @@ -// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -O0 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out -// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -m64 -O2 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -O2 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out // This is a regression test: there used to be broken "stored to memory at" diff --git a/test/msan/realloc-origin.cc b/test/msan/realloc-origin.cc index 6707cc904..e6893713e 100644 --- a/test/msan/realloc-origin.cc +++ b/test/msan/realloc-origin.cc @@ -1,6 +1,6 @@ -// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -fsanitize-memory-track-origins -O0 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out -// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O2 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -fsanitize-memory-track-origins -O2 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out // This test relies on realloc from 100 to 101 being done in-place. diff --git a/test/msan/report-demangling.cc b/test/msan/report-demangling.cc index e6d5c27ec..e75ba87ae 100644 --- a/test/msan/report-demangling.cc +++ b/test/msan/report-demangling.cc @@ -1,7 +1,7 @@ // Test that function name is mangled in the "created by an allocation" line, // and demangled in the single-frame "stack trace" that follows. -// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -fsanitize-memory-track-origins -O0 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out && FileCheck %s < %t.out __attribute__((noinline)) diff --git a/test/msan/scandir.cc b/test/msan/scandir.cc index 571ba4f60..8adfe0066 100644 --- a/test/msan/scandir.cc +++ b/test/msan/scandir.cc @@ -1,6 +1,6 @@ -// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t %p -// RUN: %clangxx_msan -m64 -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t %p -// RUN: %clangxx_msan -m64 -O3 %s -o %t && %run %t %p +// RUN: %clangxx_msan -O0 %s -o %t && %run %t %p +// RUN: %clangxx_msan -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t %p +// RUN: %clangxx_msan -O3 %s -o %t && %run %t %p #include <assert.h> #include <glob.h> diff --git a/test/msan/scandir_null.cc b/test/msan/scandir_null.cc index e7663dc43..94ac31a41 100644 --- a/test/msan/scandir_null.cc +++ b/test/msan/scandir_null.cc @@ -1,6 +1,6 @@ -// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t %p -// RUN: %clangxx_msan -m64 -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t %p -// RUN: %clangxx_msan -m64 -O3 %s -o %t && %run %t %p +// RUN: %clangxx_msan -O0 %s -o %t && %run %t %p +// RUN: %clangxx_msan -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t %p +// RUN: %clangxx_msan -O3 %s -o %t && %run %t %p #include <assert.h> #include <glob.h> diff --git a/test/msan/select.cc b/test/msan/select.cc index 89de75eba..7b8c34785 100644 --- a/test/msan/select.cc +++ b/test/msan/select.cc @@ -1,10 +1,10 @@ -// RUN: %clangxx_msan -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -O0 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out -// RUN: %clangxx_msan -m64 -O1 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -O1 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out -// RUN: %clangxx_msan -m64 -O2 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -O2 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out -// RUN: %clangxx_msan -m64 -O3 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -O3 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out #include <stdlib.h> diff --git a/test/msan/setlocale.cc b/test/msan/setlocale.cc index b7007f78d..796f4454e 100644 --- a/test/msan/setlocale.cc +++ b/test/msan/setlocale.cc @@ -1,4 +1,4 @@ -// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t +// RUN: %clangxx_msan -O0 %s -o %t && %run %t #include <assert.h> #include <locale.h> diff --git a/test/msan/stack-origin.cc b/test/msan/stack-origin.cc index c39c3a8cf..e69c07224 100644 --- a/test/msan/stack-origin.cc +++ b/test/msan/stack-origin.cc @@ -1,19 +1,19 @@ -// RUN: %clangxx_msan -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -O0 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out -// RUN: %clangxx_msan -m64 -O1 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -O1 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out -// RUN: %clangxx_msan -m64 -O2 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -O2 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out -// RUN: %clangxx_msan -m64 -O3 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -O3 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out -// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -fsanitize-memory-track-origins -O0 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out -// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O1 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -fsanitize-memory-track-origins -O1 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out -// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O2 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -fsanitize-memory-track-origins -O2 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out -// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O3 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -fsanitize-memory-track-origins -O3 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out #include <stdlib.h> diff --git a/test/msan/stack-origin2.cc b/test/msan/stack-origin2.cc index 0ba57607d..6c7428c2d 100644 --- a/test/msan/stack-origin2.cc +++ b/test/msan/stack-origin2.cc @@ -1,21 +1,21 @@ // Test that on the second entry to a function the origins are still right. -// RUN: %clangxx_msan -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -O0 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out -// RUN: %clangxx_msan -m64 -O1 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -O1 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out -// RUN: %clangxx_msan -m64 -O2 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -O2 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out -// RUN: %clangxx_msan -m64 -O3 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -O3 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out -// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -fsanitize-memory-track-origins -O0 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out -// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O1 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -fsanitize-memory-track-origins -O1 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out -// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O2 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -fsanitize-memory-track-origins -O2 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out -// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O3 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -fsanitize-memory-track-origins -O3 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out #include <stdlib.h> diff --git a/test/msan/strlen_of_shadow.cc b/test/msan/strlen_of_shadow.cc index 8f1b4e1fc..d6f8be70b 100644 --- a/test/msan/strlen_of_shadow.cc +++ b/test/msan/strlen_of_shadow.cc @@ -1,4 +1,4 @@ -// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t +// RUN: %clangxx_msan -O0 %s -o %t && %run %t // Check that strlen() and similar intercepted functions can be called on shadow // memory. diff --git a/test/msan/strxfrm.cc b/test/msan/strxfrm.cc index b930a6af6..9a30d03c3 100644 --- a/test/msan/strxfrm.cc +++ b/test/msan/strxfrm.cc @@ -1,4 +1,4 @@ -// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t +// RUN: %clangxx_msan -O0 -g %s -o %t && %run %t #include <assert.h> #include <sanitizer/msan_interface.h> diff --git a/test/msan/sync_lock_set_and_test.cc b/test/msan/sync_lock_set_and_test.cc index b6d344a61..11fd14fae 100644 --- a/test/msan/sync_lock_set_and_test.cc +++ b/test/msan/sync_lock_set_and_test.cc @@ -1,4 +1,4 @@ -// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t +// RUN: %clangxx_msan -O0 %s -o %t && %run %t int main(void) { int i; diff --git a/test/msan/textdomain.cc b/test/msan/textdomain.cc index 47e991e8c..760debd68 100644 --- a/test/msan/textdomain.cc +++ b/test/msan/textdomain.cc @@ -1,4 +1,4 @@ -// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t +// RUN: %clangxx_msan -O0 -g %s -o %t && %run %t #include <libintl.h> #include <stdio.h> diff --git a/test/msan/times.cc b/test/msan/times.cc index a042f548d..7c8188411 100644 --- a/test/msan/times.cc +++ b/test/msan/times.cc @@ -1,4 +1,4 @@ -// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t +// RUN: %clangxx_msan -O0 -g %s -o %t && %run %t #include <assert.h> #include <stdlib.h> diff --git a/test/msan/tls_reuse.cc b/test/msan/tls_reuse.cc index e024a5a8d..78a328fa3 100644 --- a/test/msan/tls_reuse.cc +++ b/test/msan/tls_reuse.cc @@ -1,4 +1,4 @@ -// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t +// RUN: %clangxx_msan -O0 %s -o %t && %run %t // Check that when TLS block is reused between threads, its shadow is cleaned. diff --git a/test/msan/tzset.cc b/test/msan/tzset.cc index ed61d7bcc..05915e047 100644 --- a/test/msan/tzset.cc +++ b/test/msan/tzset.cc @@ -1,4 +1,4 @@ -// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t +// RUN: %clangxx_msan -O0 %s -o %t && %run %t #include <stdlib.h> #include <string.h> diff --git a/test/msan/unaligned_read_origin.cc b/test/msan/unaligned_read_origin.cc index e5618efbd..b04800a13 100644 --- a/test/msan/unaligned_read_origin.cc +++ b/test/msan/unaligned_read_origin.cc @@ -1,6 +1,6 @@ -// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -fsanitize-memory-track-origins -O0 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out && FileCheck %s < %t.out -// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O3 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -fsanitize-memory-track-origins -O3 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out && FileCheck %s < %t.out #include <sanitizer/msan_interface.h> diff --git a/test/msan/unpoison_string.cc b/test/msan/unpoison_string.cc index ac947b9cf..84d952833 100644 --- a/test/msan/unpoison_string.cc +++ b/test/msan/unpoison_string.cc @@ -1,6 +1,6 @@ -// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %s -o %t +// RUN: %clangxx_msan -fsanitize-memory-track-origins -O0 %s -o %t // RUN: %run %t -// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O3 %s -o %t +// RUN: %clangxx_msan -fsanitize-memory-track-origins -O3 %s -o %t // RUN: %run %t #include <assert.h> diff --git a/test/msan/use-after-free.cc b/test/msan/use-after-free.cc index 869bad98e..c50512447 100644 --- a/test/msan/use-after-free.cc +++ b/test/msan/use-after-free.cc @@ -1,19 +1,19 @@ -// RUN: %clangxx_msan -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -O0 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out -// RUN: %clangxx_msan -m64 -O1 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -O1 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out -// RUN: %clangxx_msan -m64 -O2 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -O2 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out -// RUN: %clangxx_msan -m64 -O3 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -O3 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out -// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -fsanitize-memory-track-origins -O0 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out -// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O1 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -fsanitize-memory-track-origins -O1 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out -// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O2 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -fsanitize-memory-track-origins -O2 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out -// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O3 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -fsanitize-memory-track-origins -O3 %s -o %t && not %run %t >%t.out 2>&1 // RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out #include <stdlib.h> diff --git a/test/msan/vector_cvt.cc b/test/msan/vector_cvt.cc index bd9b6a8b8..d08ec3e3d 100644 --- a/test/msan/vector_cvt.cc +++ b/test/msan/vector_cvt.cc @@ -1,5 +1,5 @@ -// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t -// RUN: %clangxx_msan -DPOSITIVE -m64 -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_msan -O0 %s -o %t && %run %t +// RUN: %clangxx_msan -DPOSITIVE -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s #include <emmintrin.h> diff --git a/test/msan/vector_select.cc b/test/msan/vector_select.cc index afeb1ad50..4bfeba69c 100644 --- a/test/msan/vector_select.cc +++ b/test/msan/vector_select.cc @@ -1,5 +1,5 @@ -// RUN: %clangxx_msan -m64 -O0 %s -c -o %t -// RUN: %clangxx_msan -m64 -O3 %s -c -o %t +// RUN: %clangxx_msan -O0 %s -c -o %t +// RUN: %clangxx_msan -O3 %s -c -o %t // Regression test for MemorySanitizer instrumentation of a select instruction // with vector arguments. diff --git a/test/sanitizer_common/CMakeLists.txt b/test/sanitizer_common/CMakeLists.txt index 13eecbdc1..42f26902b 100644 --- a/test/sanitizer_common/CMakeLists.txt +++ b/test/sanitizer_common/CMakeLists.txt @@ -16,16 +16,26 @@ endif() # Create a separate config for each tool we support. foreach(tool ${SUPPORTED_TOOLS}) string(TOUPPER ${tool} tool_toupper) - if(${tool_toupper}_SUPPORTED_ARCH) + if(${tool_toupper}_SUPPORTED_ARCH AND NOT COMPILER_RT_STANDALONE_BUILD) + list(APPEND SANITIZER_COMMON_TEST_DEPS ${tool}) + endif() + foreach(arch ${${tool_toupper}_SUPPORTED_ARCH}) set(SANITIZER_COMMON_LIT_TEST_MODE ${tool}) + set(SANITIZER_COMMON_TEST_TARGET_ARCH ${arch}) + if(${arch} MATCHES "arm|aarch64") + # This is only true if we're cross-compiling. + set(SANITIZER_COMMON_TEST_TARGET_CFLAGS + ${COMPILER_RT_TEST_COMPILER_CFLAGS}) + else() + get_target_flags_for_arch(${arch} SANITIZER_COMMON_TEST_TARGET_CFLAGS) + endif() + set(CONFIG_NAME ${tool}-${arch}-${OS_NAME}) configure_lit_site_cfg( ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in - ${CMAKE_CURRENT_BINARY_DIR}/${tool}/lit.site.cfg) - list(APPEND SANITIZER_COMMON_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/${tool}) - if(NOT COMPILER_RT_STANDALONE_BUILD) - list(APPEND SANITIZER_COMMON_TEST_DEPS ${tool}) - endif() - endif() + ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/lit.site.cfg) + list(APPEND SANITIZER_COMMON_TESTSUITES + ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}) + endforeach() endforeach() # Unit tests. diff --git a/test/sanitizer_common/TestCases/Linux/open_memstream.cc b/test/sanitizer_common/TestCases/Linux/open_memstream.cc index 6abe0bfb1..69097c094 100644 --- a/test/sanitizer_common/TestCases/Linux/open_memstream.cc +++ b/test/sanitizer_common/TestCases/Linux/open_memstream.cc @@ -1,5 +1,6 @@ // RUN: %clangxx -m64 -O0 -g -xc++ %s -o %t && %run %t // RUN: %clangxx -m64 -O3 -g -xc++ %s -o %t && %run %t +// REQUIRES: x86_64-supported-target #include <assert.h> #include <stdio.h> diff --git a/test/tsan/signal_segv_handler.cc b/test/sanitizer_common/TestCases/Linux/signal_segv_handler.cc index 2d806eef6..9ea9fef70 100644 --- a/test/tsan/signal_segv_handler.cc +++ b/test/sanitizer_common/TestCases/Linux/signal_segv_handler.cc @@ -1,4 +1,4 @@ -// RUN: %clang_tsan -O1 %s -o %t && TSAN_OPTIONS="flush_memory_ms=1 memory_limit_mb=1" %run %t 2>&1 | FileCheck %s +// RUN: %clangxx -O1 %s -o %t && TSAN_OPTIONS="flush_memory_ms=1 memory_limit_mb=1" ASAN_OPTIONS="handle_segv=0 allow_user_segv_handler=1" %run %t 2>&1 | FileCheck %s // JVM uses SEGV to preempt threads. All threads do a load from a known address // periodically. When runtime needs to preempt threads, it unmaps the page. @@ -13,7 +13,8 @@ // "benign" SEGVs that are handled by signal handler, and ensures that // the process survive. -#include "test.h" +#include <stdio.h> +#include <stdlib.h> #include <signal.h> #include <sys/mman.h> @@ -24,15 +25,16 @@ void handler(int signo, siginfo_t *info, void *uctx) { } int main() { - struct sigaction a; + struct sigaction a, old; a.sa_sigaction = handler; a.sa_flags = SA_SIGINFO; - sigaction(SIGSEGV, &a, 0); + sigaction(SIGSEGV, &a, &old); guard = mmap(0, 4096, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0); for (int i = 0; i < 1000000; i++) { mprotect(guard, 4096, PROT_NONE); *(int*)guard = 1; } + sigaction(SIGSEGV, &old, 0); fprintf(stderr, "DONE\n"); } diff --git a/test/sanitizer_common/lit.site.cfg.in b/test/sanitizer_common/lit.site.cfg.in index 1e94aa567..64a3edf6c 100644 --- a/test/sanitizer_common/lit.site.cfg.in +++ b/test/sanitizer_common/lit.site.cfg.in @@ -3,6 +3,8 @@ lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configu # Tool-specific config options. config.tool_name = "@SANITIZER_COMMON_LIT_TEST_MODE@" +config.target_cflags = "@SANITIZER_COMMON_TEST_TARGET_CFLAGS@" +config.target_arch = "@SANITIZER_COMMON_TEST_TARGET_ARCH@" # Load tool-specific config that would do the real work. lit_config.load_config(config, "@SANITIZER_COMMON_LIT_SOURCE_DIR@/lit.common.cfg") diff --git a/test/tsan/java_heap_init.cc b/test/tsan/java_heap_init.cc new file mode 100644 index 000000000..bb7357c25 --- /dev/null +++ b/test/tsan/java_heap_init.cc @@ -0,0 +1,28 @@ +// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s +#include "java.h" +#include <errno.h> +#include <sys/mman.h> + +int main() { + // Test that munmap interceptor resets meta shadow for the memory range. + // Previously __tsan_java_move failed because it encountered non-zero meta + // shadow for the destination. + int const kHeapSize = 1024 * 1024; + jptr jheap = (jptr)mmap(0, kHeapSize, PROT_READ | PROT_WRITE, + MAP_ANON | MAP_PRIVATE, -1, 0); + if (jheap == (jptr)MAP_FAILED) + return printf("mmap failed with %d\n", errno); + __atomic_store_n((int*)jheap, 1, __ATOMIC_RELEASE); + munmap((void*)jheap, kHeapSize); + jheap = (jptr)mmap((void*)jheap, kHeapSize, PROT_READ | PROT_WRITE, + MAP_ANON | MAP_PRIVATE, -1, 0); + if (jheap == (jptr)MAP_FAILED) + return printf("second mmap failed with %d\n", errno); + __tsan_java_init(jheap, kHeapSize); + __tsan_java_move(jheap + 16, jheap, 16); + printf("DONE\n"); + return __tsan_java_fini(); +} + +// CHECK-NOT: WARNING: ThreadSanitizer: data race +// CHECK: DONE diff --git a/test/tsan/mmap_large.cc b/test/tsan/mmap_large.cc index 4ae4c0863..098530475 100644 --- a/test/tsan/mmap_large.cc +++ b/test/tsan/mmap_large.cc @@ -4,6 +4,13 @@ #include <errno.h> #include <sys/mman.h> +#if defined(__FreeBSD__) +// The MAP_NORESERVE define has been removed in FreeBSD 11.x, and even before +// that, it was never implemented. So just define it to zero. +#undef MAP_NORESERVE +#define MAP_NORESERVE 0 +#endif + int main() { #ifdef __x86_64__ const size_t kLog2Size = 39; diff --git a/test/tsan/mmap_stress.cc b/test/tsan/mmap_stress.cc new file mode 100644 index 000000000..5e3904adf --- /dev/null +++ b/test/tsan/mmap_stress.cc @@ -0,0 +1,47 @@ +// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s +#include "test.h" +#include <errno.h> +#include <sys/mman.h> + +void *SubWorker(void *arg) { + (void)arg; + const int kMmapSize = 65536; + for (int i = 0; i < 500; i++) { + int *ptr = (int*)mmap(0, kMmapSize, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, -1, 0); + *ptr = 42; + munmap(ptr, kMmapSize); + } + return 0; +} + +void *Worker1(void *arg) { + (void)arg; + pthread_t th[4]; + for (int i = 0; i < 4; i++) + pthread_create(&th[i], 0, SubWorker, 0); + for (int i = 0; i < 4; i++) + pthread_join(th[i], 0); + return 0; +} + +void *Worker(void *arg) { + (void)arg; + pthread_t th[4]; + for (int i = 0; i < 4; i++) + pthread_create(&th[i], 0, Worker1, 0); + for (int i = 0; i < 4; i++) + pthread_join(th[i], 0); + return 0; +} + +int main() { + pthread_t th[4]; + for (int i = 0; i < 4; i++) + pthread_create(&th[i], 0, Worker, 0); + for (int i = 0; i < 4; i++) + pthread_join(th[i], 0); + fprintf(stderr, "DONE\n"); +} + +// CHECK: DONE diff --git a/test/tsan/test.h b/test/tsan/test.h index bb861b077..4e877f6d8 100644 --- a/test/tsan/test.h +++ b/test/tsan/test.h @@ -11,10 +11,16 @@ __typeof(pthread_barrier_wait) *barrier_wait; void barrier_init(pthread_barrier_t *barrier, unsigned count) { +#if defined(__FreeBSD__) + static const char libpthread_name[] = "libpthread.so"; +#else + static const char libpthread_name[] = "libpthread.so.0"; +#endif + if (barrier_wait == 0) { - void *h = dlopen("libpthread.so.0", RTLD_LAZY); + void *h = dlopen(libpthread_name, RTLD_LAZY); if (h == 0) { - fprintf(stderr, "failed to dlopen libpthread.so.0, exiting\n"); + fprintf(stderr, "failed to dlopen %s, exiting\n", libpthread_name); exit(1); } barrier_wait = (__typeof(barrier_wait))dlsym(h, "pthread_barrier_wait"); diff --git a/test/ubsan/TestCases/Integer/shift.cpp b/test/ubsan/TestCases/Integer/shift.cpp index e86fac8d5..c8e01afcf 100644 --- a/test/ubsan/TestCases/Integer/shift.cpp +++ b/test/ubsan/TestCases/Integer/shift.cpp @@ -1,13 +1,20 @@ -// RUN: %clangxx -DLSH_OVERFLOW -DOP='<<' -fsanitize=shift %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-LSH_OVERFLOW -// RUN: %clangxx -DLSH_OVERFLOW -DOP='<<=' -fsanitize=shift %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-LSH_OVERFLOW -// RUN: %clangxx -DTOO_LOW -DOP='<<' -fsanitize=shift %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_LOW -// RUN: %clangxx -DTOO_LOW -DOP='>>' -fsanitize=shift %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_LOW -// RUN: %clangxx -DTOO_LOW -DOP='<<=' -fsanitize=shift %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_LOW -// RUN: %clangxx -DTOO_LOW -DOP='>>=' -fsanitize=shift %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_LOW -// RUN: %clangxx -DTOO_HIGH -DOP='<<' -fsanitize=shift %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_HIGH -// RUN: %clangxx -DTOO_HIGH -DOP='>>' -fsanitize=shift %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_HIGH -// RUN: %clangxx -DTOO_HIGH -DOP='<<=' -fsanitize=shift %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_HIGH -// RUN: %clangxx -DTOO_HIGH -DOP='>>=' -fsanitize=shift %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_HIGH +// RUN: %clangxx -DLSH_OVERFLOW -DOP='<<' -fsanitize=shift-base -fno-sanitize-recover=shift %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-LSH_OVERFLOW +// RUN: %clangxx -DLSH_OVERFLOW -DOP='<<=' -fsanitize=shift -fno-sanitize-recover=shift %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-LSH_OVERFLOW +// RUN: %clangxx -DTOO_LOW -DOP='<<' -fsanitize=shift-exponent -fno-sanitize-recover=shift %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_LOW +// RUN: %clangxx -DTOO_LOW -DOP='>>' -fsanitize=shift -fno-sanitize-recover=shift %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_LOW +// RUN: %clangxx -DTOO_LOW -DOP='<<=' -fsanitize=shift -fno-sanitize-recover=shift %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_LOW +// RUN: %clangxx -DTOO_LOW -DOP='>>=' -fsanitize=shift -fno-sanitize-recover=shift %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_LOW +// RUN: %clangxx -DTOO_HIGH -DOP='<<' -fsanitize=shift-exponent -fno-sanitize-recover=shift %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_HIGH +// RUN: %clangxx -DTOO_HIGH -DOP='>>' -fsanitize=shift -fno-sanitize-recover=shift %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_HIGH +// RUN: %clangxx -DTOO_HIGH -DOP='<<=' -fsanitize=shift -fno-sanitize-recover=shift %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_HIGH +// RUN: %clangxx -DTOO_HIGH -DOP='>>=' -fsanitize=shift -fno-sanitize-recover=shift %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_HIGH + +// RUN: %clangxx -DLSH_OVERFLOW -DOP='<<' -fsanitize=shift-exponent -fno-sanitize-recover=shift %s -o %t && %run %t +// RUN: %clangxx -DLSH_OVERFLOW -DOP='>>' -fsanitize=shift-exponent -fno-sanitize-recover=shift %s -o %t && %run %t +// RUN: %clangxx -DTOO_LOW -DOP='<<' -fsanitize=shift-base -fno-sanitize-recover=shift %s -o %t && %run %t +// RUN: %clangxx -DTOO_LOW -DOP='>>' -fsanitize=shift-base -fno-sanitize-recover=shift %s -o %t && %run %t +// RUN: %clangxx -DTOO_HIGH -DOP='<<' -fsanitize=shift-base -fno-sanitize-recover=shift %s -o %t && %run %t +// RUN: %clangxx -DTOO_HIGH -DOP='>>' -fsanitize=shift-base -fno-sanitize-recover=shift %s -o %t && %run %t #include <stdint.h> @@ -20,18 +27,19 @@ int main() { b <<= 1; // still ok, unsigned #ifdef LSH_OVERFLOW - // CHECK-LSH_OVERFLOW: shift.cpp:24:5: runtime error: left shift of negative value -2147483648 + // CHECK-LSH_OVERFLOW: shift.cpp:[[@LINE+1]]:5: runtime error: left shift of negative value -2147483648 a OP 1; #endif #ifdef TOO_LOW - // CHECK-TOO_LOW: shift.cpp:29:5: runtime error: shift exponent -3 is negative + a = 0; + // CHECK-TOO_LOW: shift.cpp:[[@LINE+1]]:5: runtime error: shift exponent -3 is negative a OP (-3); #endif #ifdef TOO_HIGH a = 0; - // CHECK-TOO_HIGH: shift.cpp:35:5: runtime error: shift exponent 32 is too large for 32-bit type 'int' + // CHECK-TOO_HIGH: shift.cpp:[[@LINE+1]]:5: runtime error: shift exponent 32 is too large for 32-bit type 'int' a OP 32; #endif } diff --git a/test/ubsan/TestCases/Integer/summary.cpp b/test/ubsan/TestCases/Integer/summary.cpp index 6e9aec63c..21f537b92 100644 --- a/test/ubsan/TestCases/Integer/summary.cpp +++ b/test/ubsan/TestCases/Integer/summary.cpp @@ -5,6 +5,6 @@ int main() { (void)(uint64_t(10000000000000000000ull) + uint64_t(9000000000000000000ull)); - // CHECK: SUMMARY: AddressSanitizer: undefined-behavior {{.*}}summary.cpp:[[@LINE-1]] + // CHECK: SUMMARY: AddressSanitizer: undefined-behavior {{.*}}summary.cpp:[[@LINE-1]]:44 return 0; } diff --git a/test/ubsan/TestCases/Misc/coverage-levels.cc b/test/ubsan/TestCases/Misc/Linux/coverage-levels.cc index 2fe12ffef..02521722f 100644 --- a/test/ubsan/TestCases/Misc/coverage-levels.cc +++ b/test/ubsan/TestCases/Misc/Linux/coverage-levels.cc @@ -14,8 +14,6 @@ // RUN: %clangxx -fsanitize=shift -O1 -fsanitize-coverage=3 %s -o %t // RUN: UBSAN_OPTIONS=$OPT ASAN_OPTIONS=$OPT %run %t 2>&1 | FileCheck %s --check-prefix=CHECK3 --check-prefix=CHECK_WARN -// XFAIL: darwin - volatile int sink; int main(int argc, char **argv) { int shift = argc * 32; diff --git a/test/ubsan/TestCases/Misc/Linux/lit.local.cfg b/test/ubsan/TestCases/Misc/Linux/lit.local.cfg new file mode 100644 index 000000000..57271b807 --- /dev/null +++ b/test/ubsan/TestCases/Misc/Linux/lit.local.cfg @@ -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 ['Linux']: + config.unsupported = True diff --git a/test/ubsan/TestCases/TypeCheck/vptr-virtual-base.cpp b/test/ubsan/TestCases/TypeCheck/vptr-virtual-base.cpp index 806e45c7d..a77680efd 100644 --- a/test/ubsan/TestCases/TypeCheck/vptr-virtual-base.cpp +++ b/test/ubsan/TestCases/TypeCheck/vptr-virtual-base.cpp @@ -1,9 +1,6 @@ // RUN: %clangxx -frtti -fsanitize=vptr -fno-sanitize-recover=vptr -g %s -O3 -o %t // RUN: not %run %t 2>&1 | FileCheck %s -// FIXME: This test produces linker errors on Darwin. -// XFAIL: darwin - struct S { virtual int f() { return 0; } }; struct T : virtual S {}; |