[compiler-rt] r210180 - [sancov] Handle fork.

Evgeniy Stepanov eugeni.stepanov at gmail.com
Tue Dec 23 00:58:49 PST 2014


This is the main mode of execution on Android.
And in Chromium.
Better keep it.


On Tue, Dec 23, 2014 at 1:53 AM, Kostya Serebryany <kcc at google.com> wrote:
> I've stumbled upon this test while changing how the coverage logic works...
> Do we need coverage to work after fork but before exec at all?
> It actually doesn't fully work today either, but I want to break it even
> more...
>
> On Wed, Jun 4, 2014 at 5:13 AM, Evgeniy Stepanov <eugeni.stepanov at gmail.com>
> wrote:
>>
>> Author: eugenis
>> Date: Wed Jun  4 07:13:54 2014
>> New Revision: 210180
>>
>> URL: http://llvm.org/viewvc/llvm-project?rev=210180&view=rev
>> Log:
>> [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.
>>
>> Added:
>>     compiler-rt/trunk/test/asan/TestCases/Linux/coverage-fork-direct.cc
>> (with props)
>>     compiler-rt/trunk/test/asan/TestCases/Linux/coverage-fork.cc   (with
>> props)
>> Modified:
>>     compiler-rt/trunk/lib/asan/asan_interceptors.cc
>>     compiler-rt/trunk/lib/asan/asan_interceptors.h
>>     compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.h
>>     compiler-rt/trunk/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
>>
>> compiler-rt/trunk/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc
>>
>> Modified: compiler-rt/trunk/lib/asan/asan_interceptors.cc
>> URL:
>> http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_interceptors.cc?rev=210180&r1=210179&r2=210180&view=diff
>>
>> ==============================================================================
>> --- compiler-rt/trunk/lib/asan/asan_interceptors.cc (original)
>> +++ compiler-rt/trunk/lib/asan/asan_interceptors.cc Wed Jun  4 07:13:54
>> 2014
>> @@ -697,6 +697,16 @@ INTERCEPTOR(int, __cxa_atexit, void (*fu
>>  }
>>  #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();
>>
>> Modified: compiler-rt/trunk/lib/asan/asan_interceptors.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_interceptors.h?rev=210180&r1=210179&r2=210180&view=diff
>>
>> ==============================================================================
>> --- compiler-rt/trunk/lib/asan/asan_interceptors.h (original)
>> +++ compiler-rt/trunk/lib/asan/asan_interceptors.h Wed Jun  4 07:13:54
>> 2014
>> @@ -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
>>
>> Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.h?rev=210180&r1=210179&r2=210180&view=diff
>>
>> ==============================================================================
>> --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.h (original)
>> +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.h Wed Jun  4
>> 07:13:54 2014
>> @@ -193,6 +193,8 @@ void CovPrepareForSandboxing(__sanitizer
>>  void SetSandboxingCallback(void (*f)());
>>
>>  void CovUpdateMapping();
>> +void CovBeforeFork();
>> +void CovAfterFork(int child_pid);
>>
>>  void InitTlsSize();
>>  uptr GetTlsSize();
>>
>> Modified:
>> compiler-rt/trunk/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
>> URL:
>> http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_coverage_libcdep.cc?rev=210180&r1=210179&r2=210180&view=diff
>>
>> ==============================================================================
>> --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
>> (original)
>> +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
>> Wed Jun  4 07:13:54 2014
>> @@ -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" {
>>
>> Modified:
>> compiler-rt/trunk/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc
>> URL:
>> http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc?rev=210180&r1=210179&r2=210180&view=diff
>>
>> ==============================================================================
>> ---
>> compiler-rt/trunk/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc
>> (original)
>> +++
>> compiler-rt/trunk/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc
>> Wed Jun  4 07:13:54 2014
>> @@ -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 +
>>
>> Added: compiler-rt/trunk/test/asan/TestCases/Linux/coverage-fork-direct.cc
>> URL:
>> http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/asan/TestCases/Linux/coverage-fork-direct.cc?rev=210180&view=auto
>>
>> ==============================================================================
>> --- compiler-rt/trunk/test/asan/TestCases/Linux/coverage-fork-direct.cc
>> (added)
>> +++ compiler-rt/trunk/test/asan/TestCases/Linux/coverage-fork-direct.cc
>> Wed Jun  4 07:13:54 2014
>> @@ -0,0 +1,38 @@
>> +// RUN: %clangxx_asan -mllvm -asan-coverage=1 %s -o %t
>> +// RUN: rm -rf %T/coverage-fork-direct
>> +// RUN: mkdir -p %T/coverage-fork-direct && cd %T/coverage-fork-direct
>> +// RUN: (ASAN_OPTIONS=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
>>
>> Propchange:
>> compiler-rt/trunk/test/asan/TestCases/Linux/coverage-fork-direct.cc
>>
>> ------------------------------------------------------------------------------
>>     svn:eol-style = LF
>>
>> Added: compiler-rt/trunk/test/asan/TestCases/Linux/coverage-fork.cc
>> URL:
>> http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/asan/TestCases/Linux/coverage-fork.cc?rev=210180&view=auto
>>
>> ==============================================================================
>> --- compiler-rt/trunk/test/asan/TestCases/Linux/coverage-fork.cc (added)
>> +++ compiler-rt/trunk/test/asan/TestCases/Linux/coverage-fork.cc Wed Jun
>> 4 07:13:54 2014
>> @@ -0,0 +1,38 @@
>> +// RUN: %clangxx_asan -mllvm -asan-coverage=1 %s -o %t
>> +// RUN: export ASAN_OPTIONS=coverage=1:coverage_direct=0:verbosity=1
>> +// RUN: rm -rf %T/coverage-fork
>> +// RUN: mkdir -p %T/coverage-fork && cd %T/coverage-fork
>> +// RUN: %run %t 2>&1 | FileCheck %s
>> +//
>> +// 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: [[ChildPID]].sancov: 1 PCs written
>> +// CHECK-DAG: Parent PID: [[ParentPID:[0-9]+]]
>> +// CHECK-DAG: [[ParentPID]].sancov: 3 PCs written
>>
>> Propchange: compiler-rt/trunk/test/asan/TestCases/Linux/coverage-fork.cc
>>
>> ------------------------------------------------------------------------------
>>     svn:eol-style = LF
>>
>>
>> _______________________________________________
>> llvm-commits mailing list
>> llvm-commits at cs.uiuc.edu
>> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits



More information about the llvm-commits mailing list