brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.8 KiB · 0cc6c7d Raw
249 lines · cpp
1//===-- tsan_shadow_test.cpp ----------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file is a part of ThreadSanitizer (TSan), a race detector.10//11//===----------------------------------------------------------------------===//12#include "tsan_platform.h"13#include "tsan_rtl.h"14#include "gtest/gtest.h"15 16namespace __tsan {17 18struct Region {19  uptr start;20  uptr end;21};22 23void CheckShadow(const Shadow *s, Sid sid, Epoch epoch, uptr addr, uptr size,24                 AccessType typ) {25  uptr addr1 = 0;26  uptr size1 = 0;27  AccessType typ1 = 0;28  s->GetAccess(&addr1, &size1, &typ1);29  CHECK_EQ(s->sid(), sid);30  CHECK_EQ(s->epoch(), epoch);31  CHECK_EQ(addr1, addr);32  CHECK_EQ(size1, size);33  CHECK_EQ(typ1, typ);34}35 36TEST(Shadow, Shadow) {37  Sid sid = static_cast<Sid>(11);38  Epoch epoch = static_cast<Epoch>(22);39  FastState fs;40  fs.SetSid(sid);41  fs.SetEpoch(epoch);42  CHECK_EQ(fs.sid(), sid);43  CHECK_EQ(fs.epoch(), epoch);44  CHECK_EQ(fs.GetIgnoreBit(), false);45  fs.SetIgnoreBit();46  CHECK_EQ(fs.GetIgnoreBit(), true);47  fs.ClearIgnoreBit();48  CHECK_EQ(fs.GetIgnoreBit(), false);49 50  Shadow s0(fs, 1, 2, kAccessWrite);51  CheckShadow(&s0, sid, epoch, 1, 2, kAccessWrite);52  Shadow s1(fs, 2, 3, kAccessRead);53  CheckShadow(&s1, sid, epoch, 2, 3, kAccessRead);54  Shadow s2(fs, 0xfffff8 + 4, 1, kAccessWrite | kAccessAtomic);55  CheckShadow(&s2, sid, epoch, 4, 1, kAccessWrite | kAccessAtomic);56  Shadow s3(fs, 0xfffff8 + 0, 8, kAccessRead | kAccessAtomic);57  CheckShadow(&s3, sid, epoch, 0, 8, kAccessRead | kAccessAtomic);58 59  CHECK(!s0.IsBothReadsOrAtomic(kAccessRead | kAccessAtomic));60  CHECK(!s1.IsBothReadsOrAtomic(kAccessAtomic));61  CHECK(!s1.IsBothReadsOrAtomic(kAccessWrite));62  CHECK(s1.IsBothReadsOrAtomic(kAccessRead));63  CHECK(s2.IsBothReadsOrAtomic(kAccessAtomic));64  CHECK(!s2.IsBothReadsOrAtomic(kAccessWrite));65  CHECK(!s2.IsBothReadsOrAtomic(kAccessRead));66  CHECK(s3.IsBothReadsOrAtomic(kAccessAtomic));67  CHECK(!s3.IsBothReadsOrAtomic(kAccessWrite));68  CHECK(s3.IsBothReadsOrAtomic(kAccessRead));69 70  CHECK(!s0.IsRWWeakerOrEqual(kAccessRead | kAccessAtomic));71  CHECK(s1.IsRWWeakerOrEqual(kAccessWrite));72  CHECK(s1.IsRWWeakerOrEqual(kAccessRead));73  CHECK(!s1.IsRWWeakerOrEqual(kAccessWrite | kAccessAtomic));74 75  CHECK(!s2.IsRWWeakerOrEqual(kAccessRead | kAccessAtomic));76  CHECK(s2.IsRWWeakerOrEqual(kAccessWrite | kAccessAtomic));77  CHECK(s2.IsRWWeakerOrEqual(kAccessRead));78  CHECK(s2.IsRWWeakerOrEqual(kAccessWrite));79 80  CHECK(s3.IsRWWeakerOrEqual(kAccessRead | kAccessAtomic));81  CHECK(s3.IsRWWeakerOrEqual(kAccessWrite | kAccessAtomic));82  CHECK(s3.IsRWWeakerOrEqual(kAccessRead));83  CHECK(s3.IsRWWeakerOrEqual(kAccessWrite));84 85  Shadow sro(Shadow::kRodata);86  CheckShadow(&sro, static_cast<Sid>(0), kEpochZero, 0, 0, kAccessRead);87}88 89TEST(Shadow, Mapping) {90  static int global;91  int stack;92  void *heap = malloc(0);93  free(heap);94 95  CHECK(IsAppMem((uptr)&global));96  CHECK(IsAppMem((uptr)&stack));97  CHECK(IsAppMem((uptr)heap));98 99  CHECK(IsShadowMem(MemToShadow((uptr)&global)));100  CHECK(IsShadowMem(MemToShadow((uptr)&stack)));101  CHECK(IsShadowMem(MemToShadow((uptr)heap)));102}103 104TEST(Shadow, Celling) {105  u64 aligned_data[4];106  char *data = (char*)aligned_data;107  CHECK(IsAligned(reinterpret_cast<uptr>(data), kShadowSize));108  RawShadow *s0 = MemToShadow((uptr)&data[0]);109  CHECK(IsAligned(reinterpret_cast<uptr>(s0), kShadowSize));110  for (unsigned i = 1; i < kShadowCell; i++)111    CHECK_EQ(s0, MemToShadow((uptr)&data[i]));112  for (unsigned i = kShadowCell; i < 2*kShadowCell; i++)113    CHECK_EQ(s0 + kShadowCnt, MemToShadow((uptr)&data[i]));114  for (unsigned i = 2*kShadowCell; i < 3*kShadowCell; i++)115    CHECK_EQ(s0 + 2 * kShadowCnt, MemToShadow((uptr)&data[i]));116}117 118// Detect is the Mapping has kBroken field.119template <uptr>120struct Has {121  typedef bool Result;122};123 124template <typename Mapping>125bool broken(...) {126  return false;127}128 129template <typename Mapping>130bool broken(uptr what, typename Has<Mapping::kBroken>::Result = false) {131  return Mapping::kBroken & what;132}133 134static int CompareRegion(const void *region_a, const void *region_b) {135  uptr start_a = ((const struct Region *)region_a)->start;136  uptr start_b = ((const struct Region *)region_b)->start;137 138  if (start_a < start_b) {139    return -1;140  } else if (start_a > start_b) {141    return 1;142  } else {143    return 0;144  }145}146 147template <typename Mapping>148static void AddMetaRegion(struct Region *shadows, int *num_regions, uptr start,149                          uptr end) {150  // If the app region is not empty, add its meta to the array.151  if (start != end) {152    shadows[*num_regions].start = (uptr)MemToMetaImpl::Apply<Mapping>(start);153    shadows[*num_regions].end = (uptr)MemToMetaImpl::Apply<Mapping>(end - 1);154    *num_regions = (*num_regions) + 1;155  }156}157 158struct MappingTest {159  template <typename Mapping>160  static void Apply() {161    // Easy (but ugly) way to print the mapping name.162    Printf("%s\n", __PRETTY_FUNCTION__);163    TestRegion<Mapping>(Mapping::kLoAppMemBeg, Mapping::kLoAppMemEnd);164    TestRegion<Mapping>(Mapping::kMidAppMemBeg, Mapping::kMidAppMemEnd);165    TestRegion<Mapping>(Mapping::kHiAppMemBeg, Mapping::kHiAppMemEnd);166    TestRegion<Mapping>(Mapping::kHeapMemBeg, Mapping::kHeapMemEnd);167 168    TestDisjointMetas<Mapping>();169 170    // Not tested: the ordering of regions (low app vs. shadow vs. mid app171    // etc.). That is enforced at runtime by CheckAndProtect.172  }173 174  template <typename Mapping>175  static void TestRegion(uptr beg, uptr end) {176    if (beg == end)177      return;178    Printf("checking region [0x%zx-0x%zx)\n", beg, end);179    uptr prev = 0;180    for (uptr p0 = beg; p0 <= end; p0 += (end - beg) / 256) {181      for (int x = -(int)kShadowCell; x <= (int)kShadowCell; x += kShadowCell) {182        const uptr p = RoundDown(p0 + x, kShadowCell);183        if (p < beg || p >= end)184          continue;185        const uptr s = MemToShadowImpl::Apply<Mapping>(p);186        u32 *const m = MemToMetaImpl::Apply<Mapping>(p);187        const uptr r = ShadowToMemImpl::Apply<Mapping>(s);188        Printf("  addr=0x%zx: shadow=0x%zx meta=%p reverse=0x%zx\n", p, s, m,189               r);190        CHECK(IsAppMemImpl::Apply<Mapping>(p));191        if (!broken<Mapping>(kBrokenMapping))192          CHECK(IsShadowMemImpl::Apply<Mapping>(s));193        CHECK(IsMetaMemImpl::Apply<Mapping>(reinterpret_cast<uptr>(m)));194        CHECK_EQ(p, RestoreAddrImpl::Apply<Mapping>(CompressAddr(p)));195        if (!broken<Mapping>(kBrokenReverseMapping))196          CHECK_EQ(p, r);197        if (prev && !broken<Mapping>(kBrokenLinearity)) {198          // Ensure that shadow and meta mappings are linear within a single199          // user range. Lots of code that processes memory ranges assumes it.200          const uptr prev_s = MemToShadowImpl::Apply<Mapping>(prev);201          u32 *const prev_m = MemToMetaImpl::Apply<Mapping>(prev);202          CHECK_EQ(s - prev_s, (p - prev) * kShadowMultiplier);203          CHECK_EQ(m - prev_m, (p - prev) / kMetaShadowCell);204        }205        prev = p;206      }207    }208  }209 210  template <typename Mapping>211  static void TestDisjointMetas() {212    // Checks that the meta for each app region does not overlap with213    // the meta for other app regions. For example, the meta for a high214    // app pointer shouldn't be aliased to the meta of a mid app pointer.215    // Notice that this is important even though there does not exist a216    // MetaToMem function.217    // (If a MetaToMem function did exist, we could simply218    // check in the TestRegion function that it inverts MemToMeta.)219    //220    // We don't try to be clever by allowing the non-PIE (low app)221    // and PIE (mid and high app) meta regions to overlap.222    struct Region metas[4];223    int num_regions = 0;224    AddMetaRegion<Mapping>(metas, &num_regions, Mapping::kLoAppMemBeg,225                           Mapping::kLoAppMemEnd);226    AddMetaRegion<Mapping>(metas, &num_regions, Mapping::kMidAppMemBeg,227                           Mapping::kMidAppMemEnd);228    AddMetaRegion<Mapping>(metas, &num_regions, Mapping::kHiAppMemBeg,229                           Mapping::kHiAppMemEnd);230    AddMetaRegion<Mapping>(metas, &num_regions, Mapping::kHeapMemBeg,231                           Mapping::kHeapMemEnd);232 233    // It is not required that the low app shadow is below the mid app234    // shadow etc., hence we sort the shadows.235    qsort(metas, num_regions, sizeof(struct Region), CompareRegion);236 237    for (int i = 0; i < num_regions; i++)238      Printf("[0x%lu, 0x%lu]\n", metas[i].start, metas[i].end);239 240    if (!broken<Mapping>(kBrokenAliasedMetas))241      for (int i = 1; i < num_regions; i++)242        CHECK(metas[i - 1].end <= metas[i].start);243  }244};245 246TEST(Shadow, AllMappings) { ForEachMapping<MappingTest>(); }247 248}  // namespace __tsan249