[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.
llvm-svn: 210180
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep.cc b/compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
index e0f021f..206d07c 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
@@ -59,6 +59,8 @@
class CoverageData {
public:
void Init();
+ void BeforeFork();
+ void AfterFork(int child_pid);
void Extend(uptr npcs);
void Add(uptr pc);
@@ -86,6 +88,7 @@
StaticSpinMutex mu;
void DirectOpen();
+ void ReInit();
};
static CoverageData coverage_data;
@@ -107,23 +110,47 @@
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 @@
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" {