[compiler-rt] 682d635 - tsan: add kBrokenAliasedMetas condition and test

Thurston Dang via llvm-commits llvm-commits at lists.llvm.org
Wed Jan 11 10:24:00 PST 2023


Author: Thurston Dang
Date: 2023-01-11T18:15:04Z
New Revision: 682d635aa508860c306deae23766ca5e2575583a

URL: https://github.com/llvm/llvm-project/commit/682d635aa508860c306deae23766ca5e2575583a
DIFF: https://github.com/llvm/llvm-project/commit/682d635aa508860c306deae23766ca5e2575583a.diff

LOG: tsan: add kBrokenAliasedMetas condition and test

This fills in a gap in the tsan_shadow_test coverage:
it is possible that the meta regions are aliased
(e.g., the heap meta region overlaps the high app meta
region). Indeed, the Aarch64_39 mapping has been
silently broken in this way for quite some time.

This CL checks whether the individual meta regions
(for low/mid/high/heap) overlap. Note that
(!kBrokenAliasedMetas && !kBrokenLinearity) implies
that MemToMeta is invertible; we cannot directly
test MetaToMem because that function does not exist.

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

Added: 
    

Modified: 
    compiler-rt/lib/tsan/rtl/tsan_platform.h
    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 2d9cc883855c7..6527a885135b5 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_platform.h
