diff --git a/compiler-rt/lib/tsan/rtl/tsan_platform.h b/compiler-rt/lib/tsan/rtl/tsan_platform.h --- a/compiler-rt/lib/tsan/rtl/tsan_platform.h +++ b/compiler-rt/lib/tsan/rtl/tsan_platform.h @@ -34,6 +34,14 @@ // 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 @@ 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 @@ 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 @@ 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 @@ 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 --- 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 @@ return Mapping::kBroken & what; } +static int compareRegion(const void *regionA, const void *regionB) { + uptr startA = ((struct region *)regionA)->start; + uptr startB = ((struct region *)regionB)->start; + + if (startA < startB) { + return -1; + } else if (startA > startB) { + return 1; + } else { + return 0; + } +} + +template +static void addMetaRegion(struct region *shadows, int *numRegions, uptr start, + uptr end) { + // If the app region is not empty, add its meta to the array. + if (start != end) { + shadows[*numRegions].start = (uptr)MemToMetaImpl::Apply(start); + shadows[*numRegions].end = (uptr)MemToMetaImpl::Apply(end - 1); + *numRegions = (*numRegions) + 1; + } +} + struct MappingTest { template static void Apply() { @@ -135,6 +164,11 @@ TestRegion(Mapping::kMidAppMemBeg, Mapping::kMidAppMemEnd); TestRegion(Mapping::kHiAppMemBeg, Mapping::kHiAppMemEnd); TestRegion(Mapping::kHeapMemBeg, Mapping::kHeapMemEnd); + + TestDisjointMetas(); + + // Not tested: the ordering of regions (low app vs. shadow vs. mid app + // etc.). That is enforced at runtime by CheckAndProtect. } template @@ -172,6 +206,44 @@ } } } + + template + static void TestDisjointMetas(void) { + // 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 numRegions = 0; + addMetaRegion(metas, &numRegions, Mapping::kLoAppMemBeg, + Mapping::kLoAppMemEnd); + addMetaRegion(metas, &numRegions, Mapping::kMidAppMemBeg, + Mapping::kMidAppMemEnd); + addMetaRegion(metas, &numRegions, Mapping::kHiAppMemBeg, + Mapping::kHiAppMemEnd); + addMetaRegion(metas, &numRegions, 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, numRegions, sizeof(struct region), compareRegion); + + for (int i = 0; i < numRegions; i++) { + Printf("[%p, %p]\n", metas[i].start, metas[i].end); + } + + if (!broken(kBrokenAliasedMetas)) { + for (int i = 1; i < numRegions; i++) { + CHECK(metas[i - 1].end <= metas[i].start); + } + } + } }; TEST(Shadow, AllMappings) { ForEachMapping(); }