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

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

Line-by-line coverage:

   1    :  // Copyright 2014 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/error_info.h"
  16    :  
  17    :  #include <windows.h>
  18    :  
  19    :  #include "gtest/gtest.h"
  20    :  #include "syzygy/agent/asan/unittest_util.h"
  21    :  #include "syzygy/crashdata/json.h"
  22    :  
  23    :  namespace agent {
  24    :  namespace asan {
  25    :  
  26    :  namespace {
  27    :  
  28    :  typedef testing::TestWithAsanRuntime AsanErrorInfoTest;
  29    :  
  30    :  }  // namespace
  31    :  
  32  E :  TEST_F(AsanErrorInfoTest, ErrorInfoAccessTypeToStr) {
  33  E :    EXPECT_EQ(kHeapUseAfterFree, ErrorInfoAccessTypeToStr(USE_AFTER_FREE));
  34    :    EXPECT_EQ(kHeapBufferUnderFlow,
  35  E :              ErrorInfoAccessTypeToStr(HEAP_BUFFER_UNDERFLOW));
  36    :    EXPECT_EQ(kHeapBufferOverFlow,
  37  E :              ErrorInfoAccessTypeToStr(HEAP_BUFFER_OVERFLOW));
  38  E :    EXPECT_EQ(kAttemptingDoubleFree, ErrorInfoAccessTypeToStr(DOUBLE_FREE));
  39  E :    EXPECT_EQ(kInvalidAddress, ErrorInfoAccessTypeToStr(INVALID_ADDRESS));
  40  E :    EXPECT_EQ(kWildAccess, ErrorInfoAccessTypeToStr(WILD_ACCESS));
  41  E :    EXPECT_EQ(kHeapUnknownError, ErrorInfoAccessTypeToStr(UNKNOWN_BAD_ACCESS));
  42  E :    EXPECT_EQ(kHeapCorruptBlock, ErrorInfoAccessTypeToStr(CORRUPT_BLOCK));
  43  E :    EXPECT_EQ(kCorruptHeap, ErrorInfoAccessTypeToStr(CORRUPT_HEAP));
  44  E :  }
  45    :  
  46  E :  TEST_F(AsanErrorInfoTest, ErrorInfoGetBadAccessInformation) {
  47  E :    testing::FakeAsanBlock fake_block(kShadowRatioLog, runtime_->stack_cache());
  48  E :    const size_t kAllocSize = 100;
  49  E :    EXPECT_TRUE(fake_block.InitializeBlock(kAllocSize));
  50    :  
  51  E :    AsanErrorInfo error_info = {};
  52    :    error_info.location = fake_block.block_info.body +
  53  E :        kAllocSize + 1;
  54    :    EXPECT_TRUE(ErrorInfoGetBadAccessInformation(runtime_->stack_cache(),
  55  E :                                                 &error_info));
  56  E :    EXPECT_EQ(HEAP_BUFFER_OVERFLOW, error_info.error_type);
  57  E :    EXPECT_EQ(kUnknownHeapType, error_info.block_info.heap_type);
  58    :  
  59  E :    EXPECT_TRUE(fake_block.MarkBlockAsQuarantined());
  60  E :    error_info.location = fake_block.block_info.body;
  61    :    EXPECT_TRUE(ErrorInfoGetBadAccessInformation(runtime_->stack_cache(),
  62  E :                                                 &error_info));
  63  E :    EXPECT_EQ(USE_AFTER_FREE, error_info.error_type);
  64  E :    EXPECT_EQ(kUnknownHeapType, error_info.block_info.heap_type);
  65    :  
  66  E :    error_info.location = fake_block.buffer_align_begin - 1;
  67    :    EXPECT_FALSE(ErrorInfoGetBadAccessInformation(runtime_->stack_cache(),
  68  E :                                                  &error_info));
  69  E :  }
  70    :  
  71  E :  TEST_F(AsanErrorInfoTest, GetBadAccessInformationNestedBlock) {
  72    :    // Test a nested use after free. We allocate an outer block and an inner block
  73    :    // inside it, then we mark the outer block as quarantined and we test a bad
  74    :    // access inside the inner block.
  75    :  
  76  E :    testing::FakeAsanBlock fake_block(kShadowRatioLog, runtime_->stack_cache());
  77  E :    const size_t kInnerBlockAllocSize = 100;
  78    :  
  79    :    // Allocates the outer block.
  80  E :    BlockLayout outer_block_layout = {};
  81    :    EXPECT_TRUE(BlockPlanLayout(kShadowRatio, kShadowRatio, kInnerBlockAllocSize,
  82  E :                                0, 0, &outer_block_layout));
  83  E :    EXPECT_TRUE(fake_block.InitializeBlock(outer_block_layout.block_size));
  84    :  
  85  E :    common::StackCapture stack;
  86  E :    stack.InitFromStack();
  87    :  
  88    :    // Initializes the inner block.
  89  E :    BlockLayout inner_block_layout = {};
  90    :    EXPECT_TRUE(BlockPlanLayout(kShadowRatio,
  91    :                                kShadowRatio,
  92    :                                kInnerBlockAllocSize,
  93    :                                0,
  94    :                                0,
  95  E :                                &inner_block_layout));
  96  E :    BlockInfo inner_block_info = {};
  97    :    BlockInitialize(inner_block_layout, fake_block.block_info.body, true,
  98  E :        &inner_block_info);
  99  E :    ASSERT_NE(reinterpret_cast<void*>(NULL), inner_block_info.body);
 100  E :    Shadow::PoisonAllocatedBlock(inner_block_info);
 101    :    inner_block_info.header->alloc_stack =
 102  E :        runtime_->stack_cache()->SaveStackTrace(stack);
 103  E :    BlockHeader* inner_header = inner_block_info.header;
 104    :    BlockHeader* outer_header = reinterpret_cast<BlockHeader*>(
 105  E :        fake_block.buffer_align_begin);
 106    :  
 107  E :    AsanErrorInfo error_info = {};
 108    :  
 109    :    // Mark the inner block as quarantined and check that we detect a use after
 110    :    // free when trying to access its data.
 111    :    inner_block_info.header->free_stack =
 112  E :        runtime_->stack_cache()->SaveStackTrace(stack);
 113  E :    EXPECT_NE(reinterpret_cast<void*>(NULL), inner_header->free_stack);
 114  E :    inner_header->state = QUARANTINED_BLOCK;
 115    :  
 116  E :    error_info.location = fake_block.block_info.body;
 117    :    EXPECT_TRUE(ErrorInfoGetBadAccessInformation(runtime_->stack_cache(),
 118  E :                                                 &error_info));
 119  E :    EXPECT_EQ(USE_AFTER_FREE, error_info.error_type);
 120  E :    EXPECT_NE(reinterpret_cast<void*>(NULL), error_info.block_info.free_stack);
 121  E :    EXPECT_EQ(kUnknownHeapType, error_info.block_info.heap_type);
 122    :  
 123    :    EXPECT_EQ(inner_header->free_stack->num_frames(),
 124  E :              error_info.block_info.free_stack_size);
 125  E :    for (size_t i = 0; i < inner_header->free_stack->num_frames(); ++i) {
 126    :      EXPECT_EQ(inner_header->free_stack->frames()[i],
 127  E :                error_info.block_info.free_stack[i]);
 128  E :    }
 129    :  
 130    :    // Mark the outer block as quarantined, we should detect a use after free
 131    :    // when trying to access the data of the inner block, and the free stack
 132    :    // should be the one of the inner block.
 133  E :    EXPECT_TRUE(fake_block.MarkBlockAsQuarantined());
 134  E :    EXPECT_NE(ALLOCATED_BLOCK, static_cast<BlockState>(outer_header->state));
 135  E :    EXPECT_NE(reinterpret_cast<void*>(NULL), outer_header->free_stack);
 136    :  
 137    :    // Tests an access in the inner block.
 138  E :    error_info.location = inner_block_info.body;
 139    :    EXPECT_TRUE(ErrorInfoGetBadAccessInformation(runtime_->stack_cache(),
 140  E :                                                 &error_info));
 141  E :    EXPECT_EQ(USE_AFTER_FREE, error_info.error_type);
 142  E :    EXPECT_NE(reinterpret_cast<void*>(NULL), error_info.block_info.free_stack);
 143  E :    EXPECT_EQ(kUnknownHeapType, error_info.block_info.heap_type);
 144    :  
 145    :    EXPECT_EQ(inner_header->free_stack->num_frames(),
 146  E :              error_info.block_info.free_stack_size);
 147  E :    for (size_t i = 0; i < inner_header->free_stack->num_frames(); ++i) {
 148    :      EXPECT_EQ(inner_header->free_stack->frames()[i],
 149  E :                error_info.block_info.free_stack[i]);
 150  E :    }
 151  E :  }
 152    :  
 153  E :  TEST_F(AsanErrorInfoTest, ErrorInfoGetBadAccessKind) {
 154  E :    const size_t kAllocSize = 100;
 155  E :    testing::FakeAsanBlock fake_block(kShadowRatioLog, runtime_->stack_cache());
 156  E :    EXPECT_TRUE(fake_block.InitializeBlock(kAllocSize));
 157  E :    uint8* heap_underflow_address = fake_block.block_info.body - 1;
 158    :    uint8* heap_overflow_address = fake_block.block_info.body +
 159  E :        kAllocSize * sizeof(uint8);
 160    :    EXPECT_EQ(HEAP_BUFFER_UNDERFLOW,
 161    :              ErrorInfoGetBadAccessKind(heap_underflow_address,
 162  E :                                        fake_block.block_info.header));
 163    :    EXPECT_EQ(HEAP_BUFFER_OVERFLOW,
 164    :              ErrorInfoGetBadAccessKind(heap_overflow_address,
 165  E :                                        fake_block.block_info.header));
 166  E :    EXPECT_TRUE(fake_block.MarkBlockAsQuarantined());
 167    :    EXPECT_EQ(USE_AFTER_FREE, ErrorInfoGetBadAccessKind(
 168  E :        fake_block.block_info.body, fake_block.block_info.header));
 169  E :  }
 170    :  
 171  E :  TEST_F(AsanErrorInfoTest, ErrorInfoGetAsanBlockInfo) {
 172  E :    const size_t kAllocSize = 100;
 173  E :    testing::FakeAsanBlock fake_block(kShadowRatioLog, runtime_->stack_cache());
 174  E :    EXPECT_TRUE(fake_block.InitializeBlock(kAllocSize));
 175    :  
 176  E :    AsanBlockInfo asan_block_info = {};
 177    :    ErrorInfoGetAsanBlockInfo(fake_block.block_info,
 178    :                              runtime_->stack_cache(),
 179  E :                              &asan_block_info);
 180    :  
 181    :    // Test ErrorInfoGetAsanBlockInfo with an allocated block.
 182  E :    EXPECT_EQ(fake_block.block_info.body_size, asan_block_info.user_size);
 183  E :    EXPECT_EQ(ALLOCATED_BLOCK, static_cast<BlockState>(asan_block_info.state));
 184    :    EXPECT_EQ(fake_block.block_info.header->state,
 185  E :              static_cast<BlockState>(asan_block_info.state));
 186  E :    EXPECT_EQ(::GetCurrentThreadId(), asan_block_info.alloc_tid);
 187  E :    EXPECT_EQ(0, asan_block_info.free_tid);
 188  E :    EXPECT_EQ(kDataIsClean, asan_block_info.analysis.block_state);
 189    :    EXPECT_EQ(fake_block.block_info.header->alloc_stack->num_frames(),
 190  E :              asan_block_info.alloc_stack_size);
 191  E :    EXPECT_EQ(0, asan_block_info.free_stack_size);
 192  E :    EXPECT_EQ(kUnknownHeapType, asan_block_info.heap_type);
 193    :  
 194    :    // Now test it with a quarantined block.
 195  E :    EXPECT_TRUE(fake_block.MarkBlockAsQuarantined());
 196    :    ErrorInfoGetAsanBlockInfo(fake_block.block_info,
 197    :                              runtime_->stack_cache(),
 198  E :                              &asan_block_info);
 199  E :    EXPECT_EQ(QUARANTINED_BLOCK, static_cast<BlockState>(asan_block_info.state));
 200    :    EXPECT_EQ(fake_block.block_info.header->state,
 201  E :              static_cast<BlockState>(asan_block_info.state));
 202  E :    EXPECT_EQ(::GetCurrentThreadId(), asan_block_info.free_tid);
 203    :    EXPECT_EQ(fake_block.block_info.header->free_stack->num_frames(),
 204  E :              asan_block_info.free_stack_size);
 205  E :    EXPECT_EQ(kUnknownHeapType, asan_block_info.heap_type);
 206    :  
 207    :    // Ensure that the block is correctly tagged as corrupt if the header is
 208    :    // invalid.
 209  E :    fake_block.block_info.header->magic = ~kBlockHeaderMagic;
 210    :    ErrorInfoGetAsanBlockInfo(fake_block.block_info,
 211    :                              runtime_->stack_cache(),
 212  E :                              &asan_block_info);
 213  E :    EXPECT_EQ(kDataIsCorrupt, asan_block_info.analysis.block_state);
 214  E :    fake_block.block_info.header->magic = kBlockHeaderMagic;
 215  E :  }
 216    :  
 217  E :  TEST_F(AsanErrorInfoTest, GetTimeSinceFree) {
 218  E :    const size_t kAllocSize = 100;
 219  E :    const size_t kSleepTime = 25;
 220  E :    testing::FakeAsanBlock fake_block(kShadowRatioLog, runtime_->stack_cache());
 221  E :    EXPECT_TRUE(fake_block.InitializeBlock(kAllocSize));
 222    :  
 223  E :    uint32 ticks_before_free = ::GetTickCount();
 224  E :    EXPECT_TRUE(fake_block.MarkBlockAsQuarantined());
 225  E :    ::Sleep(kSleepTime);
 226  E :    AsanErrorInfo error_info = {};
 227  E :    error_info.error_type = USE_AFTER_FREE;
 228  E :    error_info.location = fake_block.block_info.body;
 229    :    EXPECT_TRUE(ErrorInfoGetBadAccessInformation(runtime_->stack_cache(),
 230  E :                                                 &error_info));
 231  E :    EXPECT_NE(0U, error_info.block_info.milliseconds_since_free);
 232    :  
 233  E :    uint32 ticks_delta = ::GetTickCount() - ticks_before_free;
 234  E :    EXPECT_GT(ticks_delta, 0U);
 235    :  
 236  E :    EXPECT_GE(ticks_delta, error_info.block_info.milliseconds_since_free);
 237  E :  }
 238    :  
 239    :  namespace {
 240    :  
 241  E :  void InitAsanBlockInfo(AsanBlockInfo* block_info) {
 242  E :    block_info->header = reinterpret_cast<void*>(0xDEADBEEF);
 243  E :    block_info->user_size = 1024;
 244  E :    block_info->state = ALLOCATED_BLOCK;
 245  E :    block_info->alloc_tid = 47;
 246  E :    block_info->analysis.block_state = kDataIsCorrupt;
 247  E :    block_info->analysis.header_state = kDataIsCorrupt;
 248  E :    block_info->analysis.body_state = kDataStateUnknown;
 249  E :    block_info->analysis.trailer_state = kDataIsClean;
 250  E :    block_info->alloc_stack[0] = reinterpret_cast<void*>(1);
 251  E :    block_info->alloc_stack[1] = reinterpret_cast<void*>(2);
 252  E :    block_info->alloc_stack_size = 2;
 253  E :    block_info->heap_type = kWinHeap;
 254  E :  }
 255    :  
 256    :  }  // namespace
 257    :  
 258  E :  TEST_F(AsanErrorInfoTest, PopulateBlockInfo) {
 259  E :    AsanBlockInfo block_info = {};
 260  E :    InitAsanBlockInfo(&block_info);
 261    :  
 262    :    {
 263  E :      crashdata::Value info;
 264  E :      PopulateBlockInfo(block_info, &info);
 265  E :      std::string json;
 266  E :      EXPECT_TRUE(crashdata::ToJson(true, &info, &json));
 267    :      const char kExpected[] =
 268    :          "{\n"
 269    :          "  \"header\": 0xDEADBEEF,\n"
 270    :          "  \"user-size\": 1024,\n"
 271    :          "  \"state\": \"allocated\",\n"
 272    :          "  \"heap-type\": \"WinHeap\",\n"
 273    :          "  \"analysis\": {\n"
 274    :          "    \"block\": \"corrupt\",\n"
 275    :          "    \"header\": \"corrupt\",\n"
 276    :          "    \"body\": \"(unknown)\",\n"
 277    :          "    \"trailer\": \"clean\"\n"
 278    :          "  },\n"
 279    :          "  \"alloc-thread-id\": 47,\n"
 280    :          "  \"alloc-stack\": [\n"
 281    :          "    0x00000001, 0x00000002\n"
 282    :          "  ]\n"
 283  E :          "}";
 284  E :      EXPECT_EQ(kExpected, json);
 285  E :    }
 286    :  
 287  E :    block_info.state = QUARANTINED_BLOCK;
 288  E :    block_info.free_tid = 32;
 289  E :    block_info.free_stack[0] = reinterpret_cast<void*>(3);
 290  E :    block_info.free_stack[1] = reinterpret_cast<void*>(4);
 291  E :    block_info.free_stack[2] = reinterpret_cast<void*>(5);
 292  E :    block_info.free_stack_size = 3;
 293  E :    block_info.heap_type = kCtMallocHeap;
 294  E :    block_info.milliseconds_since_free = 100;
 295    :  
 296    :    {
 297  E :      crashdata::Value info;
 298  E :      PopulateBlockInfo(block_info, &info);
 299  E :      std::string json;
 300  E :      EXPECT_TRUE(crashdata::ToJson(true, &info, &json));
 301    :      const char kExpected[] =
 302    :          "{\n"
 303    :          "  \"header\": 0xDEADBEEF,\n"
 304    :          "  \"user-size\": 1024,\n"
 305    :          "  \"state\": \"quarantined\",\n"
 306    :          "  \"heap-type\": \"CtMallocHeap\",\n"
 307    :          "  \"analysis\": {\n"
 308    :          "    \"block\": \"corrupt\",\n"
 309    :          "    \"header\": \"corrupt\",\n"
 310    :          "    \"body\": \"(unknown)\",\n"
 311    :          "    \"trailer\": \"clean\"\n"
 312    :          "  },\n"
 313    :          "  \"alloc-thread-id\": 47,\n"
 314    :          "  \"alloc-stack\": [\n"
 315    :          "    0x00000001, 0x00000002\n"
 316    :          "  ],\n"
 317    :          "  \"free-thread-id\": 32,\n"
 318    :          "  \"free-stack\": [\n"
 319    :          "    0x00000003, 0x00000004, 0x00000005\n"
 320    :          "  ],\n"
 321    :          "  \"milliseconds-since-free\": 100\n"
 322  E :          "}";
 323  E :      EXPECT_EQ(kExpected, json);
 324  E :    }
 325  E :  }
 326    :  
 327  E :  TEST_F(AsanErrorInfoTest, PopulateCorruptBlockRange) {
 328  E :    AsanBlockInfo block_info = {};
 329  E :    InitAsanBlockInfo(&block_info);
 330    :  
 331  E :    AsanCorruptBlockRange range = {};
 332  E :    range.address = reinterpret_cast<void*>(0xBAADF00D);
 333  E :    range.length = 1024 * 1024;
 334  E :    range.block_count = 100;
 335  E :    range.block_info_count = 1;
 336  E :    range.block_info = &block_info;
 337    :  
 338  E :    crashdata::Value info;
 339  E :    PopulateCorruptBlockRange(range, &info);
 340    :  
 341  E :    std::string json;
 342  E :    EXPECT_TRUE(crashdata::ToJson(true, &info, &json));
 343    :    const char kExpected[] =
 344    :        "{\n"
 345    :        "  \"address\": 0xBAADF00D,\n"
 346    :        "  \"length\": 1048576,\n"
 347    :        "  \"block-count\": 100,\n"
 348    :        "  \"blocks\": [\n"
 349    :        "    {\n"
 350    :        "      \"header\": 0xDEADBEEF,\n"
 351    :        "      \"user-size\": 1024,\n"
 352    :        "      \"state\": \"allocated\",\n"
 353    :        "      \"heap-type\": \"WinHeap\",\n"
 354    :        "      \"analysis\": {\n"
 355    :        "        \"block\": \"corrupt\",\n"
 356    :        "        \"header\": \"corrupt\",\n"
 357    :        "        \"body\": \"(unknown)\",\n"
 358    :        "        \"trailer\": \"clean\"\n"
 359    :        "      },\n"
 360    :        "      \"alloc-thread-id\": 47,\n"
 361    :        "      \"alloc-stack\": [\n"
 362    :        "        0x00000001, 0x00000002\n"
 363    :        "      ]\n"
 364    :        "    }\n"
 365    :        "  ]\n"
 366  E :        "}";
 367  E :    EXPECT_EQ(kExpected, json);
 368  E :  }
 369    :  
 370  E :  TEST_F(AsanErrorInfoTest, PopulateErrorInfo) {
 371  E :    AsanBlockInfo block_info = {};
 372  E :    InitAsanBlockInfo(&block_info);
 373    :  
 374  E :    AsanCorruptBlockRange range = {};
 375  E :    range.address = reinterpret_cast<void*>(0xBAADF00D);
 376  E :    range.length = 1024 * 1024;
 377  E :    range.block_count = 100;
 378  E :    range.block_info_count = 1;
 379  E :    range.block_info = &block_info;
 380    :  
 381    :    // The 'location' address needs to be at a consistent place in system memory
 382    :    // so that shadow memory contents and page bits don't vary, otherwise the
 383    :    // test won't be deterministic.
 384  E :    AsanErrorInfo error_info = {};
 385  E :    error_info.location = reinterpret_cast<void*>(0x00001000);
 386  E :    error_info.crash_stack_id = 1234;
 387  E :    InitAsanBlockInfo(&error_info.block_info);
 388  E :    error_info.error_type = WILD_ACCESS;
 389  E :    error_info.access_mode = ASAN_READ_ACCESS;
 390  E :    error_info.access_size = 4;
 391    :    ::strncpy(error_info.shadow_info,
 392    :              "shadow info!",
 393  E :              sizeof(error_info.shadow_info));
 394    :    ::strncpy(error_info.shadow_memory,
 395    :              "shadow memory!",
 396  E :              sizeof(error_info.shadow_memory));
 397  E :    error_info.heap_is_corrupt = true;
 398  E :    error_info.corrupt_range_count = 10;
 399  E :    error_info.corrupt_block_count = 200;
 400  E :    error_info.corrupt_ranges_reported = 1;
 401  E :    error_info.corrupt_ranges = &range;
 402    :  
 403  E :    crashdata::Value info;
 404  E :    PopulateErrorInfo(error_info, &info);
 405    :  
 406  E :    std::string json;
 407  E :    EXPECT_TRUE(crashdata::ToJson(true, &info, &json));
 408    :    const char kExpected[] =
 409    :        "{\n"
 410    :        "  \"location\": 0x00001000,\n"
 411    :        "  \"crash-stack-id\": 1234,\n"
 412    :        "  \"block-info\": {\n"
 413    :        "    \"header\": 0xDEADBEEF,\n"
 414    :        "    \"user-size\": 1024,\n"
 415    :        "    \"state\": \"allocated\",\n"
 416    :        "    \"heap-type\": \"WinHeap\",\n"
 417    :        "    \"analysis\": {\n"
 418    :        "      \"block\": \"corrupt\",\n"
 419    :        "      \"header\": \"corrupt\",\n"
 420    :        "      \"body\": \"(unknown)\",\n"
 421    :        "      \"trailer\": \"clean\"\n"
 422    :        "    },\n"
 423    :        "    \"alloc-thread-id\": 47,\n"
 424    :        "    \"alloc-stack\": [\n"
 425    :        "      0x00000001, 0x00000002\n"
 426    :        "    ]\n"
 427    :        "  },\n"
 428    :        "  \"error-type\": \"wild-access\",\n"
 429    :        "  \"access-mode\": \"read\",\n"
 430    :        "  \"access-size\": 4,\n"
 431    :        "  \"shadow-memory-index\": 512,\n"
 432    :        "  \"shadow-memory\": {\n"
 433    :        "    \"type\": \"blob\",\n"
 434    :        "    \"address\": null,\n"
 435    :        "    \"size\": null,\n"
 436    :        "    \"data\": [\n"
 437    :        "      0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,\n"
 438    :        "      0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,\n"
 439    :        "      0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,\n"
 440    :        "      0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,\n"
 441    :        "      0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,\n"
 442    :        "      0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,\n"
 443    :        "      0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,\n"
 444    :        "      0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2\n"
 445    :        "    ]\n"
 446    :        "  },\n"
 447    :        "  \"page-bits-index\": 0,\n"
 448    :        "  \"page-bits\": {\n"
 449    :        "    \"type\": \"blob\",\n"
 450    :        "    \"address\": null,\n"
 451    :        "    \"size\": null,\n"
 452    :        "    \"data\": [\n"
 453    :        "      0x00, 0x00, 0x00\n"
 454    :        "    ]\n"
 455    :        "  },\n"
 456    :        "  \"heap-is-corrupt\": 1,\n"
 457    :        "  \"corrupt-range-count\": 10,\n"
 458    :        "  \"corrupt-block-count\": 200,\n"
 459    :        "  \"corrupt-ranges\": [\n"
 460    :        "    {\n"
 461    :        "      \"address\": 0xBAADF00D,\n"
 462    :        "      \"length\": 1048576,\n"
 463    :        "      \"block-count\": 100,\n"
 464    :        "      \"blocks\": [\n"
 465    :        "        {\n"
 466    :        "          \"header\": 0xDEADBEEF,\n"
 467    :        "          \"user-size\": 1024,\n"
 468    :        "          \"state\": \"allocated\",\n"
 469    :        "          \"heap-type\": \"WinHeap\",\n"
 470    :        "          \"analysis\": {\n"
 471    :        "            \"block\": \"corrupt\",\n"
 472    :        "            \"header\": \"corrupt\",\n"
 473    :        "            \"body\": \"(unknown)\",\n"
 474    :        "            \"trailer\": \"clean\"\n"
 475    :        "          },\n"
 476    :        "          \"alloc-thread-id\": 47,\n"
 477    :        "          \"alloc-stack\": [\n"
 478    :        "            0x00000001, 0x00000002\n"
 479    :        "          ]\n"
 480    :        "        }\n"
 481    :        "      ]\n"
 482    :        "    }\n"
 483    :        "  ]\n"
 484  E :        "}";
 485  E :    EXPECT_EQ(kExpected, json);
 486  E :  }
 487    :  
 488    :  }  // namespace asan
 489    :  }  // namespace agent

Coverage information generated Thu Mar 26 16:15:41 2015.