| Index: syzygy/agent/asan/shadow_unittest.cc
|
| diff --git a/syzygy/agent/asan/shadow_unittest.cc b/syzygy/agent/asan/shadow_unittest.cc
|
| index c666f9285aa35d7a6d70eb1d72f36671e3140fdc..a5b69879b3bedabe26c7416b5ccf5e989cbb0eae 100644
|
| --- a/syzygy/agent/asan/shadow_unittest.cc
|
| +++ b/syzygy/agent/asan/shadow_unittest.cc
|
| @@ -90,6 +90,8 @@ class TestShadow : public Shadow {
|
| static const size_t kDefaultTestShadowSize =
|
| (1 * 1024 * 1024 * 1024) >> kShadowRatioLog;
|
|
|
| + TestShadow(void* shadow, size_t length) : Shadow(shadow, length) {}
|
| +
|
| // Protected functions that we want to unittest directly.
|
| using Shadow::Reset;
|
| using Shadow::ScanLeftForBracketingBlockStart;
|
| @@ -920,5 +922,71 @@ TEST_F(ShadowWalkerTest, WalksNestedBlocks) {
|
| delete [] data;
|
| }
|
|
|
| +TEST_F(ShadowWalkerTest, WalkShadowWithUncommittedRanges) {
|
| + // Create a 512k memory block.
|
| + const size_t kMemorySize = 512 * 1024;
|
| + uint8_t memory_block[kMemorySize];
|
| + const size_t shadow_size = Shadow::RequiredLength();
|
| +
|
| + // Allocate the shadow memory, only reserve the memory.
|
| + uint8_t* shadow_memory = static_cast<uint8_t*>(
|
| + ::VirtualAlloc(nullptr, shadow_size, MEM_RESERVE, PAGE_READWRITE));
|
| + EXPECT_NE(nullptr, shadow_memory);
|
| +
|
| + uint8_t* memory_block_shadow_start =
|
| + shadow_memory + reinterpret_cast<size_t>(memory_block) / kShadowRatio;
|
| +
|
| + TestShadow ts1(shadow_memory, Shadow::RequiredLength());
|
| +
|
| + std::vector<BlockInfo> block_info_vec;
|
| + BlockLayout l = {};
|
| + EXPECT_TRUE(BlockPlanLayout(kShadowRatio, kShadowRatio, 7, 0, 0, &l));
|
| + EXPECT_LT(l.block_size, GetPageSize() * kShadowRatio);
|
| +
|
| + // Calculate the size of the shadow necessary to cover this block
|
| + // as well as the number of pages in it.
|
| + const size_t kBlockShadowSize = kMemorySize / kShadowRatio;
|
| + size_t shadow_page_count = kBlockShadowSize / GetPageSize();
|
| +
|
| + // Allocate a block that will fit on every other pages of the shadow.
|
| + for (size_t i = 0; i < shadow_page_count; ++i) {
|
| + if (i % 2 == 0)
|
| + continue;
|
| + // Address of the shadow memory for this page.
|
| + uint8_t* shadow_address = memory_block_shadow_start + i * GetPageSize();
|
| + uint8_t* shadow_address_page_begin =
|
| + ::common::AlignDown(shadow_address, GetPageSize());
|
| + // Commit the shadow memory for this block.
|
| + EXPECT_EQ(static_cast<void*>(shadow_address_page_begin),
|
| + ::VirtualAlloc(shadow_address, GetPageSize(), MEM_COMMIT,
|
| + PAGE_READWRITE));
|
| +
|
| + // Address of the memory for this block.
|
| + uint8_t* page_address = ::common::AlignUp(
|
| + memory_block + i * GetPageSize() * kShadowRatio, kShadowRatio);
|
| + BlockInfo block_info = {};
|
| + BlockInitialize(l, page_address, false, &block_info);
|
| + block_info_vec.push_back(block_info);
|
| +
|
| + // Poison the block.
|
| + ts1.PoisonAllocatedBlock(block_info);
|
| + }
|
| +
|
| + size_t block_count = 0;
|
| + ShadowWalker w(&ts1, true, memory_block, memory_block + kMemorySize);
|
| + BlockInfo i = {};
|
| + while (w.Next(&i)) {
|
| + EXPECT_LT(block_count, block_info_vec.size());
|
| + EXPECT_EQ(block_info_vec[block_count].header, i.header);
|
| + EXPECT_EQ(block_info_vec[block_count].body, i.body);
|
| + EXPECT_EQ(block_info_vec[block_count].trailer, i.trailer);
|
| + block_count++;
|
| + }
|
| + EXPECT_EQ(block_info_vec.size(), block_count);
|
| + EXPECT_FALSE(w.Next(&i));
|
| +
|
| + EXPECT_GT(::VirtualFree(shadow_memory, 0, MEM_RELEASE), 0U);
|
| +}
|
| +
|
| } // namespace asan
|
| } // namespace agent
|
|
|