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

Kostya Serebryany kcc at google.com
Mon Dec 22 14:53:30 PST 2014


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
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20141222/7dd2edaf/attachment.html>


More information about the llvm-commits mailing list