aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-05-02 18:30:55 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-05-02 18:30:55 +0000
commit8d8e909cdc9f4e78e1e1600497d827e1acde6cea (patch)
treec8c6047827589e56f2ed1f77f23b1f7d1a10e793
parent2953104c9a262728031dc518429d15b969dd6028 (diff)
downloadsrc-8d8e909cdc9f4e78e1e1600497d827e1acde6cea.tar.gz
src-8d8e909cdc9f4e78e1e1600497d827e1acde6cea.zip
Vendor import of compiler-rt trunk r301939:vendor/compiler-rt/compiler-rt-trunk-r301939
Notes
Notes: svn path=/vendor/compiler-rt/dist/; revision=317687 svn path=/vendor/compiler-rt/compiler-rt-trunk-r301939/; revision=317688; tag=vendor/compiler-rt/compiler-rt-trunk-r301939
-rw-r--r--cmake/Modules/AddCompilerRT.cmake8
-rw-r--r--include/sanitizer/tsan_interface.h3
-rw-r--r--include/xray/xray_log_interface.h171
-rw-r--r--lib/asan/asan_globals.cc20
-rw-r--r--lib/asan/asan_interceptors.cc7
-rw-r--r--lib/asan/asan_interface.inc2
-rw-r--r--lib/asan/asan_interface_internal.h5
-rw-r--r--lib/sanitizer_common/sanitizer_coverage_libcdep.cc40
-rw-r--r--lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc4
-rw-r--r--lib/sanitizer_common/sanitizer_flags.inc6
-rw-r--r--lib/sanitizer_common/sanitizer_linux.h40
-rw-r--r--lib/scudo/CMakeLists.txt1
-rw-r--r--lib/scudo/scudo_allocator.cpp217
-rw-r--r--lib/scudo/scudo_allocator.h55
-rw-r--r--lib/scudo/scudo_tls.h40
-rw-r--r--lib/scudo/scudo_tls_linux.cpp62
-rw-r--r--lib/scudo/scudo_tls_linux.h48
-rw-r--r--lib/scudo/scudo_utils.cpp4
-rw-r--r--lib/scudo/scudo_utils.h2
-rwxr-xr-xlib/tsan/go/buildgo.sh1
-rw-r--r--lib/tsan/rtl/tsan_external.cc29
-rw-r--r--lib/tsan/rtl/tsan_interface_ann.cc2
-rw-r--r--lib/tsan/rtl/tsan_platform_linux.cc24
-rw-r--r--lib/tsan/rtl/tsan_report.cc2
-rw-r--r--lib/tsan/rtl/tsan_rtl.cc5
-rw-r--r--lib/tsan/rtl/tsan_rtl.h36
-rw-r--r--lib/tsan/rtl/tsan_rtl_mutex.cc4
-rw-r--r--lib/tsan/rtl/tsan_rtl_report.cc16
-rw-r--r--lib/tsan/tests/rtl/tsan_posix.cc5
-rw-r--r--lib/ubsan/ubsan_diag.cc17
-rw-r--r--lib/ubsan/ubsan_handlers.cc2
-rw-r--r--lib/xray/xray_log_interface.cc10
-rw-r--r--test/asan/CMakeLists.txt51
-rw-r--r--test/asan/TestCases/Darwin/dead-strip.c1
-rw-r--r--test/asan/TestCases/Darwin/dump_registers.cc2
-rw-r--r--test/asan/TestCases/Darwin/reexec-insert-libraries-env.cc2
-rw-r--r--test/asan/TestCases/Darwin/scribble.cc2
-rw-r--r--test/asan/TestCases/Darwin/unset-insert-libraries-on-exec.cc2
-rw-r--r--test/asan/TestCases/Linux/global-overflow-bfd.cc18
-rw-r--r--test/asan/TestCases/Linux/global-overflow-lld.cc19
-rw-r--r--test/asan/TestCases/Linux/globals-gc-sections-lld.cc15
-rw-r--r--test/asan/TestCases/Linux/globals-gc-sections.cc13
-rw-r--r--test/asan/TestCases/Posix/asan-sigbus.cpp2
-rw-r--r--test/asan/TestCases/Posix/coverage-direct-activation.cc59
-rw-r--r--test/asan/TestCases/Posix/coverage-direct-large.cc65
-rw-r--r--test/asan/TestCases/Posix/coverage-direct.cc83
-rw-r--r--test/asan/TestCases/Posix/coverage-fork-direct.cc38
-rw-r--r--test/asan/TestCases/Posix/current_allocated_bytes.cc3
-rw-r--r--test/asan/TestCases/Posix/fread_fwrite.cc4
-rw-r--r--test/asan/TestCases/coverage-disabled.cc5
-rw-r--r--test/asan/TestCases/coverage-levels.cc31
-rw-r--r--test/asan/TestCases/initialization-bug.cc1
-rw-r--r--test/asan/TestCases/small_memcpy_test.cc28
-rw-r--r--test/asan/TestCases/strtok.c2
-rw-r--r--test/asan/lit.cfg6
-rw-r--r--test/asan/lit.site.cfg.in2
-rw-r--r--test/lit.common.cfg21
-rw-r--r--test/lit.common.configured.in2
-rw-r--r--test/sanitizer_common/TestCases/sanitizer_coverage_symbolize.cc6
-rwxr-xr-xtest/sanitizer_common/ios_commands/iossim_compile.py32
-rwxr-xr-xtest/sanitizer_common/ios_commands/iossim_env.py17
-rwxr-xr-xtest/sanitizer_common/ios_commands/iossim_run.py17
-rw-r--r--test/tsan/Darwin/xpc-cancel.mm2
-rw-r--r--test/tsan/Darwin/xpc-race.mm6
-rw-r--r--test/tsan/Darwin/xpc.mm2
-rw-r--r--test/tsan/ignore_lib1.cc3
-rw-r--r--test/tsan/ignore_lib5.cc3
-rw-r--r--test/ubsan/TestCases/Float/cast-overflow.cpp20
-rw-r--r--test/ubsan/TestCases/Misc/log-path_test.cc2
-rw-r--r--test/ubsan/TestCases/Misc/missing_return.cpp7
-rw-r--r--test/ubsan/TestCases/TypeCheck/misaligned.cpp8
71 files changed, 911 insertions, 579 deletions
diff --git a/cmake/Modules/AddCompilerRT.cmake b/cmake/Modules/AddCompilerRT.cmake
index b64eb4246346..bc5fb9ff722b 100644
--- a/cmake/Modules/AddCompilerRT.cmake
+++ b/cmake/Modules/AddCompilerRT.cmake
@@ -210,6 +210,14 @@ function(add_compiler_rt_runtime name type)
set_target_properties(${libname} PROPERTIES IMPORT_PREFIX "")
set_target_properties(${libname} PROPERTIES IMPORT_SUFFIX ".lib")
endif()
+ if(APPLE)
+ # Ad-hoc sign the dylibs
+ add_custom_command(TARGET ${libname}
+ POST_BUILD
+ COMMAND codesign --sign - $<TARGET_FILE:${libname}>
+ WORKING_DIRECTORY ${COMPILER_RT_LIBRARY_OUTPUT_DIR}
+ )
+ endif()
endif()
install(TARGETS ${libname}
ARCHIVE DESTINATION ${COMPILER_RT_LIBRARY_INSTALL_DIR}
diff --git a/include/sanitizer/tsan_interface.h b/include/sanitizer/tsan_interface.h
index 45e54f7581a1..a0c70263895a 100644
--- a/include/sanitizer/tsan_interface.h
+++ b/include/sanitizer/tsan_interface.h
@@ -68,7 +68,8 @@ const unsigned __tsan_mutex_recursive_unlock = 1 << 7;
void __tsan_mutex_create(void *addr, unsigned flags);
// Annotate destruction of a mutex.
-// Supported flags: none.
+// Supported flags:
+// - __tsan_mutex_linker_init
void __tsan_mutex_destroy(void *addr, unsigned flags);
// Annotate start of lock operation.
diff --git a/include/xray/xray_log_interface.h b/include/xray/xray_log_interface.h
index a8709c3a7c8a..cdb20094dc26 100644
--- a/include/xray/xray_log_interface.h
+++ b/include/xray/xray_log_interface.h
@@ -10,7 +10,73 @@
// This file is a part of XRay, a function call tracing system.
//
// APIs for installing a new logging implementation.
+//
//===----------------------------------------------------------------------===//
+///
+/// XRay allows users to implement their own logging handlers and install them
+/// to replace the default runtime-controllable implementation that comes with
+/// compiler-rt/xray. The "flight data recorder" (FDR) mode implementation uses
+/// this API to install itself in an XRay-enabled binary. See
+/// compiler-rt/lib/xray_fdr_logging.{h,cc} for details of that implementation.
+///
+/// The high-level usage pattern for these APIs look like the following:
+///
+/// // Before we try initializing the log implementation, we must set it as
+/// // the log implementation. We provide the function pointers that define
+/// // the various initialization, finalization, and other pluggable hooks
+/// // that we need.
+/// __xray_set_log_impl({...});
+///
+/// // Once that's done, we can now initialize the implementation. Each
+/// // implementation has a chance to let users customize the implementation
+/// // with a struct that their implementation supports. Roughly this might
+/// // look like:
+/// MyImplementationOptions opts;
+/// opts.enable_feature = true;
+/// ...
+/// auto init_status = __xray_log_init(
+/// BufferSize, MaxBuffers, &opts, sizeof opts);
+/// if (init_status != XRayLogInitStatus::XRAY_LOG_INITIALIZED) {
+/// // deal with the error here, if there is one.
+/// }
+///
+/// // When the log implementation has had the chance to initialize, we can
+/// // now patch the sleds.
+/// auto patch_status = __xray_patch();
+/// if (patch_status != XRayPatchingStatus::SUCCESS) {
+/// // deal with the error here, if it is an error.
+/// }
+///
+/// // If we want to stop the implementation, we can then finalize it (before
+/// // optionally flushing the log).
+/// auto fin_status = __xray_log_finalize();
+/// if (fin_status != XRayLogInitStatus::XRAY_LOG_FINALIZED) {
+/// // deal with the error here, if it is an error.
+/// }
+///
+/// // We can optionally wait before flushing the log to give other threads a
+/// // chance to see that the implementation is already finalized. Also, at
+/// // this point we can optionally unpatch the sleds to reduce overheads at
+/// // runtime.
+/// auto unpatch_status = __xray_unpatch();
+/// if (unpatch_status != XRayPatchingStatus::SUCCESS) {
+// // deal with the error here, if it is an error.
+// }
+///
+/// // If there are logs or data to be flushed somewhere, we can do so only
+/// // after we've finalized the log. Some implementations may not actually
+/// // have anything to log (it might keep the data in memory, or periodically
+/// // be logging the data anyway).
+/// auto flush_status = __xray_log_flushLog();
+/// if (flush_status != XRayLogFlushStatus::XRAY_LOG_FLUSHED) {
+/// // deal with the error here, if it is an error.
+/// }
+///
+///
+/// NOTE: Before calling __xray_patch() again, consider re-initializing the
+/// implementation first. Some implementations might stay in an "off" state when
+/// they are finalized, while some might be in an invalid/unknown state.
+///
#ifndef XRAY_XRAY_LOG_INTERFACE_H
#define XRAY_XRAY_LOG_INTERFACE_H
@@ -19,36 +85,141 @@
extern "C" {
+/// This enum defines the valid states in which the logging implementation can
+/// be at.
enum XRayLogInitStatus {
+ /// The default state is uninitialized, and in case there were errors in the
+ /// initialization, the implementation MUST return XRAY_LOG_UNINITIALIZED.
XRAY_LOG_UNINITIALIZED = 0,
+
+ /// Some implementations support multi-stage init (or asynchronous init), and
+ /// may return XRAY_LOG_INITIALIZING to signal callers of the API that
+ /// there's an ongoing initialization routine running. This allows
+ /// implementations to support concurrent threads attempting to initialize,
+ /// while only signalling success in one.
XRAY_LOG_INITIALIZING = 1,
+
+ /// When an implementation is done initializing, it MUST return
+ /// XRAY_LOG_INITIALIZED. When users call `__xray_patch()`, they are
+ /// guaranteed that the implementation installed with
+ /// `__xray_set_log_impl(...)` has been initialized.
XRAY_LOG_INITIALIZED = 2,
+
+ /// Some implementations might support multi-stage finalization (or
+ /// asynchronous finalization), and may return XRAY_LOG_FINALIZING to signal
+ /// callers of the API that there's an ongoing finalization routine running.
+ /// This allows implementations to support concurrent threads attempting to
+ /// finalize, while only signalling success/completion in one.
XRAY_LOG_FINALIZING = 3,
+
+ /// When an implementation is done finalizing, it MUST return
+ /// XRAY_LOG_FINALIZED. It is up to the implementation to determine what the
+ /// semantics of a finalized implementation is. Some implementations might
+ /// allow re-initialization once the log is finalized, while some might always
+ /// be on (and that finalization is a no-op).
XRAY_LOG_FINALIZED = 4,
};
+/// This enum allows an implementation to signal log flushing operations via
+/// `__xray_log_flushLog()`, and the state of flushing the log.
enum XRayLogFlushStatus {
XRAY_LOG_NOT_FLUSHING = 0,
XRAY_LOG_FLUSHING = 1,
XRAY_LOG_FLUSHED = 2,
};
+/// A valid XRay logging implementation MUST provide all of the function
+/// pointers in XRayLogImpl when being installed through `__xray_set_log_impl`.
+/// To be precise, ALL the functions pointers MUST NOT be nullptr.
struct XRayLogImpl {
+ /// The log initialization routine provided by the implementation, always
+ /// provided with the following parameters:
+ ///
+ /// - buffer size
+ /// - maximum number of buffers
+ /// - a pointer to an argument struct that the implementation MUST handle
+ /// - the size of the argument struct
+ ///
+ /// See XRayLogInitStatus for details on what the implementation MUST return
+ /// when called.
+ ///
+ /// If the implementation needs to install handlers aside from the 0-argument
+ /// function call handler, it MUST do so in this initialization handler.
+ ///
+ /// See xray_interface.h for available handler installation routines.
XRayLogInitStatus (*log_init)(size_t, size_t, void *, size_t);
+
+ /// The log finalization routine provided by the implementation.
+ ///
+ /// See XRayLogInitStatus for details on what the implementation MUST return
+ /// when called.
XRayLogInitStatus (*log_finalize)();
+
+ /// The 0-argument function call handler. XRay logging implementations MUST
+ /// always have a handler for function entry and exit events. In case the
+ /// implementation wants to support arg1 (or other future extensions to XRay
+ /// logging) those MUST be installed by the installed 'log_init' handler.
void (*handle_arg0)(int32_t, XRayEntryType);
+
+ /// The log implementation provided routine for when __xray_log_flushLog() is
+ /// called.
+ ///
+ /// See XRayLogFlushStatus for details on what the implementation MUST return
+ /// when called.
XRayLogFlushStatus (*flush_log)();
};
+/// This function installs a new logging implementation that XRay will use. In
+/// case there are any nullptr members in Impl, XRay will *uninstall any
+/// existing implementations*. It does NOT patch the instrumentation sleds.
+///
+/// NOTE: This function does NOT attempt to finalize the currently installed
+/// implementation. Use with caution.
+///
+/// It is guaranteed safe to call this function in the following states:
+///
+/// - When the implementation is UNINITIALIZED.
+/// - When the implementation is FINALIZED.
+/// - When there is no current implementation installed.
+///
+/// It is logging implementation defined what happens when this function is
+/// called while in any other states.
void __xray_set_log_impl(XRayLogImpl Impl);
+
+/// This function removes the currently installed implementation. It will also
+/// uninstall any handlers that have been previously installed. It does NOT
+/// unpatch the instrumentation sleds.
+///
+/// NOTE: This function does NOT attempt to finalize the currently installed
+/// implementation. Use with caution.
+///
+/// It is guaranteed safe to call this function in the following states:
+///
+/// - When the implementation is UNINITIALIZED.
+/// - When the implementation is FINALIZED.
+/// - When there is no current implementation installed.
+///
+/// It is logging implementation defined what happens when this function is
+/// called while in any other states.
+void __xray_remove_log_impl();
+
+/// Invokes the installed implementation initialization routine. See
+/// XRayLogInitStatus for what the return values mean.
XRayLogInitStatus __xray_log_init(size_t BufferSize, size_t MaxBuffers,
void *Args, size_t ArgsSize);
+
+/// Invokes the installed implementation finalization routine. See
+/// XRayLogInitStatus for what the return values mean.
XRayLogInitStatus __xray_log_finalize();
+
+/// Invokes the install implementation log flushing routine. See
+/// XRayLogFlushStatus for what the return values mean.
XRayLogFlushStatus __xray_log_flushLog();
} // extern "C"
namespace __xray {
+
// Options used by the LLVM XRay FDR implementation.
struct FDRLoggingOptions {
bool ReportErrors = false;
diff --git a/lib/asan/asan_globals.cc b/lib/asan/asan_globals.cc
index b7233067358c..eebada804f07 100644
--- a/lib/asan/asan_globals.cc
+++ b/lib/asan/asan_globals.cc
@@ -332,6 +332,26 @@ void __asan_unregister_image_globals(uptr *flag) {
*flag = 0;
}
+void __asan_register_elf_globals(uptr *flag, void *start, void *stop) {
+ if (*flag) return;
+ if (!start) return;
+ CHECK_EQ(0, ((uptr)stop - (uptr)start) % sizeof(__asan_global));
+ __asan_global *globals_start = (__asan_global*)start;
+ __asan_global *globals_stop = (__asan_global*)stop;
+ __asan_register_globals(globals_start, globals_stop - globals_start);
+ *flag = 1;
+}
+
+void __asan_unregister_elf_globals(uptr *flag, void *start, void *stop) {
+ if (!*flag) return;
+ if (!start) return;
+ CHECK_EQ(0, ((uptr)stop - (uptr)start) % sizeof(__asan_global));
+ __asan_global *globals_start = (__asan_global*)start;
+ __asan_global *globals_stop = (__asan_global*)stop;
+ __asan_unregister_globals(globals_start, globals_stop - globals_start);
+ *flag = 0;
+}
+
// Register an array of globals.
void __asan_register_globals(__asan_global *globals, uptr n) {
if (!flags()->report_globals) return;
diff --git a/lib/asan/asan_interceptors.cc b/lib/asan/asan_interceptors.cc
index 6ee3266062f8..905dd2e23870 100644
--- a/lib/asan/asan_interceptors.cc
+++ b/lib/asan/asan_interceptors.cc
@@ -37,12 +37,19 @@
namespace __asan {
// Return true if we can quickly decide that the region is unpoisoned.
+// We assume that a redzone is at least 16 bytes.
static inline bool QuickCheckForUnpoisonedRegion(uptr beg, uptr size) {
if (size == 0) return true;
if (size <= 32)
return !AddressIsPoisoned(beg) &&
!AddressIsPoisoned(beg + size - 1) &&
!AddressIsPoisoned(beg + size / 2);
+ if (size <= 64)
+ return !AddressIsPoisoned(beg) &&
+ !AddressIsPoisoned(beg + size / 4) &&
+ !AddressIsPoisoned(beg + size - 1) &&
+ !AddressIsPoisoned(beg + 3 * size / 4) &&
+ !AddressIsPoisoned(beg + size / 2);
return false;
}
diff --git a/lib/asan/asan_interface.inc b/lib/asan/asan_interface.inc
index 351be4da5108..e65f61722b10 100644
--- a/lib/asan/asan_interface.inc
+++ b/lib/asan/asan_interface.inc
@@ -64,6 +64,7 @@ INTERFACE_FUNCTION(__asan_poison_stack_memory)
INTERFACE_FUNCTION(__asan_print_accumulated_stats)
INTERFACE_FUNCTION(__asan_region_is_poisoned)
INTERFACE_FUNCTION(__asan_register_globals)
+INTERFACE_FUNCTION(__asan_register_elf_globals)
INTERFACE_FUNCTION(__asan_register_image_globals)
INTERFACE_FUNCTION(__asan_report_error)
INTERFACE_FUNCTION(__asan_report_exp_load1)
@@ -149,6 +150,7 @@ INTERFACE_FUNCTION(__asan_unpoison_intra_object_redzone)
INTERFACE_FUNCTION(__asan_unpoison_memory_region)
INTERFACE_FUNCTION(__asan_unpoison_stack_memory)
INTERFACE_FUNCTION(__asan_unregister_globals)
+INTERFACE_FUNCTION(__asan_unregister_elf_globals)
INTERFACE_FUNCTION(__asan_unregister_image_globals)
INTERFACE_FUNCTION(__asan_version_mismatch_check_v8)
INTERFACE_FUNCTION(__sanitizer_finish_switch_fiber)
diff --git a/lib/asan/asan_interface_internal.h b/lib/asan/asan_interface_internal.h
index b18c31548860..b974c0cc4b43 100644
--- a/lib/asan/asan_interface_internal.h
+++ b/lib/asan/asan_interface_internal.h
@@ -67,6 +67,11 @@ extern "C" {
SANITIZER_INTERFACE_ATTRIBUTE
void __asan_unregister_image_globals(uptr *flag);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_register_elf_globals(uptr *flag, void *start, void *stop);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_unregister_elf_globals(uptr *flag, void *start, void *stop);
+
// These two functions should be called by the instrumented code.
// 'globals' is an array of structures describing 'n' globals.
SANITIZER_INTERFACE_ATTRIBUTE
diff --git a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
index bb59c344edc2..754ece9840ef 100644
--- a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
@@ -84,7 +84,6 @@ class CoverageData {
void AfterFork(int child_pid);
void Extend(uptr npcs);
void Add(uptr pc, u32 *guard);
- void DumpAsBitSet();
void DumpOffsets();
void DumpAll();
@@ -156,6 +155,13 @@ void CoverageData::DirectOpen() {
void CoverageData::Init() {
pc_fd = kInvalidFd;
+
+ if (!common_flags()->coverage) return;
+ Printf("**\n***\n***\n");
+ Printf("**WARNING: this implementation of SanitizerCoverage is deprecated\n");
+ Printf("**WARNING: and will be removed in future versions\n");
+ Printf("**WARNING: See https://clang.llvm.org/docs/SanitizerCoverage.html\n");
+ Printf("**\n***\n***\n");
}
void CoverageData::Enable() {
@@ -165,6 +171,8 @@ void CoverageData::Enable() {
MmapNoReserveOrDie(sizeof(uptr) * kPcArrayMaxSize, "CovInit"));
atomic_store(&pc_array_index, 0, memory_order_relaxed);
if (common_flags()->coverage_direct) {
+ Report("coverage_direct=1 is deprecated, don't use it.\n");
+ Die();
atomic_store(&pc_array_size, 0, memory_order_relaxed);
} else {
atomic_store(&pc_array_size, kPcArrayMaxSize, memory_order_relaxed);
@@ -419,35 +427,6 @@ static fd_t CovOpenFile(InternalScopedString *path, bool packed,
return fd;
}
-void CoverageData::DumpAsBitSet() {
- if (!common_flags()->coverage_bitset) return;
- 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);
- fd_t fd = CovOpenFile(&path, /* packed */false, base_name, "bitset-sancov");
- if (fd == kInvalidFd) return;
- WriteToFile(fd, out.data() + r.beg, r.end - r.beg);
- CloseFile(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);
- }
-}
-
-
void CoverageData::GetRangeOffsets(const NamedPcRange& r, Symbolizer* sym,
InternalMmapVector<uptr>* offsets) const {
offsets->clear();
@@ -565,7 +544,6 @@ void CoverageData::DumpAll() {
if (!coverage_enabled || common_flags()->coverage_direct) return;
if (atomic_fetch_add(&dump_once_guard, 1, memory_order_relaxed))
return;
- DumpAsBitSet();
DumpOffsets();
}
diff --git a/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc b/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc
index 73c36082bc67..6d8e3e041cc0 100644
--- a/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc
+++ b/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc
@@ -98,10 +98,6 @@ static void SanitizerDumpCoverage(const uptr* unsorted_pcs, uptr len) {
InternalFree(file_path);
InternalFree(module_name);
InternalFree(pcs);
-
- if (sancov_flags()->symbolize) {
- Printf("TODO(aizatsky): call sancov to symbolize\n");
- }
}
// Collects trace-pc guard coverage.
diff --git a/lib/sanitizer_common/sanitizer_flags.inc b/lib/sanitizer_common/sanitizer_flags.inc
index 40f8b6204cda..7a5fffcf6165 100644
--- a/lib/sanitizer_common/sanitizer_flags.inc
+++ b/lib/sanitizer_common/sanitizer_flags.inc
@@ -142,12 +142,6 @@ COMMON_FLAG(bool, coverage_pcs, true,
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.h b/lib/sanitizer_common/sanitizer_linux.h
index 14047b4803f8..ee336f7ddff3 100644
--- a/lib/sanitizer_common/sanitizer_linux.h
+++ b/lib/sanitizer_common/sanitizer_linux.h
@@ -88,6 +88,46 @@ bool LibraryNameIs(const char *full_name, const char *base_name);
// Call cb for each region mapped by map.
void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr));
+
+#if SANITIZER_ANDROID
+
+#if defined(__aarch64__)
+# define __get_tls() \
+ ({ void** __v; __asm__("mrs %0, tpidr_el0" : "=r"(__v)); __v; })
+#elif defined(__arm__)
+# define __get_tls() \
+ ({ void** __v; __asm__("mrc p15, 0, %0, c13, c0, 3" : "=r"(__v)); __v; })
+#elif defined(__mips__)
+// On mips32r1, this goes via a kernel illegal instruction trap that's
+// optimized for v1.
+# define __get_tls() \
+ ({ register void** __v asm("v1"); \
+ __asm__(".set push\n" \
+ ".set mips32r2\n" \
+ "rdhwr %0,$29\n" \
+ ".set pop\n" : "=r"(__v)); \
+ __v; })
+#elif defined(__i386__)
+# define __get_tls() \
+ ({ void** __v; __asm__("movl %%gs:0, %0" : "=r"(__v)); __v; })
+#elif defined(__x86_64__)
+# define __get_tls() \
+ ({ void** __v; __asm__("mov %%fs:0, %0" : "=r"(__v)); __v; })
+#else
+#error "Unsupported architecture."
+#endif
+
+// The Android Bionic team has allocated a TLS slot for TSan starting with N,
+// given that Android currently doesn't support ELF TLS. It is used to store
+// Sanitizers thread specific data.
+static const int TLS_SLOT_TSAN = 8;
+
+ALWAYS_INLINE uptr *get_android_tls_ptr() {
+ return reinterpret_cast<uptr *>(&__get_tls()[TLS_SLOT_TSAN]);
+}
+
+#endif // SANITIZER_ANDROID
+
} // namespace __sanitizer
#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
diff --git a/lib/scudo/CMakeLists.txt b/lib/scudo/CMakeLists.txt
index ba5e8acd8598..3a8f4ae4fa9e 100644
--- a/lib/scudo/CMakeLists.txt
+++ b/lib/scudo/CMakeLists.txt
@@ -14,6 +14,7 @@ set(SCUDO_SOURCES
scudo_interceptors.cpp
scudo_new_delete.cpp
scudo_termination.cpp
+ scudo_tls_linux.cpp
scudo_utils.cpp)
# Enable the SSE 4.2 instruction set for scudo_crc32.cpp, if available.
diff --git a/lib/scudo/scudo_allocator.cpp b/lib/scudo/scudo_allocator.cpp
index e89e09223ff8..2ccdcd903dad 100644
--- a/lib/scudo/scudo_allocator.cpp
+++ b/lib/scudo/scudo_allocator.cpp
@@ -15,6 +15,7 @@
//===----------------------------------------------------------------------===//
#include "scudo_allocator.h"
+#include "scudo_tls.h"
#include "scudo_utils.h"
#include "sanitizer_common/sanitizer_allocator_interface.h"
@@ -26,44 +27,6 @@
namespace __scudo {
-#if SANITIZER_CAN_USE_ALLOCATOR64
-const uptr AllocatorSpace = ~0ULL;
-const uptr AllocatorSize = 0x40000000000ULL;
-typedef DefaultSizeClassMap SizeClassMap;
-struct AP {
- static const uptr kSpaceBeg = AllocatorSpace;
- static const uptr kSpaceSize = AllocatorSize;
- static const uptr kMetadataSize = 0;
- typedef __scudo::SizeClassMap SizeClassMap;
- typedef NoOpMapUnmapCallback MapUnmapCallback;
- static const uptr kFlags =
- SizeClassAllocator64FlagMasks::kRandomShuffleChunks;
-};
-typedef SizeClassAllocator64<AP> PrimaryAllocator;
-#else
-// Currently, the 32-bit Sanitizer allocator has not yet benefited from all the
-// security improvements brought to the 64-bit one. This makes the 32-bit
-// version of Scudo slightly less toughened.
-static const uptr RegionSizeLog = 20;
-static const uptr NumRegions = SANITIZER_MMAP_RANGE_SIZE >> RegionSizeLog;
-# if SANITIZER_WORDSIZE == 32
-typedef FlatByteMap<NumRegions> ByteMap;
-# elif SANITIZER_WORDSIZE == 64
-typedef TwoLevelByteMap<(NumRegions >> 12), 1 << 12> ByteMap;
-# endif // SANITIZER_WORDSIZE
-typedef DefaultSizeClassMap SizeClassMap;
-typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, 0, SizeClassMap,
- RegionSizeLog, ByteMap> PrimaryAllocator;
-#endif // SANITIZER_CAN_USE_ALLOCATOR64
-
-typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
-typedef ScudoLargeMmapAllocator SecondaryAllocator;
-typedef CombinedAllocator<PrimaryAllocator, AllocatorCache, SecondaryAllocator>
- ScudoBackendAllocator;
-
-static ScudoBackendAllocator &getBackendAllocator();
-
-static thread_local Xorshift128Plus Prng;
// Global static cookie, initialized at start-up.
static uptr Cookie;
@@ -88,6 +51,8 @@ INLINE u32 computeCRC32(u32 Crc, uptr Data, u8 HashType) {
#endif // defined(__SSE4_2__)
}
+static ScudoBackendAllocator &getBackendAllocator();
+
struct ScudoChunk : UnpackedHeader {
// We can't use the offset member of the chunk itself, as we would double
// fetch it without any warranty that it wouldn't have been tampered. To
@@ -188,32 +153,44 @@ ScudoChunk *getScudoChunk(uptr UserBeg) {
return reinterpret_cast<ScudoChunk *>(UserBeg - AlignedChunkHeaderSize);
}
-static bool ScudoInitIsRunning = false;
+struct AllocatorOptions {
+ u32 QuarantineSizeMb;
+ u32 ThreadLocalQuarantineSizeKb;
+ bool MayReturnNull;
+ s32 ReleaseToOSIntervalMs;
+ bool DeallocationTypeMismatch;
+ bool DeleteSizeMismatch;
+ bool ZeroContents;
-static pthread_once_t GlobalInited = PTHREAD_ONCE_INIT;
-static pthread_key_t PThreadKey;
-
-static thread_local bool ThreadInited = false;
-static thread_local bool ThreadTornDown = false;
-static thread_local AllocatorCache Cache;
-
-static void teardownThread(void *p) {
- uptr v = reinterpret_cast<uptr>(p);
- // The glibc POSIX thread-local-storage deallocation routine calls user
- // provided destructors in a loop of PTHREAD_DESTRUCTOR_ITERATIONS.
- // We want to be called last since other destructors might call free and the
- // like, so we wait until PTHREAD_DESTRUCTOR_ITERATIONS before draining the
- // quarantine and swallowing the cache.
- if (v < PTHREAD_DESTRUCTOR_ITERATIONS) {
- pthread_setspecific(PThreadKey, reinterpret_cast<void *>(v + 1));
- return;
- }
- drainQuarantine();
- getBackendAllocator().DestroyCache(&Cache);
- ThreadTornDown = true;
+ void setFrom(const Flags *f, const CommonFlags *cf);
+ void copyTo(Flags *f, CommonFlags *cf) const;
+};
+
+void AllocatorOptions::setFrom(const Flags *f, const CommonFlags *cf) {
+ MayReturnNull = cf->allocator_may_return_null;
+ ReleaseToOSIntervalMs = cf->allocator_release_to_os_interval_ms;
+ QuarantineSizeMb = f->QuarantineSizeMb;
+ ThreadLocalQuarantineSizeKb = f->ThreadLocalQuarantineSizeKb;
+ DeallocationTypeMismatch = f->DeallocationTypeMismatch;
+ DeleteSizeMismatch = f->DeleteSizeMismatch;
+ ZeroContents = f->ZeroContents;
+}
+
+void AllocatorOptions::copyTo(Flags *f, CommonFlags *cf) const {
+ cf->allocator_may_return_null = MayReturnNull;
+ cf->allocator_release_to_os_interval_ms = ReleaseToOSIntervalMs;
+ f->QuarantineSizeMb = QuarantineSizeMb;
+ f->ThreadLocalQuarantineSizeKb = ThreadLocalQuarantineSizeKb;
+ f->DeallocationTypeMismatch = DeallocationTypeMismatch;
+ f->DeleteSizeMismatch = DeleteSizeMismatch;
+ f->ZeroContents = ZeroContents;
}
-static void initInternal() {
+static void initScudoInternal(const AllocatorOptions &Options);
+
+static bool ScudoInitIsRunning = false;
+
+void initScudo() {
SanitizerToolName = "Scudo";
CHECK(!ScudoInitIsRunning && "Scudo init calls itself!");
ScudoInitIsRunning = true;
@@ -227,25 +204,13 @@ static void initInternal() {
AllocatorOptions Options;
Options.setFrom(getFlags(), common_flags());
- initAllocator(Options);
+ initScudoInternal(Options);
- MaybeStartBackgroudThread();
+ // TODO(kostyak): determine if MaybeStartBackgroudThread could be of some use.
ScudoInitIsRunning = false;
}
-static void initGlobal() {
- pthread_key_create(&PThreadKey, teardownThread);
- initInternal();
-}
-
-static void NOINLINE initThread() {
- pthread_once(&GlobalInited, initGlobal);
- pthread_setspecific(PThreadKey, reinterpret_cast<void *>(1));
- getBackendAllocator().InitCache(&Cache);
- ThreadInited = true;
-}
-
struct QuarantineCallback {
explicit QuarantineCallback(AllocatorCache *Cache)
: Cache_(Cache) {}
@@ -278,26 +243,20 @@ struct QuarantineCallback {
typedef Quarantine<QuarantineCallback, ScudoChunk> ScudoQuarantine;
typedef ScudoQuarantine::Cache ScudoQuarantineCache;
-static thread_local ScudoQuarantineCache ThreadQuarantineCache;
+COMPILER_CHECK(sizeof(ScudoQuarantineCache) <=
+ sizeof(ScudoThreadContext::QuarantineCachePlaceHolder));
-void AllocatorOptions::setFrom(const Flags *f, const CommonFlags *cf) {
- MayReturnNull = cf->allocator_may_return_null;
- ReleaseToOSIntervalMs = cf->allocator_release_to_os_interval_ms;
- QuarantineSizeMb = f->QuarantineSizeMb;
- ThreadLocalQuarantineSizeKb = f->ThreadLocalQuarantineSizeKb;
- DeallocationTypeMismatch = f->DeallocationTypeMismatch;
- DeleteSizeMismatch = f->DeleteSizeMismatch;
- ZeroContents = f->ZeroContents;
+AllocatorCache *getAllocatorCache(ScudoThreadContext *ThreadContext) {
+ return &ThreadContext->Cache;
}
-void AllocatorOptions::copyTo(Flags *f, CommonFlags *cf) const {
- cf->allocator_may_return_null = MayReturnNull;
- cf->allocator_release_to_os_interval_ms = ReleaseToOSIntervalMs;
- f->QuarantineSizeMb = QuarantineSizeMb;
- f->ThreadLocalQuarantineSizeKb = ThreadLocalQuarantineSizeKb;
- f->DeallocationTypeMismatch = DeallocationTypeMismatch;
- f->DeleteSizeMismatch = DeleteSizeMismatch;
- f->ZeroContents = ZeroContents;
+ScudoQuarantineCache *getQuarantineCache(ScudoThreadContext *ThreadContext) {
+ return reinterpret_cast<
+ ScudoQuarantineCache *>(ThreadContext->QuarantineCachePlaceHolder);
+}
+
+Xorshift128Plus *getPrng(ScudoThreadContext *ThreadContext) {
+ return &ThreadContext->Prng;
}
struct ScudoAllocator {
@@ -313,6 +272,7 @@ struct ScudoAllocator {
StaticSpinMutex FallbackMutex;
AllocatorCache FallbackAllocatorCache;
ScudoQuarantineCache FallbackQuarantineCache;
+ Xorshift128Plus FallbackPrng;
bool DeallocationTypeMismatch;
bool ZeroContents;
@@ -361,13 +321,13 @@ struct ScudoAllocator {
static_cast<uptr>(Options.QuarantineSizeMb) << 20,
static_cast<uptr>(Options.ThreadLocalQuarantineSizeKb) << 10);
BackendAllocator.InitCache(&FallbackAllocatorCache);
- Cookie = Prng.getNext();
+ FallbackPrng.initFromURandom();
+ Cookie = FallbackPrng.getNext();
}
// Helper function that checks for a valid Scudo chunk. nullptr isn't.
bool isValidPointer(const void *UserPtr) {
- if (UNLIKELY(!ThreadInited))
- initThread();
+ initThreadMaybe();
if (!UserPtr)
return false;
uptr UserBeg = reinterpret_cast<uptr>(UserPtr);
@@ -379,8 +339,7 @@ struct ScudoAllocator {
// Allocates a chunk.
void *allocate(uptr Size, uptr Alignment, AllocType Type,
bool ForceZeroContents = false) {
- if (UNLIKELY(!ThreadInited))
- initThread();
+ initThreadMaybe();
if (UNLIKELY(!IsPowerOfTwo(Alignment))) {
dieWithMessage("ERROR: alignment is not a power of 2\n");
}
@@ -407,11 +366,16 @@ struct ScudoAllocator {
bool FromPrimary = PrimaryAllocator::CanAllocate(NeededSize, MinAlignment);
void *Ptr;
+ uptr Salt;
uptr AllocationAlignment = FromPrimary ? MinAlignment : Alignment;
- if (LIKELY(!ThreadTornDown)) {
- Ptr = BackendAllocator.Allocate(&Cache, NeededSize, AllocationAlignment);
+ ScudoThreadContext *ThreadContext = getThreadContext();
+ if (LIKELY(ThreadContext)) {
+ Salt = getPrng(ThreadContext)->getNext();
+ Ptr = BackendAllocator.Allocate(getAllocatorCache(ThreadContext),
+ NeededSize, AllocationAlignment);
} else {
SpinMutexLock l(&FallbackMutex);
+ Salt = FallbackPrng.getNext();
Ptr = BackendAllocator.Allocate(&FallbackAllocatorCache, NeededSize,
AllocationAlignment);
}
@@ -453,7 +417,7 @@ struct ScudoAllocator {
if (TrailingBytes)
Header.SizeOrUnusedBytes = PageSize - TrailingBytes;
}
- Header.Salt = static_cast<u8>(Prng.getNext());
+ Header.Salt = static_cast<u8>(Salt);
getScudoChunk(UserBeg)->storeHeader(&Header);
void *UserPtr = reinterpret_cast<void *>(UserBeg);
// if (&__sanitizer_malloc_hook) __sanitizer_malloc_hook(UserPtr, Size);
@@ -462,16 +426,17 @@ struct ScudoAllocator {
// Place a chunk in the quarantine. In the event of a zero-sized quarantine,
// we directly deallocate the chunk, otherwise the flow would lead to the
- // chunk being checksummed twice, once before Put and once in Recycle, with
- // no additional security value.
+ // chunk being loaded (and checked) twice, and stored (and checksummed) once,
+ // with no additional security value.
void quarantineOrDeallocateChunk(ScudoChunk *Chunk, UnpackedHeader *Header,
uptr Size) {
bool BypassQuarantine = (AllocatorQuarantine.GetCacheSize() == 0);
if (BypassQuarantine) {
Chunk->eraseHeader();
void *Ptr = Chunk->getAllocBeg(Header);
- if (LIKELY(!ThreadTornDown)) {
- getBackendAllocator().Deallocate(&Cache, Ptr);
+ ScudoThreadContext *ThreadContext = getThreadContext();
+ if (LIKELY(ThreadContext)) {
+ getBackendAllocator().Deallocate(getAllocatorCache(ThreadContext), Ptr);
} else {
SpinMutexLock Lock(&FallbackMutex);
getBackendAllocator().Deallocate(&FallbackAllocatorCache, Ptr);
@@ -480,9 +445,12 @@ struct ScudoAllocator {
UnpackedHeader NewHeader = *Header;
NewHeader.State = ChunkQuarantine;
Chunk->compareExchangeHeader(&NewHeader, Header);
- if (LIKELY(!ThreadTornDown)) {
- AllocatorQuarantine.Put(&ThreadQuarantineCache,
- QuarantineCallback(&Cache), Chunk, Size);
+ ScudoThreadContext *ThreadContext = getThreadContext();
+ if (LIKELY(ThreadContext)) {
+ AllocatorQuarantine.Put(getQuarantineCache(ThreadContext),
+ QuarantineCallback(
+ getAllocatorCache(ThreadContext)),
+ Chunk, Size);
} else {
SpinMutexLock l(&FallbackMutex);
AllocatorQuarantine.Put(&FallbackQuarantineCache,
@@ -495,8 +463,7 @@ struct ScudoAllocator {
// Deallocates a Chunk, which means adding it to the delayed free list (or
// Quarantine).
void deallocate(void *UserPtr, uptr DeleteSize, AllocType Type) {
- if (UNLIKELY(!ThreadInited))
- initThread();
+ initThreadMaybe();
// if (&__sanitizer_free_hook) __sanitizer_free_hook(UserPtr);
if (!UserPtr)
return;
@@ -542,8 +509,7 @@ struct ScudoAllocator {
// Reallocates a chunk. We can save on a new allocation if the new requested
// size still fits in the chunk.
void *reallocate(void *OldPtr, uptr NewSize) {
- if (UNLIKELY(!ThreadInited))
- initThread();
+ initThreadMaybe();
uptr UserBeg = reinterpret_cast<uptr>(OldPtr);
if (UNLIKELY(!IsAligned(UserBeg, MinAlignment))) {
dieWithMessage("ERROR: attempted to reallocate a chunk not properly "
@@ -585,8 +551,7 @@ struct ScudoAllocator {
// Helper function that returns the actual usable size of a chunk.
uptr getUsableSize(const void *Ptr) {
- if (UNLIKELY(!ThreadInited))
- initThread();
+ initThreadMaybe();
if (!Ptr)
return 0;
uptr UserBeg = reinterpret_cast<uptr>(Ptr);
@@ -602,22 +567,22 @@ struct ScudoAllocator {
}
void *calloc(uptr NMemB, uptr Size) {
- if (UNLIKELY(!ThreadInited))
- initThread();
+ initThreadMaybe();
uptr Total = NMemB * Size;
if (Size != 0 && Total / Size != NMemB) // Overflow check
return BackendAllocator.ReturnNullOrDieOnBadRequest();
return allocate(Total, MinAlignment, FromMalloc, true);
}
- void drainQuarantine() {
- AllocatorQuarantine.Drain(&ThreadQuarantineCache,
- QuarantineCallback(&Cache));
+ void commitBack(ScudoThreadContext *ThreadContext) {
+ AllocatorCache *Cache = getAllocatorCache(ThreadContext);
+ AllocatorQuarantine.Drain(getQuarantineCache(ThreadContext),
+ QuarantineCallback(Cache));
+ BackendAllocator.DestroyCache(Cache);
}
uptr getStats(AllocatorStat StatType) {
- if (UNLIKELY(!ThreadInited))
- initThread();
+ initThreadMaybe();
uptr stats[AllocatorStatCount];
BackendAllocator.GetStats(stats);
return stats[StatType];
@@ -630,12 +595,18 @@ static ScudoBackendAllocator &getBackendAllocator() {
return Instance.BackendAllocator;
}
-void initAllocator(const AllocatorOptions &Options) {
+static void initScudoInternal(const AllocatorOptions &Options) {
Instance.init(Options);
}
-void drainQuarantine() {
- Instance.drainQuarantine();
+void ScudoThreadContext::init() {
+ getBackendAllocator().InitCache(&Cache);
+ Prng.initFromURandom();
+ memset(QuarantineCachePlaceHolder, 0, sizeof(QuarantineCachePlaceHolder));
+}
+
+void ScudoThreadContext::commitBack() {
+ Instance.commitBack(this);
}
void *scudoMalloc(uptr Size, AllocType Type) {
diff --git a/lib/scudo/scudo_allocator.h b/lib/scudo/scudo_allocator.h
index e7428f170271..2cac2de71cb0 100644
--- a/lib/scudo/scudo_allocator.h
+++ b/lib/scudo/scudo_allocator.h
@@ -53,7 +53,7 @@ struct UnpackedHeader {
u64 Offset : 16; // Offset from the beginning of the backend
// allocation to the beginning of the chunk
// itself, in multiples of MinAlignment. See
- /// comment about its maximum value and in init().
+ // comment about its maximum value and in init().
u64 Salt : 8;
};
@@ -62,7 +62,7 @@ COMPILER_CHECK(sizeof(UnpackedHeader) == sizeof(PackedHeader));
// Minimum alignment of 8 bytes for 32-bit, 16 for 64-bit
const uptr MinAlignmentLog = FIRST_32_SECOND_64(3, 4);
-const uptr MaxAlignmentLog = 24; // 16 MB
+const uptr MaxAlignmentLog = 24; // 16 MB
const uptr MinAlignment = 1 << MinAlignmentLog;
const uptr MaxAlignment = 1 << MaxAlignmentLog;
@@ -70,21 +70,44 @@ const uptr ChunkHeaderSize = sizeof(PackedHeader);
const uptr AlignedChunkHeaderSize =
(ChunkHeaderSize + MinAlignment - 1) & ~(MinAlignment - 1);
-struct AllocatorOptions {
- u32 QuarantineSizeMb;
- u32 ThreadLocalQuarantineSizeKb;
- bool MayReturnNull;
- s32 ReleaseToOSIntervalMs;
- bool DeallocationTypeMismatch;
- bool DeleteSizeMismatch;
- bool ZeroContents;
-
- void setFrom(const Flags *f, const CommonFlags *cf);
- void copyTo(Flags *f, CommonFlags *cf) const;
+#if SANITIZER_CAN_USE_ALLOCATOR64
+const uptr AllocatorSpace = ~0ULL;
+const uptr AllocatorSize = 0x40000000000ULL; // 4TB.
+typedef DefaultSizeClassMap SizeClassMap;
+struct AP {
+ static const uptr kSpaceBeg = AllocatorSpace;
+ static const uptr kSpaceSize = AllocatorSize;
+ static const uptr kMetadataSize = 0;
+ typedef __scudo::SizeClassMap SizeClassMap;
+ typedef NoOpMapUnmapCallback MapUnmapCallback;
+ static const uptr kFlags =
+ SizeClassAllocator64FlagMasks::kRandomShuffleChunks;
};
+typedef SizeClassAllocator64<AP> PrimaryAllocator;
+#else
+// Currently, the 32-bit Sanitizer allocator has not yet benefited from all the
+// security improvements brought to the 64-bit one. This makes the 32-bit
+// version of Scudo slightly less toughened.
+static const uptr RegionSizeLog = 20;
+static const uptr NumRegions = SANITIZER_MMAP_RANGE_SIZE >> RegionSizeLog;
+# if SANITIZER_WORDSIZE == 32
+typedef FlatByteMap<NumRegions> ByteMap;
+# elif SANITIZER_WORDSIZE == 64
+typedef TwoLevelByteMap<(NumRegions >> 12), 1 << 12> ByteMap;
+# endif // SANITIZER_WORDSIZE
+typedef DefaultSizeClassMap SizeClassMap;
+typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, 0, SizeClassMap,
+ RegionSizeLog, ByteMap> PrimaryAllocator;
+#endif // SANITIZER_CAN_USE_ALLOCATOR64
-void initAllocator(const AllocatorOptions &options);
-void drainQuarantine();
+#include "scudo_allocator_secondary.h"
+
+typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
+typedef ScudoLargeMmapAllocator SecondaryAllocator;
+typedef CombinedAllocator<PrimaryAllocator, AllocatorCache, SecondaryAllocator>
+ ScudoBackendAllocator;
+
+void initScudo();
void *scudoMalloc(uptr Size, AllocType Type);
void scudoFree(void *Ptr, AllocType Type);
@@ -98,8 +121,6 @@ int scudoPosixMemalign(void **MemPtr, uptr Alignment, uptr Size);
void *scudoAlignedAlloc(uptr Alignment, uptr Size);
uptr scudoMallocUsableSize(void *Ptr);
-#include "scudo_allocator_secondary.h"
-
} // namespace __scudo
#endif // SCUDO_ALLOCATOR_H_
diff --git a/lib/scudo/scudo_tls.h b/lib/scudo/scudo_tls.h
new file mode 100644
index 000000000000..0d7d1bffd0b6
--- /dev/null
+++ b/lib/scudo/scudo_tls.h
@@ -0,0 +1,40 @@
+//===-- scudo_tls.h ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// Scudo thread local structure definition.
+/// Implementation will differ based on the thread local storage primitives
+/// offered by the underlying platform.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef SCUDO_TLS_H_
+#define SCUDO_TLS_H_
+
+#include "scudo_allocator.h"
+#include "scudo_utils.h"
+
+namespace __scudo {
+
+struct ALIGNED(64) ScudoThreadContext {
+ public:
+ AllocatorCache Cache;
+ Xorshift128Plus Prng;
+ uptr QuarantineCachePlaceHolder[4];
+ void init();
+ void commitBack();
+};
+
+void initThread();
+
+// Fastpath functions are defined in the following platform specific headers.
+#include "scudo_tls_linux.h"
+
+} // namespace __scudo
+
+#endif // SCUDO_TLS_H_
diff --git a/lib/scudo/scudo_tls_linux.cpp b/lib/scudo/scudo_tls_linux.cpp
new file mode 100644
index 000000000000..3453367f8a53
--- /dev/null
+++ b/lib/scudo/scudo_tls_linux.cpp
@@ -0,0 +1,62 @@
+//===-- scudo_tls_linux.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// Scudo thread local structure implementation for platforms supporting
+/// thread_local.
+///
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+
+#if SANITIZER_LINUX
+
+#include "scudo_tls.h"
+
+#include <limits.h>
+#include <pthread.h>
+
+namespace __scudo {
+
+static pthread_once_t GlobalInitialized = PTHREAD_ONCE_INIT;
+static pthread_key_t PThreadKey;
+
+thread_local ThreadState ScudoThreadState = ThreadNotInitialized;
+thread_local ScudoThreadContext ThreadLocalContext;
+
+static void teardownThread(void *Ptr) {
+ uptr Iteration = reinterpret_cast<uptr>(Ptr);
+ // The glibc POSIX thread-local-storage deallocation routine calls user
+ // provided destructors in a loop of PTHREAD_DESTRUCTOR_ITERATIONS.
+ // We want to be called last since other destructors might call free and the
+ // like, so we wait until PTHREAD_DESTRUCTOR_ITERATIONS before draining the
+ // quarantine and swallowing the cache.
+ if (Iteration < PTHREAD_DESTRUCTOR_ITERATIONS) {
+ pthread_setspecific(PThreadKey, reinterpret_cast<void *>(Iteration + 1));
+ return;
+ }
+ ThreadLocalContext.commitBack();
+ ScudoThreadState = ThreadTornDown;
+}
+
+
+static void initOnce() {
+ CHECK_EQ(pthread_key_create(&PThreadKey, teardownThread), 0);
+ initScudo();
+}
+
+void initThread() {
+ pthread_once(&GlobalInitialized, initOnce);
+ pthread_setspecific(PThreadKey, reinterpret_cast<void *>(1));
+ ThreadLocalContext.init();
+ ScudoThreadState = ThreadInitialized;
+}
+
+} // namespace __scudo
+
+#endif // SANITIZER_LINUX
diff --git a/lib/scudo/scudo_tls_linux.h b/lib/scudo/scudo_tls_linux.h
new file mode 100644
index 000000000000..0994f2d7b24d
--- /dev/null
+++ b/lib/scudo/scudo_tls_linux.h
@@ -0,0 +1,48 @@
+//===-- scudo_tls_linux.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// Scudo thread local structure fastpath functions implementation for platforms
+/// supporting thread_local.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef SCUDO_TLS_LINUX_H_
+#define SCUDO_TLS_LINUX_H_
+
+#ifndef SCUDO_TLS_H_
+# error "This file must be included inside scudo_tls.h."
+#endif // SCUDO_TLS_H_
+
+#include "sanitizer_common/sanitizer_platform.h"
+
+#if SANITIZER_LINUX
+
+enum ThreadState : u8 {
+ ThreadNotInitialized = 0,
+ ThreadInitialized,
+ ThreadTornDown,
+};
+extern thread_local ThreadState ScudoThreadState;
+extern thread_local ScudoThreadContext ThreadLocalContext;
+
+ALWAYS_INLINE void initThreadMaybe() {
+ if (LIKELY(ScudoThreadState != ThreadNotInitialized))
+ return;
+ initThread();
+}
+
+ALWAYS_INLINE ScudoThreadContext *getThreadContext() {
+ if (UNLIKELY(ScudoThreadState == ThreadTornDown))
+ return nullptr;
+ return &ThreadLocalContext;
+}
+
+#endif // SANITIZER_LINUX
+
+#endif // SCUDO_TLS_LINUX_H_
diff --git a/lib/scudo/scudo_utils.cpp b/lib/scudo/scudo_utils.cpp
index 98bd591aa868..31c391946c15 100644
--- a/lib/scudo/scudo_utils.cpp
+++ b/lib/scudo/scudo_utils.cpp
@@ -153,9 +153,9 @@ static void fillRandom(u8 *Data, ssize_t Size) {
}
}
-// Default constructor for Xorshift128Plus seeds the state with /dev/urandom.
+// Seeds the xorshift state with /dev/urandom.
// TODO(kostyak): investigate using getrandom() if available.
-Xorshift128Plus::Xorshift128Plus() {
+void Xorshift128Plus::initFromURandom() {
fillRandom(reinterpret_cast<u8 *>(State), sizeof(State));
}
diff --git a/lib/scudo/scudo_utils.h b/lib/scudo/scudo_utils.h
index f30c86125799..484b0c859e3d 100644
--- a/lib/scudo/scudo_utils.h
+++ b/lib/scudo/scudo_utils.h
@@ -40,7 +40,7 @@ bool testCPUFeature(CPUFeature feature);
// The state (128 bits) will be stored in thread local storage.
struct Xorshift128Plus {
public:
- Xorshift128Plus();
+ void initFromURandom();
u64 getNext() {
u64 x = State[0];
const u64 y = State[1];
diff --git a/lib/tsan/go/buildgo.sh b/lib/tsan/go/buildgo.sh
index 42d479064c49..59176809eae0 100755
--- a/lib/tsan/go/buildgo.sh
+++ b/lib/tsan/go/buildgo.sh
@@ -5,6 +5,7 @@ set -e
SRCS="
tsan_go.cc
../rtl/tsan_clock.cc
+ ../rtl/tsan_external.cc
../rtl/tsan_flags.cc
../rtl/tsan_interface_atomic.cc
../rtl/tsan_md5.cc
diff --git a/lib/tsan/rtl/tsan_external.cc b/lib/tsan/rtl/tsan_external.cc
index 88468e406651..2d32b6dac75a 100644
--- a/lib/tsan/rtl/tsan_external.cc
+++ b/lib/tsan/rtl/tsan_external.cc
@@ -17,11 +17,8 @@ namespace __tsan {
#define CALLERPC ((uptr)__builtin_return_address(0))
-const uptr kMaxTag = 128; // Limited to 65,536, since MBlock only stores tags
- // as 16-bit values, see tsan_defs.h.
-
-const char *registered_tags[kMaxTag];
-static atomic_uint32_t used_tags{1}; // Tag 0 means "no tag". NOLINT
+const char *registered_tags[kExternalTagMax];
+static atomic_uint32_t used_tags{kExternalTagFirstUserAvailable}; // NOLINT.
const char *GetObjectTypeFromTag(uptr tag) {
if (tag == 0) return nullptr;
@@ -30,25 +27,39 @@ const char *GetObjectTypeFromTag(uptr tag) {
return registered_tags[tag];
}
+void InsertShadowStackFrameForTag(ThreadState *thr, uptr tag) {
+ FuncEntry(thr, (uptr)&registered_tags[tag]);
+}
+
+uptr TagFromShadowStackFrame(uptr pc) {
+ uptr tag_count = atomic_load(&used_tags, memory_order_relaxed);
+ void *pc_ptr = (void *)pc;
+ if (pc_ptr < &registered_tags[0] || pc_ptr >= &registered_tags[tag_count])
+ return 0;
+ return (const char **)pc_ptr - &registered_tags[0];
+}
+
+#if !SANITIZER_GO
+
typedef void(*AccessFunc)(ThreadState *, uptr, uptr, int);
void ExternalAccess(void *addr, void *caller_pc, void *tag, AccessFunc access) {
CHECK_LT(tag, atomic_load(&used_tags, memory_order_relaxed));
ThreadState *thr = cur_thread();
- thr->external_tag = (uptr)tag;
if (caller_pc) FuncEntry(thr, (uptr)caller_pc);
+ InsertShadowStackFrameForTag(thr, (uptr)tag);
bool in_ignored_lib;
if (!caller_pc || !libignore()->IsIgnored((uptr)caller_pc, &in_ignored_lib)) {
access(thr, CALLERPC, (uptr)addr, kSizeLog1);
}
+ FuncExit(thr);
if (caller_pc) FuncExit(thr);
- thr->external_tag = 0;
}
extern "C" {
SANITIZER_INTERFACE_ATTRIBUTE
void *__tsan_external_register_tag(const char *object_type) {
uptr new_tag = atomic_fetch_add(&used_tags, 1, memory_order_relaxed);
- CHECK_LT(new_tag, kMaxTag);
+ CHECK_LT(new_tag, kExternalTagMax);
registered_tags[new_tag] = internal_strdup(object_type);
return (void *)new_tag;
}
@@ -78,4 +89,6 @@ void __tsan_external_write(void *addr, void *caller_pc, void *tag) {
}
} // extern "C"
+#endif // !SANITIZER_GO
+
} // namespace __tsan
diff --git a/lib/tsan/rtl/tsan_interface_ann.cc b/lib/tsan/rtl/tsan_interface_ann.cc
index 810c84025f23..45ec45bbdbbe 100644
--- a/lib/tsan/rtl/tsan_interface_ann.cc
+++ b/lib/tsan/rtl/tsan_interface_ann.cc
@@ -471,7 +471,7 @@ void __tsan_mutex_create(void *m, unsigned flagz) {
INTERFACE_ATTRIBUTE
void __tsan_mutex_destroy(void *m, unsigned flagz) {
SCOPED_ANNOTATION(__tsan_mutex_destroy);
- MutexDestroy(thr, pc, (uptr)m);
+ MutexDestroy(thr, pc, (uptr)m, flagz);
}
INTERFACE_ATTRIBUTE
diff --git a/lib/tsan/rtl/tsan_platform_linux.cc b/lib/tsan/rtl/tsan_platform_linux.cc
index 3313288a728a..2d488cadd4fe 100644
--- a/lib/tsan/rtl/tsan_platform_linux.cc
+++ b/lib/tsan/rtl/tsan_platform_linux.cc
@@ -341,36 +341,22 @@ void ReplaceSystemMalloc() { }
#if !SANITIZER_GO
#if SANITIZER_ANDROID
-
-#if defined(__aarch64__)
-# define __get_tls() \
- ({ void** __val; __asm__("mrs %0, tpidr_el0" : "=r"(__val)); __val; })
-#elif defined(__x86_64__)
-# define __get_tls() \
- ({ void** __val; __asm__("mov %%fs:0, %0" : "=r"(__val)); __val; })
-#else
-#error unsupported architecture
-#endif
-
-// On Android, __thread is not supported. So we store the pointer to ThreadState
-// in TLS_SLOT_TSAN, which is the tls slot allocated by Android bionic for tsan.
-static const int TLS_SLOT_TSAN = 8;
// On Android, one thread can call intercepted functions after
// DestroyThreadState(), so add a fake thread state for "dead" threads.
static ThreadState *dead_thread_state = nullptr;
ThreadState *cur_thread() {
- ThreadState* thr = (ThreadState*)__get_tls()[TLS_SLOT_TSAN];
+ ThreadState* thr = reinterpret_cast<ThreadState*>(*get_android_tls_ptr());
if (thr == nullptr) {
__sanitizer_sigset_t emptyset;
internal_sigfillset(&emptyset);
__sanitizer_sigset_t oldset;
CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, &emptyset, &oldset));
- thr = reinterpret_cast<ThreadState*>(__get_tls()[TLS_SLOT_TSAN]);
+ thr = reinterpret_cast<ThreadState*>(*get_android_tls_ptr());
if (thr == nullptr) {
thr = reinterpret_cast<ThreadState*>(MmapOrDie(sizeof(ThreadState),
"ThreadState"));
- __get_tls()[TLS_SLOT_TSAN] = thr;
+ *get_android_tls_ptr() = reinterpret_cast<uptr>(thr);
if (dead_thread_state == nullptr) {
dead_thread_state = reinterpret_cast<ThreadState*>(
MmapOrDie(sizeof(ThreadState), "ThreadState"));
@@ -392,9 +378,9 @@ void cur_thread_finalize() {
internal_sigfillset(&emptyset);
__sanitizer_sigset_t oldset;
CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, &emptyset, &oldset));
- ThreadState* thr = (ThreadState*)__get_tls()[TLS_SLOT_TSAN];
+ ThreadState* thr = reinterpret_cast<ThreadState*>(*get_android_tls_ptr());
if (thr != dead_thread_state) {
- __get_tls()[TLS_SLOT_TSAN] = dead_thread_state;
+ *get_android_tls_ptr() = reinterpret_cast<uptr>(dead_thread_state);
UnmapOrDie(thr, sizeof(ThreadState));
}
CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, &oldset, nullptr));
diff --git a/lib/tsan/rtl/tsan_report.cc b/lib/tsan/rtl/tsan_report.cc
index af5fe61761d7..b188af2a0d48 100644
--- a/lib/tsan/rtl/tsan_report.cc
+++ b/lib/tsan/rtl/tsan_report.cc
@@ -164,7 +164,7 @@ static void PrintMop(const ReportMop *mop, bool first) {
char thrbuf[kThreadBufSize];
Printf("%s", d.Access());
const char *object_type = GetObjectTypeFromTag(mop->external_tag);
- if (!object_type) {
+ if (mop->external_tag == kExternalTagNone || !object_type) {
Printf(" %s of size %d at %p by %s",
MopDesc(first, mop->write, mop->atomic), mop->size,
(void *)mop->addr, thread_name(thrbuf, mop->tid));
diff --git a/lib/tsan/rtl/tsan_rtl.cc b/lib/tsan/rtl/tsan_rtl.cc
index 70393037e786..fa60f3247c38 100644
--- a/lib/tsan/rtl/tsan_rtl.cc
+++ b/lib/tsan/rtl/tsan_rtl.cc
@@ -866,9 +866,8 @@ static void MemoryRangeSet(ThreadState *thr, uptr pc, uptr addr, uptr size,
// Don't want to touch lots of shadow memory.
// If a program maps 10MB stack, there is no need reset the whole range.
size = (size + (kShadowCell - 1)) & ~(kShadowCell - 1);
- // UnmapOrDie/MmapFixedNoReserve does not work on Windows,
- // so we do it only for C/C++.
- if (SANITIZER_GO || size < common_flags()->clear_shadow_mmap_threshold) {
+ // UnmapOrDie/MmapFixedNoReserve does not work on Windows.
+ if (SANITIZER_WINDOWS || size < common_flags()->clear_shadow_mmap_threshold) {
u64 *p = (u64*)MemToShadow(addr);
CHECK(IsShadowMem((uptr)p));
CHECK(IsShadowMem((uptr)(p + size * kShadowCnt / kShadowCell - 1)));
diff --git a/lib/tsan/rtl/tsan_rtl.h b/lib/tsan/rtl/tsan_rtl.h
index 09c97a3a4f3d..8bf1c191ad76 100644
--- a/lib/tsan/rtl/tsan_rtl.h
+++ b/lib/tsan/rtl/tsan_rtl.h
@@ -411,7 +411,6 @@ struct ThreadState {
bool is_dead;
bool is_freeing;
bool is_vptr_access;
- uptr external_tag;
const uptr stk_addr;
const uptr stk_size;
const uptr tls_addr;
@@ -565,6 +564,16 @@ struct ScopedIgnoreInterceptors {
}
};
+enum ExternalTag : uptr {
+ kExternalTagNone = 0,
+ kExternalTagFirstUserAvailable = 1,
+ kExternalTagMax = 1024,
+ // Don't set kExternalTagMax over 65,536, since MBlock only stores tags
+ // as 16-bit values, see tsan_defs.h.
+};
+const char *GetObjectTypeFromTag(uptr tag);
+uptr TagFromShadowStackFrame(uptr pc);
+
class ScopedReport {
public:
explicit ScopedReport(ReportType typ);
@@ -598,10 +607,26 @@ class ScopedReport {
ThreadContext *IsThreadStackOrTls(uptr addr, bool *is_stack);
void RestoreStack(int tid, const u64 epoch, VarSizeStackTrace *stk,
- MutexSet *mset);
+ MutexSet *mset, uptr *tag = nullptr);
+
+// The stack could look like:
+// <start> | <main> | <foo> | tag | <bar>
+// This will extract the tag and keep:
+// <start> | <main> | <foo> | <bar>
+template<typename StackTraceTy>
+void ExtractTagFromStack(StackTraceTy *stack, uptr *tag = nullptr) {
+ if (stack->size < 2) return;
+ uptr possible_tag_pc = stack->trace[stack->size - 2];
+ uptr possible_tag = TagFromShadowStackFrame(possible_tag_pc);
+ if (possible_tag == kExternalTagNone) return;
+ stack->trace_buffer[stack->size - 2] = stack->trace_buffer[stack->size - 1];
+ stack->size -= 1;
+ if (tag) *tag = possible_tag;
+}
template<typename StackTraceTy>
-void ObtainCurrentStack(ThreadState *thr, uptr toppc, StackTraceTy *stack) {
+void ObtainCurrentStack(ThreadState *thr, uptr toppc, StackTraceTy *stack,
+ uptr *tag = nullptr) {
uptr size = thr->shadow_stack_pos - thr->shadow_stack;
uptr start = 0;
if (size + !!toppc > kStackTraceMax) {
@@ -609,6 +634,7 @@ void ObtainCurrentStack(ThreadState *thr, uptr toppc, StackTraceTy *stack) {
size = kStackTraceMax - !!toppc;
}
stack->Init(&thr->shadow_stack[start], size, toppc);
+ ExtractTagFromStack(stack, tag);
}
@@ -646,8 +672,6 @@ bool IsFiredSuppression(Context *ctx, ReportType type, StackTrace trace);
bool IsExpectedReport(uptr addr, uptr size);
void PrintMatchedBenignRaces();
-const char *GetObjectTypeFromTag(uptr tag);
-
#if defined(TSAN_DEBUG_OUTPUT) && TSAN_DEBUG_OUTPUT >= 1
# define DPrintf Printf
#else
@@ -739,7 +763,7 @@ void ProcUnwire(Processor *proc, ThreadState *thr);
// Note: the parameter is called flagz, because flags is already taken
// by the global function that returns flags.
void MutexCreate(ThreadState *thr, uptr pc, uptr addr, u32 flagz = 0);
-void MutexDestroy(ThreadState *thr, uptr pc, uptr addr);
+void MutexDestroy(ThreadState *thr, uptr pc, uptr addr, u32 flagz = 0);
void MutexPreLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz = 0);
void MutexPostLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz = 0,
int rec = 1);
diff --git a/lib/tsan/rtl/tsan_rtl_mutex.cc b/lib/tsan/rtl/tsan_rtl_mutex.cc
index 086b28927919..54938f37e243 100644
--- a/lib/tsan/rtl/tsan_rtl_mutex.cc
+++ b/lib/tsan/rtl/tsan_rtl_mutex.cc
@@ -78,13 +78,13 @@ void MutexCreate(ThreadState *thr, uptr pc, uptr addr, u32 flagz) {
s->mtx.Unlock();
}
-void MutexDestroy(ThreadState *thr, uptr pc, uptr addr) {
+void MutexDestroy(ThreadState *thr, uptr pc, uptr addr, u32 flagz) {
DPrintf("#%d: MutexDestroy %zx\n", thr->tid, addr);
StatInc(thr, StatMutexDestroy);
SyncVar *s = ctx->metamap.GetIfExistsAndLock(addr, true);
if (s == 0)
return;
- if (s->IsFlagSet(MutexFlagLinkerInit)) {
+ if ((flagz & MutexFlagLinkerInit) || s->IsFlagSet(MutexFlagLinkerInit)) {
// Destroy is no-op for linker-initialized mutexes.
s->mtx.Unlock();
return;
diff --git a/lib/tsan/rtl/tsan_rtl_report.cc b/lib/tsan/rtl/tsan_rtl_report.cc
index 5cd93a184ce7..055029b91f5b 100644
--- a/lib/tsan/rtl/tsan_rtl_report.cc
+++ b/lib/tsan/rtl/tsan_rtl_report.cc
@@ -377,7 +377,7 @@ const ReportDesc *ScopedReport::GetReport() const {
}
void RestoreStack(int tid, const u64 epoch, VarSizeStackTrace *stk,
- MutexSet *mset) {
+ MutexSet *mset, uptr *tag) {
// This function restores stack trace and mutex set for the thread/epoch.
// It does so by getting stack trace and mutex set at the beginning of
// trace part, and then replaying the trace till the given epoch.
@@ -436,6 +436,7 @@ void RestoreStack(int tid, const u64 epoch, VarSizeStackTrace *stk,
return;
pos++;
stk->Init(&stack[0], pos);
+ ExtractTagFromStack(stk, tag);
}
static bool HandleRacyStacks(ThreadState *thr, VarSizeStackTrace traces[2],
@@ -625,16 +626,15 @@ void ReportRace(ThreadState *thr) {
typ = ReportTypeVptrRace;
else if (freed)
typ = ReportTypeUseAfterFree;
- else if (thr->external_tag > 0)
- typ = ReportTypeExternalRace;
if (IsFiredSuppression(ctx, typ, addr))
return;
const uptr kMop = 2;
VarSizeStackTrace traces[kMop];
+ uptr tags[kMop] = {kExternalTagNone};
const uptr toppc = TraceTopPC(thr);
- ObtainCurrentStack(thr, toppc, &traces[0]);
+ ObtainCurrentStack(thr, toppc, &traces[0], &tags[0]);
if (IsFiredSuppression(ctx, typ, traces[0]))
return;
@@ -644,18 +644,22 @@ void ReportRace(ThreadState *thr) {
MutexSet *mset2 = new(&mset_buffer[0]) MutexSet();
Shadow s2(thr->racy_state[1]);
- RestoreStack(s2.tid(), s2.epoch(), &traces[1], mset2);
+ RestoreStack(s2.tid(), s2.epoch(), &traces[1], mset2, &tags[1]);
if (IsFiredSuppression(ctx, typ, traces[1]))
return;
if (HandleRacyStacks(thr, traces, addr_min, addr_max))
return;
+ // If any of the two accesses has a tag, treat this as an "external" race.
+ if (tags[0] != kExternalTagNone || tags[1] != kExternalTagNone)
+ typ = ReportTypeExternalRace;
+
ThreadRegistryLock l0(ctx->thread_registry);
ScopedReport rep(typ);
for (uptr i = 0; i < kMop; i++) {
Shadow s(thr->racy_state[i]);
- rep.AddMemoryAccess(addr, thr->external_tag, s, traces[i],
+ rep.AddMemoryAccess(addr, tags[i], s, traces[i],
i == 0 ? &thr->mset : mset2);
}
diff --git a/lib/tsan/tests/rtl/tsan_posix.cc b/lib/tsan/tests/rtl/tsan_posix.cc
index 9c0e013e5735..e66dab609c62 100644
--- a/lib/tsan/tests/rtl/tsan_posix.cc
+++ b/lib/tsan/tests/rtl/tsan_posix.cc
@@ -94,8 +94,9 @@ TEST(Posix, ThreadLocalAccesses) {
// The test is failing with high thread count for aarch64.
// FIXME: track down the issue and re-enable the test.
// On Darwin, we're running unit tests without interceptors and __thread is
-// using malloc and free, which causes false data race reports.
-#if !defined(__aarch64__) && !defined(__APPLE__)
+// using malloc and free, which causes false data race reports. On rare
+// occasions on powerpc64le this test also fails.
+#if !defined(__aarch64__) && !defined(__APPLE__) && !defined(powerpc64le)
local_thread((void*)2);
#endif
}
diff --git a/lib/ubsan/ubsan_diag.cc b/lib/ubsan/ubsan_diag.cc
index bbe1e07390ad..742802b8f341 100644
--- a/lib/ubsan/ubsan_diag.cc
+++ b/lib/ubsan/ubsan_diag.cc
@@ -31,15 +31,16 @@ static void MaybePrintStackTrace(uptr pc, uptr bp) {
// will definitely be called when we print the first diagnostics message.
if (!flags()->print_stacktrace)
return;
- // We can only use slow unwind, as we don't have any information about stack
- // top/bottom.
- // FIXME: It's better to respect "fast_unwind_on_fatal" runtime flag and
- // fetch stack top/bottom information if we have it (e.g. if we're running
- // under ASan).
- if (StackTrace::WillUseFastUnwind(false))
- return;
+
+ uptr top = 0;
+ uptr bottom = 0;
+ bool request_fast_unwind = common_flags()->fast_unwind_on_fatal;
+ if (request_fast_unwind)
+ __sanitizer::GetThreadStackTopAndBottom(false, &top, &bottom);
+
BufferedStackTrace stack;
- stack.Unwind(kStackTraceMax, pc, bp, 0, 0, 0, false);
+ stack.Unwind(kStackTraceMax, pc, bp, nullptr, top, bottom,
+ request_fast_unwind);
stack.Print();
}
diff --git a/lib/ubsan/ubsan_handlers.cc b/lib/ubsan/ubsan_handlers.cc
index 4e025a8ddddd..de13ab893bec 100644
--- a/lib/ubsan/ubsan_handlers.cc
+++ b/lib/ubsan/ubsan_handlers.cc
@@ -390,7 +390,7 @@ static void handleFloatCastOverflow(void *DataPtr, ValueHandle From,
ScopedReport R(Opts, Loc, ET);
Diag(Loc, DL_Error,
- "value %0 is outside the range of representable values of type %2")
+ "%0 is outside the range of representable values of type %2")
<< Value(*FromType, From) << *FromType << *ToType;
}
diff --git a/lib/xray/xray_log_interface.cc b/lib/xray/xray_log_interface.cc
index ffed601c05c6..ee14ae4b1b62 100644
--- a/lib/xray/xray_log_interface.cc
+++ b/lib/xray/xray_log_interface.cc
@@ -27,12 +27,22 @@ void __xray_set_log_impl(XRayLogImpl Impl) XRAY_NEVER_INSTRUMENT {
Impl.handle_arg0 == nullptr || Impl.flush_log == nullptr) {
__sanitizer::SpinMutexLock Guard(&XRayImplMutex);
GlobalXRayImpl.reset();
+ __xray_remove_handler();
+ __xray_remove_handler_arg1();
return;
}
__sanitizer::SpinMutexLock Guard(&XRayImplMutex);
GlobalXRayImpl.reset(new XRayLogImpl);
*GlobalXRayImpl = Impl;
+ __xray_set_handler(Impl.handle_arg0);
+}
+
+void __xray_remove_log_impl() XRAY_NEVER_INSTRUMENT {
+ __sanitizer::SpinMutexLock Guard(&XRayImplMutex);
+ GlobalXRayImpl.reset();
+ __xray_remove_handler();
+ __xray_remove_handler_arg1();
}
XRayLogInitStatus __xray_log_init(size_t BufferSize, size_t MaxBuffers,
diff --git a/test/asan/CMakeLists.txt b/test/asan/CMakeLists.txt
index 4b4fdf19d18c..b8e365227780 100644
--- a/test/asan/CMakeLists.txt
+++ b/test/asan/CMakeLists.txt
@@ -22,7 +22,7 @@ endmacro()
set(ASAN_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS})
if(NOT COMPILER_RT_STANDALONE_BUILD)
list(APPEND ASAN_TEST_DEPS asan)
- if(WIN32 AND COMPILER_RT_HAS_LLD)
+ if(NOT APPLE AND COMPILER_RT_HAS_LLD)
list(APPEND ASAN_TEST_DEPS
lld
)
@@ -41,6 +41,12 @@ foreach(arch ${ASAN_TEST_ARCH})
else()
set(ASAN_TEST_TARGET_ARCH ${arch})
endif()
+
+ set(ASAN_TEST_IOS "0")
+ pythonize_bool(ASAN_TEST_IOS)
+ set(ASAN_TEST_IOSSIM "0")
+ pythonize_bool(ASAN_TEST_IOSSIM)
+
string(TOLOWER "-${arch}-${OS_NAME}" ASAN_TEST_CONFIG_SUFFIX)
get_bits_for_arch(${arch} ASAN_TEST_BITS)
get_test_cc_for_arch(${arch} ASAN_TEST_TARGET_CC ASAN_TEST_TARGET_CFLAGS)
@@ -69,6 +75,49 @@ foreach(arch ${ASAN_TEST_ARCH})
endif()
endforeach()
+# iOS and iOS simulator test suites
+# These are not added into "check-all", in order to run these tests, you have to
+# manually call (from the build directory). They also require that an extra env
+# variable to select which iOS device or simulator to use, e.g.:
+# $ SANITIZER_IOSSIM_TEST_DEVICE_IDENTIFIER=BBE44C1C-8AAA-4000-8D06-91C89ED58172
+# $ ./bin/llvm-lit ./projects/compiler-rt/test/asan/IOSSimI386Config
+if(APPLE)
+ set(ASAN_TEST_TARGET_CC ${COMPILER_RT_TEST_COMPILER})
+ set(ASAN_TEST_IOS "1")
+ pythonize_bool(ASAN_TEST_IOS)
+ set(ASAN_TEST_DYNAMIC True)
+
+ foreach(arch ${DARWIN_iossim_ARCHS})
+ set(ASAN_TEST_IOSSIM "1")
+ pythonize_bool(ASAN_TEST_IOSSIM)
+ set(ASAN_TEST_TARGET_ARCH ${arch})
+ set(ASAN_TEST_TARGET_CFLAGS "-arch ${arch} -isysroot ${DARWIN_iossim_SYSROOT} ${COMPILER_RT_TEST_COMPILER_CFLAGS}")
+ set(ASAN_TEST_CONFIG_SUFFIX "-${arch}-iossim")
+ get_bits_for_arch(${arch} ASAN_TEST_BITS)
+ string(TOUPPER ${arch} ARCH_UPPER_CASE)
+ set(CONFIG_NAME "IOSSim${ARCH_UPPER_CASE}Config")
+ configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/lit.site.cfg
+ )
+ endforeach()
+
+ foreach (arch ${DARWIN_ios_ARCHS})
+ set(ASAN_TEST_IOSSIM "0")
+ pythonize_bool(ASAN_TEST_IOSSIM)
+ set(ASAN_TEST_TARGET_ARCH ${arch})
+ set(ASAN_TEST_TARGET_CFLAGS "-arch ${arch} -isysroot ${DARWIN_ios_SYSROOT} ${COMPILER_RT_TEST_COMPILER_CFLAGS}")
+ set(ASAN_TEST_CONFIG_SUFFIX "-${arch}-ios")
+ get_bits_for_arch(${arch} ASAN_TEST_BITS)
+ string(TOUPPER ${arch} ARCH_UPPER_CASE)
+ set(CONFIG_NAME "IOS${ARCH_UPPER_CASE}Config")
+ configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/lit.site.cfg
+ )
+ endforeach()
+endif()
+
# Add unit tests.
if(COMPILER_RT_INCLUDE_TESTS)
set(ASAN_TEST_DYNAMIC False)
diff --git a/test/asan/TestCases/Darwin/dead-strip.c b/test/asan/TestCases/Darwin/dead-strip.c
index f87a5e52b1cf..8165fcd08be7 100644
--- a/test/asan/TestCases/Darwin/dead-strip.c
+++ b/test/asan/TestCases/Darwin/dead-strip.c
@@ -6,6 +6,7 @@
// runtime is able to register globals in the __DATA,__asan_globals section.
// REQUIRES: osx-ld64-live_support
+// UNSUPPORTED: ios
// RUN: %clang_asan -mmacosx-version-min=10.11 -Xlinker -dead_strip -o %t %s
// RUN: llvm-nm -format=posix %t | FileCheck --check-prefix NM-CHECK %s
// RUN: not %run %t 2>&1 | FileCheck --check-prefix ASAN-CHECK %s
diff --git a/test/asan/TestCases/Darwin/dump_registers.cc b/test/asan/TestCases/Darwin/dump_registers.cc
index 884ad2ed44c0..42db446ffc1c 100644
--- a/test/asan/TestCases/Darwin/dump_registers.cc
+++ b/test/asan/TestCases/Darwin/dump_registers.cc
@@ -18,7 +18,7 @@ int main() {
assert(0 && "Your computer is weird.");
char c = *ptr; // BOOM
- // CHECK: ERROR: AddressSanitizer: SEGV
+ // CHECK: ERROR: AddressSanitizer: {{SEGV|BUS}}
// CHECK: Register values:
// CHECK: {{0x55555555|0x6666666666666666}}
fprintf(stderr, "World\n");
diff --git a/test/asan/TestCases/Darwin/reexec-insert-libraries-env.cc b/test/asan/TestCases/Darwin/reexec-insert-libraries-env.cc
index aa4d92b00a01..cd277a05b40b 100644
--- a/test/asan/TestCases/Darwin/reexec-insert-libraries-env.cc
+++ b/test/asan/TestCases/Darwin/reexec-insert-libraries-env.cc
@@ -7,7 +7,7 @@
// RUN: -dynamiclib -o darwin-dummy-shared-lib-so.dylib
// FIXME: the following command line may hang in the case of a regression.
-// RUN: env DYLD_INSERT_LIBRARIES=darwin-dummy-shared-lib-so.dylib \
+// RUN: %env DYLD_INSERT_LIBRARIES=darwin-dummy-shared-lib-so.dylib \
// RUN: %run %t 2>&1 | FileCheck %s || exit 1
#if !defined(SHARED_LIB)
diff --git a/test/asan/TestCases/Darwin/scribble.cc b/test/asan/TestCases/Darwin/scribble.cc
index 0ddee6b5eef5..8303cf316a9c 100644
--- a/test/asan/TestCases/Darwin/scribble.cc
+++ b/test/asan/TestCases/Darwin/scribble.cc
@@ -1,6 +1,6 @@
// RUN: %clang_asan -O2 %s -o %t
// RUN: %run %t 2>&1 | FileCheck --check-prefix=CHECK-NOSCRIBBLE %s
-// RUN: env MallocScribble=1 MallocPreScribble=1 %run %t 2>&1 | FileCheck --check-prefix=CHECK-SCRIBBLE %s
+// RUN: %env MallocScribble=1 MallocPreScribble=1 %run %t 2>&1 | FileCheck --check-prefix=CHECK-SCRIBBLE %s
// RUN: %env_asan_opts=max_free_fill_size=4096 %run %t 2>&1 | FileCheck --check-prefix=CHECK-SCRIBBLE %s
#include <stdint.h>
diff --git a/test/asan/TestCases/Darwin/unset-insert-libraries-on-exec.cc b/test/asan/TestCases/Darwin/unset-insert-libraries-on-exec.cc
index f8a330ad5fe0..62cf853a5436 100644
--- a/test/asan/TestCases/Darwin/unset-insert-libraries-on-exec.cc
+++ b/test/asan/TestCases/Darwin/unset-insert-libraries-on-exec.cc
@@ -10,7 +10,7 @@
// execl().
// RUN: %run %t %T/echo-env >/dev/null 2>&1
-// RUN: env DYLD_INSERT_LIBRARIES=%t-darwin-dummy-shared-lib-so.dylib \
+// RUN: %env DYLD_INSERT_LIBRARIES=%t-darwin-dummy-shared-lib-so.dylib \
// RUN: %run %t %T/echo-env 2>&1 | FileCheck %s || exit 1
#if !defined(SHARED_LIB)
diff --git a/test/asan/TestCases/Linux/global-overflow-bfd.cc b/test/asan/TestCases/Linux/global-overflow-bfd.cc
new file mode 100644
index 000000000000..117a761af91f
--- /dev/null
+++ b/test/asan/TestCases/Linux/global-overflow-bfd.cc
@@ -0,0 +1,18 @@
+// Test that gc-sections-friendly instrumentation of globals does not introduce
+// false negatives with the BFD linker.
+// RUN: %clangxx_asan -fuse-ld=bfd -Wl,-gc-sections -ffunction-sections -fdata-sections -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
+
+#include <string.h>
+int main(int argc, char **argv) {
+ static char XXX[10];
+ static char YYY[10];
+ static char ZZZ[10];
+ memset(XXX, 0, 10);
+ memset(YYY, 0, 10);
+ memset(ZZZ, 0, 10);
+ int res = YYY[argc * 10]; // BOOOM
+ // CHECK: {{READ of size 1 at}}
+ // CHECK: {{located 0 bytes to the right of global variable}}
+ res += XXX[argc] + ZZZ[argc];
+ return res;
+}
diff --git a/test/asan/TestCases/Linux/global-overflow-lld.cc b/test/asan/TestCases/Linux/global-overflow-lld.cc
new file mode 100644
index 000000000000..f4d0bc977604
--- /dev/null
+++ b/test/asan/TestCases/Linux/global-overflow-lld.cc
@@ -0,0 +1,19 @@
+// Test that gc-sections-friendly instrumentation of globals does not introduce
+// false negatives with the LLD linker.
+// RUN: %clangxx_asan -fuse-ld=lld -Wl,-gc-sections -ffunction-sections -fdata-sections -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// REQUIRES: lld
+
+#include <string.h>
+int main(int argc, char **argv) {
+ static char XXX[10];
+ static char YYY[10];
+ static char ZZZ[10];
+ memset(XXX, 0, 10);
+ memset(YYY, 0, 10);
+ memset(ZZZ, 0, 10);
+ int res = YYY[argc * 10]; // BOOOM
+ // CHECK: {{READ of size 1 at}}
+ // CHECK: {{located 0 bytes to the right of global variable}}
+ res += XXX[argc] + ZZZ[argc];
+ return res;
+}
diff --git a/test/asan/TestCases/Linux/globals-gc-sections-lld.cc b/test/asan/TestCases/Linux/globals-gc-sections-lld.cc
new file mode 100644
index 000000000000..0d8bcdd1cb17
--- /dev/null
+++ b/test/asan/TestCases/Linux/globals-gc-sections-lld.cc
@@ -0,0 +1,15 @@
+// RUN: %clangxx_asan %s -o %t -Wl,--gc-sections -fuse-ld=lld -ffunction-sections -fdata-sections -mllvm -asan-globals=0
+// RUN: %clangxx_asan %s -o %t -Wl,--gc-sections -fuse-ld=lld -ffunction-sections -fdata-sections -mllvm -asan-globals=1
+
+// https://code.google.com/p/address-sanitizer/issues/detail?id=260
+// REQUIRES: lld
+
+int undefined();
+
+// On i386 clang adds --export-dynamic when linking with ASan, which adds all
+// non-hidden globals to GC roots.
+__attribute__((visibility("hidden"))) int (*unused)() = undefined;
+
+int main() {
+ return 0;
+}
diff --git a/test/asan/TestCases/Linux/globals-gc-sections.cc b/test/asan/TestCases/Linux/globals-gc-sections.cc
deleted file mode 100644
index 72a9e9498f85..000000000000
--- a/test/asan/TestCases/Linux/globals-gc-sections.cc
+++ /dev/null
@@ -1,13 +0,0 @@
-// RUN: %clangxx_asan %s -o %t -Wl,--gc-sections -ffunction-sections -mllvm -asan-globals=0
-// RUN: %clangxx_asan %s -o %t -Wl,--gc-sections -ffunction-sections -mllvm -asan-globals=1
-
-// https://code.google.com/p/address-sanitizer/issues/detail?id=260
-// XFAIL: *
-
-int undefined();
-
-int (*unused)() = undefined;
-
-int main() {
- return 0;
-}
diff --git a/test/asan/TestCases/Posix/asan-sigbus.cpp b/test/asan/TestCases/Posix/asan-sigbus.cpp
index e07392b4cd4b..a7d032acec03 100644
--- a/test/asan/TestCases/Posix/asan-sigbus.cpp
+++ b/test/asan/TestCases/Posix/asan-sigbus.cpp
@@ -4,6 +4,8 @@
// RUN: not %run %t %T/file 2>&1 | FileCheck %s -check-prefix=CHECK-BUS
// RUN: %env_asan_opts=handle_sigbus=false not --crash %run %t %T/file 2>&1 | FileCheck %s
+// UNSUPPORTED: ios
+
#include <assert.h>
#include <fcntl.h>
#include <stdio.h>
diff --git a/test/asan/TestCases/Posix/coverage-direct-activation.cc b/test/asan/TestCases/Posix/coverage-direct-activation.cc
deleted file mode 100644
index 0af3296f22d4..000000000000
--- a/test/asan/TestCases/Posix/coverage-direct-activation.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Test for direct coverage writing enabled at activation time.
-
-// RUN: %clangxx_asan -fsanitize-coverage=func -DSHARED %s -shared -o %dynamiclib -fPIC
-// RUN: %clangxx -c -DSO_DIR=\"%T\" %s -o %t.o
-// RUN: %clangxx_asan -fsanitize-coverage=func %t.o %libdl -o %t
-
-// RUN: rm -rf %T/coverage-direct-activation
-
-// RUN: mkdir -p %T/coverage-direct-activation/normal
-// RUN: %env_asan_opts=coverage=1,coverage_direct=0,coverage_dir=%T/coverage-direct-activation/normal:verbosity=1 %run %t %dynamiclib
-// RUN: %sancov print %T/coverage-direct-activation/normal/*.sancov >%T/coverage-direct-activation/normal/out.txt
-
-// RUN: mkdir -p %T/coverage-direct-activation/direct
-// RUN: %env_asan_opts=start_deactivated=1,coverage_direct=1,verbosity=1 \
-// RUN: ASAN_ACTIVATION_OPTIONS=coverage=1,coverage_dir=%T/coverage-direct-activation/direct %run %t %dynamiclib
-// RUN: cd %T/coverage-direct-activation/direct
-// RUN: %sancov rawunpack *.sancov.raw
-// RUN: %sancov print *.sancov >out.txt
-// RUN: cd ../..
-
-// Test start_deactivated=1,coverage=1 in ASAN_OPTIONS.
-
-// RUN: diff -u coverage-direct-activation/normal/out.txt coverage-direct-activation/direct/out.txt
-
-// RUN: mkdir -p %T/coverage-direct-activation/direct2
-// RUN: %env_asan_opts=start_deactivated=1,coverage=1,coverage_direct=1,verbosity=1 \
-// RUN: ASAN_ACTIVATION_OPTIONS=coverage_dir=%T/coverage-direct-activation/direct2 %run %t %dynamiclib
-// RUN: cd %T/coverage-direct-activation/direct2
-// RUN: %sancov rawunpack *.sancov.raw
-// RUN: %sancov print *.sancov >out.txt
-// RUN: cd ../..
-
-// RUN: diff -u coverage-direct-activation/normal/out.txt coverage-direct-activation/direct2/out.txt
-
-// XFAIL: android
-
-#include <assert.h>
-#include <dlfcn.h>
-#include <stdio.h>
-#include <unistd.h>
-
-#ifdef SHARED
-extern "C" {
-void bar() { printf("bar\n"); }
-}
-#else
-
-int main(int argc, char **argv) {
- fprintf(stderr, "PID: %d\n", getpid());
- assert(argc > 1);
- void *handle1 = dlopen(argv[1], RTLD_LAZY); // %dynamiclib
- assert(handle1);
- void (*bar1)() = (void (*)())dlsym(handle1, "bar");
- assert(bar1);
- bar1();
-
- return 0;
-}
-#endif
diff --git a/test/asan/TestCases/Posix/coverage-direct-large.cc b/test/asan/TestCases/Posix/coverage-direct-large.cc
deleted file mode 100644
index 367a5667a711..000000000000
--- a/test/asan/TestCases/Posix/coverage-direct-large.cc
+++ /dev/null
@@ -1,65 +0,0 @@
-// Test for direct coverage writing with lots of data.
-// Current implementation maps output file in chunks of 64K. This test overflows
-// 1 chunk.
-
-// RUN: %clangxx_asan -fsanitize-coverage=func -O0 -DSHARED %s -shared -o %dynamiclib -fPIC
-// RUN: %clangxx_asan -fsanitize-coverage=func -O0 %s %libdl -o %t
-
-// RUN: rm -rf %T/coverage-direct-large
-
-// RUN: mkdir -p %T/coverage-direct-large/normal && cd %T/coverage-direct-large/normal
-// RUN: %env_asan_opts=coverage=1:coverage_direct=0:verbosity=1 %run %t %dynamiclib
-// RUN: %sancov print *.sancov >out.txt
-// RUN: cd ../..
-
-// RUN: mkdir -p %T/coverage-direct-large/direct && cd %T/coverage-direct-large/direct
-// RUN: %env_asan_opts=coverage=1:coverage_direct=1:verbosity=1 %run %t %dynamiclib
-// RUN: %sancov rawunpack *.sancov.raw
-// RUN: %sancov print *.sancov >out.txt
-// RUN: cd ../..
-
-// RUN: diff -u coverage-direct-large/normal/out.txt coverage-direct-large/direct/out.txt
-//
-// XFAIL: android
-
-#define F0(Q, x) Q(x)
-#define F1(Q, x) \
- F0(Q, x##0) F0(Q, x##1) F0(Q, x##2) F0(Q, x##3) F0(Q, x##4) F0(Q, x##5) \
- F0(Q, x##6) F0(Q, x##7) F0(Q, x##8) F0(Q, x##9)
-#define F2(Q, x) \
- F1(Q, x##0) F1(Q, x##1) F1(Q, x##2) F1(Q, x##3) F1(Q, x##4) F1(Q, x##5) \
- F1(Q, x##6) F1(Q, x##7) F1(Q, x##8) F1(Q, x##9)
-#define F3(Q, x) \
- F2(Q, x##0) F2(Q, x##1) F2(Q, x##2) F2(Q, x##3) F2(Q, x##4) F2(Q, x##5) \
- F2(Q, x##6) F2(Q, x##7) F2(Q, x##8) F2(Q, x##9)
-#define F4(Q, x) \
- F3(Q, x##0) F3(Q, x##1) F3(Q, x##2) F3(Q, x##3) F3(Q, x##4) F3(Q, x##5) \
- F3(Q, x##6) F3(Q, x##7) F3(Q, x##8) F3(Q, x##9)
-
-#define DECL(x) __attribute__((noinline)) static void x() {}
-#define CALL(x) x();
-
-F4(DECL, f)
-
-#ifdef SHARED
-extern "C" void so_entry() {
- F4(CALL, f)
-}
-#else
-
-#include <assert.h>
-#include <dlfcn.h>
-#include <stdio.h>
-int main(int argc, char **argv) {
- F4(CALL, f)
- assert(argc > 1);
- void *handle1 = dlopen(argv[1], RTLD_LAZY); // %dynamiclib
- assert(handle1);
- void (*so_entry)() = (void (*)())dlsym(handle1, "so_entry");
- assert(so_entry);
- so_entry();
-
- return 0;
-}
-
-#endif // SHARED
diff --git a/test/asan/TestCases/Posix/coverage-direct.cc b/test/asan/TestCases/Posix/coverage-direct.cc
deleted file mode 100644
index 8caa9c553f2e..000000000000
--- a/test/asan/TestCases/Posix/coverage-direct.cc
+++ /dev/null
@@ -1,83 +0,0 @@
-// Test for direct coverage writing with dlopen at coverage level 1 to 3.
-
-// RUN: %clangxx_asan -fsanitize-coverage=func -DSHARED %s -shared -o %dynamiclib -fPIC
-// RUN: %clangxx_asan -fsanitize-coverage=func %s %libdl -o %t
-
-// RUN: rm -rf %T/coverage-direct
-
-// RUN: mkdir -p %T/coverage-direct/normal
-// RUN: %env_asan_opts=coverage=1:coverage_direct=0:coverage_dir=%T/coverage-direct/normal:verbosity=1 %run %t %dynamiclib
-// RUN: %sancov print %T/coverage-direct/normal/*.sancov >%T/coverage-direct/normal/out.txt
-
-// RUN: mkdir -p %T/coverage-direct/direct
-// RUN: %env_asan_opts=coverage=1:coverage_direct=1:coverage_dir=%T/coverage-direct/direct:verbosity=1 %run %t %dynamiclib
-// RUN: cd %T/coverage-direct/direct
-// RUN: %sancov rawunpack *.sancov.raw
-// RUN: %sancov print *.sancov >out.txt
-// RUN: cd ../..
-
-// RUN: diff -u coverage-direct/normal/out.txt coverage-direct/direct/out.txt
-
-
-// RUN: %clangxx_asan -fsanitize-coverage=bb -DSHARED %s -shared -o %dynamiclib -fPIC
-// RUN: %clangxx_asan -fsanitize-coverage=bb -DSO_DIR=\"%T\" %s %libdl -o %t
-
-// RUN: rm -rf %T/coverage-direct
-
-// RUN: mkdir -p %T/coverage-direct/normal
-// RUN: %env_asan_opts=coverage=1:coverage_direct=0:coverage_dir=%T/coverage-direct/normal:verbosity=1 %run %t %dynamiclib
-// RUN: %sancov print %T/coverage-direct/normal/*.sancov >%T/coverage-direct/normal/out.txt
-
-// RUN: mkdir -p %T/coverage-direct/direct
-// RUN: %env_asan_opts=coverage=1:coverage_direct=1:coverage_dir=%T/coverage-direct/direct:verbosity=1 %run %t %dynamiclib
-// RUN: cd %T/coverage-direct/direct
-// RUN: %sancov rawunpack *.sancov.raw
-// RUN: %sancov print *.sancov >out.txt
-// RUN: cd ../..
-
-// RUN: diff -u coverage-direct/normal/out.txt coverage-direct/direct/out.txt
-
-
-// RUN: %clangxx_asan -fsanitize-coverage=edge -DSHARED %s -shared -o %dynamiclib -fPIC
-// RUN: %clangxx_asan -fsanitize-coverage=edge -DSO_DIR=\"%T\" %s %libdl -o %t
-
-// RUN: rm -rf %T/coverage-direct
-
-// RUN: mkdir -p %T/coverage-direct/normal
-// RUN: %env_asan_opts=coverage=1:coverage_direct=0:coverage_dir=%T/coverage-direct/normal:verbosity=1 %run %t %dynamiclib
-// RUN: %sancov print %T/coverage-direct/normal/*.sancov >%T/coverage-direct/normal/out.txt
-
-// RUN: mkdir -p %T/coverage-direct/direct
-// RUN: %env_asan_opts=coverage=1:coverage_direct=1:coverage_dir=%T/coverage-direct/direct:verbosity=1 %run %t %dynamiclib
-// RUN: cd %T/coverage-direct/direct
-// RUN: %sancov rawunpack *.sancov.raw
-// RUN: %sancov print *.sancov >out.txt
-// RUN: cd ../..
-
-// RUN: diff -u coverage-direct/normal/out.txt coverage-direct/direct/out.txt
-
-// XFAIL: android
-
-#include <assert.h>
-#include <dlfcn.h>
-#include <stdio.h>
-#include <unistd.h>
-
-#ifdef SHARED
-extern "C" {
-void bar() { printf("bar\n"); }
-}
-#else
-
-int main(int argc, char **argv) {
- fprintf(stderr, "PID: %d\n", getpid());
- assert(argc > 1);
- void *handle1 = dlopen(argv[1], RTLD_LAZY);
- assert(handle1);
- void (*bar1)() = (void (*)())dlsym(handle1, "bar");
- assert(bar1);
- bar1();
-
- return 0;
-}
-#endif
diff --git a/test/asan/TestCases/Posix/coverage-fork-direct.cc b/test/asan/TestCases/Posix/coverage-fork-direct.cc
deleted file mode 100644
index c19671953809..000000000000
--- a/test/asan/TestCases/Posix/coverage-fork-direct.cc
+++ /dev/null
@@ -1,38 +0,0 @@
-// RUN: %clangxx_asan -fsanitize-coverage=func %s -o %t
-// RUN: rm -rf %T/coverage-fork-direct
-// RUN: mkdir -p %T/coverage-fork-direct && cd %T/coverage-fork-direct
-// RUN: (%env_asan_opts=coverage=1:coverage_direct=1:verbosity=1 %run %t; \
-// RUN: %sancov rawunpack *.sancov.raw; %sancov print *.sancov) 2>&1
-//
-// XFAIL: android
-
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-
-__attribute__((noinline))
-void foo() { printf("foo\n"); }
-
-__attribute__((noinline))
-void bar() { printf("bar\n"); }
-
-__attribute__((noinline))
-void baz() { printf("baz\n"); }
-
-int main(int argc, char **argv) {
- pid_t child_pid = fork();
- if (child_pid == 0) {
- fprintf(stderr, "Child PID: %d\n", getpid());
- baz();
- } else {
- fprintf(stderr, "Parent PID: %d\n", getpid());
- foo();
- bar();
- }
- return 0;
-}
-
-// CHECK-DAG: Child PID: [[ChildPID:[0-9]+]]
-// CHECK-DAG: Parent PID: [[ParentPID:[0-9]+]]
-// CHECK-DAG: read 3 PCs from {{.*}}.[[ParentPID]].sancov
-// CHECK-DAG: read 1 PCs from {{.*}}.[[ChildPID]].sancov
diff --git a/test/asan/TestCases/Posix/current_allocated_bytes.cc b/test/asan/TestCases/Posix/current_allocated_bytes.cc
index c49e433b1e8b..51630cfd8a6b 100644
--- a/test/asan/TestCases/Posix/current_allocated_bytes.cc
+++ b/test/asan/TestCases/Posix/current_allocated_bytes.cc
@@ -1,6 +1,9 @@
// RUN: %clangxx_asan -O0 %s -pthread -o %t && %run %t
// RUN: %clangxx_asan -O2 %s -pthread -o %t && %run %t
// REQUIRES: stable-runtime
+// UNSUPPORTED: powerpc64le
+// FIXME: This test occasionally fails on powerpc64 LE possibly starting with
+// r279664. Re-enable the test once the problem(s) have been fixed.
#include <assert.h>
#include <pthread.h>
diff --git a/test/asan/TestCases/Posix/fread_fwrite.cc b/test/asan/TestCases/Posix/fread_fwrite.cc
index 97d44b7528ba..c0629260418a 100644
--- a/test/asan/TestCases/Posix/fread_fwrite.cc
+++ b/test/asan/TestCases/Posix/fread_fwrite.cc
@@ -1,6 +1,6 @@
// RUN: %clangxx_asan -g %s -o %t
-// RUN: not %t 2>&1 | FileCheck %s --check-prefix=CHECK-FWRITE
-// RUN: not %t 1 2>&1 | FileCheck %s --check-prefix=CHECK-FREAD
+// RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-FWRITE
+// RUN: not %run %t 1 2>&1 | FileCheck %s --check-prefix=CHECK-FREAD
#include <stdio.h>
#include <stdlib.h>
diff --git a/test/asan/TestCases/coverage-disabled.cc b/test/asan/TestCases/coverage-disabled.cc
index 490f2b27236a..b225035ee4ca 100644
--- a/test/asan/TestCases/coverage-disabled.cc
+++ b/test/asan/TestCases/coverage-disabled.cc
@@ -8,11 +8,6 @@
// RUN: %env_asan_opts=coverage_direct=0:coverage_dir='"%T/coverage-disabled/normal"':verbosity=1 %run %t
// RUN: not %sancov print %T/coverage-disabled/normal/*.sancov 2>&1
//
-// RUN: mkdir -p %T/coverage-disabled/direct
-// RUN: %env_asan_opts=coverage_direct=1:coverage_dir='"%T/coverage-disabled/direct"':verbosity=1 %run %t
-// RUN: cd %T/coverage-disabled/direct
-// RUN: not %sancov rawunpack *.sancov
-//
// UNSUPPORTED: android
int main(int argc, char **argv) {
diff --git a/test/asan/TestCases/coverage-levels.cc b/test/asan/TestCases/coverage-levels.cc
deleted file mode 100644
index ae9ac4841e52..000000000000
--- a/test/asan/TestCases/coverage-levels.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// Test various levels of coverage
-//
-// RUN: %clangxx_asan -O1 -fsanitize-coverage=func %s -o %t
-// RUN: %env_asan_opts=coverage=1:coverage_bitset=1:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1
-// RUN: %clangxx_asan -O1 -fsanitize-coverage=bb %s -o %t
-// RUN: %env_asan_opts=coverage=1:coverage_bitset=1:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2
-// RUN: %clangxx_asan -O1 -fsanitize-coverage=edge %s -o %t
-// RUN: %env_asan_opts=coverage=1:coverage_bitset=1:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK3
-// RUN: %clangxx_asan -O1 -fsanitize-coverage=edge -mllvm -sanitizer-coverage-block-threshold=0 %s -o %t
-// RUN: %env_asan_opts=coverage=1:coverage_bitset=1:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK3
-
-// RUN: %env_asan_opts=coverage=1:coverage_bitset=0:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK3_NOBITSET
-// RUN: %env_asan_opts=coverage=1:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK3_NOBITSET
-// RUN: %env_asan_opts=coverage=1:coverage_pcs=0:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK3_NOPCS
-//
-// REQUIRES: asan-64-bits
-// UNSUPPORTED: android
-volatile int sink;
-int main(int argc, char **argv) {
- if (argc == 0)
- sink = 0;
-}
-
-// CHECK1: CovDump: bitset of 1 bits written for '{{.*}}', 1 bits are set
-// CHECK1: 1 PCs written
-// CHECK2: CovDump: bitset of 2 bits written for '{{.*}}', 1 bits are set
-// CHECK2: 1 PCs written
-// CHECK3: CovDump: bitset of 3 bits written for '{{.*}}', 2 bits are set
-// CHECK3: 2 PCs written
-// CHECK3_NOBITSET-NOT: bitset of
-// CHECK3_NOPCS-NOT: PCs written
diff --git a/test/asan/TestCases/initialization-bug.cc b/test/asan/TestCases/initialization-bug.cc
index b28174f59aeb..6ecc6c836c5c 100644
--- a/test/asan/TestCases/initialization-bug.cc
+++ b/test/asan/TestCases/initialization-bug.cc
@@ -10,6 +10,7 @@
// The test is expected to fail on OS X Yosemite and older
// UNSUPPORTED: osx-no-ld64-live_support
+// UNSUPPORTED: ios
#include <cstdio>
diff --git a/test/asan/TestCases/small_memcpy_test.cc b/test/asan/TestCases/small_memcpy_test.cc
new file mode 100644
index 000000000000..2d6dea60caed
--- /dev/null
+++ b/test/asan/TestCases/small_memcpy_test.cc
@@ -0,0 +1,28 @@
+// Test that small memcpy works correctly.
+
+// RUN: %clangxx_asan %s -o %t
+// RUN: not %run %t 8 24 2>&1 | FileCheck %s --check-prefix=CHECK
+// RUN: not %run %t 16 32 2>&1 | FileCheck %s --check-prefix=CHECK
+// RUN: not %run %t 24 40 2>&1 | FileCheck %s --check-prefix=CHECK
+// RUN: not %run %t 32 48 2>&1 | FileCheck %s --check-prefix=CHECK
+// RUN: not %run %t 40 56 2>&1 | FileCheck %s --check-prefix=CHECK
+// RUN: not %run %t 48 64 2>&1 | FileCheck %s --check-prefix=CHECK
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <sanitizer/asan_interface.h>
+
+int main(int argc, char **argv) {
+ assert(argc == 3);
+ size_t poison_from = atoi(argv[1]);
+ size_t poison_to = atoi(argv[2]);
+ assert(poison_from <= poison_to);
+ char A1[64], A2[64];
+ fprintf(stderr, "%zd %zd\n", poison_from, poison_to - poison_from);
+ __asan_poison_memory_region(&A1[0] + poison_from, poison_to - poison_from);
+ memcpy(A1, A2, sizeof(A1));
+// CHECK: AddressSanitizer: use-after-poison
+ return 0;
+}
diff --git a/test/asan/TestCases/strtok.c b/test/asan/TestCases/strtok.c
index e1eee89ee709..c7b261777254 100644
--- a/test/asan/TestCases/strtok.c
+++ b/test/asan/TestCases/strtok.c
@@ -4,7 +4,7 @@
// RUN: %env_asan_opts=strict_string_checks=true not %run %t test1 2>&1 | \
// RUN: FileCheck %s --check-prefix=CHECK1
-// RUN: %env_asan_opts=intercept_strtok=false%run %t test1 2>&1
+// RUN: %env_asan_opts=intercept_strtok=false %run %t test1 2>&1
// RUN: %env_asan_opts=strict_string_checks=true not %run %t test2 2>&1 | \
// RUN: FileCheck %s --check-prefix=CHECK2
// RUN: %env_asan_opts=intercept_strtok=false %run %t test2 2>&1
diff --git a/test/asan/lit.cfg b/test/asan/lit.cfg
index 7d684a1ae7a7..b433a91e830e 100644
--- a/test/asan/lit.cfg
+++ b/test/asan/lit.cfg
@@ -108,14 +108,12 @@ if platform.system() == 'Windows':
asan_lit_source_dir = get_required_attr(config, "asan_lit_source_dir")
if config.android == "1":
config.available_features.add('android')
- clang_wrapper = os.path.join(asan_lit_source_dir,
- "android_commands", "android_compile.py") + " "
+ compile_wrapper = os.path.join(asan_lit_source_dir, "android_commands", "android_compile.py") + " "
else:
config.available_features.add('not-android')
- clang_wrapper = ""
def build_invocation(compile_flags):
- return " " + " ".join([clang_wrapper, config.clang] + compile_flags) + " "
+ return " " + " ".join([config.compile_wrapper, config.clang] + compile_flags) + " "
# Clang driver link 'x86' (i686) architecture to 'i386'.
target_arch = config.target_arch
diff --git a/test/asan/lit.site.cfg.in b/test/asan/lit.site.cfg.in
index 1b6fed2cb9d6..100592db267d 100644
--- a/test/asan/lit.site.cfg.in
+++ b/test/asan/lit.site.cfg.in
@@ -7,6 +7,8 @@ config.target_cflags = "@ASAN_TEST_TARGET_CFLAGS@"
config.clang = "@ASAN_TEST_TARGET_CC@"
config.bits = "@ASAN_TEST_BITS@"
config.android = "@ANDROID@"
+config.ios = @ASAN_TEST_IOS_PYBOOL@
+config.iossim = @ASAN_TEST_IOSSIM_PYBOOL@
config.asan_dynamic = @ASAN_TEST_DYNAMIC@
config.target_arch = "@ASAN_TEST_TARGET_ARCH@"
diff --git a/test/lit.common.cfg b/test/lit.common.cfg
index 4b03a5504221..6080edca4fbf 100644
--- a/test/lit.common.cfg
+++ b/test/lit.common.cfg
@@ -94,7 +94,26 @@ config.substitutions.append(
instead define '%clangXXX' substitution in lit config. ***\n\n""") )
# Allow tests to be executed on a simulator or remotely.
-config.substitutions.append( ('%run', config.emulator) )
+if config.emulator:
+ config.substitutions.append( ('%run', config.emulator) )
+ config.substitutions.append( ('%env ', "env ") )
+ config.compile_wrapper = ""
+elif config.ios:
+ config.available_features.add('ios')
+
+ device_id_env = "SANITIZER_IOSSIM_TEST_DEVICE_IDENTIFIER" if config.iossim else "SANITIZER_IOS_TEST_DEVICE_IDENTIFIER"
+ if device_id_env in os.environ: config.environment[device_id_env] = os.environ[device_id_env]
+ ios_commands_dir = os.path.join(config.compiler_rt_src_root, "test", "sanitizer_common", "ios_commands")
+ run_wrapper = os.path.join(ios_commands_dir, "iossim_run.py" if config.iossim else "ios_run.py")
+ config.substitutions.append(('%run', run_wrapper))
+ env_wrapper = os.path.join(ios_commands_dir, "iossim_env.py" if config.iossim else "ios_env.py")
+ config.substitutions.append(('%env ', env_wrapper + " "))
+ compile_wrapper = os.path.join(ios_commands_dir, "iossim_compile.py" if config.iossim else "ios_compile.py")
+ config.compile_wrapper = compile_wrapper
+else:
+ config.substitutions.append( ('%run', "") )
+ config.substitutions.append( ('%env ', "env ") )
+ config.compile_wrapper = ""
# Define CHECK-%os to check for OS-dependent output.
config.substitutions.append( ('CHECK-%os', ("CHECK-" + config.host_os)))
diff --git a/test/lit.common.configured.in b/test/lit.common.configured.in
index 0ad03a180042..dc3081d6a53b 100644
--- a/test/lit.common.configured.in
+++ b/test/lit.common.configured.in
@@ -25,6 +25,8 @@ set_default("python_executable", "@PYTHON_EXECUTABLE@")
set_default("compiler_rt_debug", @COMPILER_RT_DEBUG_PYBOOL@)
set_default("compiler_rt_libdir", "@COMPILER_RT_LIBRARY_OUTPUT_DIR@")
set_default("emulator", "@COMPILER_RT_EMULATOR@")
+set_default("ios", False)
+set_default("iossim", False)
set_default("sanitizer_can_use_cxxabi", @SANITIZER_CAN_USE_CXXABI_PYBOOL@)
set_default("has_lld", @COMPILER_RT_HAS_LLD_PYBOOL@)
set_default("can_symbolize", @CAN_SYMBOLIZE@)
diff --git a/test/sanitizer_common/TestCases/sanitizer_coverage_symbolize.cc b/test/sanitizer_common/TestCases/sanitizer_coverage_symbolize.cc
index 48f32a705c3a..266dc3f0e976 100644
--- a/test/sanitizer_common/TestCases/sanitizer_coverage_symbolize.cc
+++ b/test/sanitizer_common/TestCases/sanitizer_coverage_symbolize.cc
@@ -9,7 +9,6 @@
// RUN: cd $DIR
// RUN: %clangxx -O0 -fsanitize-coverage=trace-pc-guard %s -ldl -o %t
// RUN: %env_tool_opts=coverage=1 %t 2>&1 | FileCheck %s
-// RUN: %env_tool_opts=coverage=1 SANCOV_OPTIONS=symbolize=0 %t 2>&1 | FileCheck %s --check-prefix=CHECK-NOSYM
// RUN: rm -rf $DIR
#include <stdio.h>
@@ -27,8 +26,3 @@ int main() {
// CHECK: main
// CHECK: SanitizerCoverage: ./sanitizer_coverage_symbolize.{{.*}}.sancov 2 PCs written
-// CHECK: call sancov
-
-// CHECK-NOSYM: main
-// CHECK-NOSYM: SanitizerCoverage: ./sanitizer_coverage_symbolize.{{.*}}.sancov 2 PCs written
-// CHECK-NOSYM-NOT: call sancov
diff --git a/test/sanitizer_common/ios_commands/iossim_compile.py b/test/sanitizer_common/ios_commands/iossim_compile.py
new file mode 100755
index 000000000000..8fa480ed5f60
--- /dev/null
+++ b/test/sanitizer_common/ios_commands/iossim_compile.py
@@ -0,0 +1,32 @@
+#!/usr/bin/python
+
+import os, sys, subprocess
+
+output = None
+output_type = 'executable'
+
+args = sys.argv[1:]
+while args:
+ arg = args.pop(0)
+ if arg == '-shared':
+ output_type = 'shared'
+ elif arg == '-dynamiclib':
+ output_type = 'dylib'
+ elif arg == '-c':
+ output_type = 'object'
+ elif arg == '-S':
+ output_type = 'assembly'
+ elif arg == '-o':
+ output = args.pop(0)
+
+if output == None:
+ print "No output file name!"
+ sys.exit(1)
+
+ret = subprocess.call(sys.argv[1:])
+if ret != 0:
+ sys.exit(ret)
+
+# If we produce a dylib, ad-hoc sign it.
+if output_type in ['shared', 'dylib']:
+ ret = subprocess.call(["codesign", "-s", "-", output])
diff --git a/test/sanitizer_common/ios_commands/iossim_env.py b/test/sanitizer_common/ios_commands/iossim_env.py
new file mode 100755
index 000000000000..28f626900f0b
--- /dev/null
+++ b/test/sanitizer_common/ios_commands/iossim_env.py
@@ -0,0 +1,17 @@
+#!/usr/bin/python
+
+import os, sys, subprocess
+
+
+idx = 1
+for arg in sys.argv[1:]:
+ if not "=" in arg:
+ break
+ idx += 1
+ (argname, argval) = arg.split("=")
+ os.environ["SIMCTL_CHILD_" + argname] = argval
+
+exitcode = subprocess.call(sys.argv[idx:])
+if exitcode > 125:
+ exitcode = 126
+sys.exit(exitcode)
diff --git a/test/sanitizer_common/ios_commands/iossim_run.py b/test/sanitizer_common/ios_commands/iossim_run.py
new file mode 100755
index 000000000000..732880f35183
--- /dev/null
+++ b/test/sanitizer_common/ios_commands/iossim_run.py
@@ -0,0 +1,17 @@
+#!/usr/bin/python
+
+import os, sys, subprocess
+
+
+if not "SANITIZER_IOSSIM_TEST_DEVICE_IDENTIFIER" in os.environ:
+ raise EnvironmentError("Specify SANITIZER_IOSSIM_TEST_DEVICE_IDENTIFIER to select which simulator to use.")
+
+device_id = os.environ["SANITIZER_IOSSIM_TEST_DEVICE_IDENTIFIER"]
+
+if "ASAN_OPTIONS" in os.environ:
+ os.environ["SIMCTL_CHILD_ASAN_OPTIONS"] = os.environ["ASAN_OPTIONS"]
+
+exitcode = subprocess.call(["xcrun", "simctl", "spawn", device_id] + sys.argv[1:])
+if exitcode > 125:
+ exitcode = 126
+sys.exit(exitcode)
diff --git a/test/tsan/Darwin/xpc-cancel.mm b/test/tsan/Darwin/xpc-cancel.mm
index 5e326b7e4973..91dafc3eadda 100644
--- a/test/tsan/Darwin/xpc-cancel.mm
+++ b/test/tsan/Darwin/xpc-cancel.mm
@@ -1,6 +1,8 @@
// RUN: %clang_tsan %s -o %t -framework Foundation
// RUN: %run %t 2>&1 | FileCheck %s
+// XFAIL: ios
+
#import <Foundation/Foundation.h>
#import <xpc/xpc.h>
diff --git a/test/tsan/Darwin/xpc-race.mm b/test/tsan/Darwin/xpc-race.mm
index eaef4e06c1f6..2e965e4a0a1c 100644
--- a/test/tsan/Darwin/xpc-race.mm
+++ b/test/tsan/Darwin/xpc-race.mm
@@ -1,6 +1,8 @@
// RUN: %clang_tsan %s -o %t -framework Foundation
// RUN: %deflake %run %t 2>&1 | FileCheck %s
+// XFAIL: ios
+
#import <Foundation/Foundation.h>
#import <xpc/xpc.h>
@@ -74,8 +76,8 @@ int main(int argc, const char *argv[]) {
// CHECK: Hello world.
// CHECK: WARNING: ThreadSanitizer: data race
// CHECK: Write of size 8
-// CHECK: #0 {{.*}}xpc-race.mm:34
+// CHECK: #0 {{.*}}xpc-race.mm:36
// CHECK: Previous write of size 8
-// CHECK: #0 {{.*}}xpc-race.mm:34
+// CHECK: #0 {{.*}}xpc-race.mm:36
// CHECK: Location is global 'global'
// CHECK: Done.
diff --git a/test/tsan/Darwin/xpc.mm b/test/tsan/Darwin/xpc.mm
index 2d6de269b59f..c5e78a5779e0 100644
--- a/test/tsan/Darwin/xpc.mm
+++ b/test/tsan/Darwin/xpc.mm
@@ -1,6 +1,8 @@
// RUN: %clang_tsan %s -o %t -framework Foundation
// RUN: %run %t 2>&1 | FileCheck %s
+// XFAIL: ios
+
#import <Foundation/Foundation.h>
#import <xpc/xpc.h>
diff --git a/test/tsan/ignore_lib1.cc b/test/tsan/ignore_lib1.cc
index e6a13a394395..5949d811ed44 100644
--- a/test/tsan/ignore_lib1.cc
+++ b/test/tsan/ignore_lib1.cc
@@ -9,6 +9,9 @@
// in called_from_lib suppression are ignored.
// REQUIRES: stable-runtime
+// UNSUPPORTED: powerpc64le
+// FIXME: This test regularly fails on powerpc64 LE possibly starting with
+// r279664. Re-enable the test once the problem(s) have been fixed.
#ifndef LIB
diff --git a/test/tsan/ignore_lib5.cc b/test/tsan/ignore_lib5.cc
index d7cd28500be9..54630d534c34 100644
--- a/test/tsan/ignore_lib5.cc
+++ b/test/tsan/ignore_lib5.cc
@@ -6,6 +6,9 @@
// RUN: %env_tsan_opts=suppressions='%s.supp' %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-WITHSUPP
// REQUIRES: stable-runtime
+// UNSUPPORTED: powerpc64le
+// FIXME: This test occasionally fails on powerpc64 LE possibly starting with
+// r279664. Re-enable the test once the problem(s) have been fixed.
// Previously the test episodically failed with:
// ThreadSanitizer: called_from_lib suppression '/libignore_lib1.so$' is
diff --git a/test/ubsan/TestCases/Float/cast-overflow.cpp b/test/ubsan/TestCases/Float/cast-overflow.cpp
index 5f51553f4e4e..85c5049b40ab 100644
--- a/test/ubsan/TestCases/Float/cast-overflow.cpp
+++ b/test/ubsan/TestCases/Float/cast-overflow.cpp
@@ -86,42 +86,42 @@ int main(int argc, char **argv) {
case '0': {
// Note that values between 0x7ffffe00 and 0x80000000 may or may not
// successfully round-trip, depending on the rounding mode.
- // CHECK-0: {{.*}}cast-overflow.cpp:[[@LINE+1]]:27: runtime error: value 2.14748{{.*}} is outside the range of representable values of type 'int'
+ // CHECK-0: {{.*}}cast-overflow.cpp:[[@LINE+1]]:27: runtime error: 2.14748{{.*}} is outside the range of representable values of type 'int'
static int test_int = MaxFloatRepresentableAsInt + 0x80;
// CHECK-0: SUMMARY: {{.*}}Sanitizer: float-cast-overflow {{.*}}cast-overflow.cpp:[[@LINE-1]]
return 0;
}
case '1': {
- // CHECK-1: {{.*}}cast-overflow.cpp:[[@LINE+1]]:27: runtime error: value -2.14748{{.*}} is outside the range of representable values of type 'int'
+ // CHECK-1: {{.*}}cast-overflow.cpp:[[@LINE+1]]:27: runtime error: -2.14748{{.*}} is outside the range of representable values of type 'int'
static int test_int = MinFloatRepresentableAsInt - 0x100;
return 0;
}
case '2': {
- // CHECK-2: {{.*}}cast-overflow.cpp:[[@LINE+2]]:37: runtime error: value -1 is outside the range of representable values of type 'unsigned int'
+ // CHECK-2: {{.*}}cast-overflow.cpp:[[@LINE+2]]:37: runtime error: -1 is outside the range of representable values of type 'unsigned int'
volatile float f = -1.0;
volatile unsigned u = (unsigned)f;
return 0;
}
case '3': {
- // CHECK-3: {{.*}}cast-overflow.cpp:[[@LINE+1]]:37: runtime error: value 4.2949{{.*}} is outside the range of representable values of type 'unsigned int'
+ // CHECK-3: {{.*}}cast-overflow.cpp:[[@LINE+1]]:37: runtime error: 4.2949{{.*}} is outside the range of representable values of type 'unsigned int'
static int test_int = (unsigned)(MaxFloatRepresentableAsUInt + 0x100);
return 0;
}
case '4': {
- // CHECK-4: {{.*}}cast-overflow.cpp:[[@LINE+1]]:27: runtime error: value {{.*}} is outside the range of representable values of type 'int'
+ // CHECK-4: {{.*}}cast-overflow.cpp:[[@LINE+1]]:27: runtime error: {{.*}} is outside the range of representable values of type 'int'
static int test_int = Inf;
return 0;
}
case '5': {
- // CHECK-5: {{.*}}cast-overflow.cpp:[[@LINE+1]]:27: runtime error: value {{.*}} is outside the range of representable values of type 'int'
+ // CHECK-5: {{.*}}cast-overflow.cpp:[[@LINE+1]]:27: runtime error: {{.*}} is outside the range of representable values of type 'int'
static int test_int = NaN;
return 0;
}
// Integer -> floating point overflow.
case '6': {
- // CHECK-6: cast-overflow.cpp:[[@LINE+2]]:{{34: runtime error: value 0xffffff00000000000000000000000001 is outside the range of representable values of type 'float'| __int128 not supported}}
+ // CHECK-6: cast-overflow.cpp:[[@LINE+2]]:{{34: runtime error: 0xffffff00000000000000000000000001 is outside the range of representable values of type 'float'| __int128 not supported}}
#if defined(__SIZEOF_INT128__) && !defined(_WIN32)
static int test_int = (float)(FloatMaxAsUInt128 + 1);
return 0;
@@ -135,16 +135,16 @@ int main(int argc, char **argv) {
// FIXME: The backend cannot lower __fp16 operations on x86 yet.
//case '7':
// (__fp16)65504; // ok
- // // CHECK-7: runtime error: value 65505 is outside the range of representable values of type '__fp16'
+ // // CHECK-7: runtime error: 65505 is outside the range of representable values of type '__fp16'
// return (__fp16)65505;
// Floating point -> floating point overflow.
case '8':
- // CHECK-8: {{.*}}cast-overflow.cpp:[[@LINE+1]]:19: runtime error: value 1e+39 is outside the range of representable values of type 'float'
+ // CHECK-8: {{.*}}cast-overflow.cpp:[[@LINE+1]]:19: runtime error: 1e+39 is outside the range of representable values of type 'float'
return (float)1e39;
case '9':
volatile long double ld = 300.0;
- // CHECK-9: {{.*}}cast-overflow.cpp:[[@LINE+1]]:14: runtime error: value 300 is outside the range of representable values of type 'char'
+ // CHECK-9: {{.*}}cast-overflow.cpp:[[@LINE+1]]:14: runtime error: 300 is outside the range of representable values of type 'char'
char c = ld;
return c;
}
diff --git a/test/ubsan/TestCases/Misc/log-path_test.cc b/test/ubsan/TestCases/Misc/log-path_test.cc
index 5b45f0b6f847..40bb35a06aaf 100644
--- a/test/ubsan/TestCases/Misc/log-path_test.cc
+++ b/test/ubsan/TestCases/Misc/log-path_test.cc
@@ -32,5 +32,5 @@ int main(int argc, char *argv[]) {
return 0;
}
-// CHECK-ERROR: runtime error: value -4 is outside the range of representable values of type 'unsigned int'
+// CHECK-ERROR: runtime error: -4 is outside the range of representable values of type 'unsigned int'
diff --git a/test/ubsan/TestCases/Misc/missing_return.cpp b/test/ubsan/TestCases/Misc/missing_return.cpp
index 68082272d62c..7b56b97048e3 100644
--- a/test/ubsan/TestCases/Misc/missing_return.cpp
+++ b/test/ubsan/TestCases/Misc/missing_return.cpp
@@ -1,13 +1,10 @@
// RUN: %clangxx -fsanitize=return -g %s -O3 -o %t
// RUN: not %run %t 2>&1 | FileCheck %s
-// RUN: %env_ubsan_opts=print_stacktrace=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%os-STACKTRACE
+// RUN: %env_ubsan_opts=print_stacktrace=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-STACKTRACE
// CHECK: missing_return.cpp:[[@LINE+1]]:5: runtime error: execution reached the end of a value-returning function without returning a value
int f() {
-// Slow stack unwinding is not available on Darwin for now, see
-// https://code.google.com/p/address-sanitizer/issues/detail?id=137
-// CHECK-Linux-STACKTRACE: #0 {{.*}}f(){{.*}}missing_return.cpp:[[@LINE-3]]
-// CHECK-FreeBSD-STACKTRACE: #0 {{.*}}f(void){{.*}}missing_return.cpp:[[@LINE-4]]
+// CHECK-STACKTRACE: #0 {{.*}}f{{.*}}missing_return.cpp:[[@LINE-1]]
}
int main(int, char **argv) {
diff --git a/test/ubsan/TestCases/TypeCheck/misaligned.cpp b/test/ubsan/TestCases/TypeCheck/misaligned.cpp
index 35b1ec3fe706..b3ff3588ba28 100644
--- a/test/ubsan/TestCases/TypeCheck/misaligned.cpp
+++ b/test/ubsan/TestCases/TypeCheck/misaligned.cpp
@@ -11,7 +11,7 @@
// RUN: %run %t f1 2>&1 | FileCheck %s --check-prefix=CHECK-MEMFUN
// RUN: %run %t n1 2>&1 | FileCheck %s --check-prefix=CHECK-NEW
// RUN: %run %t u1 2>&1 | FileCheck %s --check-prefix=CHECK-UPCAST
-// RUN: %env_ubsan_opts=print_stacktrace=1 %run %t l1 2>&1 | FileCheck %s --check-prefix=CHECK-LOAD --check-prefix=CHECK-%os-STACK-LOAD
+// RUN: %env_ubsan_opts=print_stacktrace=1 %run %t l1 2>&1 | FileCheck %s --check-prefix=CHECK-LOAD --check-prefix=CHECK-STACK-LOAD
// RUN: %clangxx -fsanitize=alignment -fno-sanitize-recover=alignment %s -O3 -o %t
// RUN: not %run %t w1 2>&1 | FileCheck %s --check-prefix=CHECK-WILD
@@ -47,11 +47,7 @@ int main(int, char **argv) {
// CHECK-LOAD-NEXT: {{^ 00 00 00 01 02 03 04 05}}
// CHECK-LOAD-NEXT: {{^ \^}}
return *p && 0;
- // Slow stack unwinding is disabled on Darwin for now, see
- // https://code.google.com/p/address-sanitizer/issues/detail?id=137
- // CHECK-Linux-STACK-LOAD: #0 {{.*}}main{{.*}}misaligned.cpp
- // Check for the already checked line to avoid lit error reports.
- // CHECK-Darwin-STACK-LOAD: {{ }}
+ // CHECK-STACK-LOAD: #0 {{.*}}main{{.*}}misaligned.cpp
case 's':
// CHECK-STORE: misaligned.cpp:[[@LINE+4]]{{(:5)?}}: runtime error: store to misaligned address [[PTR:0x[0-9a-f]*]] for type 'int', which requires 4 byte alignment