[compiler-rt] 0ebfe7c - tsan: unit-test all mappings

Dmitry Vyukov via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 10 11:07:19 PDT 2021


Author: Dmitry Vyukov
Date: 2021-08-10T20:07:15+02:00
New Revision: 0ebfe7c3126df8f6bc5b721053369065fa2d0c8c

URL: https://github.com/llvm/llvm-project/commit/0ebfe7c3126df8f6bc5b721053369065fa2d0c8c
DIFF: https://github.com/llvm/llvm-project/commit/0ebfe7c3126df8f6bc5b721053369065fa2d0c8c.diff

LOG: tsan: unit-test all mappings

Move the mapping checking logic from startup to unit tests
and test all mapping instead of just the active one.
This makes it much more feasible to make any global changes
to the mappings since we have 17 of them.

Depends on D107740.

Reviewed By: vitalybuka, melver

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

Added: 
    

Modified: 
    compiler-rt/lib/tsan/rtl/tsan_platform.h
    compiler-rt/lib/tsan/rtl/tsan_rtl.cpp
    compiler-rt/lib/tsan/tests/unit/tsan_shadow_test.cpp

Removed: 
    


################################################################################
diff  --git a/compiler-rt/lib/tsan/rtl/tsan_platform.h b/compiler-rt/lib/tsan/rtl/tsan_platform.h
index 4a752a237fb85..1cf764ace7f1d 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_platform.h
+++ b/compiler-rt/lib/tsan/rtl/tsan_platform.h
@@ -23,6 +23,19 @@
 
 namespace __tsan {
 
+enum {
+  // App memory is not mapped onto shadow memory range.
+  kBrokenMapping = 1 << 0,
+  // Mapping app memory and back does not produce the same address,
+  // this can lead to wrong addresses in reports and potentially
+  // other bad consequences.
+  kBrokenReverseMapping = 1 << 1,
+  // Mapping is non-linear for linear user range.
+  // This is bad and can lead to unpredictable memory corruptions, etc
+  // because range access functions assume linearity.
+  kBrokenLinearity = 1 << 2,
+};
+
 /*
 C/C++ on linux/x86_64 and freebsd/x86_64
 0000 0000 1000 - 0080 0000 0000: main binary and/or MAP_32BIT mappings (512GB)
@@ -195,6 +208,7 @@ C/C++ on linux/aarch64 (42-bit VMA)
 3f000 0000 00 - 3ffff ffff ff: modules and main thread stack
 */
 struct MappingAarch64_42 {
+  static const uptr kBroken = kBrokenReverseMapping;
   static const uptr kLoAppMemBeg   = 0x00000001000ull;
   static const uptr kLoAppMemEnd   = 0x01000000000ull;
   static const uptr kShadowBeg     = 0x10000000000ull;
@@ -251,6 +265,8 @@ C/C++ on linux/powerpc64 (44-bit VMA)
 0f60 0000 0000 - 1000 0000 0000: modules and main thread stack
 */
 struct MappingPPC64_44 {
+  static const uptr kBroken =
+      kBrokenMapping | kBrokenReverseMapping | kBrokenLinearity;
   static const uptr kMetaShadowBeg = 0x0b0000000000ull;
   static const uptr kMetaShadowEnd = 0x0d0000000000ull;
   static const uptr kTraceMemBeg   = 0x0d0000000000ull;
@@ -724,6 +740,27 @@ ALWAYS_INLINE auto SelectMapping(Arg arg) {
 #endif
 }
 
+template <typename Func>
+void ForEachMapping() {
+  Func::template Apply<Mapping48AddressSpace>();
+  Func::template Apply<MappingMips64_40>();
+  Func::template Apply<MappingAppleAarch64>();
+  Func::template Apply<MappingAarch64_39>();
+  Func::template Apply<MappingAarch64_42>();
+  Func::template Apply<MappingAarch64_48>();
+  Func::template Apply<MappingPPC64_44>();
+  Func::template Apply<MappingPPC64_46>();
+  Func::template Apply<MappingPPC64_47>();
+  Func::template Apply<MappingS390x>();
+  Func::template Apply<MappingGo48>();
+  Func::template Apply<MappingGoWindows>();
+  Func::template Apply<MappingGoPPC64_46>();
+  Func::template Apply<MappingGoPPC64_47>();
+  Func::template Apply<MappingGoAarch64>();
+  Func::template Apply<MappingGoMips64_47>();
+  Func::template Apply<MappingGoS390x>();
+}
+
 enum MappingType {
   MAPPING_LO_APP_BEG,
   MAPPING_LO_APP_END,
@@ -801,33 +838,6 @@ uptr HiAppMemEnd(void) {
 ALWAYS_INLINE
 uptr VdsoBeg(void) { return SelectMapping<MappingField>(MAPPING_VDSO_BEG); }
 
-static inline
-bool GetUserRegion(int i, uptr *start, uptr *end) {
-  switch (i) {
-  case 0:
-    *start = LoAppMemBeg();
-    *end = LoAppMemEnd();
-    return true;
-  case 1:
-    *start = HiAppMemBeg();
-    *end = HiAppMemEnd();
-    return true;
-  case 2:
-    *start = HeapMemBeg();
-    *end = HeapMemEnd();
-    return true;
-  case 3:
-    if (MidAppMemBeg()) {
-      *start = MidAppMemBeg();
-      *end = MidAppMemEnd();
-      return true;
-    }
-    FALLTHROUGH;
-  default:
-    return false;
-  }
-}
-
 ALWAYS_INLINE
 uptr ShadowBeg(void) { return SelectMapping<MappingField>(MAPPING_SHADOW_BEG); }
 ALWAYS_INLINE
@@ -920,12 +930,13 @@ u32 *MemToMeta(uptr x) { return SelectMapping<MemToMetaImpl>(x); }
 struct ShadowToMemImpl {
   template <typename Mapping>
   static uptr Apply(uptr sp) {
-    DCHECK(IsShadowMemImpl::Apply<Mapping>(sp));
-  // The shadow mapping is non-linear and we've lost some bits, so we don't have
-  // an easy way to restore the original app address. But the mapping is a
-  // bijection, so we try to restore the address as belonging to low/mid/high
-  // range consecutively and see if shadow->app->shadow mapping gives us the
-  // same address.
+    if (!IsShadowMemImpl::Apply<Mapping>(sp))
+      return 0;
+    // The shadow mapping is non-linear and we've lost some bits, so we don't
+    // have an easy way to restore the original app address. But the mapping is
+    // a bijection, so we try to restore the address as belonging to
+    // low/mid/high range consecutively and see if shadow->app->shadow mapping
+    // gives us the same address.
     uptr p = ((sp - Mapping::kShadowAdd) / kShadowCnt) ^ Mapping::kShadowXor;
     if (p >= Mapping::kLoAppMemBeg && p < Mapping::kLoAppMemEnd &&
         MemToShadowImpl::Apply<Mapping>(p) == sp)

diff  --git a/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp b/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp
index 080a106f14f8b..e82d727371886 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp
+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp
@@ -314,41 +314,6 @@ void MapThreadTrace(uptr addr, uptr size, const char *name) {
   }
 }
 
-static void CheckShadowMapping() {
-  uptr beg, end;
-  for (int i = 0; GetUserRegion(i, &beg, &end); i++) {
-    // Skip cases for empty regions (heap definition for architectures that
-    // do not use 64-bit allocator).
-    if (beg == end)
-      continue;
-    VPrintf(3, "checking shadow region %p-%p\n", beg, end);
-    uptr prev = 0;
-    for (uptr p0 = beg; p0 <= end; p0 += (end - beg) / 4) {
-      for (int x = -(int)kShadowCell; x <= (int)kShadowCell; x += kShadowCell) {
-        const uptr p = RoundDown(p0 + x, kShadowCell);
-        if (p < beg || p >= end)
-          continue;
-        RawShadow *const s = MemToShadow(p);
-        u32 *const m = MemToMeta(p);
-        VPrintf(3, "  checking pointer %p: shadow=%p meta=%p\n", p, s, m);
-        CHECK(IsAppMem(p));
-        CHECK(IsShadowMem(s));
-        CHECK_EQ(p, ShadowToMem(s));
-        CHECK(IsMetaMem(m));
-        if (prev) {
-          // Ensure that shadow and meta mappings are linear within a single
-          // user range. Lots of code that processes memory ranges assumes it.
-          RawShadow *const prev_s = MemToShadow(prev);
-          u32 *const prev_m = MemToMeta(prev);
-          CHECK_EQ((s - prev_s) * kShadowSize, (p - prev) * kShadowMultiplier);
-          CHECK_EQ(m - prev_m, (p - prev) / kMetaShadowCell);
-        }
-        prev = p;
-      }
-    }
-  }
-}
-
 #if !SANITIZER_GO
 static void OnStackUnwind(const SignalContext &sig, const void *,
                           BufferedStackTrace *stack) {
@@ -408,7 +373,6 @@ void Initialize(ThreadState *thr) {
   Processor *proc = ProcCreate();
   ProcWire(proc, thr);
   InitializeInterceptors();
-  CheckShadowMapping();
   InitializePlatform();
   InitializeDynamicAnnotations();
 #if !SANITIZER_GO

diff  --git a/compiler-rt/lib/tsan/tests/unit/tsan_shadow_test.cpp b/compiler-rt/lib/tsan/tests/unit/tsan_shadow_test.cpp
index 8f4cde797a819..3d5d482053fe8 100644
--- a/compiler-rt/lib/tsan/tests/unit/tsan_shadow_test.cpp
+++ b/compiler-rt/lib/tsan/tests/unit/tsan_shadow_test.cpp
@@ -74,4 +74,68 @@ TEST(Shadow, Celling) {
     CHECK_EQ(s0 + 2 * kShadowCnt, MemToShadow((uptr)&data[i]));
 }
 
+// Detect is the Mapping has kBroken field.
+template <uptr>
+struct Has {
+  typedef bool Result;
+};
+
+template <typename Mapping>
+bool broken(...) {
+  return false;
+}
+
+template <typename Mapping>
+bool broken(uptr what, typename Has<Mapping::kBroken>::Result = false) {
+  return Mapping::kBroken & what;
+}
+
+struct MappingTest {
+  template <typename Mapping>
+  static void Apply() {
+    // Easy (but ugly) way to print the mapping name.
+    Printf("%s\n", __PRETTY_FUNCTION__);
+    TestRegion<Mapping>(Mapping::kLoAppMemBeg, Mapping::kLoAppMemEnd);
+    TestRegion<Mapping>(Mapping::kMidAppMemBeg, Mapping::kMidAppMemEnd);
+    TestRegion<Mapping>(Mapping::kHiAppMemBeg, Mapping::kHiAppMemEnd);
+    TestRegion<Mapping>(Mapping::kHeapMemBeg, Mapping::kHeapMemEnd);
+  }
+
+  template <typename Mapping>
+  static void TestRegion(uptr beg, uptr end) {
+    if (beg == end)
+      return;
+    Printf("checking region [%p-%p)\n", beg, end);
+    uptr prev = 0;
+    for (uptr p0 = beg; p0 <= end; p0 += (end - beg) / 256) {
+      for (int x = -(int)kShadowCell; x <= (int)kShadowCell; x += kShadowCell) {
+        const uptr p = RoundDown(p0 + x, kShadowCell);
+        if (p < beg || p >= end)
+          continue;
+        const uptr s = MemToShadowImpl::Apply<Mapping>(p);
+        u32 *const m = MemToMetaImpl::Apply<Mapping>(p);
+        const uptr r = ShadowToMemImpl::Apply<Mapping>(s);
+        Printf("  addr=%p: shadow=%p meta=%p reverse=%p\n", p, s, m, r);
+        CHECK(IsAppMemImpl::Apply<Mapping>(p));
+        if (!broken<Mapping>(kBrokenMapping))
+          CHECK(IsShadowMemImpl::Apply<Mapping>(s));
+        CHECK(IsMetaMemImpl::Apply<Mapping>(reinterpret_cast<uptr>(m)));
+        if (!broken<Mapping>(kBrokenReverseMapping))
+          CHECK_EQ(p, r);
+        if (prev && !broken<Mapping>(kBrokenLinearity)) {
+          // Ensure that shadow and meta mappings are linear within a single
+          // user range. Lots of code that processes memory ranges assumes it.
+          const uptr prev_s = MemToShadowImpl::Apply<Mapping>(prev);
+          u32 *const prev_m = MemToMetaImpl::Apply<Mapping>(prev);
+          CHECK_EQ(s - prev_s, (p - prev) * kShadowMultiplier);
+          CHECK_EQ(m - prev_m, (p - prev) / kMetaShadowCell);
+        }
+        prev = p;
+      }
+    }
+  }
+};
+
+TEST(Shadow, AllMappings) { ForEachMapping<MappingTest>(); }
+
 }  // namespace __tsan


        


More information about the llvm-commits mailing list