[compiler-rt] r371439 - [TSan] Add interceptors for mach_vm_[de]allocate

Julian Lettner via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 9 11:57:32 PDT 2019


Author: yln
Date: Mon Sep  9 11:57:32 2019
New Revision: 371439

URL: http://llvm.org/viewvc/llvm-project?rev=371439&view=rev
Log:
[TSan] Add interceptors for mach_vm_[de]allocate

I verified that the test is red without the interceptors.

rdar://40334350

Reviewed By: kubamracek, vitalybuka

Differential Revision: https://reviews.llvm.org/D66616

Added:
    compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors_mach_vm.cpp
    compiler-rt/trunk/test/tsan/Darwin/mach_vm_allocate.c
Modified:
    compiler-rt/trunk/lib/tsan/CMakeLists.txt
    compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cpp
    compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.cpp
    compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h

Modified: compiler-rt/trunk/lib/tsan/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/CMakeLists.txt?rev=371439&r1=371438&r2=371439&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/CMakeLists.txt (original)
+++ compiler-rt/trunk/lib/tsan/CMakeLists.txt Mon Sep  9 11:57:32 2019
@@ -63,6 +63,7 @@ set(TSAN_CXX_SOURCES
 if(APPLE)
   list(APPEND TSAN_SOURCES
     rtl/tsan_interceptors_mac.cpp
+    rtl/tsan_interceptors_mach_vm.cpp
     rtl/tsan_platform_mac.cpp
     rtl/tsan_platform_posix.cpp
     )

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cpp?rev=371439&r1=371438&r2=371439&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cpp (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cpp Mon Sep  9 11:57:32 2019
@@ -745,6 +745,8 @@ TSAN_INTERCEPTOR(char*, strdup, const ch
   return REAL(strdup)(str);
 }
 
+// Zero out addr if it points into shadow memory and was provided as a hint
+// only, i.e., MAP_FIXED is not set.
 static bool fix_mmap_addr(void **addr, long_t sz, int flags) {
   if (*addr) {
     if (!IsAppMem((uptr)*addr) || !IsAppMem((uptr)*addr + sz - 1)) {
@@ -767,22 +769,14 @@ static void *mmap_interceptor(ThreadStat
   void *res = real_mmap(addr, sz, prot, flags, fd, off);
   if (res != MAP_FAILED) {
     if (fd > 0) FdAccess(thr, pc, fd);
-    if (thr->ignore_reads_and_writes == 0)
-      MemoryRangeImitateWrite(thr, pc, (uptr)res, sz);
-    else
-      MemoryResetRange(thr, pc, (uptr)res, sz);
+    MemoryRangeImitateWriteOrResetRange(thr, pc, (uptr)res, sz);
   }
   return res;
 }
 
 TSAN_INTERCEPTOR(int, munmap, void *addr, long_t sz) {
   SCOPED_TSAN_INTERCEPTOR(munmap, addr, sz);
-  if (sz != 0) {
-    // If sz == 0, munmap will return EINVAL and don't unmap any memory.
-    DontNeedShadowFor((uptr)addr, sz);
-    ScopedGlobalProcessor sgp;
-    ctx->metamap.ResetRange(thr->proc(), (uptr)addr, (uptr)sz);
-  }
+  UnmapShadow(thr, (uptr)addr, sz);
   int res = REAL(munmap)(addr, sz);
   return res;
 }

Added: compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors_mach_vm.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors_mach_vm.cpp?rev=371439&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors_mach_vm.cpp (added)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors_mach_vm.cpp Mon Sep  9 11:57:32 2019
@@ -0,0 +1,52 @@
+//===-- tsan_interceptors_mach_vm.cpp -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer (TSan), a race detector.
+//
+// Interceptors for mach_vm_* user space memory routines on Darwin.
+//===----------------------------------------------------------------------===//
+
+#include "interception/interception.h"
+#include "tsan_interceptors.h"
+#include "tsan_platform.h"
+
+#include <mach/mach.h>
+
+namespace __tsan {
+
+static bool intersects_with_shadow(mach_vm_address_t *address,
+                                   mach_vm_size_t size, int flags) {
+  // VM_FLAGS_FIXED is 0x0, so we have to test for VM_FLAGS_ANYWHERE.
+  if (flags & VM_FLAGS_ANYWHERE) return false;
+  uptr ptr = *address;
+  return !IsAppMem(ptr) || !IsAppMem(ptr + size - 1);
+}
+
+TSAN_INTERCEPTOR(kern_return_t, mach_vm_allocate, vm_map_t target,
+                 mach_vm_address_t *address, mach_vm_size_t size, int flags) {
+  SCOPED_TSAN_INTERCEPTOR(mach_vm_allocate, target, address, size, flags);
+  if (target != mach_task_self())
+    return REAL(mach_vm_allocate)(target, address, size, flags);
+  if (intersects_with_shadow(address, size, flags))
+    return KERN_NO_SPACE;
+  kern_return_t res = REAL(mach_vm_allocate)(target, address, size, flags);
+  if (res == KERN_SUCCESS)
+    MemoryRangeImitateWriteOrResetRange(thr, pc, *address, size);
+  return res;
+}
+
+TSAN_INTERCEPTOR(kern_return_t, mach_vm_deallocate, vm_map_t target,
+                 mach_vm_address_t address, mach_vm_size_t size) {
+  SCOPED_TSAN_INTERCEPTOR(mach_vm_deallocate, target, address, size);
+  if (target != mach_task_self())
+    return REAL(mach_vm_deallocate)(target, address, size);
+  UnmapShadow(thr, address, size);
+  return REAL(mach_vm_deallocate)(target, address, size);
+}
+
+}  // namespace __tsan

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.cpp?rev=371439&r1=371438&r2=371439&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.cpp (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.cpp Mon Sep  9 11:57:32 2019
@@ -239,6 +239,15 @@ void DontNeedShadowFor(uptr addr, uptr s
   ReleaseMemoryPagesToOS(MemToShadow(addr), MemToShadow(addr + size));
 }
 
+#if !SANITIZER_GO
+void UnmapShadow(ThreadState *thr, uptr addr, uptr size) {
+  if (size == 0) return;
+  DontNeedShadowFor(addr, size);
+  ScopedGlobalProcessor sgp;
+  ctx->metamap.ResetRange(thr->proc(), addr, size);
+}
+#endif
+
 void MapShadow(uptr addr, uptr size) {
   // Global data is not 64K aligned, but there are no adjacent mappings,
   // so we can get away with unaligned mapping.
@@ -987,6 +996,14 @@ void MemoryRangeImitateWrite(ThreadState
   MemoryRangeSet(thr, pc, addr, size, s.raw());
 }
 
+void MemoryRangeImitateWriteOrResetRange(ThreadState *thr, uptr pc, uptr addr,
+                                         uptr size) {
+  if (thr->ignore_reads_and_writes == 0)
+    MemoryRangeImitateWrite(thr, pc, addr, size);
+  else
+    MemoryResetRange(thr, pc, addr, size);
+}
+
 ALWAYS_INLINE USED
 void FuncEntry(ThreadState *thr, uptr pc) {
   StatInc(thr, StatFuncEnter);

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h?rev=371439&r1=371438&r2=371439&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h Mon Sep  9 11:57:32 2019
@@ -680,6 +680,7 @@ void ALWAYS_INLINE StatSet(ThreadState *
 void MapShadow(uptr addr, uptr size);
 void MapThreadTrace(uptr addr, uptr size, const char *name);
 void DontNeedShadowFor(uptr addr, uptr size);
+void UnmapShadow(ThreadState *thr, uptr addr, uptr size);
 void InitializeShadowMemory();
 void InitializeInterceptors();
 void InitializeLibIgnore();
@@ -759,6 +760,8 @@ void ALWAYS_INLINE MemoryWriteAtomic(Thr
 void MemoryResetRange(ThreadState *thr, uptr pc, uptr addr, uptr size);
 void MemoryRangeFreed(ThreadState *thr, uptr pc, uptr addr, uptr size);
 void MemoryRangeImitateWrite(ThreadState *thr, uptr pc, uptr addr, uptr size);
+void MemoryRangeImitateWriteOrResetRange(ThreadState *thr, uptr pc, uptr addr,
+                                         uptr size);
 
 void ThreadIgnoreBegin(ThreadState *thr, uptr pc, bool save_stack = true);
 void ThreadIgnoreEnd(ThreadState *thr, uptr pc);

Added: compiler-rt/trunk/test/tsan/Darwin/mach_vm_allocate.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/tsan/Darwin/mach_vm_allocate.c?rev=371439&view=auto
==============================================================================
--- compiler-rt/trunk/test/tsan/Darwin/mach_vm_allocate.c (added)
+++ compiler-rt/trunk/test/tsan/Darwin/mach_vm_allocate.c Mon Sep  9 11:57:32 2019
@@ -0,0 +1,73 @@
+// Test that mach_vm_[de]allocate resets shadow memory status.
+//
+// RUN: %clang_tsan %s -o %t
+// RUN: %run %t 2>&1 | FileCheck %s --implicit-check-not='ThreadSanitizer'
+
+#include <mach/mach.h>
+#include <mach/mach_vm.h>
+#include <pthread.h>
+#include <assert.h>
+#include <stdio.h>
+
+#include "../test.h"
+
+void AnnotateIgnoreReadsBegin(const char *f, int l);
+void AnnotateIgnoreReadsEnd(const char *f, int l);
+void AnnotateIgnoreWritesBegin(const char *f, int l);
+void AnnotateIgnoreWritesEnd(const char *f, int l);
+
+static int *global_ptr;
+const mach_vm_size_t alloc_size = sizeof(int);
+
+static int *alloc() {
+  mach_vm_address_t addr;
+  kern_return_t res =
+      mach_vm_allocate(mach_task_self(), &addr, alloc_size, VM_FLAGS_ANYWHERE);
+  assert(res == KERN_SUCCESS);
+  return (int *)addr;
+}
+
+static void alloc_fixed(int *ptr) {
+  mach_vm_address_t addr = (mach_vm_address_t)ptr;
+  kern_return_t res =
+      mach_vm_allocate(mach_task_self(), &addr, alloc_size, VM_FLAGS_FIXED);
+  assert(res == KERN_SUCCESS);
+}
+
+static void dealloc(int *ptr) {
+  kern_return_t res =
+      mach_vm_deallocate(mach_task_self(), (mach_vm_address_t)ptr, alloc_size);
+  assert(res == KERN_SUCCESS);
+}
+
+static void *Thread(void *arg) {
+  *global_ptr = 7;  // Assignment 1
+
+  // We want to test that TSan does not report a race between the two
+  // assignments to global_ptr when memory is re-allocated here. The calls to
+  // the API itself are racy though, so ignore them.
+  AnnotateIgnoreWritesBegin(__FILE__, __LINE__);
+  dealloc(global_ptr);
+  alloc_fixed(global_ptr);
+  AnnotateIgnoreWritesEnd(__FILE__, __LINE__);
+
+  barrier_wait(&barrier);
+  return NULL;;
+}
+
+int main(int argc, const char *argv[]) {
+  barrier_init(&barrier, 2);
+  global_ptr = alloc();
+  pthread_t t;
+  pthread_create(&t, NULL, Thread, NULL);
+
+  barrier_wait(&barrier);
+  *global_ptr = 8;  // Assignment 2
+
+  pthread_join(t, NULL);
+  dealloc(global_ptr);
+  printf("Done.\n");
+  return 0;
+}
+
+// CHECK: Done.




More information about the llvm-commits mailing list