+++ b/compiler-rt/lib/tsan/rtl/tsan_platform.h
@@ -34,6 +34,14 @@ enum {
   // This is bad and can lead to unpredictable memory corruptions, etc
   // because range access functions assume linearity.
   kBrokenLinearity = 1 << 2,
+  // Meta for an app region overlaps with the meta of another app region.
+  // This is determined by recomputing the individual meta regions for
+  // each app region.
+  //
+  // N.B. There is no "kBrokenReverseMetaMapping" constant because there
+  // is no MetaToMem function. However, note that (!kBrokenLinearity
+  // && !kBrokenAliasedMetas) implies that MemToMeta is invertible.
+  kBrokenAliasedMetas = 1 << 3,
 };
 
 /*
@@ -159,6 +167,7 @@ C/C++ on linux/aarch64 (39-bit VMA)
 7d00 0000 00 - 7fff ffff ff: modules and main thread stack
 */
 struct MappingAarch64_39 {
+  static const uptr kBroken = kBrokenAliasedMetas;
   static const uptr kLoAppMemBeg   = 0x0000001000ull;
   static const uptr kLoAppMemEnd   = 0x0100000000ull;
   static const uptr kShadowBeg = 0x0400000000ull;
@@ -191,7 +200,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 kBroken = kBrokenReverseMapping | kBrokenAliasedMetas;
   static const uptr kLoAppMemBeg   = 0x00000001000ull;
   static const uptr kLoAppMemEnd   = 0x01000000000ull;
   static const uptr kShadowBeg = 0x08000000000ull;
@@ -274,8 +283,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 kBroken = kBrokenMapping | kBrokenReverseMapping |
+                              kBrokenLinearity | kBrokenAliasedMetas;
   static const uptr kMetaShadowBeg = 0x0b0000000000ull;
   static const uptr kMetaShadowEnd = 0x0d0000000000ull;
   static const uptr kShadowBeg     = 0x000100000000ull;
@@ -286,6 +295,7 @@ struct MappingPPC64_44 {
   static const uptr kHeapMemEnd    = 0x0f5000000000ull;
   static const uptr kHiAppMemBeg   = 0x0f6000000000ull;
   static const uptr kHiAppMemEnd   = 0x100000000000ull; // 44 bits
+
   static const uptr kShadowMsk = 0x0f0000000000ull;
   static const uptr kShadowXor = 0x002100000000ull;
   static const uptr kShadowAdd = 0x000000000000ull;

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 ba49df7deda3c..78398acc253a6 100644
--- a/compiler-rt/lib/tsan/tests/unit/tsan_shadow_test.cpp
+++ b/compiler-rt/lib/tsan/tests/unit/tsan_shadow_test.cpp
@@ -15,6 +15,11 @@
 
 namespace __tsan {
 
+struct Region {
+  uptr start;
+  uptr end;
+};
+
 void CheckShadow(const Shadow *s, Sid sid, Epoch epoch, uptr addr, uptr size,
                  AccessType typ) {
   uptr addr1 = 0;
@@ -126,6 +131,30 @@ bool broken(uptr what, typename Has<Mapping::kBroken>::Result = false) {
   return Mapping::kBroken & what;
 }
 
+static int CompareRegion(const void *region_a, const void *region_b) {
+  uptr start_a = ((struct Region *)region_a)->start;
+  uptr start_b = ((struct Region *)region_b)->start;
+
+  if (start_a < start_b) {
+    return -1;
+  } else if (start_a > start_b) {
+    return 1;
+  } else {
+    return 0;
+  }
+}
+
+template <typename Mapping>
+static void AddMetaRegion(struct Region *shadows, int *num_regions, uptr start,
+                          uptr end) {
+  // If the app region is not empty, add its meta to the array.
+  if (start != end) {
+    shadows[*num_regions].start = (uptr)MemToMetaImpl::Apply<Mapping>(start);
+    shadows[*num_regions].end = (uptr)MemToMetaImpl::Apply<Mapping>(end - 1);
+    *num_regions = (*num_regions) + 1;
+  }
+}
+
 struct MappingTest {
   template <typename Mapping>
   static void Apply() {
@@ -135,6 +164,11 @@ struct MappingTest {
     TestRegion<Mapping>(Mapping::kMidAppMemBeg, Mapping::kMidAppMemEnd);
     TestRegion<Mapping>(Mapping::kHiAppMemBeg, Mapping::kHiAppMemEnd);
     TestRegion<Mapping>(Mapping::kHeapMemBeg, Mapping::kHeapMemEnd);
+
+    TestDisjointMetas<Mapping>();
+
+    // Not tested: the ordering of regions (low app vs. shadow vs. mid app
+    // etc.). That is enforced at runtime by CheckAndProtect.
   }
 
   template <typename Mapping>
@@ -172,6 +206,41 @@ struct MappingTest {
       }
     }
   }
+
+  template <typename Mapping>
+  static void TestDisjointMetas() {
+    // Checks that the meta for each app region does not overlap with
+    // the meta for other app regions. For example, the meta for a high
+    // app pointer shouldn't be aliased to the meta of a mid app pointer.
+    // Notice that this is important even though there does not exist a
+    // MetaToMem function.
+    // (If a MetaToMem function did exist, we could simply
+    // check in the TestRegion function that it inverts MemToMeta.)
+    //
+    // We don't try to be clever by allowing the non-PIE (low app)
+    // and PIE (mid and high app) meta regions to overlap.
+    struct Region metas[4];
+    int num_regions = 0;
+    AddMetaRegion<Mapping>(metas, &num_regions, Mapping::kLoAppMemBeg,
+                           Mapping::kLoAppMemEnd);
+    AddMetaRegion<Mapping>(metas, &num_regions, Mapping::kMidAppMemBeg,
+                           Mapping::kMidAppMemEnd);
+    AddMetaRegion<Mapping>(metas, &num_regions, Mapping::kHiAppMemBeg,
+                           Mapping::kHiAppMemEnd);
+    AddMetaRegion<Mapping>(metas, &num_regions, Mapping::kHeapMemBeg,
+                           Mapping::kHeapMemEnd);
+
+    // It is not required that the low app shadow is below the mid app
+    // shadow etc., hence we sort the shadows.
+    qsort(metas, num_regions, sizeof(struct Region), CompareRegion);
+
+    for (int i = 0; i < num_regions; i++)
+      Printf("[0x%lu, 0x%lu]\n", metas[i].start, metas[i].end);
+
+    if (!broken<Mapping>(kBrokenAliasedMetas))
+      for (int i = 1; i < num_regions; i++)
+        CHECK(metas[i - 1].end <= metas[i].start);
+  }
 };
 
 TEST(Shadow, AllMappings) { ForEachMapping<MappingTest>(); }


        


More information about the llvm-commits mailing list