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

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
100.0%3173170.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 <string>
  20    :  
  21    :  #include "base/strings/stringprintf.h"
  22    :  #include "gtest/gtest.h"
  23    :  #include "syzygy/agent/asan/unittest_util.h"
  24    :  #include "syzygy/crashdata/json.h"
  25    :  
  26    :  namespace agent {
  27    :  namespace asan {
  28    :  
  29    :  namespace {
  30    :  
  31    :  class AsanErrorInfoTest : public testing::TestWithAsanRuntime {
  32    :   public:
  33    :    typedef testing::TestWithAsanRuntime Super;
  34  E :    void SetUp() override {
  35  E :      Super::SetUp();
  36  E :    }
  37    :  
  38  E :    void TearDown() override {
  39    :      // Clean up the fake asan block if there is one.
  40    :      // TODO(chrisha): Migrate this to using a dynamic shadow.
  41  E :      if (!dummy_block_data_.empty()) {
  42    :        runtime_->shadow()->Unpoison(dummy_block_data_.data(),
  43  E :                                     dummy_block_data_.size());
  44    :      }
  45    :  
  46  E :      Super::TearDown();
  47  E :    }
  48    :  
  49  E :    void InitAsanBlockInfo(AsanBlockInfo* block_info) {
  50  E :      if (dummy_block_data_.empty()) {
  51    :        // Create a dummy block to physically back the report.
  52  E :        BlockLayout layout = {};
  53  E :        BlockPlanLayout(kShadowRatio, kShadowRatio, 8, 0, 0, &layout);
  54  E :        dummy_block_data_.resize(layout.block_size);
  55  E :        BlockInfo info = {};
  56  E :        BlockInitialize(layout, &dummy_block_data_.at(0), false, &info);
  57  E :        runtime_->shadow()->PoisonAllocatedBlock(info);
  58    :  
  59    :        // Normalize a handful of fields to make the comparison simpler.
  60  E :        info.trailer->alloc_ticks = 0;
  61  E :        info.trailer->alloc_tid = 0;
  62    :      }
  63    :  
  64  E :      block_info->header = &dummy_block_data_.at(0);
  65  E :      block_info->user_size = 8;
  66  E :      block_info->state = ALLOCATED_BLOCK;
  67  E :      block_info->alloc_tid = 47;
  68  E :      block_info->analysis.block_state = kDataIsCorrupt;
  69  E :      block_info->analysis.header_state = kDataIsCorrupt;
  70  E :      block_info->analysis.body_state = kDataStateUnknown;
  71  E :      block_info->analysis.trailer_state = kDataIsClean;
  72  E :      block_info->alloc_stack[0] = reinterpret_cast<void*>(1);
  73  E :      block_info->alloc_stack[1] = reinterpret_cast<void*>(2);
  74  E :      block_info->alloc_stack_size = 2;
  75  E :      block_info->heap_type = kWinHeap;
  76  E :    }
  77    :  
  78  E :    const void* BlockShadowAddress() {
  79    :      return runtime_->shadow()->shadow() +
  80  E :          reinterpret_cast<uintptr_t>(dummy_block_data_.data()) / kShadowRatio;
  81  E :    }
  82    :  
  83    :   private:
  84    :    std::vector<unsigned char> dummy_block_data_;
  85    :  };
  86    :  
  87    :  
  88    :  }  // namespace
  89    :  
  90  E :  TEST_F(AsanErrorInfoTest, ErrorInfoAccessTypeToStr) {
  91  E :    EXPECT_EQ(kHeapUseAfterFree, ErrorInfoAccessTypeToStr(USE_AFTER_FREE));
  92    :    EXPECT_EQ(kHeapBufferUnderFlow,
  93  E :              ErrorInfoAccessTypeToStr(HEAP_BUFFER_UNDERFLOW));
  94    :    EXPECT_EQ(kHeapBufferOverFlow,
  95  E :              ErrorInfoAccessTypeToStr(HEAP_BUFFER_OVERFLOW));
  96  E :    EXPECT_EQ(kAttemptingDoubleFree, ErrorInfoAccessTypeToStr(DOUBLE_FREE));
  97  E :    EXPECT_EQ(kInvalidAddress, ErrorInfoAccessTypeToStr(INVALID_ADDRESS));
  98  E :    EXPECT_EQ(kWildAccess, ErrorInfoAccessTypeToStr(WILD_ACCESS));
  99  E :    EXPECT_EQ(kHeapUnknownError, ErrorInfoAccessTypeToStr(UNKNOWN_BAD_ACCESS));
 100  E :    EXPECT_EQ(kHeapCorruptBlock, ErrorInfoAccessTypeToStr(CORRUPT_BLOCK));
 101  E :    EXPECT_EQ(kCorruptHeap, ErrorInfoAccessTypeToStr(CORRUPT_HEAP));
 102  E :  }
 103    :  
 104  E :  TEST_F(AsanErrorInfoTest, ErrorInfoGetBadAccessInformation) {
 105    :    testing::FakeAsanBlock fake_block(
 106  E :        runtime_->shadow(), kShadowRatioLog, runtime_->stack_cache());
 107  E :    const size_t kAllocSize = 100;
 108  E :    EXPECT_TRUE(fake_block.InitializeBlock(kAllocSize));
 109    :  
 110  E :    AsanErrorInfo error_info = {};
 111  E :    error_info.location = fake_block.block_info.RawBody() + kAllocSize + 1;
 112    :    EXPECT_TRUE(ErrorInfoGetBadAccessInformation(runtime_->shadow(),
 113    :                                                 runtime_->stack_cache(),
 114  E :                                                 &error_info));
 115  E :    EXPECT_EQ(HEAP_BUFFER_OVERFLOW, error_info.error_type);
 116  E :    EXPECT_EQ(kUnknownHeapType, error_info.block_info.heap_type);
 117    :  
 118  E :    EXPECT_TRUE(fake_block.MarkBlockAsQuarantined());
 119  E :    error_info.location = fake_block.block_info.body;
 120    :    EXPECT_TRUE(ErrorInfoGetBadAccessInformation(runtime_->shadow(),
 121    :                                                 runtime_->stack_cache(),
 122  E :                                                 &error_info));
 123  E :    EXPECT_EQ(USE_AFTER_FREE, error_info.error_type);
 124  E :    EXPECT_EQ(kUnknownHeapType, error_info.block_info.heap_type);
 125    :  
 126  E :    error_info.location = fake_block.buffer_align_begin - 1;
 127    :    EXPECT_FALSE(ErrorInfoGetBadAccessInformation(runtime_->shadow(),
 128    :                                                  runtime_->stack_cache(),
 129  E :                                                  &error_info));
 130  E :  }
 131    :  
 132  E :  TEST_F(AsanErrorInfoTest, GetBadAccessInformationNestedBlock) {
 133    :    // Test a nested use after free. We allocate an outer block and an inner block
 134    :    // inside it, then we mark the outer block as quarantined and we test a bad
 135    :    // access inside the inner block.
 136    :  
 137    :    testing::FakeAsanBlock fake_block(
 138  E :        runtime_->shadow(), kShadowRatioLog, runtime_->stack_cache());
 139  E :    const size_t kInnerBlockAllocSize = 100;
 140    :  
 141    :    // Allocates the outer block.
 142  E :    BlockLayout outer_block_layout = {};
 143    :    EXPECT_TRUE(BlockPlanLayout(kShadowRatio, kShadowRatio, kInnerBlockAllocSize,
 144  E :                                0, 0, &outer_block_layout));
 145  E :    EXPECT_TRUE(fake_block.InitializeBlock(outer_block_layout.block_size));
 146    :  
 147  E :    common::StackCapture stack;
 148  E :    stack.InitFromStack();
 149    :  
 150    :    // Initializes the inner block.
 151  E :    BlockLayout inner_block_layout = {};
 152    :    EXPECT_TRUE(BlockPlanLayout(kShadowRatio,
 153    :                                kShadowRatio,
 154    :                                kInnerBlockAllocSize,
 155    :                                0,
 156    :                                0,
 157  E :                                &inner_block_layout));
 158  E :    BlockInfo inner_block_info = {};
 159    :    BlockInitialize(inner_block_layout, fake_block.block_info.body, true,
 160  E :        &inner_block_info);
 161  E :    ASSERT_NE(reinterpret_cast<void*>(NULL), inner_block_info.body);
 162  E :    runtime_->shadow()->PoisonAllocatedBlock(inner_block_info);
 163    :    inner_block_info.header->alloc_stack =
 164  E :        runtime_->stack_cache()->SaveStackTrace(stack);
 165  E :    BlockHeader* inner_header = inner_block_info.header;
 166    :    BlockHeader* outer_header = reinterpret_cast<BlockHeader*>(
 167  E :        fake_block.buffer_align_begin);
 168    :  
 169  E :    AsanErrorInfo error_info = {};
 170    :  
 171    :    // Mark the inner block as quarantined and check that we detect a use after
 172    :    // free when trying to access its data.
 173    :    inner_block_info.header->free_stack =
 174  E :        runtime_->stack_cache()->SaveStackTrace(stack);
 175  E :    EXPECT_NE(reinterpret_cast<void*>(NULL), inner_header->free_stack);
 176  E :    inner_header->state = QUARANTINED_BLOCK;
 177    :  
 178  E :    error_info.location = fake_block.block_info.body;
 179    :    EXPECT_TRUE(ErrorInfoGetBadAccessInformation(runtime_->shadow(),
 180    :                                                 runtime_->stack_cache(),
 181  E :                                                 &error_info));
 182  E :    EXPECT_EQ(USE_AFTER_FREE, error_info.error_type);
 183  E :    EXPECT_NE(reinterpret_cast<void*>(NULL), error_info.block_info.free_stack);
 184  E :    EXPECT_EQ(kUnknownHeapType, error_info.block_info.heap_type);
 185    :  
 186    :    EXPECT_EQ(inner_header->free_stack->num_frames(),
 187  E :              error_info.block_info.free_stack_size);
 188  E :    for (size_t i = 0; i < inner_header->free_stack->num_frames(); ++i) {
 189    :      EXPECT_EQ(inner_header->free_stack->frames()[i],
 190  E :                error_info.block_info.free_stack[i]);
 191  E :    }
 192    :  
 193    :    // Mark the outer block as quarantined, we should detect a use after free
 194    :    // when trying to access the data of the inner block, and the free stack
 195    :    // should be the one of the inner block.
 196  E :    EXPECT_TRUE(fake_block.MarkBlockAsQuarantined());
 197  E :    EXPECT_NE(ALLOCATED_BLOCK, static_cast<BlockState>(outer_header->state));
 198  E :    EXPECT_NE(reinterpret_cast<void*>(NULL), outer_header->free_stack);
 199    :  
 200    :    // Tests an access in the inner block.
 201  E :    error_info.location = inner_block_info.body;
 202    :    EXPECT_TRUE(ErrorInfoGetBadAccessInformation(runtime_->shadow(),
 203    :                                                 runtime_->stack_cache(),
 204  E :                                                 &error_info));
 205  E :    EXPECT_EQ(USE_AFTER_FREE, error_info.error_type);
 206  E :    EXPECT_NE(reinterpret_cast<void*>(NULL), error_info.block_info.free_stack);
 207  E :    EXPECT_EQ(kUnknownHeapType, error_info.block_info.heap_type);
 208    :  
 209    :    EXPECT_EQ(inner_header->free_stack->num_frames(),
 210  E :              error_info.block_info.free_stack_size);
 211  E :    for (size_t i = 0; i < inner_header->free_stack->num_frames(); ++i) {
 212    :      EXPECT_EQ(inner_header->free_stack->frames()[i],
 213  E :                error_info.block_info.free_stack[i]);
 214  E :    }
 215  E :  }
 216    :  
 217  E :  TEST_F(AsanErrorInfoTest, ErrorInfoGetBadAccessKind) {
 218  E :    const size_t kAllocSize = 100;
 219    :    testing::FakeAsanBlock fake_block(
 220  E :        runtime_->shadow(), kShadowRatioLog, runtime_->stack_cache());
 221  E :    EXPECT_TRUE(fake_block.InitializeBlock(kAllocSize));
 222  E :    uint8* heap_underflow_address = fake_block.block_info.RawBody() - 1;
 223    :    uint8* heap_overflow_address = fake_block.block_info.RawBody() +
 224  E :        kAllocSize * sizeof(uint8);
 225    :    EXPECT_EQ(HEAP_BUFFER_UNDERFLOW,
 226    :              ErrorInfoGetBadAccessKind(runtime_->shadow(),
 227    :                                        heap_underflow_address,
 228  E :                                        fake_block.block_info.header));
 229    :    EXPECT_EQ(HEAP_BUFFER_OVERFLOW,
 230    :              ErrorInfoGetBadAccessKind(runtime_->shadow(),
 231    :                                        heap_overflow_address,
 232  E :                                        fake_block.block_info.header));
 233  E :    EXPECT_TRUE(fake_block.MarkBlockAsQuarantined());
 234    :    EXPECT_EQ(USE_AFTER_FREE, ErrorInfoGetBadAccessKind(runtime_->shadow(),
 235  E :        fake_block.block_info.body, fake_block.block_info.header));
 236  E :  }
 237    :  
 238  E :  TEST_F(AsanErrorInfoTest, ErrorInfoGetAsanBlockInfo) {
 239  E :    const size_t kAllocSize = 100;
 240    :    testing::FakeAsanBlock fake_block(
 241  E :        runtime_->shadow(), kShadowRatioLog, runtime_->stack_cache());
 242  E :    EXPECT_TRUE(fake_block.InitializeBlock(kAllocSize));
 243    :  
 244  E :    AsanBlockInfo asan_block_info = {};
 245    :    ErrorInfoGetAsanBlockInfo(runtime_->shadow(), fake_block.block_info,
 246  E :                              runtime_->stack_cache(), &asan_block_info);
 247    :  
 248    :    // Test ErrorInfoGetAsanBlockInfo with an allocated block.
 249  E :    EXPECT_EQ(fake_block.block_info.body_size, asan_block_info.user_size);
 250  E :    EXPECT_EQ(ALLOCATED_BLOCK, static_cast<BlockState>(asan_block_info.state));
 251    :    EXPECT_EQ(fake_block.block_info.header->state,
 252  E :              static_cast<BlockState>(asan_block_info.state));
 253  E :    EXPECT_EQ(::GetCurrentThreadId(), asan_block_info.alloc_tid);
 254  E :    EXPECT_EQ(0, asan_block_info.free_tid);
 255  E :    EXPECT_EQ(kDataIsClean, asan_block_info.analysis.block_state);
 256    :    EXPECT_EQ(fake_block.block_info.header->alloc_stack->num_frames(),
 257  E :              asan_block_info.alloc_stack_size);
 258  E :    EXPECT_EQ(0, asan_block_info.free_stack_size);
 259  E :    EXPECT_EQ(kUnknownHeapType, asan_block_info.heap_type);
 260    :  
 261    :    // Now test it with a quarantined block.
 262  E :    EXPECT_TRUE(fake_block.MarkBlockAsQuarantined());
 263    :    ErrorInfoGetAsanBlockInfo(runtime_->shadow(), fake_block.block_info,
 264  E :                              runtime_->stack_cache(), &asan_block_info);
 265  E :    EXPECT_EQ(QUARANTINED_BLOCK, static_cast<BlockState>(asan_block_info.state));
 266    :    EXPECT_EQ(fake_block.block_info.header->state,
 267  E :              static_cast<BlockState>(asan_block_info.state));
 268  E :    EXPECT_EQ(::GetCurrentThreadId(), asan_block_info.free_tid);
 269    :    EXPECT_EQ(fake_block.block_info.header->free_stack->num_frames(),
 270  E :              asan_block_info.free_stack_size);
 271  E :    EXPECT_EQ(kUnknownHeapType, asan_block_info.heap_type);
 272    :  
 273    :    // Ensure that the block is correctly tagged as corrupt if the header is
 274    :    // invalid.
 275    :    fake_block.block_info.header->magic =
 276  E :        static_cast<unsigned>(~kBlockHeaderMagic);
 277    :    ErrorInfoGetAsanBlockInfo(runtime_->shadow(), fake_block.block_info,
 278  E :                              runtime_->stack_cache(), &asan_block_info);
 279  E :    EXPECT_EQ(kDataIsCorrupt, asan_block_info.analysis.block_state);
 280    :    fake_block.block_info.header->magic =
 281  E :        static_cast<unsigned>(~kBlockHeaderMagic);
 282  E :  }
 283    :  
 284  E :  TEST_F(AsanErrorInfoTest, GetTimeSinceFree) {
 285  E :    const size_t kAllocSize = 100;
 286  E :    const size_t kSleepTime = 25;
 287    :    testing::FakeAsanBlock fake_block(
 288  E :        runtime_->shadow(), kShadowRatioLog, runtime_->stack_cache());
 289  E :    EXPECT_TRUE(fake_block.InitializeBlock(kAllocSize));
 290    :  
 291  E :    uint32 ticks_before_free = ::GetTickCount();
 292  E :    EXPECT_TRUE(fake_block.MarkBlockAsQuarantined());
 293  E :    ::Sleep(kSleepTime);
 294  E :    AsanErrorInfo error_info = {};
 295  E :    error_info.error_type = USE_AFTER_FREE;
 296  E :    error_info.location = fake_block.block_info.body;
 297    :    EXPECT_TRUE(ErrorInfoGetBadAccessInformation(runtime_->shadow(),
 298    :                                                 runtime_->stack_cache(),
 299  E :                                                 &error_info));
 300  E :    EXPECT_NE(0U, error_info.block_info.milliseconds_since_free);
 301    :  
 302  E :    uint32 ticks_delta = ::GetTickCount() - ticks_before_free;
 303  E :    EXPECT_GT(ticks_delta, 0U);
 304    :  
 305  E :    EXPECT_GE(ticks_delta, error_info.block_info.milliseconds_since_free);
 306  E :  }
 307    :  
 308  E :  TEST_F(AsanErrorInfoTest, PopulateBlockInfo) {
 309  E :    AsanBlockInfo block_info = {};
 310  E :    InitAsanBlockInfo(&block_info);
 311    :  
 312    :    {
 313  E :      crashdata::Value info;
 314  E :      PopulateBlockInfo(runtime_->shadow(), block_info, false, &info, nullptr);
 315  E :      std::string json;
 316  E :      EXPECT_TRUE(crashdata::ToJson(true, &info, &json));
 317    :      const char kExpected[] =
 318    :          "{\n"
 319    :          "  \"header\": \"0x%08X\",\n"
 320    :          "  \"user-size\": 8,\n"
 321    :          "  \"state\": \"allocated\",\n"
 322    :          "  \"heap-type\": \"WinHeap\",\n"
 323    :          "  \"analysis\": {\n"
 324    :          "    \"block\": \"corrupt\",\n"
 325    :          "    \"header\": \"corrupt\",\n"
 326    :          "    \"body\": \"(unknown)\",\n"
 327    :          "    \"trailer\": \"clean\"\n"
 328    :          "  },\n"
 329    :          "  \"alloc-thread-id\": 47,\n"
 330    :          "  \"alloc-stack\": [\n"
 331    :          "    \"0x00000001\", \"0x00000002\"\n"
 332    :          "  ]\n"
 333  E :          "}";
 334    :      std::string expected = base::StringPrintf(
 335  E :          kExpected, block_info.header);
 336  E :      EXPECT_EQ(expected, json);
 337  E :    }
 338    :  
 339    :    {
 340  E :      block_info.state = QUARANTINED_FLOODED_BLOCK;
 341  E :      block_info.free_tid = 32;
 342  E :      block_info.free_stack[0] = reinterpret_cast<void*>(3);
 343  E :      block_info.free_stack[1] = reinterpret_cast<void*>(4);
 344  E :      block_info.free_stack[2] = reinterpret_cast<void*>(5);
 345  E :      block_info.free_stack_size = 3;
 346  E :      block_info.heap_type = kWinHeap;
 347  E :      block_info.milliseconds_since_free = 100;
 348    :  
 349  E :      crashdata::Value value;
 350  E :      PopulateBlockInfo(runtime_->shadow(), block_info, true, &value, nullptr);
 351  E :      std::string json;
 352  E :      EXPECT_TRUE(crashdata::ToJson(true, &value, &json));
 353    :      const char kExpected[] =
 354    :          "{\n"
 355    :          "  \"header\": \"0x%08X\",\n"
 356    :          "  \"user-size\": 8,\n"
 357    :          "  \"state\": \"quarantined (flooded)\",\n"
 358    :          "  \"heap-type\": \"WinHeap\",\n"
 359    :          "  \"analysis\": {\n"
 360    :          "    \"block\": \"corrupt\",\n"
 361    :          "    \"header\": \"corrupt\",\n"
 362    :          "    \"body\": \"(unknown)\",\n"
 363    :          "    \"trailer\": \"clean\"\n"
 364    :          "  },\n"
 365    :          "  \"alloc-thread-id\": 47,\n"
 366    :          "  \"alloc-stack\": [\n"
 367    :          "    \"0x00000001\", \"0x00000002\"\n"
 368    :          "  ],\n"
 369    :          "  \"free-thread-id\": 32,\n"
 370    :          "  \"free-stack\": [\n"
 371    :          "    \"0x00000003\", \"0x00000004\", \"0x00000005\"\n"
 372    :          "  ],\n"
 373    :          "  \"milliseconds-since-free\": 100,\n"
 374    :          "  \"contents\": {\n"
 375    :          "    \"type\": \"blob\",\n"
 376    :          "    \"address\": \"0x%08X\",\n"
 377    :          "    \"size\": null,\n"
 378    :          "    \"data\": [\n"
 379    :          "      \"0x80\", \"0xCA\", \"0x00\", \"0x00\", \"0x20\", \"0x00\","
 380    :          " \"0x00\", \"0x00\",\n"
 381    :          "      \"0x00\", \"0x00\", \"0x00\", \"0x00\", \"0x00\", \"0x00\","
 382    :          " \"0x00\", \"0x00\",\n"
 383    :          "      \"0x00\", \"0x00\", \"0x00\", \"0x00\", \"0x00\", \"0x00\","
 384    :          " \"0x00\", \"0x00\",\n"
 385    :          "      \"0xC3\", \"0xC3\", \"0xC3\", \"0xC3\", \"0x00\", \"0x00\","
 386    :          " \"0x00\", \"0x00\",\n"
 387    :          "      \"0x00\", \"0x00\", \"0x00\", \"0x00\", \"0x00\", \"0x00\","
 388    :          " \"0x00\", \"0x00\",\n"
 389    :          "      \"0x00\", \"0x00\", \"0x00\", \"0x00\", \"0x00\", \"0x00\","
 390    :          " \"0x00\", \"0x00\"\n"
 391    :          "    ]\n"
 392    :          "  },\n"
 393    :          "  \"shadow\": {\n"
 394    :          "    \"type\": \"blob\",\n"
 395    :          "    \"address\": \"0x%08X\",\n"
 396    :          "    \"size\": null,\n"
 397    :          "    \"data\": [\n"
 398    :          "      \"0xE0\", \"0xFA\", \"0x00\", \"0xFB\", \"0xFB\", \"0xF4\"\n"
 399    :          "    ]\n"
 400    :          "  }\n"
 401  E :          "}";
 402    :      std::string expected = base::StringPrintf(
 403    :          kExpected,
 404    :          block_info.header,
 405    :          block_info.header,
 406  E :          BlockShadowAddress());
 407  E :      EXPECT_EQ(expected, json);
 408  E :    }
 409  E :  }
 410    :  
 411  E :  TEST_F(AsanErrorInfoTest, PopulateBlockInfoWithMemoryRanges) {
 412  E :    AsanBlockInfo block_info = {};
 413  E :    InitAsanBlockInfo(&block_info);
 414    :  
 415    :    {
 416  E :      crashdata::Value info;
 417  E :      PopulateBlockInfo(runtime_->shadow(), block_info, false, &info, nullptr);
 418  E :      std::string json;
 419  E :      EXPECT_TRUE(crashdata::ToJson(true, &info, &json));
 420    :      const char kExpected[] =
 421    :          "{\n"
 422    :          "  \"header\": \"0x%08X\",\n"
 423    :          "  \"user-size\": 8,\n"
 424    :          "  \"state\": \"allocated\",\n"
 425    :          "  \"heap-type\": \"WinHeap\",\n"
 426    :          "  \"analysis\": {\n"
 427    :          "    \"block\": \"corrupt\",\n"
 428    :          "    \"header\": \"corrupt\",\n"
 429    :          "    \"body\": \"(unknown)\",\n"
 430    :          "    \"trailer\": \"clean\"\n"
 431    :          "  },\n"
 432    :          "  \"alloc-thread-id\": 47,\n"
 433    :          "  \"alloc-stack\": [\n"
 434    :          "    \"0x00000001\", \"0x00000002\"\n"
 435    :          "  ]\n"
 436  E :          "}";
 437  E :      std::string expected = base::StringPrintf(kExpected, block_info.header);
 438  E :      EXPECT_EQ(expected, json);
 439  E :    }
 440    :  
 441    :    {
 442  E :      block_info.state = QUARANTINED_FLOODED_BLOCK;
 443  E :      block_info.free_tid = 32;
 444  E :      block_info.free_stack[0] = reinterpret_cast<void*>(3);
 445  E :      block_info.free_stack[1] = reinterpret_cast<void*>(4);
 446  E :      block_info.free_stack[2] = reinterpret_cast<void*>(5);
 447  E :      block_info.free_stack_size = 3;
 448  E :      block_info.heap_type = kWinHeap;
 449  E :      block_info.milliseconds_since_free = 100;
 450    :  
 451  E :      crashdata::Value value;
 452  E :      MemoryRanges memory_ranges;
 453    :      PopulateBlockInfo(runtime_->shadow(), block_info, true, &value,
 454  E :                        &memory_ranges);
 455  E :      std::string json;
 456  E :      EXPECT_TRUE(crashdata::ToJson(true, &value, &json));
 457    :      const char kExpected[] =
 458    :          "{\n"
 459    :          "  \"header\": \"0x%08X\",\n"
 460    :          "  \"user-size\": 8,\n"
 461    :          "  \"state\": \"quarantined (flooded)\",\n"
 462    :          "  \"heap-type\": \"WinHeap\",\n"
 463    :          "  \"analysis\": {\n"
 464    :          "    \"block\": \"corrupt\",\n"
 465    :          "    \"header\": \"corrupt\",\n"
 466    :          "    \"body\": \"(unknown)\",\n"
 467    :          "    \"trailer\": \"clean\"\n"
 468    :          "  },\n"
 469    :          "  \"alloc-thread-id\": 47,\n"
 470    :          "  \"alloc-stack\": [\n"
 471    :          "    \"0x00000001\", \"0x00000002\"\n"
 472    :          "  ],\n"
 473    :          "  \"free-thread-id\": 32,\n"
 474    :          "  \"free-stack\": [\n"
 475    :          "    \"0x00000003\", \"0x00000004\", \"0x00000005\"\n"
 476    :          "  ],\n"
 477    :          "  \"milliseconds-since-free\": 100,\n"
 478    :          "  \"contents\": {\n"
 479    :          "    \"type\": \"blob\",\n"
 480    :          "    \"address\": \"0x%08X\",\n"
 481    :          "    \"size\": 48,\n"
 482    :          "    \"data\": null\n"
 483    :          "  },\n"
 484    :          "  \"shadow\": {\n"
 485    :          "    \"type\": \"blob\",\n"
 486    :          "    \"address\": \"0x%08X\",\n"
 487    :          "    \"size\": 6,\n"
 488    :          "    \"data\": null\n"
 489    :          "  }\n"
 490  E :          "}";
 491    :      std::string expected = base::StringPrintf(
 492  E :          kExpected, block_info.header, block_info.header, BlockShadowAddress());
 493  E :      EXPECT_EQ(expected, json);
 494    :  
 495  E :      ASSERT_EQ(2, memory_ranges.size());
 496    :      const char* kExpectedMemoryRangesAddresses[] = {
 497    :          reinterpret_cast<const char*>(block_info.header),
 498  E :          reinterpret_cast<const char*>(BlockShadowAddress())};
 499  E :      size_t kExpectedMemoryRangesSize[] = {48, 6};
 500  E :      for (int i = 0; i < 2; i++) {
 501  E :        EXPECT_EQ(kExpectedMemoryRangesAddresses[i], memory_ranges[i].first);
 502  E :        EXPECT_EQ(kExpectedMemoryRangesSize[i], memory_ranges[i].second);
 503  E :      }
 504  E :    }
 505  E :  }
 506    :  
 507  E :  TEST_F(AsanErrorInfoTest, PopulateCorruptBlockRange) {
 508  E :    AsanBlockInfo block_info = {};
 509  E :    InitAsanBlockInfo(&block_info);
 510    :  
 511  E :    AsanCorruptBlockRange range = {};
 512  E :    range.address = reinterpret_cast<void*>(0xBAADF00D);
 513  E :    range.length = 1024 * 1024;
 514  E :    range.block_count = 100;
 515  E :    range.block_info_count = 1;
 516  E :    range.block_info = &block_info;
 517    :  
 518  E :    crashdata::Value info;
 519  E :    PopulateCorruptBlockRange(runtime_->shadow(), range, &info, nullptr);
 520    :  
 521  E :    std::string json;
 522  E :    EXPECT_TRUE(crashdata::ToJson(true, &info, &json));
 523    :    const char kExpected[] =
 524    :        "{\n"
 525    :        "  \"address\": \"0xBAADF00D\",\n"
 526    :        "  \"length\": 1048576,\n"
 527    :        "  \"block-count\": 100,\n"
 528    :        "  \"blocks\": [\n"
 529    :        "    {\n"
 530    :        "      \"header\": \"0x%08X\",\n"
 531    :        "      \"user-size\": 8,\n"
 532    :        "      \"state\": \"allocated\",\n"
 533    :        "      \"heap-type\": \"WinHeap\",\n"
 534    :        "      \"analysis\": {\n"
 535    :        "        \"block\": \"corrupt\",\n"
 536    :        "        \"header\": \"corrupt\",\n"
 537    :        "        \"body\": \"(unknown)\",\n"
 538    :        "        \"trailer\": \"clean\"\n"
 539    :        "      },\n"
 540    :        "      \"alloc-thread-id\": 47,\n"
 541    :        "      \"alloc-stack\": [\n"
 542    :        "        \"0x00000001\", \"0x00000002\"\n"
 543    :        "      ]\n"
 544    :        "    }\n"
 545    :        "  ]\n"
 546  E :        "}";
 547  E :    std::string expected = base::StringPrintf(kExpected, block_info.header);
 548  E :    EXPECT_EQ(expected, json);
 549  E :  }
 550    :  
 551  E :  TEST_F(AsanErrorInfoTest, PopulateErrorInfo) {
 552  E :    AsanBlockInfo block_info = {};
 553  E :    InitAsanBlockInfo(&block_info);
 554    :  
 555  E :    AsanCorruptBlockRange range = {};
 556  E :    range.address = reinterpret_cast<void*>(0xBAADF00D);
 557  E :    range.length = 1024 * 1024;
 558  E :    range.block_count = 100;
 559  E :    range.block_info_count = 1;
 560  E :    range.block_info = &block_info;
 561    :  
 562    :    // The 'location' address needs to be at a consistent place in system memory
 563    :    // so that shadow memory contents and page bits don't vary, otherwise the
 564    :    // test won't be deterministic.
 565  E :    AsanErrorInfo error_info = {};
 566  E :    error_info.location = reinterpret_cast<void*>(0x00001000);
 567  E :    error_info.crash_stack_id = 1234;
 568  E :    InitAsanBlockInfo(&error_info.block_info);
 569  E :    error_info.error_type = WILD_ACCESS;
 570  E :    error_info.access_mode = ASAN_READ_ACCESS;
 571  E :    error_info.access_size = 4;
 572    :    ::strncpy(error_info.shadow_info,
 573    :              "shadow info!",
 574  E :              sizeof(error_info.shadow_info));
 575    :    ::strncpy(error_info.shadow_memory,
 576    :              "shadow memory!",
 577  E :              sizeof(error_info.shadow_memory));
 578  E :    error_info.heap_is_corrupt = true;
 579  E :    error_info.corrupt_range_count = 10;
 580  E :    error_info.corrupt_block_count = 200;
 581  E :    error_info.corrupt_ranges_reported = 1;
 582  E :    error_info.corrupt_ranges = &range;
 583    :  
 584  E :    ::common::SetDefaultAsanParameters(&error_info.asan_parameters);
 585    :  
 586  E :    crashdata::Value info;
 587  E :    PopulateErrorInfo(runtime_->shadow(), error_info, &info, nullptr);
 588    :  
 589  E :    std::string json;
 590  E :    EXPECT_TRUE(crashdata::ToJson(true, &info, &json));
 591    :    const char kExpected[] =
 592    :        "{\n"
 593    :        "  \"location\": \"0x00001000\",\n"
 594    :        "  \"crash-stack-id\": 1234,\n"
 595    :        "  \"block-info\": {\n"
 596    :        "    \"header\": \"0x%08X\",\n"
 597    :        "    \"user-size\": 8,\n"
 598    :        "    \"state\": \"allocated\",\n"
 599    :        "    \"heap-type\": \"WinHeap\",\n"
 600    :        "    \"analysis\": {\n"
 601    :        "      \"block\": \"corrupt\",\n"
 602    :        "      \"header\": \"corrupt\",\n"
 603    :        "      \"body\": \"(unknown)\",\n"
 604    :        "      \"trailer\": \"clean\"\n"
 605    :        "    },\n"
 606    :        "    \"alloc-thread-id\": 47,\n"
 607    :        "    \"alloc-stack\": [\n"
 608    :        "      \"0x00000001\", \"0x00000002\"\n"
 609    :        "    ],\n"
 610    :        "    \"contents\": {\n"
 611    :        "      \"type\": \"blob\",\n"
 612    :        "      \"address\": \"0x%08X\",\n"
 613    :        "      \"size\": null,\n"
 614    :        "      \"data\": [\n"
 615    :        "        \"0x80\", \"0xCA\", \"0x00\", \"0x00\", \"0x20\", \"0x00\","
 616    :        " \"0x00\", \"0x00\",\n"
 617    :        "        \"0x00\", \"0x00\", \"0x00\", \"0x00\", \"0x00\", \"0x00\","
 618    :        " \"0x00\", \"0x00\",\n"
 619    :        "        \"0x00\", \"0x00\", \"0x00\", \"0x00\", \"0x00\", \"0x00\","
 620    :        " \"0x00\", \"0x00\",\n"
 621    :        "        \"0xC3\", \"0xC3\", \"0xC3\", \"0xC3\", \"0x00\", \"0x00\","
 622    :        " \"0x00\", \"0x00\",\n"
 623    :        "        \"0x00\", \"0x00\", \"0x00\", \"0x00\", \"0x00\", \"0x00\","
 624    :        " \"0x00\", \"0x00\",\n"
 625    :        "        \"0x00\", \"0x00\", \"0x00\", \"0x00\", \"0x00\", \"0x00\","
 626    :        " \"0x00\", \"0x00\"\n"
 627    :        "      ]\n"
 628    :        "    },\n"
 629    :        "    \"shadow\": {\n"
 630    :        "      \"type\": \"blob\",\n"
 631    :        "      \"address\": \"0x%08X\",\n"
 632    :        "      \"size\": null,\n"
 633    :        "      \"data\": [\n"
 634    :        "        \"0xE0\", \"0xFA\", \"0x00\", \"0xFB\", \"0xFB\", \"0xF4\"\n"
 635    :        "      ]\n"
 636    :        "    }\n"
 637    :        "  },\n"
 638    :        "  \"error-type\": \"wild-access\",\n"
 639    :        "  \"access-mode\": \"read\",\n"
 640    :        "  \"access-size\": 4,\n"
 641    :        "  \"shadow-memory-index\": 512,\n"
 642    :        "  \"shadow-memory\": {\n"
 643    :        "    \"type\": \"blob\",\n"
 644    :        "    \"address\": \"0x%08X\",\n"
 645    :        "    \"size\": null,\n"
 646    :        "    \"data\": [\n"
 647    :        "      \"0xF2\", \"0xF2\", \"0xF2\", \"0xF2\", \"0xF2\", \"0xF2\","
 648    :        " \"0xF2\", \"0xF2\",\n"
 649    :        "      \"0xF2\", \"0xF2\", \"0xF2\", \"0xF2\", \"0xF2\", \"0xF2\","
 650    :        " \"0xF2\", \"0xF2\",\n"
 651    :        "      \"0xF2\", \"0xF2\", \"0xF2\", \"0xF2\", \"0xF2\", \"0xF2\","
 652    :        " \"0xF2\", \"0xF2\",\n"
 653    :        "      \"0xF2\", \"0xF2\", \"0xF2\", \"0xF2\", \"0xF2\", \"0xF2\","
 654    :        " \"0xF2\", \"0xF2\",\n"
 655    :        "      \"0xF2\", \"0xF2\", \"0xF2\", \"0xF2\", \"0xF2\", \"0xF2\","
 656    :        " \"0xF2\", \"0xF2\",\n"
 657    :        "      \"0xF2\", \"0xF2\", \"0xF2\", \"0xF2\", \"0xF2\", \"0xF2\","
 658    :        " \"0xF2\", \"0xF2\",\n"
 659    :        "      \"0xF2\", \"0xF2\", \"0xF2\", \"0xF2\", \"0xF2\", \"0xF2\","
 660    :        " \"0xF2\", \"0xF2\",\n"
 661    :        "      \"0xF2\", \"0xF2\", \"0xF2\", \"0xF2\", \"0xF2\", \"0xF2\","
 662    :        " \"0xF2\", \"0xF2\"\n"
 663    :        "    ]\n"
 664    :        "  },\n"
 665    :        "  \"page-bits-index\": 0,\n"
 666    :        "  \"page-bits\": {\n"
 667    :        "    \"type\": \"blob\",\n"
 668    :        "    \"address\": \"0x%08X\",\n"
 669    :        "    \"size\": null,\n"
 670    :        "    \"data\": [\n"
 671    :        "      \"0x00\", \"0x00\", \"0x00\"\n"
 672    :        "    ]\n"
 673    :        "  },\n"
 674    :        "  \"heap-is-corrupt\": 1,\n"
 675    :        "  \"corrupt-range-count\": 10,\n"
 676    :        "  \"corrupt-block-count\": 200,\n"
 677    :        "  \"corrupt-ranges\": [\n"
 678    :        "    {\n"
 679    :        "      \"address\": \"0xBAADF00D\",\n"
 680    :        "      \"length\": 1048576,\n"
 681    :        "      \"block-count\": 100,\n"
 682    :        "      \"blocks\": [\n"
 683    :        "        {\n"
 684    :        "          \"header\": \"0x%08X\",\n"
 685    :        "          \"user-size\": 8,\n"
 686    :        "          \"state\": \"allocated\",\n"
 687    :        "          \"heap-type\": \"WinHeap\",\n"
 688    :        "          \"analysis\": {\n"
 689    :        "            \"block\": \"corrupt\",\n"
 690    :        "            \"header\": \"corrupt\",\n"
 691    :        "            \"body\": \"(unknown)\",\n"
 692    :        "            \"trailer\": \"clean\"\n"
 693    :        "          },\n"
 694    :        "          \"alloc-thread-id\": 47,\n"
 695    :        "          \"alloc-stack\": [\n"
 696    :        "            \"0x00000001\", \"0x00000002\"\n"
 697    :        "          ]\n"
 698    :        "        }\n"
 699    :        "      ]\n"
 700    :        "    }\n"
 701    :        "  ],\n"
 702    :        "  \"asan-parameters\": {\n"
 703    :        "    \"quarantine-size\": 16777216,\n"
 704    :        "    \"trailer-padding-size\": 0,\n"
 705    :        "    \"quarantine-block-size\": 4194304,\n"
 706    :        "    \"check-heap-on-failure\": 1,\n"
 707    :        "    \"enable-zebra-block-heap\": 0,\n"
 708    :        "    \"enable-large-block-heap\": 1,\n"
 709    :        "    \"enable-allocation-filter\": 0,\n"
 710    :        "    \"allocation-guard-rate\": 1.0000000000000000E+000,\n"
 711    :        "    \"zebra-block-heap-size\": 16777216,\n"
 712    :        "    \"zebra-block-heap-quarantine-ratio\": 2.5000000000000000E-001,\n"
 713    :        "    \"large-allocation-threshold\": 20480,\n"
 714    :        "    \"quarantine-flood-fill-rate\": 5.0000000000000000E-001\n"
 715    :        "  }\n"
 716  E :        "}";
 717  E :    AsanErrorShadowMemory shadow_memory = {};
 718    :    GetAsanErrorShadowMemory(runtime_->shadow(), error_info.location,
 719  E :                             &shadow_memory);
 720    :    std::string expected =
 721    :        base::StringPrintf(kExpected, block_info.header, block_info.header,
 722    :                           BlockShadowAddress(), shadow_memory.address,
 723  E :                           runtime_->shadow()->page_bits(), block_info.header);
 724  E :    EXPECT_EQ(expected, json);
 725  E :  }
 726    :  
 727  E :  TEST_F(AsanErrorInfoTest, PopulateErrorInfoWithMemoryRanges) {
 728  E :    AsanBlockInfo block_info = {};
 729  E :    InitAsanBlockInfo(&block_info);
 730    :  
 731  E :    AsanCorruptBlockRange range = {};
 732  E :    range.address = reinterpret_cast<void*>(0xBAADF00D);
 733  E :    range.length = 1024 * 1024;
 734  E :    range.block_count = 100;
 735  E :    range.block_info_count = 1;
 736  E :    range.block_info = &block_info;
 737    :  
 738    :    // The 'location' address needs to be at a consistent place in system memory
 739    :    // so that shadow memory contents and page bits don't vary, otherwise the
 740    :    // test won't be deterministic.
 741  E :    AsanErrorInfo error_info = {};
 742  E :    error_info.location = reinterpret_cast<void*>(0x00001000);
 743  E :    error_info.crash_stack_id = 1234;
 744  E :    InitAsanBlockInfo(&error_info.block_info);
 745  E :    error_info.error_type = WILD_ACCESS;
 746  E :    error_info.access_mode = ASAN_READ_ACCESS;
 747  E :    error_info.access_size = 4;
 748    :    ::strncpy(error_info.shadow_info, "shadow info!",
 749  E :              sizeof(error_info.shadow_info));
 750    :    ::strncpy(error_info.shadow_memory, "shadow memory!",
 751  E :              sizeof(error_info.shadow_memory));
 752  E :    error_info.heap_is_corrupt = true;
 753  E :    error_info.corrupt_range_count = 10;
 754  E :    error_info.corrupt_block_count = 200;
 755  E :    error_info.corrupt_ranges_reported = 1;
 756  E :    error_info.corrupt_ranges = &range;
 757    :  
 758  E :    ::common::SetDefaultAsanParameters(&error_info.asan_parameters);
 759    :  
 760  E :    crashdata::Value info;
 761  E :    MemoryRanges memory_ranges;
 762  E :    PopulateErrorInfo(runtime_->shadow(), error_info, &info, &memory_ranges);
 763    :  
 764  E :    std::string json;
 765  E :    EXPECT_TRUE(crashdata::ToJson(true, &info, &json));
 766    :    const char kExpected[] =
 767    :        "{\n"
 768    :        "  \"location\": \"0x00001000\",\n"
 769    :        "  \"crash-stack-id\": 1234,\n"
 770    :        "  \"block-info\": {\n"
 771    :        "    \"header\": \"0x%08X\",\n"
 772    :        "    \"user-size\": 8,\n"
 773    :        "    \"state\": \"allocated\",\n"
 774    :        "    \"heap-type\": \"WinHeap\",\n"
 775    :        "    \"analysis\": {\n"
 776    :        "      \"block\": \"corrupt\",\n"
 777    :        "      \"header\": \"corrupt\",\n"
 778    :        "      \"body\": \"(unknown)\",\n"
 779    :        "      \"trailer\": \"clean\"\n"
 780    :        "    },\n"
 781    :        "    \"alloc-thread-id\": 47,\n"
 782    :        "    \"alloc-stack\": [\n"
 783    :        "      \"0x00000001\", \"0x00000002\"\n"
 784    :        "    ],\n"
 785    :        "    \"contents\": {\n"
 786    :        "      \"type\": \"blob\",\n"
 787    :        "      \"address\": \"0x%08X\",\n"
 788    :        "      \"size\": 48,\n"
 789    :        "      \"data\": null\n"
 790    :        "    },\n"
 791    :        "    \"shadow\": {\n"
 792    :        "      \"type\": \"blob\",\n"
 793    :        "      \"address\": \"0x%08X\",\n"
 794    :        "      \"size\": 6,\n"
 795    :        "      \"data\": null\n"
 796    :        "    }\n"
 797    :        "  },\n"
 798    :        "  \"error-type\": \"wild-access\",\n"
 799    :        "  \"access-mode\": \"read\",\n"
 800    :        "  \"access-size\": 4,\n"
 801    :        "  \"shadow-memory-index\": 512,\n"
 802    :        "  \"shadow-memory\": {\n"
 803    :        "    \"type\": \"blob\",\n"
 804    :        "    \"address\": \"0x%08X\",\n"
 805    :        "    \"size\": 64,\n"
 806    :        "    \"data\": null\n"
 807    :        "  },\n"
 808    :        "  \"page-bits-index\": 0,\n"
 809    :        "  \"page-bits\": {\n"
 810    :        "    \"type\": \"blob\",\n"
 811    :        "    \"address\": \"0x%08X\",\n"
 812    :        "    \"size\": 3,\n"
 813    :        "    \"data\": null\n"
 814    :        "  },\n"
 815    :        "  \"heap-is-corrupt\": 1,\n"
 816    :        "  \"corrupt-range-count\": 10,\n"
 817    :        "  \"corrupt-block-count\": 200,\n"
 818    :        "  \"corrupt-ranges\": [\n"
 819    :        "    {\n"
 820    :        "      \"address\": \"0xBAADF00D\",\n"
 821    :        "      \"length\": 1048576,\n"
 822    :        "      \"block-count\": 100,\n"
 823    :        "      \"blocks\": [\n"
 824    :        "        {\n"
 825    :        "          \"header\": \"0x%08X\",\n"
 826    :        "          \"user-size\": 8,\n"
 827    :        "          \"state\": \"allocated\",\n"
 828    :        "          \"heap-type\": \"WinHeap\",\n"
 829    :        "          \"analysis\": {\n"
 830    :        "            \"block\": \"corrupt\",\n"
 831    :        "            \"header\": \"corrupt\",\n"
 832    :        "            \"body\": \"(unknown)\",\n"
 833    :        "            \"trailer\": \"clean\"\n"
 834    :        "          },\n"
 835    :        "          \"alloc-thread-id\": 47,\n"
 836    :        "          \"alloc-stack\": [\n"
 837    :        "            \"0x00000001\", \"0x00000002\"\n"
 838    :        "          ]\n"
 839    :        "        }\n"
 840    :        "      ]\n"
 841    :        "    }\n"
 842    :        "  ],\n"
 843    :        "  \"asan-parameters\": {\n"
 844    :        "    \"quarantine-size\": 16777216,\n"
 845    :        "    \"trailer-padding-size\": 0,\n"
 846    :        "    \"quarantine-block-size\": 4194304,\n"
 847    :        "    \"check-heap-on-failure\": 1,\n"
 848    :        "    \"enable-zebra-block-heap\": 0,\n"
 849    :        "    \"enable-large-block-heap\": 1,\n"
 850    :        "    \"enable-allocation-filter\": 0,\n"
 851    :        "    \"allocation-guard-rate\": 1.0000000000000000E+000,\n"
 852    :        "    \"zebra-block-heap-size\": 16777216,\n"
 853    :        "    \"zebra-block-heap-quarantine-ratio\": 2.5000000000000000E-001,\n"
 854    :        "    \"large-allocation-threshold\": 20480,\n"
 855    :        "    \"quarantine-flood-fill-rate\": 5.0000000000000000E-001\n"
 856    :        "  }\n"
 857  E :        "}";
 858  E :    AsanErrorShadowMemory shadow_memory = {};
 859    :    GetAsanErrorShadowMemory(runtime_->shadow(), error_info.location,
 860  E :                             &shadow_memory);
 861    :    std::string expected =
 862    :        base::StringPrintf(kExpected, block_info.header, block_info.header,
 863    :                           BlockShadowAddress(), shadow_memory.address,
 864  E :                           runtime_->shadow()->page_bits(), block_info.header);
 865  E :    EXPECT_EQ(expected, json);
 866    :  
 867    :    // Check memory ranges.
 868  E :    ASSERT_EQ(4, memory_ranges.size());
 869    :    const char* kExpectedMemoryRangesAddresses[] = {
 870    :        reinterpret_cast<const char*>(block_info.header),
 871    :        reinterpret_cast<const char*>(BlockShadowAddress()),
 872    :        reinterpret_cast<const char*>(shadow_memory.address),
 873  E :        reinterpret_cast<const char*>(runtime_->shadow()->page_bits())};
 874  E :    size_t kExpectedMemoryRangesSize[] = {48, 6, 64, 3};
 875  E :    for (int i = 0; i < memory_ranges.size(); i++) {
 876  E :      EXPECT_EQ(kExpectedMemoryRangesAddresses[i], memory_ranges[i].first)
 877    :          << " Where i = " << i;
 878  E :      EXPECT_EQ(kExpectedMemoryRangesSize[i], memory_ranges[i].second)
 879    :          << " Where i = " << i;
 880  E :    }
 881  E :  }
 882    :  
 883    :  }  // namespace asan
 884    :  }  // namespace agent

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