summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorEvgeniy Stepanov <eugeni.stepanov@gmail.com>2014-06-04 12:13:54 +0000
committerEvgeniy Stepanov <eugeni.stepanov@gmail.com>2014-06-04 12:13:54 +0000
commit03a95f4ed435d58ab742eeabc83ad59320b4840f (patch)
treea2a48e6d5171b61e313899e9c470439996f37888 /lib
parent29c00f1ff1d6294bf6f6298ef4246b31f08e082c (diff)
[sancov] Handle fork.
Reset coverage data on fork(). For memory-mapped mode (coverage_direct=1) this helps avoid loss of data (before this change two processes would write to the same file simultaneously). For normal mode, this reduces coverage dump size, because PCs from the parent process are no longer inherited by the child. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@210180 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r--lib/asan/asan_interceptors.cc14
-rw-r--r--lib/asan/asan_interceptors.h2
-rw-r--r--lib/sanitizer_common/sanitizer_common.h2
-rw-r--r--lib/sanitizer_common/sanitizer_coverage_libcdep.cc42
-rw-r--r--lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc27
5 files changed, 79 insertions, 8 deletions
diff --git a/lib/asan/asan_interceptors.cc b/lib/asan/asan_interceptors.cc
index 9dccddfa7..4ae03ece2 100644
--- a/lib/asan/asan_interceptors.cc
+++ b/lib/asan/asan_interceptors.cc
@@ -697,6 +697,16 @@ INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
}
#endif // ASAN_INTERCEPT___CXA_ATEXIT
+#if ASAN_INTERCEPT_FORK
+INTERCEPTOR(int, fork, void) {
+ ENSURE_ASAN_INITED();
+ if (common_flags()->coverage) CovBeforeFork();
+ int pid = REAL(fork)();
+ if (common_flags()->coverage) CovAfterFork(pid);
+ return pid;
+}
+#endif // ASAN_INTERCEPT_FORK
+
#if SANITIZER_WINDOWS
INTERCEPTOR_WINAPI(DWORD, CreateThread,
void* security, uptr stack_size,
@@ -808,6 +818,10 @@ void InitializeAsanInterceptors() {
ASAN_INTERCEPT_FUNC(__cxa_atexit);
#endif
+#if ASAN_INTERCEPT_FORK
+ ASAN_INTERCEPT_FUNC(fork);
+#endif
+
// Some Windows-specific interceptors.
#if SANITIZER_WINDOWS
InitializeWindowsInterceptors();
diff --git a/lib/asan/asan_interceptors.h b/lib/asan/asan_interceptors.h
index 3b7b2653b..9ba4cd7bf 100644
--- a/lib/asan/asan_interceptors.h
+++ b/lib/asan/asan_interceptors.h
@@ -27,6 +27,7 @@
# define ASAN_INTERCEPT_INDEX 1
# define ASAN_INTERCEPT_PTHREAD_CREATE 1
# define ASAN_INTERCEPT_MLOCKX 1
+# define ASAN_INTERCEPT_FORK 1
#else
# define ASAN_INTERCEPT_ATOLL_AND_STRTOLL 0
# define ASAN_INTERCEPT__LONGJMP 0
@@ -34,6 +35,7 @@
# define ASAN_INTERCEPT_INDEX 0
# define ASAN_INTERCEPT_PTHREAD_CREATE 0
# define ASAN_INTERCEPT_MLOCKX 0
+# define ASAN_INTERCEPT_FORK 0
#endif
#if SANITIZER_FREEBSD || SANITIZER_LINUX
diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h
index 7411b8dd9..435e1fafb 100644
--- a/lib/sanitizer_common/sanitizer_common.h
+++ b/lib/sanitizer_common/sanitizer_common.h
@@ -193,6 +193,8 @@ void CovPrepareForSandboxing(__sanitizer_sandbox_arguments *args);
void SetSandboxingCallback(void (*f)());
void CovUpdateMapping();
+void CovBeforeFork();
+void CovAfterFork(int child_pid);
void InitTlsSize();
uptr GetTlsSize();
diff --git a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
index e0f021f89..206d07ccd 100644
--- a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
@@ -59,6 +59,8 @@ namespace __sanitizer {
class CoverageData {
public:
void Init();
+ void BeforeFork();
+ void AfterFork(int child_pid);
void Extend(uptr npcs);
void Add(uptr pc);
@@ -86,6 +88,7 @@ class CoverageData {
StaticSpinMutex mu;
void DirectOpen();
+ void ReInit();
};
static CoverageData coverage_data;
@@ -107,23 +110,47 @@ void CoverageData::DirectOpen() {
void CoverageData::Init() {
pc_array = reinterpret_cast<uptr *>(
MmapNoReserveOrDie(sizeof(uptr) * kPcArrayMaxSize, "CovInit"));
+ pc_fd = kInvalidFd;
if (common_flags()->coverage_direct) {
atomic_store(&pc_array_size, 0, memory_order_relaxed);
atomic_store(&pc_array_index, 0, memory_order_relaxed);
} else {
- pc_fd = 0;
atomic_store(&pc_array_size, kPcArrayMaxSize, memory_order_relaxed);
atomic_store(&pc_array_index, 0, memory_order_relaxed);
}
}
+void CoverageData::ReInit() {
+ internal_munmap(pc_array, sizeof(uptr) * kPcArrayMaxSize);
+ if (pc_fd != kInvalidFd) internal_close(pc_fd);
+ if (common_flags()->coverage_direct) {
+ // In memory-mapped mode we must extend the new file to the known array
+ // size.
+ uptr size = atomic_load(&pc_array_size, memory_order_relaxed);
+ Init();
+ if (size) Extend(size);
+ } else {
+ Init();
+ }
+}
+
+void CoverageData::BeforeFork() {
+ mu.Lock();
+}
+
+void CoverageData::AfterFork(int child_pid) {
+ // We are single-threaded so it's OK to release the lock early.
+ mu.Unlock();
+ if (child_pid == 0) ReInit();
+}
+
// Extend coverage PC array to fit additional npcs elements.
void CoverageData::Extend(uptr npcs) {
if (!common_flags()->coverage_direct) return;
SpinMutexLock l(&mu);
- if (!pc_fd) DirectOpen();
- CHECK(pc_fd);
+ if (pc_fd == kInvalidFd) DirectOpen();
+ CHECK_NE(pc_fd, kInvalidFd);
uptr size = atomic_load(&pc_array_size, memory_order_relaxed);
size += npcs * sizeof(uptr);
@@ -324,6 +351,15 @@ int MaybeOpenCovFile(const char *name) {
if (!common_flags()->coverage) return -1;
return CovOpenFile(true /* packed */, name);
}
+
+void CovBeforeFork() {
+ coverage_data.BeforeFork();
+}
+
+void CovAfterFork(int child_pid) {
+ coverage_data.AfterFork(child_pid);
+}
+
} // namespace __sanitizer
extern "C" {
diff --git a/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc b/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc
index b3c8dc891..bfeb32107 100644
--- a/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc
@@ -36,8 +36,27 @@
namespace __sanitizer {
static const uptr kMaxNumberOfModules = 1 << 14;
+static const uptr kMaxTextSize = 64 * 1024;
-static char *last_mapping;
+struct CachedMapping {
+ public:
+ bool TestAndUpdate(const char *new_mapping) {
+ int new_pid = internal_getpid();
+ if (last_mapping && last_pid == new_pid &&
+ internal_strcmp(last_mapping, new_mapping) == 0)
+ return false;
+ if (!last_mapping) last_mapping = (char *)InternalAlloc(kMaxTextSize);
+ last_pid = new_pid;
+ internal_strncpy(last_mapping, new_mapping, kMaxTextSize);
+ return true;
+ }
+
+ private:
+ char *last_mapping;
+ int last_pid;
+};
+
+static CachedMapping cached_mapping;
static StaticSpinMutex mapping_mu;
void CovUpdateMapping() {
@@ -45,7 +64,6 @@ void CovUpdateMapping() {
SpinMutexLock l(&mapping_mu);
- const uptr kMaxTextSize = 64 * 1024;
InternalScopedString text(kMaxTextSize);
InternalScopedBuffer<char> modules_data(kMaxNumberOfModules *
sizeof(LoadedModule));
@@ -66,9 +84,8 @@ void CovUpdateMapping() {
}
// Do not write mapping if it is the same as the one we've wrote last time.
- if (last_mapping && (internal_strcmp(last_mapping, text.data()) == 0)) return;
- if (!last_mapping) last_mapping = (char *)InternalAlloc(kMaxTextSize);
- internal_strncpy(last_mapping, text.data(), kMaxTextSize);
+ if (!cached_mapping.TestAndUpdate(text.data()))
+ return;
int err;
InternalScopedString tmp_path(64 +