Coverage for /Syzygy/agent/asan/shadow_unittest.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
100.0%4904900.C++test

Line-by-line coverage:

   1    :  // Copyright 2012 Google Inc. All Rights Reserved.
   2    :  //
   3    :  // Licensed under the Apache License, Version 2.0 (the "License");
   4    :  // you may not use this file except in compliance with the License.
   5    :  // You may obtain a copy of the License at
   6    :  //
   7    :  //     http://www.apache.org/licenses/LICENSE-2.0
   8    :  //
   9    :  // Unless required by applicable law or agreed to in writing, software
  10    :  // distributed under the License is distributed on an "AS IS" BASIS,
  11    :  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12    :  // See the License for the specific language governing permissions and
  13    :  // limitations under the License.
  14    :  
  15    :  #include "syzygy/agent/asan/shadow.h"
  16    :  
  17    :  #include "base/rand_util.h"
  18    :  #include "base/memory/scoped_ptr.h"
  19    :  #include "gtest/gtest.h"
  20    :  #include "syzygy/common/align.h"
  21    :  #include "syzygy/testing/metrics.h"
  22    :  
  23    :  namespace agent {
  24    :  namespace asan {
  25    :  
  26    :  namespace {
  27    :  
  28    :  // A derived class to expose protected members for unit-testing.
  29    :  class TestShadow : public Shadow {
  30    :   public:
  31  E :    TestShadow() : Shadow(kTestShadowSize) {
  32  E :    }
  33    :  
  34    :    // We'll simulate memory as being 1GB in size.
  35    :    static const size_t kTestShadowSize =
  36    :        (1 * 1024 * 1024 * 1024) >> kShadowRatioLog;
  37    :  
  38    :    // Protected functions that we want to unittest directly.
  39    :    using Shadow::Reset;
  40    :    using Shadow::ScanLeftForBracketingBlockStart;
  41    :    using Shadow::ScanRightForBracketingBlockEnd;
  42    :    using Shadow::shadow_;
  43    :  };
  44    :  
  45    :  // A fixture for shadow memory tests.
  46    :  class ShadowTest : public testing::Test {
  47    :   public:
  48    :    TestShadow test_shadow;
  49    :  };
  50    :  
  51    :  }  // namespace
  52    :  
  53  E :  TEST_F(ShadowTest, PoisonUnpoisonAccess) {
  54  E :    for (size_t count = 0; count < 100; ++count) {
  55    :      // Use a random 8-byte aligned end address.
  56  E :      const size_t size = base::RandInt(1, 16384);
  57    :      const uint8* end_addr =
  58  E :          reinterpret_cast<const uint8*>(base::RandInt(65536, 10*1024*1024) * 8);
  59  E :      const uint8* start_addr = end_addr - size;
  60    :  
  61  E :      for (size_t i = 0; i < size; ++i)
  62  E :        EXPECT_TRUE(test_shadow.IsAccessible(start_addr + i));
  63    :  
  64  E :      test_shadow.Poison(start_addr, size, kAsanReservedMarker);
  65  E :      for (size_t i = 0; i < size; ++i)
  66  E :        EXPECT_FALSE(test_shadow.IsAccessible(start_addr + i));
  67  E :      EXPECT_TRUE(test_shadow.IsAccessible(start_addr - 1));
  68  E :      EXPECT_TRUE(test_shadow.IsAccessible(start_addr + size));
  69    :  
  70    :      const size_t aligned_size = ::common::AlignUp(size,
  71  E :                                                    kShadowRatio);
  72  E :      const uint8* aligned_start_addr = end_addr - aligned_size;
  73  E :      test_shadow.Unpoison(aligned_start_addr, aligned_size);
  74  E :      for (size_t i = 0; i < size; ++i)
  75  E :        EXPECT_TRUE(test_shadow.IsAccessible(start_addr + i));
  76  E :    }
  77  E :  }
  78    :  
  79  E :  TEST_F(ShadowTest, SetUpAndTearDown) {
  80    :    // Don't check all the shadow bytes otherwise this test will take too much
  81    :    // time.
  82  E :    const size_t kLookupInterval = 25;
  83    :  
  84  E :    intptr_t shadow_array_start = reinterpret_cast<intptr_t>(test_shadow.shadow_);
  85  E :    size_t shadow_start = shadow_array_start >> 3;
  86  E :    size_t shadow_end = shadow_start + (test_shadow.length() >> 3);
  87    :  
  88  E :    const size_t non_addressable_memory_end = (0x10000 >> 3);
  89    :  
  90  E :    test_shadow.SetUp();
  91  E :    for (size_t i = shadow_start; i < shadow_end; i += kLookupInterval)
  92  E :      ASSERT_EQ(kAsanMemoryMarker, test_shadow.shadow_[i]);
  93    :  
  94  E :    for (size_t i = 0; i < non_addressable_memory_end; i += kLookupInterval)
  95  E :      ASSERT_EQ(kInvalidAddressMarker, test_shadow.shadow_[i]);
  96    :  
  97  E :    test_shadow.TearDown();
  98  E :    for (size_t i = shadow_start; i < shadow_end; i += kLookupInterval)
  99  E :      ASSERT_EQ(kHeapAddressableMarker, test_shadow.shadow_[i]);
 100    :  
 101  E :    for (size_t i = 0; i < non_addressable_memory_end; i += kLookupInterval)
 102  E :      ASSERT_EQ(kHeapAddressableMarker, test_shadow.shadow_[i]);
 103  E :  }
 104    :  
 105  E :  TEST_F(ShadowTest, GetNullTerminatedArraySize) {
 106  E :    const size_t kArrayLength = 100;
 107  E :    const uint8 kMarkerValue = 0xAA;
 108    :  
 109    :    uint8 test_array[kArrayLength];
 110    :    uint8* aligned_test_array = reinterpret_cast<uint8*>(
 111    :        ::common::AlignUp(reinterpret_cast<size_t>(test_array),
 112  E :                          kShadowRatio));
 113    :    size_t aligned_array_length = ::common::AlignDown(kArrayLength -
 114  E :        (aligned_test_array - test_array), kShadowRatio);
 115    :  
 116  E :    ::memset(aligned_test_array, kMarkerValue, aligned_array_length);
 117    :    test_shadow.Poison(
 118  E :        aligned_test_array, aligned_array_length, kAsanReservedMarker);
 119    :  
 120  E :    size_t sizes_to_test[] = { 4, 7, 12, 15, 21, 87, 88 };
 121    :  
 122  E :    for (size_t i = 0; i < arraysize(sizes_to_test); ++i) {
 123  E :      test_shadow.Unpoison(aligned_test_array, sizes_to_test[i]);
 124  E :      size_t size = 0;
 125    :  
 126    :      // Put a null byte at the end of the array and call the
 127    :      // GetNullTerminatedArraySize function with a 1-byte template argument. This
 128    :      // simulates the use of this function for a null terminated string.
 129  E :      aligned_test_array[sizes_to_test[i] - 1] = 0;
 130    :      EXPECT_TRUE(test_shadow.GetNullTerminatedArraySize<uint8>(
 131  E :          aligned_test_array, 0U, &size));
 132  E :      EXPECT_EQ(sizes_to_test[i], size);
 133    :  
 134  E :      if (sizes_to_test[i] % sizeof(uint16) == 0) {
 135    :        // Call the GetNullTerminatedArraySize with a 2-byte template argument.
 136    :        // As there is only one null byte at the end of the array we expect the
 137    :        // function to return false.
 138    :        EXPECT_FALSE(test_shadow.GetNullTerminatedArraySize<uint16>(
 139  E :            aligned_test_array, 0U, &size));
 140  E :        EXPECT_EQ(sizes_to_test[i], size);
 141    :        // Put a second null byte at the end of the array and call the function
 142    :        // again, this time we expect the function to succeed.
 143  E :        aligned_test_array[sizes_to_test[i] - sizeof(uint16)] = 0;
 144    :        EXPECT_TRUE(test_shadow.GetNullTerminatedArraySize<uint16>(
 145  E :            aligned_test_array, 0U, &size));
 146  E :        EXPECT_EQ(sizes_to_test[i], size);
 147  E :        aligned_test_array[sizes_to_test[i] - sizeof(uint16)] = kMarkerValue;
 148    :      }
 149  E :      aligned_test_array[sizes_to_test[i] - 1] = kMarkerValue;
 150    :  
 151  E :      aligned_test_array[sizes_to_test[i]] = kMarkerValue;
 152    :      EXPECT_FALSE(test_shadow.GetNullTerminatedArraySize<uint8>(
 153  E :          aligned_test_array, 0U, &size));
 154  E :      EXPECT_EQ(sizes_to_test[i], size);
 155    :      EXPECT_TRUE(test_shadow.GetNullTerminatedArraySize<uint8>(
 156  E :          aligned_test_array, sizes_to_test[i], &size));
 157    :  
 158    :      test_shadow.Poison(
 159    :          aligned_test_array,
 160    :          ::common::AlignUp(sizes_to_test[i], kShadowRatio),
 161  E :          kAsanReservedMarker);
 162  E :    }
 163  E :    test_shadow.Unpoison(aligned_test_array, aligned_array_length);
 164  E :  }
 165    :  
 166  E :  TEST_F(ShadowTest, MarkAsFreed) {
 167  E :    BlockLayout l0 = {}, l1 = {};
 168  E :    EXPECT_TRUE(BlockPlanLayout(kShadowRatio, kShadowRatio, 16, 30, 30, &l1));
 169    :    EXPECT_TRUE(BlockPlanLayout(kShadowRatio, kShadowRatio,
 170  E :                                l1.block_size + 2 * kShadowRatio, 30, 30, &l0));
 171    :  
 172  E :    uint8* data = new uint8[l0.block_size];
 173    :  
 174  E :    uint8* d0 = data;
 175  E :    BlockInfo i0 = {};
 176  E :    BlockInitialize(l0, d0, false, &i0);
 177  E :    test_shadow.PoisonAllocatedBlock(i0);
 178    :  
 179  E :    uint8* d1 = i0.RawBody() + kShadowRatio;
 180  E :    BlockInfo i1 = {};
 181  E :    BlockInitialize(l1, d1, true, &i1);
 182  E :    test_shadow.PoisonAllocatedBlock(i1);
 183    :  
 184  E :    test_shadow.MarkAsFreed(i0.body, i0.body_size);
 185  E :    for (uint8* p = i0.RawBlock(); p < i0.RawBlock() + i0.block_size; ++p) {
 186  E :      if (p >= i0.RawBlock() && p < i0.RawBody()) {
 187  E :        EXPECT_TRUE(test_shadow.IsLeftRedzone(p));
 188  E :      } else if (p >= i0.RawBody() &&
 189  E :          p < i0.RawTrailerPadding()) {
 190  E :        if (p >= i1.RawBlock() && p < i1.RawBody()) {
 191  E :          EXPECT_TRUE(test_shadow.IsLeftRedzone(p));
 192  E :        } else if (p >= i1.RawBody() && p < i1.RawTrailerPadding()) {
 193    :          EXPECT_EQ(kHeapFreedMarker,
 194  E :                    test_shadow.GetShadowMarkerForAddress(p));
 195  E :        } else if (p >= i1.RawTrailerPadding() &&
 196  E :            p < i1.RawBlock() + i1.block_size) {
 197  E :          EXPECT_TRUE(test_shadow.IsRightRedzone(p));
 198  E :        } else {
 199    :          EXPECT_EQ(kHeapFreedMarker,
 200  E :                    test_shadow.GetShadowMarkerForAddress(p));
 201    :        }
 202  E :      } else if (p >= i0.RawTrailerPadding() &&
 203  E :          p < i0.RawBlock() + i0.block_size) {
 204  E :        EXPECT_TRUE(test_shadow.IsRightRedzone(p));
 205    :      }
 206  E :    }
 207    :  
 208  E :    test_shadow.Unpoison(data, l0.block_size);
 209  E :    delete [] data;
 210  E :  }
 211    :  
 212  E :  TEST_F(ShadowTest, PoisonAllocatedBlock) {
 213  E :    BlockLayout layout = {};
 214  E :    EXPECT_TRUE(BlockPlanLayout(kShadowRatio, kShadowRatio, 15, 22, 0, &layout));
 215    :  
 216  E :    uint8* data = new uint8[layout.block_size];
 217  E :    BlockInfo info = {};
 218  E :    BlockInitialize(layout, data, false, &info);
 219    :  
 220  E :    test_shadow.PoisonAllocatedBlock(info);
 221    :    EXPECT_EQ(test_shadow.GetShadowMarkerForAddress(data + 0 * 8),
 222  E :              kHeapBlockStartMarker0 | 7);
 223    :    EXPECT_EQ(test_shadow.GetShadowMarkerForAddress(data + 1 * 8),
 224  E :              kHeapLeftPaddingMarker);
 225    :    EXPECT_EQ(test_shadow.GetShadowMarkerForAddress(data + 2 * 8),
 226  E :              kHeapLeftPaddingMarker);
 227    :    EXPECT_EQ(test_shadow.GetShadowMarkerForAddress(data + 3 * 8),
 228  E :              0);
 229    :    EXPECT_EQ(test_shadow.GetShadowMarkerForAddress(data + 4 * 8),
 230  E :              7);
 231    :    EXPECT_EQ(test_shadow.GetShadowMarkerForAddress(data + 5 * 8),
 232  E :              kHeapRightPaddingMarker);
 233    :    EXPECT_EQ(test_shadow.GetShadowMarkerForAddress(data + 6 * 8),
 234  E :              kHeapRightPaddingMarker);
 235    :    EXPECT_EQ(test_shadow.GetShadowMarkerForAddress(data + 7 * 8),
 236  E :              kHeapBlockEndMarker);
 237    :  
 238  E :    uint8* cursor = info.RawHeader();
 239  E :    for (; cursor < info.RawBody(); ++cursor)
 240  E :      EXPECT_FALSE(test_shadow.IsAccessible(cursor));
 241  E :    for (; cursor < info.RawBody() + info.body_size; ++cursor)
 242  E :      EXPECT_TRUE(test_shadow.IsAccessible(cursor));
 243  E :    for (; cursor < info.RawHeader() + info.block_size; ++cursor)
 244  E :      EXPECT_FALSE(test_shadow.IsAccessible(cursor));
 245  E :    test_shadow.Unpoison(info.RawBlock(), info.block_size);
 246    :  
 247  E :    delete [] data;
 248  E :  }
 249    :  
 250  E :  TEST_F(ShadowTest, ScanLeftAndRight) {
 251  E :    size_t offset = test_shadow.length() / 2;
 252  E :    size_t l = 0;
 253  E :    test_shadow.shadow_[offset + 0] = kHeapBlockStartMarker0;
 254  E :    test_shadow.shadow_[offset + 1] = kHeapNestedBlockStartMarker0;
 255  E :    test_shadow.shadow_[offset + 2] = kHeapAddressableMarker;
 256  E :    test_shadow.shadow_[offset + 3] = kHeapNestedBlockEndMarker;
 257  E :    test_shadow.shadow_[offset + 4] = kHeapBlockEndMarker;
 258    :  
 259  E :    EXPECT_TRUE(test_shadow.ScanLeftForBracketingBlockStart(0, offset + 0, &l));
 260  E :    EXPECT_EQ(offset, l);
 261  E :    EXPECT_TRUE(test_shadow.ScanLeftForBracketingBlockStart(0, offset + 1, &l));
 262  E :    EXPECT_EQ(offset + 1, l);
 263  E :    EXPECT_TRUE(test_shadow.ScanLeftForBracketingBlockStart(0, offset + 2, &l));
 264  E :    EXPECT_EQ(offset + 1, l);
 265  E :    EXPECT_TRUE(test_shadow.ScanLeftForBracketingBlockStart(0, offset + 3, &l));
 266  E :    EXPECT_EQ(offset + 1, l);
 267  E :    EXPECT_TRUE(test_shadow.ScanLeftForBracketingBlockStart(0, offset + 4, &l));
 268  E :    EXPECT_EQ(offset, l);
 269    :  
 270  E :    EXPECT_FALSE(test_shadow.ScanLeftForBracketingBlockStart(1, offset + 0, &l));
 271  E :    EXPECT_TRUE(test_shadow.ScanLeftForBracketingBlockStart(1, offset + 1, &l));
 272  E :    EXPECT_EQ(offset, l);
 273  E :    EXPECT_TRUE(test_shadow.ScanLeftForBracketingBlockStart(1, offset + 2, &l));
 274  E :    EXPECT_EQ(offset, l);
 275  E :    EXPECT_TRUE(test_shadow.ScanLeftForBracketingBlockStart(1, offset + 3, &l));
 276  E :    EXPECT_EQ(offset, l);
 277  E :    EXPECT_FALSE(test_shadow.ScanLeftForBracketingBlockStart(1, offset + 4, &l));
 278    :  
 279  E :    EXPECT_FALSE(test_shadow.ScanLeftForBracketingBlockStart(2, offset + 0, &l));
 280  E :    EXPECT_FALSE(test_shadow.ScanLeftForBracketingBlockStart(2, offset + 1, &l));
 281  E :    EXPECT_FALSE(test_shadow.ScanLeftForBracketingBlockStart(2, offset + 2, &l));
 282  E :    EXPECT_FALSE(test_shadow.ScanLeftForBracketingBlockStart(2, offset + 3, &l));
 283  E :    EXPECT_FALSE(test_shadow.ScanLeftForBracketingBlockStart(2, offset + 4, &l));
 284    :  
 285  E :    EXPECT_TRUE(test_shadow.ScanRightForBracketingBlockEnd(0, offset + 0, &l));
 286  E :    EXPECT_EQ(offset + 4, l);
 287  E :    EXPECT_TRUE(test_shadow.ScanRightForBracketingBlockEnd(0, offset + 1, &l));
 288  E :    EXPECT_EQ(offset + 3, l);
 289  E :    EXPECT_TRUE(test_shadow.ScanRightForBracketingBlockEnd(0, offset + 2, &l));
 290  E :    EXPECT_EQ(offset + 3, l);
 291  E :    EXPECT_TRUE(test_shadow.ScanRightForBracketingBlockEnd(0, offset + 3, &l));
 292  E :    EXPECT_EQ(offset + 3, l);
 293  E :    EXPECT_TRUE(test_shadow.ScanRightForBracketingBlockEnd(0, offset + 4, &l));
 294  E :    EXPECT_EQ(offset + 4, l);
 295    :  
 296  E :    EXPECT_FALSE(test_shadow.ScanRightForBracketingBlockEnd(1, offset + 0, &l));
 297  E :    EXPECT_TRUE(test_shadow.ScanRightForBracketingBlockEnd(1, offset + 1, &l));
 298  E :    EXPECT_EQ(offset + 4, l);
 299  E :    EXPECT_TRUE(test_shadow.ScanRightForBracketingBlockEnd(1, offset + 2, &l));
 300  E :    EXPECT_EQ(offset + 4, l);
 301  E :    EXPECT_TRUE(test_shadow.ScanRightForBracketingBlockEnd(1, offset + 3, &l));
 302  E :    EXPECT_EQ(offset + 4, l);
 303  E :    EXPECT_FALSE(test_shadow.ScanRightForBracketingBlockEnd(1, offset + 4, &l));
 304    :  
 305  E :    EXPECT_FALSE(test_shadow.ScanRightForBracketingBlockEnd(2, offset + 0, &l));
 306  E :    EXPECT_FALSE(test_shadow.ScanRightForBracketingBlockEnd(2, offset + 1, &l));
 307  E :    EXPECT_FALSE(test_shadow.ScanRightForBracketingBlockEnd(2, offset + 2, &l));
 308  E :    EXPECT_FALSE(test_shadow.ScanRightForBracketingBlockEnd(2, offset + 3, &l));
 309  E :    EXPECT_FALSE(test_shadow.ScanRightForBracketingBlockEnd(2, offset + 4, &l));
 310    :  
 311  E :    ::memset(test_shadow.shadow_ + offset, 0, 5);
 312  E :  }
 313    :  
 314  E :  TEST_F(ShadowTest, ScanRightPerfTest) {
 315  E :    size_t offset = test_shadow.length() / 2;
 316  E :    size_t length = 1 * 1024 * 1024;
 317    :  
 318  E :    ::memset(test_shadow.shadow_ + offset, 0, length);
 319    :  
 320  E :    test_shadow.shadow_[offset + 0] = kHeapBlockStartMarker0;
 321    :    // A nested block with freed contents.
 322  E :    test_shadow.shadow_[offset + 50] = kHeapNestedBlockStartMarker0;
 323  E :    ::memset(test_shadow.shadow_ + offset + 51, kHeapFreedMarker, 8);
 324  E :    test_shadow.shadow_[offset + 60] = kHeapNestedBlockEndMarker;
 325    :    // A nested block with a nested block.
 326  E :    test_shadow.shadow_[offset + 100000] = kHeapNestedBlockStartMarker0;
 327  E :    test_shadow.shadow_[offset + 100100] = kHeapNestedBlockStartMarker0;
 328  E :    test_shadow.shadow_[offset + 100400] = kHeapNestedBlockEndMarker;
 329  E :    test_shadow.shadow_[offset + 200000] = kHeapNestedBlockEndMarker;
 330    :    // The end of the outer block.
 331  E :    test_shadow.shadow_[offset + length - 1] = kHeapBlockEndMarker;
 332    :  
 333  E :    uint64 tnet = 0;
 334  E :    for (size_t i = 0; i < 100; ++i) {
 335  E :      size_t l = 0;
 336  E :      uint64 t0 = ::__rdtsc();
 337  E :      test_shadow.ScanRightForBracketingBlockEnd(0, offset + 1, &l);
 338  E :      uint64 t1 = ::__rdtsc();
 339  E :      tnet += t1 - t0;
 340  E :    }
 341    :    testing::EmitMetric("Syzygy.Asan.Shadow.ScanRightForBracketingBlockEnd",
 342  E :                        tnet);
 343    :  
 344    :    // Reset the shadow memory.
 345  E :    ::memset(test_shadow.shadow_ + offset, 0, length);
 346  E :  }
 347    :  
 348  E :  TEST_F(ShadowTest, IsLeftOrRightRedzone) {
 349  E :    BlockLayout layout = {};
 350  E :    const size_t kAllocSize = 15;
 351  E :    ASSERT_NE(0U, kAllocSize % kShadowRatio);
 352    :    EXPECT_TRUE(BlockPlanLayout(kShadowRatio, kShadowRatio, kAllocSize, 0, 0,
 353  E :                                &layout));
 354    :  
 355  E :    scoped_ptr<uint8> data(new uint8[layout.block_size]);
 356  E :    BlockInfo info = {};
 357  E :    BlockInitialize(layout, data.get(), false, &info);
 358    :  
 359  E :    test_shadow.PoisonAllocatedBlock(info);
 360  E :    uint8* block = reinterpret_cast<uint8*>(info.header);
 361  E :    uint8* cursor = block;
 362    :  
 363  E :    for (; cursor < info.RawBody(); ++cursor) {
 364  E :      EXPECT_TRUE(test_shadow.IsLeftRedzone(cursor));
 365  E :      EXPECT_FALSE(test_shadow.IsRightRedzone(cursor));
 366  E :    }
 367  E :    for (; cursor < info.RawBody() + info.body_size; ++cursor) {
 368  E :      EXPECT_FALSE(test_shadow.IsLeftRedzone(cursor));
 369  E :      EXPECT_FALSE(test_shadow.IsRightRedzone(cursor));
 370  E :    }
 371  E :    for (; cursor < block + info.block_size; ++cursor) {
 372  E :      EXPECT_FALSE(test_shadow.IsLeftRedzone(cursor));
 373  E :      EXPECT_TRUE(test_shadow.IsRightRedzone(cursor));
 374  E :    }
 375    :  
 376  E :    test_shadow.Unpoison(block, info.block_size);
 377  E :  }
 378    :  
 379    :  namespace {
 380    :  
 381    :  void TestBlockInfoFromShadow(Shadow* shadow,
 382    :                               const BlockLayout& outer,
 383  E :                               const BlockLayout& nested) {
 384  E :    ASSERT_TRUE(shadow != nullptr);
 385  E :    ASSERT_LE(nested.block_size, outer.body_size);
 386    :  
 387  E :    uint8* data = new uint8[outer.block_size];
 388    :  
 389    :    // Try recovering the block from every position within it when no nested
 390    :    // block exists. Expect finding a nested block to fail.
 391  E :    BlockInfo info = {};
 392  E :    BlockInitialize(outer, data, false, &info);
 393  E :    shadow->PoisonAllocatedBlock(info);
 394  E :    BlockInfo info_recovered = {};
 395  E :    for (size_t i = 0; i < info.block_size; ++i) {
 396    :      EXPECT_TRUE(shadow->BlockInfoFromShadow(
 397  E :          info.RawBlock() + i, &info_recovered));
 398  E :      EXPECT_EQ(0, ::memcmp(&info, &info_recovered, sizeof(info)));
 399    :  
 400    :      // This block should have no parent block as its not nested.
 401    :      EXPECT_FALSE(shadow->ParentBlockInfoFromShadow(
 402  E :          info, &info_recovered));
 403  E :    }
 404    :  
 405    :    // Place a nested block and try the recovery from every position again.
 406    :    size_t padding = ::common::AlignDown(info.body_size - nested.block_size,
 407  E :                                         kShadowRatio * 2);
 408  E :    uint8* nested_begin = info.RawBody() + padding / 2;
 409  E :    uint8* nested_end = nested_begin + nested.block_size;
 410  E :    BlockInfo nested_info = {};
 411  E :    BlockInitialize(nested, nested_begin, true, &nested_info);
 412  E :    nested_info.header->is_nested = true;
 413  E :    shadow->PoisonAllocatedBlock(nested_info);
 414  E :    for (size_t i = 0; i < info.block_size; ++i) {
 415  E :      uint8* pos = info.RawBlock() + i;
 416  E :      EXPECT_TRUE(shadow->BlockInfoFromShadow(pos, &info_recovered));
 417    :  
 418  E :      BlockInfo parent_info = {};
 419    :      bool found_parent = shadow->ParentBlockInfoFromShadow(
 420  E :          info_recovered, &parent_info);
 421    :  
 422  E :      if (pos >= nested_begin && pos < nested_end) {
 423    :        EXPECT_EQ(0, ::memcmp(&nested_info, &info_recovered,
 424  E :                              sizeof(nested_info)));
 425  E :        EXPECT_TRUE(found_parent);
 426  E :        EXPECT_EQ(0, ::memcmp(&info, &parent_info, sizeof(info)));
 427  E :      } else {
 428  E :        EXPECT_EQ(0, ::memcmp(&info, &info_recovered, sizeof(info)));
 429  E :        EXPECT_FALSE(found_parent);
 430    :      }
 431  E :    }
 432  E :    shadow->Unpoison(info.header, info.block_size);
 433    :  
 434  E :    delete [] data;
 435  E :  }
 436    :  
 437    :  }  // namespace
 438    :  
 439  E :  TEST_F(ShadowTest, BlockInfoFromShadow) {
 440    :    // This is a simple layout that will be nested inside of another block.
 441  E :    BlockLayout layout0 = {};
 442  E :    EXPECT_TRUE(BlockPlanLayout(kShadowRatio, kShadowRatio, 6, 0, 0, &layout0));
 443    :  
 444    :    // Plan two layouts, one with padding and another with none. The first has
 445    :    // exactly enough space for the nested block, while the second has room to
 446    :    // spare.
 447  E :    BlockLayout layout1 = {};
 448  E :    BlockLayout layout2 = {};
 449    :    EXPECT_TRUE(BlockPlanLayout(kShadowRatio, kShadowRatio,
 450    :        ::common::AlignUp(layout0.block_size, kShadowRatio) + 4, 0, 0,
 451  E :        &layout1));
 452  E :    ASSERT_EQ(0u, layout1.header_padding_size);
 453  E :    ASSERT_EQ(0u, layout1.trailer_padding_size);
 454    :    EXPECT_TRUE(BlockPlanLayout(kShadowRatio, kShadowRatio,
 455  E :        layout0.block_size + 2 * kShadowRatio, 32, 13, &layout2));
 456  E :    ASSERT_LT(0u, layout2.header_padding_size);
 457  E :    ASSERT_LT(0u, layout2.trailer_padding_size);
 458    :  
 459    :    EXPECT_NO_FATAL_FAILURE(TestBlockInfoFromShadow(
 460  E :        &test_shadow, layout1, layout0));
 461    :    EXPECT_NO_FATAL_FAILURE(TestBlockInfoFromShadow(
 462  E :        &test_shadow, layout2, layout0));
 463  E :  }
 464    :  
 465  E :  TEST_F(ShadowTest, IsBeginningOfBlockBody) {
 466  E :    BlockLayout l = {};
 467  E :    EXPECT_TRUE(BlockPlanLayout(kShadowRatio, kShadowRatio, 7, 0, 0, &l));
 468    :  
 469  E :    size_t data_size = l.block_size;
 470  E :    scoped_ptr<uint8> data(new uint8[data_size]);
 471    :  
 472  E :    BlockInfo block_info = {};
 473  E :    BlockInitialize(l, data.get(), false, &block_info);
 474    :  
 475  E :    test_shadow.PoisonAllocatedBlock(block_info);
 476    :  
 477  E :    EXPECT_TRUE(test_shadow.IsBeginningOfBlockBody(block_info.body));
 478  E :    EXPECT_FALSE(test_shadow.IsBeginningOfBlockBody(data.get()));
 479    :  
 480  E :    block_info.header->state = QUARANTINED_BLOCK;
 481  E :    test_shadow.MarkAsFreed(block_info.body, block_info.body_size);
 482    :  
 483  E :    EXPECT_TRUE(test_shadow.IsBeginningOfBlockBody(block_info.body));
 484  E :    EXPECT_FALSE(test_shadow.IsBeginningOfBlockBody(data.get()));
 485    :  
 486  E :    test_shadow.Unpoison(data.get(), data_size);
 487  E :  }
 488    :  
 489  E :  TEST_F(ShadowTest, IsBeginningOfBlockBodyForBlockOfSizeZero) {
 490  E :    BlockLayout l = {};
 491  E :    EXPECT_TRUE(BlockPlanLayout(kShadowRatio, kShadowRatio, 0, 0, 0, &l));
 492    :  
 493  E :    size_t data_size = l.block_size;
 494  E :    scoped_ptr<uint8> data(new uint8[data_size]);
 495    :  
 496  E :    BlockInfo block_info = {};
 497  E :    BlockInitialize(l, data.get(), false, &block_info);
 498    :  
 499  E :    test_shadow.PoisonAllocatedBlock(block_info);
 500    :  
 501  E :    EXPECT_TRUE(test_shadow.IsBeginningOfBlockBody(block_info.body));
 502  E :    EXPECT_FALSE(test_shadow.IsBeginningOfBlockBody(data.get()));
 503    :  
 504  E :    block_info.header->state = QUARANTINED_FLOODED_BLOCK;
 505  E :    test_shadow.MarkAsFreed(block_info.body, block_info.body_size);
 506    :  
 507  E :    EXPECT_TRUE(test_shadow.IsBeginningOfBlockBody(block_info.body));
 508  E :    EXPECT_FALSE(test_shadow.IsBeginningOfBlockBody(data.get()));
 509    :  
 510  E :    test_shadow.Unpoison(data.get(), data_size);
 511  E :  }
 512    :  
 513  E :  TEST_F(ShadowTest, MarkAsFreedPerfTest) {
 514  E :    std::vector<uint8> buf;
 515  E :    buf.resize(10 * 1024 * 1024, 0);
 516    :  
 517  E :    uint64 tnet = 0;
 518  E :    for (size_t i = 0; i < 1000; ++i) {
 519  E :      test_shadow.Unpoison(buf.data(), buf.size());
 520  E :      uint64 t0 = ::__rdtsc();
 521  E :      test_shadow.MarkAsFreed(buf.data(), buf.size());
 522  E :      uint64 t1 = ::__rdtsc();
 523  E :      tnet += t1 - t0;
 524  E :      test_shadow.Unpoison(buf.data(), buf.size());
 525  E :    }
 526  E :    testing::EmitMetric("Syzygy.Asan.Shadow.MarkAsFreed", tnet);
 527  E :  }
 528    :  
 529  E :  TEST_F(ShadowTest, PageBits) {
 530    :    // Set an individual page.
 531  E :    const uint8* addr = reinterpret_cast<const uint8*>(16 * 4096);
 532  E :    EXPECT_FALSE(test_shadow.PageIsProtected(addr));
 533  E :    test_shadow.MarkPageProtected(addr);
 534  E :    EXPECT_TRUE(test_shadow.PageIsProtected(addr));
 535  E :    test_shadow.MarkPageProtected(addr);
 536  E :    EXPECT_TRUE(test_shadow.PageIsProtected(addr));
 537  E :    test_shadow.MarkPageUnprotected(addr);
 538  E :    EXPECT_FALSE(test_shadow.PageIsProtected(addr));
 539  E :    test_shadow.MarkPageUnprotected(addr);
 540  E :    EXPECT_FALSE(test_shadow.PageIsProtected(addr));
 541    :  
 542    :    // Set a range of pages at once.
 543  E :    const uint8* addr2 = addr + 4096;
 544  E :    EXPECT_FALSE(test_shadow.PageIsProtected(addr - 4096));
 545  E :    EXPECT_FALSE(test_shadow.PageIsProtected(addr));
 546  E :    EXPECT_FALSE(test_shadow.PageIsProtected(addr2));
 547  E :    EXPECT_FALSE(test_shadow.PageIsProtected(addr2 + 4096));
 548  E :    test_shadow.MarkPagesProtected(addr, 2 * 4096);
 549  E :    EXPECT_FALSE(test_shadow.PageIsProtected(addr - 4096));
 550  E :    EXPECT_TRUE(test_shadow.PageIsProtected(addr));
 551  E :    EXPECT_TRUE(test_shadow.PageIsProtected(addr2));
 552  E :    EXPECT_FALSE(test_shadow.PageIsProtected(addr2 + 4096));
 553  E :    test_shadow.MarkPagesProtected(addr, 2 * 4096);
 554  E :    EXPECT_FALSE(test_shadow.PageIsProtected(addr - 4096));
 555  E :    EXPECT_TRUE(test_shadow.PageIsProtected(addr));
 556  E :    EXPECT_TRUE(test_shadow.PageIsProtected(addr2));
 557  E :    EXPECT_FALSE(test_shadow.PageIsProtected(addr2 + 4096));
 558  E :    test_shadow.MarkPagesUnprotected(addr, 2 * 4096);
 559  E :    EXPECT_FALSE(test_shadow.PageIsProtected(addr - 4096));
 560  E :    EXPECT_FALSE(test_shadow.PageIsProtected(addr));
 561  E :    EXPECT_FALSE(test_shadow.PageIsProtected(addr2));
 562  E :    EXPECT_FALSE(test_shadow.PageIsProtected(addr2 + 4096));
 563  E :    test_shadow.MarkPagesUnprotected(addr, 2 * 4096);
 564  E :    EXPECT_FALSE(test_shadow.PageIsProtected(addr - 4096));
 565  E :    EXPECT_FALSE(test_shadow.PageIsProtected(addr));
 566  E :    EXPECT_FALSE(test_shadow.PageIsProtected(addr2));
 567  E :    EXPECT_FALSE(test_shadow.PageIsProtected(addr2 + 4096));
 568  E :  }
 569    :  
 570    :  namespace {
 571    :  
 572    :  // A fixture for shadow walker tests.
 573    :  class ShadowWalkerTest : public testing::Test {
 574    :   public:
 575    :    TestShadow test_shadow;
 576    :  };
 577    :  
 578    :  }  // namespace
 579    :  
 580  E :  TEST_F(ShadowWalkerTest, WalksNonNestedBlocks) {
 581  E :    BlockLayout l = {};
 582  E :    EXPECT_TRUE(BlockPlanLayout(kShadowRatio, kShadowRatio, 7, 0, 0, &l));
 583    :  
 584  E :    size_t data_size = l.block_size * 3 + kShadowRatio;
 585  E :    uint8* data = new uint8[data_size];
 586  E :    uint8* data0 = data;
 587  E :    uint8* data1 = data0 + l.block_size + kShadowRatio;
 588  E :    uint8* data2 = data1 + l.block_size;
 589    :  
 590  E :    BlockInfo i0 = {}, i1 = {}, i2 = {};
 591  E :    BlockInitialize(l, data0, false, &i0);
 592  E :    BlockInitialize(l, data1, false, &i1);
 593  E :    BlockInitialize(l, data2, false, &i2);
 594    :  
 595  E :    test_shadow.PoisonAllocatedBlock(i0);
 596  E :    test_shadow.PoisonAllocatedBlock(i1);
 597  E :    test_shadow.PoisonAllocatedBlock(i2);
 598    :  
 599  E :    i2.header->state = QUARANTINED_BLOCK;
 600  E :    test_shadow.MarkAsFreed(i2.body, i2.body_size);
 601    :  
 602    :    // Do a non-recursive walk through the shadow.
 603  E :    BlockInfo i = {};
 604  E :    ShadowWalker w0(&test_shadow, false, data, data + data_size);
 605  E :    EXPECT_EQ(-1, w0.nesting_depth());
 606  E :    EXPECT_TRUE(w0.Next(&i));
 607  E :    EXPECT_EQ(0, w0.nesting_depth());
 608  E :    EXPECT_TRUE(w0.Next(&i));
 609  E :    EXPECT_EQ(0, w0.nesting_depth());
 610  E :    EXPECT_TRUE(w0.Next(&i));
 611  E :    EXPECT_EQ(0, w0.nesting_depth());
 612  E :    EXPECT_FALSE(w0.Next(&i));
 613  E :    EXPECT_EQ(-1, w0.nesting_depth());
 614    :  
 615    :    // Walk recursively through the shadow and expect the same results.
 616  E :    ShadowWalker w1(&test_shadow, true, data, data + data_size);
 617  E :    EXPECT_EQ(-1, w1.nesting_depth());
 618  E :    EXPECT_TRUE(w1.Next(&i));
 619  E :    EXPECT_EQ(0, w1.nesting_depth());
 620  E :    EXPECT_EQ(0, ::memcmp(&i, &i0, sizeof(i)));
 621  E :    EXPECT_TRUE(w1.Next(&i));
 622  E :    EXPECT_EQ(0, w1.nesting_depth());
 623  E :    EXPECT_EQ(0, ::memcmp(&i, &i1, sizeof(i)));
 624  E :    EXPECT_TRUE(w1.Next(&i));
 625  E :    EXPECT_EQ(0, w1.nesting_depth());
 626  E :    EXPECT_EQ(0, ::memcmp(&i, &i2, sizeof(i)));
 627  E :    EXPECT_FALSE(w1.Next(&i));
 628  E :    EXPECT_EQ(-1, w1.nesting_depth());
 629    :  
 630  E :    test_shadow.Unpoison(data, data_size);
 631  E :    delete [] data;
 632  E :  }
 633    :  
 634  E :  TEST_F(ShadowWalkerTest, WalksNestedBlocks) {
 635  E :    BlockLayout b0 = {}, b1 = {}, b2 = {}, b00 = {}, b01 = {}, b10 = {},
 636  E :        b100 = {};
 637  E :    EXPECT_TRUE(BlockPlanLayout(kShadowRatio, kShadowRatio, 15, 30, 30, &b00));
 638  E :    EXPECT_TRUE(BlockPlanLayout(kShadowRatio, kShadowRatio, 7, 0, 0, &b01));
 639    :    EXPECT_TRUE(BlockPlanLayout(kShadowRatio, kShadowRatio,
 640  E :        b00.block_size + b01.block_size + kShadowRatio, 0, 0, &b0));
 641  E :    EXPECT_TRUE(BlockPlanLayout(kShadowRatio, kShadowRatio, 7, 0, 0, &b100));
 642    :    EXPECT_TRUE(BlockPlanLayout(kShadowRatio, kShadowRatio, b100.block_size, 0, 0,
 643  E :                                &b10));
 644    :    EXPECT_TRUE(BlockPlanLayout(kShadowRatio, kShadowRatio, b10.block_size, 0, 0,
 645  E :                                &b1));
 646  E :    EXPECT_TRUE(BlockPlanLayout(kShadowRatio, kShadowRatio, 100, 0, 0, &b2));
 647    :  
 648    :    size_t data_size = b0.block_size + b1.block_size + kShadowRatio +
 649  E :        b2.block_size;
 650  E :    uint8* data = new uint8[data_size];
 651    :  
 652    :    // Initialize the depth 0 blocks.
 653  E :    uint8* d0 = data;
 654  E :    uint8* d1 = d0 + b0.block_size;
 655  E :    uint8* d2 = d1 + b1.block_size + kShadowRatio;
 656  E :    BlockInfo i0 = {}, i1 = {}, i2 = {};
 657  E :    BlockInitialize(b0, d0, false, &i0);
 658  E :    BlockInitialize(b1, d1, false, &i1);
 659  E :    BlockInitialize(b2, d2, false, &i2);
 660  E :    test_shadow.PoisonAllocatedBlock(i0);
 661  E :    test_shadow.PoisonAllocatedBlock(i1);
 662  E :    test_shadow.PoisonAllocatedBlock(i2);
 663    :  
 664    :    // Initialize depth 1 blocks.
 665  E :    uint8* d00 = i0.RawBody();
 666  E :    uint8* d01 = d00 + b00.block_size + kShadowRatio;
 667  E :    uint8* d10 = i1.RawBody();
 668  E :    BlockInfo i00 = {}, i01 = {}, i10 = {};
 669  E :    BlockInitialize(b00, d00, true, &i00);
 670  E :    BlockInitialize(b01, d01, true, &i01);
 671  E :    BlockInitialize(b10, d10, true, &i10);
 672  E :    test_shadow.PoisonAllocatedBlock(i00);
 673  E :    test_shadow.PoisonAllocatedBlock(i01);
 674  E :    test_shadow.PoisonAllocatedBlock(i10);
 675    :  
 676    :    // Initialize depth 2 blocks.
 677  E :    uint8* d100 = i10.RawBody();
 678  E :    BlockInfo i100 = {};
 679  E :    BlockInitialize(b100, d100, true, &i100);
 680  E :    test_shadow.PoisonAllocatedBlock(i100);
 681  E :    i100.header->state = QUARANTINED_FLOODED_BLOCK;
 682  E :    test_shadow.MarkAsFreed(i100.body, i100.body_size);
 683    :  
 684    :    // Do a non-recursive walk through the shadow.
 685  E :    BlockInfo i = {};
 686  E :    ShadowWalker w0(&test_shadow, false, data, data + data_size);
 687  E :    EXPECT_EQ(-1, w0.nesting_depth());
 688  E :    EXPECT_TRUE(w0.Next(&i));
 689  E :    EXPECT_EQ(0, w0.nesting_depth());
 690  E :    EXPECT_EQ(0, ::memcmp(&i, &i0, sizeof(i)));
 691  E :    EXPECT_TRUE(w0.Next(&i));
 692  E :    EXPECT_EQ(0, w0.nesting_depth());
 693  E :    EXPECT_EQ(0, ::memcmp(&i, &i1, sizeof(i)));
 694  E :    EXPECT_TRUE(w0.Next(&i));
 695  E :    EXPECT_EQ(0, w0.nesting_depth());
 696  E :    EXPECT_EQ(0, ::memcmp(&i, &i2, sizeof(i)));
 697  E :    EXPECT_FALSE(w0.Next(&i));
 698  E :    EXPECT_EQ(-1, w0.nesting_depth());
 699    :  
 700    :    // Walk recursively through the shadow.
 701  E :    ShadowWalker w1(&test_shadow, true, data, data + data_size);
 702  E :    EXPECT_EQ(-1, w1.nesting_depth());
 703  E :    EXPECT_TRUE(w1.Next(&i));
 704  E :    EXPECT_EQ(0, w1.nesting_depth());
 705  E :    EXPECT_EQ(0, ::memcmp(&i, &i0, sizeof(i)));
 706  E :    EXPECT_TRUE(w1.Next(&i));
 707  E :    EXPECT_EQ(1, w1.nesting_depth());
 708  E :    EXPECT_EQ(0, ::memcmp(&i, &i00, sizeof(i)));
 709  E :    EXPECT_TRUE(w1.Next(&i));
 710  E :    EXPECT_EQ(1, w1.nesting_depth());
 711  E :    EXPECT_EQ(0, ::memcmp(&i, &i01, sizeof(i)));
 712  E :    EXPECT_TRUE(w1.Next(&i));
 713  E :    EXPECT_EQ(0, w1.nesting_depth());
 714  E :    EXPECT_EQ(0, ::memcmp(&i, &i1, sizeof(i)));
 715  E :    EXPECT_TRUE(w1.Next(&i));
 716  E :    EXPECT_EQ(1, w1.nesting_depth());
 717  E :    EXPECT_EQ(0, ::memcmp(&i, &i10, sizeof(i)));
 718  E :    EXPECT_TRUE(w1.Next(&i));
 719  E :    EXPECT_EQ(2, w1.nesting_depth());
 720  E :    EXPECT_EQ(0, ::memcmp(&i, &i100, sizeof(i)));
 721  E :    EXPECT_TRUE(w1.Next(&i));
 722  E :    EXPECT_EQ(0, w1.nesting_depth());
 723  E :    EXPECT_EQ(0, ::memcmp(&i, &i2, sizeof(i)));
 724  E :    EXPECT_FALSE(w1.Next(&i));
 725  E :    EXPECT_EQ(-1, w1.nesting_depth());
 726    :  
 727  E :    test_shadow.Unpoison(data, data_size);
 728  E :    delete [] data;
 729  E :  }
 730    :  
 731    :  }  // namespace asan
 732    :  }  // namespace agent

Coverage information generated Thu Jan 14 17:40:38 2016.