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

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
95.5%2782910.C++source

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 <string>
  18    :  
  19    :  #include "base/strings/string_util.h"
  20    :  #include "syzygy/agent/asan/block_utils.h"
  21    :  #include "syzygy/agent/asan/runtime.h"
  22    :  #include "syzygy/agent/asan/shadow.h"
  23    :  #include "syzygy/agent/asan/stack_capture_cache.h"
  24    :  #include "syzygy/crashdata/crashdata.h"
  25    :  
  26    :  namespace agent {
  27    :  namespace asan {
  28    :  
  29    :  namespace {
  30    :  
  31    :  // Copy a stack capture object into an array.
  32    :  // @param stack_capture The stack capture that we want to copy.
  33    :  // @param dst Will receive the stack frames.
  34    :  // @param dst_size Will receive the number of frames that has been copied.
  35    :  void CopyStackCaptureToArray(const common::StackCapture* stack_capture,
  36  E :                               void* dst, uint8* dst_size) {
  37  E :    DCHECK_NE(static_cast<common::StackCapture*>(nullptr), stack_capture);
  38  E :    DCHECK_NE(static_cast<void*>(nullptr), dst);
  39  E :    DCHECK_NE(static_cast<uint8*>(nullptr), dst_size);
  40    :    ::memcpy(dst,
  41    :             stack_capture->frames(),
  42  E :             stack_capture->num_frames() * sizeof(void*));
  43  E :    *dst_size = stack_capture->num_frames();
  44  E :  }
  45    :  
  46    :  // Get the information about an address relative to a block.
  47    :  // @param shadow The shadow memory to query.
  48    :  // @param header The header of the block containing this address.
  49    :  // @param bad_access_info Will receive the information about this address.
  50    :  void GetAddressInformation(const Shadow* shadow,
  51    :                             BlockHeader* header,
  52  E :                             AsanErrorInfo* bad_access_info) {
  53  E :    DCHECK_NE(static_cast<Shadow*>(nullptr), shadow);
  54  E :    DCHECK_NE(static_cast<BlockHeader*>(nullptr), header);
  55  E :    DCHECK_NE(static_cast<AsanErrorInfo*>(nullptr), bad_access_info);
  56  E :    DCHECK_NE(static_cast<void*>(nullptr), bad_access_info->location);
  57    :  
  58  E :    BlockInfo block_info = {};
  59  E :    shadow->BlockInfoFromShadow(header, &block_info);
  60  E :    int offset = 0;
  61  E :    char* offset_relativity = "";
  62  E :    switch (bad_access_info->error_type) {
  63    :      case HEAP_BUFFER_OVERFLOW: {
  64    :        offset = static_cast<const uint8*>(bad_access_info->location) -
  65  E :            block_info.RawBody() - block_info.body_size;
  66  E :        offset_relativity = "beyond";
  67  E :        break;
  68    :      }
  69    :      case HEAP_BUFFER_UNDERFLOW: {
  70    :        offset = block_info.RawBody() -
  71  E :            static_cast<const uint8*>(bad_access_info->location);
  72  E :        offset_relativity = "before";
  73  E :        break;
  74    :      }
  75    :      case USE_AFTER_FREE: {
  76    :        offset = static_cast<const uint8*>(bad_access_info->location) -
  77  E :            block_info.RawBody();
  78  E :        offset_relativity = "inside";
  79  E :        break;
  80    :      }
  81    :      case WILD_ACCESS:
  82    :      case DOUBLE_FREE:
  83    :      case UNKNOWN_BAD_ACCESS:
  84    :      case CORRUPT_BLOCK:
  85  E :        return;
  86    :      default:
  87  i :        NOTREACHED() << "Error trying to dump address information.";
  88    :    }
  89    :  
  90    :    size_t shadow_info_bytes = base::snprintf(
  91    :        bad_access_info->shadow_info,
  92    :        arraysize(bad_access_info->shadow_info) - 1,
  93    :        "%08X is %d bytes %s %d-byte block [%08X,%08X)\n",
  94    :        bad_access_info->location,
  95    :        offset,
  96    :        offset_relativity,
  97    :        block_info.body_size,
  98    :        block_info.body,
  99  E :        block_info.trailer_padding);
 100    :  
 101  E :    std::string shadow_memory;
 102    :    shadow->AppendShadowArrayText(
 103  E :        bad_access_info->location, &shadow_memory);
 104    :    size_t shadow_mem_bytes = base::snprintf(
 105    :        bad_access_info->shadow_memory,
 106    :        arraysize(bad_access_info->shadow_memory) - 1,
 107    :        "%s",
 108  E :        shadow_memory.c_str());
 109    :  
 110    :    // Ensure that we had enough space to store the full shadow information.
 111  E :    DCHECK_LE(shadow_info_bytes, arraysize(bad_access_info->shadow_info) - 1);
 112  E :    DCHECK_LE(shadow_mem_bytes, arraysize(bad_access_info->shadow_memory) - 1);
 113  E :  }
 114    :  
 115    :  }  // namespace
 116    :  
 117    :  const char kHeapUseAfterFree[] = "heap-use-after-free";
 118    :  const char kHeapBufferUnderFlow[] = "heap-buffer-underflow";
 119    :  const char kHeapBufferOverFlow[] = "heap-buffer-overflow";
 120    :  const char kAttemptingDoubleFree[] = "attempting double-free";
 121    :  const char kInvalidAddress[] = "invalid-address";
 122    :  const char kWildAccess[] = "wild-access";
 123    :  const char kHeapUnknownError[] = "heap-unknown-error";
 124    :  const char kHeapCorruptBlock[] = "corrupt-block";
 125    :  const char kCorruptHeap[] = "corrupt-heap";
 126    :  
 127  E :  const char* ErrorInfoAccessTypeToStr(BadAccessKind bad_access_kind) {
 128  E :    switch (bad_access_kind) {
 129    :      case USE_AFTER_FREE:
 130  E :        return kHeapUseAfterFree;
 131    :      case HEAP_BUFFER_UNDERFLOW:
 132  E :        return kHeapBufferUnderFlow;
 133    :      case HEAP_BUFFER_OVERFLOW:
 134  E :        return kHeapBufferOverFlow;
 135    :      case WILD_ACCESS:
 136  E :        return kWildAccess;
 137    :      case INVALID_ADDRESS:
 138  E :        return kInvalidAddress;
 139    :      case DOUBLE_FREE:
 140  E :        return kAttemptingDoubleFree;
 141    :      case UNKNOWN_BAD_ACCESS:
 142  E :        return kHeapUnknownError;
 143    :      case CORRUPT_BLOCK:
 144  E :        return kHeapCorruptBlock;
 145    :      case CORRUPT_HEAP:
 146  E :        return kCorruptHeap;
 147    :      default:
 148  i :        NOTREACHED() << "Unexpected bad access kind.";
 149  i :        return nullptr;
 150    :    }
 151  E :  }
 152    :  
 153    :  bool ErrorInfoGetBadAccessInformation(const Shadow* shadow,
 154    :                                        StackCaptureCache* stack_cache,
 155  E :                                        AsanErrorInfo* bad_access_info) {
 156  E :    DCHECK_NE(static_cast<Shadow*>(nullptr), shadow);
 157  E :    DCHECK_NE(static_cast<StackCaptureCache*>(nullptr), stack_cache);
 158  E :    DCHECK_NE(static_cast<AsanErrorInfo*>(nullptr), bad_access_info);
 159  E :    BlockInfo block_info = {};
 160    :    if (!shadow->BlockInfoFromShadow(
 161  E :        bad_access_info->location, &block_info)) {
 162  E :      return false;
 163    :    }
 164    :  
 165    :    // Fill out the information about the primary block.
 166    :    ErrorInfoGetAsanBlockInfo(shadow, block_info, stack_cache,
 167  E :                              &bad_access_info->block_info);
 168    :  
 169    :    if (bad_access_info->error_type != DOUBLE_FREE &&
 170  E :        bad_access_info->error_type != CORRUPT_BLOCK) {
 171    :      bad_access_info->error_type = ErrorInfoGetBadAccessKind(
 172  E :          shadow, bad_access_info->location, block_info.header);
 173    :    }
 174    :  
 175    :    // Get the bad access description if we've been able to determine its kind.
 176  E :    if (bad_access_info->error_type != UNKNOWN_BAD_ACCESS) {
 177  E :      GetAddressInformation(shadow, block_info.header, bad_access_info);
 178  E :      return true;
 179    :    }
 180    :  
 181  i :    return false;
 182  E :  }
 183    :  
 184    :  BadAccessKind ErrorInfoGetBadAccessKind(const Shadow* shadow,
 185    :                                          const void* addr,
 186  E :                                          const BlockHeader* header) {
 187  E :    DCHECK_NE(static_cast<Shadow*>(nullptr), shadow);
 188  E :    DCHECK_NE(static_cast<const void*>(nullptr), addr);
 189  E :    DCHECK_NE(static_cast<const BlockHeader*>(nullptr), header);
 190    :  
 191  E :    switch (static_cast<BlockState>(header->state)) {
 192    :      case ALLOCATED_BLOCK: {
 193  E :        BlockInfo block_info = {};
 194  E :        shadow->BlockInfoFromShadow(header, &block_info);
 195  E :        if (addr < block_info.body) {
 196  E :          return HEAP_BUFFER_UNDERFLOW;
 197  E :        } else if (addr >= (block_info.RawBody() + block_info.body_size)) {
 198  E :          return HEAP_BUFFER_OVERFLOW;
 199  i :        } else if (shadow->GetShadowMarkerForAddress(addr) ==
 200  i :            kHeapFreedMarker) {
 201    :          // This is a use after free on a block managed by a nested heap.
 202  i :          return USE_AFTER_FREE;
 203    :        }
 204  i :        break;
 205    :      }
 206    :  
 207    :      case QUARANTINED_BLOCK:
 208    :      case QUARANTINED_FLOODED_BLOCK:
 209    :      case FREED_BLOCK: {
 210  E :        return USE_AFTER_FREE;
 211    :        break;
 212    :      }
 213    :    }
 214    :  
 215  i :    return UNKNOWN_BAD_ACCESS;
 216  E :  }
 217    :  
 218    :  void ErrorInfoGetAsanBlockInfo(const Shadow* shadow,
 219    :                                 const BlockInfo& block_info,
 220    :                                 StackCaptureCache* stack_cache,
 221  E :                                 AsanBlockInfo* asan_block_info) {
 222  E :    DCHECK_NE(static_cast<StackCaptureCache*>(nullptr), stack_cache);
 223  E :    DCHECK_NE(static_cast<AsanBlockInfo*>(nullptr), asan_block_info);
 224    :  
 225  E :    ::memset(asan_block_info, 0, sizeof(*asan_block_info));
 226  E :    BlockState block_state = BlockDetermineMostLikelyState(shadow, block_info);
 227  E :    BlockAnalyze(block_state, block_info, &asan_block_info->analysis);
 228    :  
 229  E :    asan_block_info->header = block_info.header;
 230  E :    asan_block_info->user_size = block_info.header->body_size;
 231  E :    asan_block_info->state = block_info.header->state;
 232  E :    asan_block_info->alloc_tid = block_info.trailer->alloc_tid;
 233  E :    asan_block_info->free_tid = block_info.trailer->free_tid;
 234    :  
 235    :    if (block_info.header->state != ALLOCATED_BLOCK &&
 236  E :        block_info.trailer->free_ticks != 0) {
 237    :      asan_block_info->milliseconds_since_free =
 238  E :          ::GetTickCount() - block_info.trailer->free_ticks;
 239    :    }
 240    :  
 241    :    // TODO(chrisha): Use detailed analysis results to do this more efficiently.
 242  E :    asan_block_info->heap_type = kUnknownHeapType;
 243  E :    HeapManagerInterface::HeapId heap_id = block_info.trailer->heap_id;
 244  E :    if (heap_id != 0) {
 245  E :      AsanRuntime* runtime = AsanRuntime::runtime();
 246  E :      DCHECK_NE(static_cast<AsanRuntime*>(nullptr), runtime);
 247  E :      asan_block_info->heap_type = runtime->GetHeapType(heap_id);
 248    :    }
 249    :  
 250    :    // Copy the alloc and free stack traces if they're valid.
 251    :    // TODO(chrisha): Use detailed analysis results that have been gathered
 252    :    //                once, rather than recalculating this.
 253    :    if (stack_cache->StackCapturePointerIsValid(
 254  E :            block_info.header->alloc_stack)) {
 255    :      CopyStackCaptureToArray(block_info.header->alloc_stack,
 256    :                              asan_block_info->alloc_stack,
 257  E :                              &asan_block_info->alloc_stack_size);
 258    :    }
 259    :    if (block_info.header->state != ALLOCATED_BLOCK &&
 260    :        stack_cache->StackCapturePointerIsValid(
 261  E :            block_info.header->free_stack)) {
 262    :      CopyStackCaptureToArray(block_info.header->free_stack,
 263    :                              asan_block_info->free_stack,
 264  E :                              &asan_block_info->free_stack_size);
 265    :    }
 266  E :  }
 267    :  
 268    :  void GetAsanErrorShadowMemory(const Shadow* shadow,
 269    :                                const void* error_location,
 270  E :                                AsanErrorShadowMemory* shadow_memory) {
 271  E :    DCHECK_NE(static_cast<AsanErrorShadowMemory*>(nullptr), shadow_memory);
 272    :  
 273  E :    shadow_memory->index = reinterpret_cast<uintptr_t>(error_location);
 274  E :    shadow_memory->index >>= kShadowRatioLog;
 275    :    shadow_memory->index = (shadow_memory->index / shadow->kShadowBytesPerLine) *
 276  E :                           Shadow::kShadowBytesPerLine;
 277    :  
 278    :    uintptr_t index_min =
 279    :        shadow_memory->index -
 280  E :        Shadow::kShadowContextLines * Shadow::kShadowBytesPerLine;
 281  E :    if (index_min > shadow_memory->index)
 282  i :      index_min = 0;
 283    :    uintptr_t index_max =
 284    :        shadow_memory->index +
 285  E :        Shadow::kShadowContextLines * Shadow::kShadowBytesPerLine;
 286  E :    if (index_max < shadow_memory->index)
 287  i :      index_max = 0;
 288    :  
 289    :    shadow_memory->address =
 290  E :        reinterpret_cast<uintptr_t>(shadow->shadow() + index_min);
 291  E :    shadow_memory->length = index_max - index_min;
 292  E :  }
 293    :  
 294    :  namespace {
 295    :  
 296    :  // Converts an access mode to a string.
 297  E :  void AccessModeToString(AccessMode access_mode, std::string* str) {
 298  E :    DCHECK_NE(static_cast<std::string*>(nullptr), str);
 299  E :    switch (access_mode) {
 300  E :      case ASAN_READ_ACCESS: *str = "read"; break;
 301  E :      case ASAN_WRITE_ACCESS: *str = "write"; break;
 302  E :      default: *str = "(unknown)"; break;
 303    :    }
 304  E :  }
 305    :  
 306    :  // Converts a block state to a string.
 307  E :  void BlockStateToString(BlockState block_state, std::string* str) {
 308  E :    DCHECK_NE(static_cast<std::string*>(nullptr), str);
 309  E :    switch (block_state) {
 310  E :      case ALLOCATED_BLOCK: *str = "allocated"; break;
 311  E :      case QUARANTINED_BLOCK: *str = "quarantined"; break;
 312  E :      case QUARANTINED_FLOODED_BLOCK: *str = "quarantined (flooded)"; break;
 313  i :      case FREED_BLOCK: *str = "freed"; break;
 314    :    }
 315  E :  }
 316    :  
 317  E :  uint64 CastAddress(const void* address) {
 318  E :    return static_cast<uint64>(reinterpret_cast<uint32>(address));
 319  E :  }
 320    :  
 321    :  void PopulateStackTrace(const void* const* frames,
 322    :                          size_t frame_count,
 323  E :                          crashdata::StackTrace* stack_trace) {
 324  E :    DCHECK_NE(static_cast<void*>(nullptr), frames);
 325  E :    DCHECK_LT(0u, frame_count);
 326  E :    DCHECK_NE(static_cast<crashdata::StackTrace*>(nullptr), stack_trace);
 327  E :    for (size_t i = 0; i < frame_count; ++i)
 328  E :      stack_trace->add_frames(CastAddress(frames[i]));
 329  E :  }
 330    :  
 331  E :  void DataStateToString(DataState data_state, std::string* str) {
 332  E :    DCHECK_NE(static_cast<std::string*>(nullptr), str);
 333  E :    switch (data_state) {
 334    :      default:
 335  E :      case kDataStateUnknown: *str = "(unknown)"; break;
 336  E :      case kDataIsClean: *str = "clean"; break;
 337  E :      case kDataIsCorrupt: *str = "corrupt"; break;
 338    :    }
 339  E :  }
 340    :  
 341    :  void PopulateBlockAnalysisResult(const BlockAnalysisResult& analysis,
 342  E :                                   crashdata::Dictionary* dict) {
 343  E :    DCHECK_NE(static_cast<crashdata::Dictionary*>(nullptr), dict);
 344    :    DataStateToString(
 345    :        analysis.block_state,
 346  E :        crashdata::LeafGetString(crashdata::DictAddLeaf("block", dict)));
 347    :    DataStateToString(
 348    :        analysis.header_state,
 349  E :        crashdata::LeafGetString(crashdata::DictAddLeaf("header", dict)));
 350    :    DataStateToString(
 351    :        analysis.body_state,
 352  E :        crashdata::LeafGetString(crashdata::DictAddLeaf("body", dict)));
 353    :    DataStateToString(
 354    :        analysis.trailer_state,
 355  E :        crashdata::LeafGetString(crashdata::DictAddLeaf("trailer", dict)));
 356  E :  }
 357    :  
 358    :  }  // namespace
 359    :  
 360    :  void PopulateBlockInfo(const Shadow* shadow,
 361    :                         const AsanBlockInfo& block_info,
 362    :                         bool include_block_contents,
 363    :                         crashdata::Value* value,
 364  E :                         MemoryRanges* memory_ranges) {
 365  E :    DCHECK_NE(static_cast<Shadow*>(nullptr), shadow);
 366  E :    DCHECK_NE(static_cast<crashdata::Value*>(nullptr), value);
 367    :  
 368  E :    crashdata::Dictionary* dict = ValueGetDict(value);
 369  E :    DCHECK_NE(static_cast<crashdata::Dictionary*>(nullptr), dict);
 370    :  
 371    :    // Set block properties.
 372    :    crashdata::LeafGetAddress(crashdata::DictAddLeaf("header", dict))
 373  E :        ->set_address(CastAddress(block_info.header));
 374    :    crashdata::LeafSetUInt(block_info.user_size,
 375  E :                           crashdata::DictAddLeaf("user-size", dict));
 376    :    BlockStateToString(
 377    :        static_cast<BlockState>(block_info.state),
 378  E :        crashdata::LeafGetString(crashdata::DictAddLeaf("state", dict)));
 379    :    crashdata::LeafGetString(crashdata::DictAddLeaf("heap-type", dict))
 380  E :        ->assign(kHeapTypes[block_info.heap_type]);
 381    :  
 382    :    // Set the block analysis.
 383    :    PopulateBlockAnalysisResult(
 384    :        block_info.analysis,
 385  E :        crashdata::ValueGetDict(crashdata::DictAddValue("analysis", dict)));
 386    :  
 387    :    // Set the allocation information.
 388  E :    if (block_info.alloc_stack_size != 0) {
 389    :      crashdata::LeafSetUInt(block_info.alloc_tid,
 390  E :                             crashdata::DictAddLeaf("alloc-thread-id", dict));
 391    :      PopulateStackTrace(block_info.alloc_stack,
 392    :                         block_info.alloc_stack_size,
 393    :                         crashdata::LeafGetStackTrace(
 394  E :                             crashdata::DictAddLeaf("alloc-stack", dict)));
 395    :    }
 396    :  
 397    :    // Set the free information if available.
 398  E :    if (block_info.free_stack_size != 0) {
 399    :      crashdata::LeafSetUInt(block_info.free_tid,
 400  E :                             crashdata::DictAddLeaf("free-thread-id", dict));
 401    :      PopulateStackTrace(block_info.free_stack,
 402    :                         block_info.free_stack_size,
 403    :                         crashdata::LeafGetStackTrace(
 404  E :                             crashdata::DictAddLeaf("free-stack", dict)));
 405    :      crashdata::LeafSetUInt(
 406    :          block_info.milliseconds_since_free,
 407  E :          crashdata::DictAddLeaf("milliseconds-since-free", dict));
 408    :    }
 409    :  
 410  E :    if (include_block_contents) {
 411    :      // Get the full block information from the shadow memory.
 412  E :      BlockInfo full_block_info = {};
 413  E :      shadow->BlockInfoFromShadow(block_info.header, &full_block_info);
 414    :  
 415    :      // Copy the entire block contents.
 416    :      crashdata::Blob* blob = crashdata::LeafGetBlob(
 417  E :          crashdata::DictAddLeaf("contents", dict));
 418  E :      blob->mutable_address()->set_address(CastAddress(block_info.header));
 419    :  
 420    :      // Use memory range feature if available. Fallback on blob data.
 421  E :      if (memory_ranges) {
 422  E :        blob->set_size(full_block_info.block_size);
 423    :  
 424    :        memory_ranges->push_back(std::pair<const char*, size_t>(
 425    :            static_cast<const char*>(block_info.header),
 426  E :            full_block_info.block_size));
 427  E :      } else {
 428    :        blob->mutable_data()->assign(
 429    :            reinterpret_cast<const char*>(block_info.header),
 430  E :            full_block_info.block_size);
 431    :      }
 432    :  
 433    :      // Copy the associated shadow memory.
 434    :      size_t shadow_index =
 435  E :          reinterpret_cast<size_t>(block_info.header) / kShadowRatio;
 436  E :      size_t shadow_length = full_block_info.block_size / kShadowRatio;
 437    :      const char* shadow_data =
 438    :          reinterpret_cast<const char*>(shadow->shadow()) +
 439  E :          shadow_index;
 440    :      blob = crashdata::LeafGetBlob(
 441  E :          crashdata::DictAddLeaf("shadow", dict));
 442  E :      blob->mutable_address()->set_address(CastAddress(shadow_data));
 443    :  
 444    :      // Use memory range feature if available. Fallback on blob data.
 445  E :      if (memory_ranges) {
 446  E :        blob->set_size(shadow_length);
 447    :  
 448    :        memory_ranges->push_back(
 449  E :            std::pair<const char*, size_t>(shadow_data, shadow_length));
 450  E :      } else {
 451  E :        blob->mutable_data()->assign(shadow_data, shadow_length);
 452    :      }
 453    :    }
 454  E :  }
 455    :  
 456    :  void PopulateCorruptBlockRange(const Shadow* shadow,
 457    :                                 const AsanCorruptBlockRange& range,
 458    :                                 crashdata::Value* value,
 459  E :                                 MemoryRanges* memory_ranges) {
 460  E :    DCHECK_NE(static_cast<Shadow*>(nullptr), shadow);
 461  E :    DCHECK_NE(static_cast<crashdata::Value*>(nullptr), value);
 462    :  
 463  E :    crashdata::Dictionary* dict = ValueGetDict(value);
 464  E :    DCHECK_NE(static_cast<crashdata::Dictionary*>(nullptr), dict);
 465    :  
 466    :    crashdata::LeafGetAddress(crashdata::DictAddLeaf("address", dict))
 467  E :        ->set_address(CastAddress(range.address));
 468  E :    crashdata::LeafSetUInt(range.length, crashdata::DictAddLeaf("length", dict));
 469    :    crashdata::LeafSetUInt(range.block_count,
 470  E :                           crashdata::DictAddLeaf("block-count", dict));
 471    :  
 472    :    // Add the blocks.
 473  E :    if (range.block_info_count > 0) {
 474    :      crashdata::ValueList* list =
 475  E :          crashdata::ValueGetValueList(crashdata::DictAddValue("blocks", dict));
 476  E :      for (size_t i = 0; i < range.block_info_count; ++i) {
 477  E :        if (range.block_info[i].header != nullptr)
 478    :          // Emit the block info but don't explicitly include the contents.
 479    :          PopulateBlockInfo(shadow, range.block_info[i], false,
 480  E :                            list->add_values(), memory_ranges);
 481  E :      }
 482    :    }
 483  E :  }
 484    :  
 485    :  namespace {
 486    :  
 487    :  void PopulateShadowMemoryBlob(const Shadow* shadow,
 488    :                                const AsanErrorInfo& error_info,
 489    :                                crashdata::Dictionary* dict,
 490  E :                                MemoryRanges* memory_ranges) {
 491  E :    DCHECK_NE(static_cast<Shadow*>(nullptr), shadow);
 492  E :    DCHECK_NE(static_cast<crashdata::Dictionary*>(nullptr), dict);
 493    :  
 494    :    // The shadow-info string can be reconstructed from information already in
 495    :    // the crash (location, block-info, access-mode, access-size), so there's no
 496    :    // need to send it. This is emitted as a blob.
 497  E :    AsanErrorShadowMemory shadow_memory = {};
 498  E :    GetAsanErrorShadowMemory(shadow, error_info.location, &shadow_memory);
 499    :  
 500    :    crashdata::LeafSetUInt(shadow_memory.index,
 501  E :                           crashdata::DictAddLeaf("shadow-memory-index", dict));
 502    :    crashdata::Blob* blob = crashdata::LeafGetBlob(
 503  E :        crashdata::DictAddLeaf("shadow-memory", dict));
 504  E :    blob->mutable_address()->set_address(shadow_memory.address);
 505    :  
 506    :    // Use memory range feature if available. Fallback on blob data.
 507  E :    if (memory_ranges) {
 508  E :      blob->set_size(shadow_memory.length);
 509    :  
 510  E :      const char* data = reinterpret_cast<const char*>(shadow_memory.address);
 511    :      memory_ranges->push_back(
 512  E :          std::pair<const char*, size_t>(data, shadow_memory.length));
 513  E :    } else {
 514    :      blob->mutable_data()->assign(
 515    :          reinterpret_cast<const char*>(shadow_memory.address),
 516  E :          shadow_memory.length);
 517    :    }
 518  E :  }
 519    :  
 520    :  void PopulatePageBitsBlob(const Shadow* shadow,
 521    :                            const AsanErrorInfo& error_info,
 522    :                            crashdata::Dictionary* dict,
 523  E :                            MemoryRanges* memory_ranges) {
 524  E :    DCHECK_NE(static_cast<crashdata::Dictionary*>(nullptr), dict);
 525    :  
 526    :    // Emit information about page protections surround the address in question.
 527    :    static const size_t kPageBitsContext = 2;
 528  E :    uintptr_t index = reinterpret_cast<uintptr_t>(error_info.location);
 529  E :    index /= GetPageSize();  // 1 bit per page.
 530  E :    index /= 8;  // 8 bits per byte.
 531  E :    uintptr_t index_min = index - kPageBitsContext;
 532  E :    if (index_min > index)
 533  E :      index_min = 0;
 534  E :    uintptr_t index_max = index + 1 + kPageBitsContext;
 535  E :    if (index_max < index)
 536  i :      index_max = 0;
 537  E :    uintptr_t length = index_max - index_min;
 538    :  
 539    :    crashdata::LeafSetUInt(
 540  E :        index, crashdata::DictAddLeaf("page-bits-index", dict));
 541    :    crashdata::Blob* blob =
 542  E :        crashdata::LeafGetBlob(crashdata::DictAddLeaf("page-bits", dict));
 543    :    blob->mutable_address()->set_address(
 544  E :        CastAddress(shadow->page_bits() + index_min));
 545    :  
 546    :    // Use memory range feature if available. Fallback on blob data.
 547  E :    if (memory_ranges) {
 548  E :      blob->set_size(length);
 549    :  
 550    :      const char* data =
 551  E :          reinterpret_cast<const char*>(shadow->page_bits() + index_min);
 552  E :      memory_ranges->push_back(std::pair<const char*, size_t>(data, length));
 553  E :    } else {
 554    :      blob->mutable_data()->assign(
 555  E :          reinterpret_cast<const char*>(shadow->page_bits() + index_min), length);
 556    :    }
 557  E :  }
 558    :  
 559    :  void PopulateAsanParameters(const AsanErrorInfo& error_info,
 560  E :                              crashdata::Dictionary* dict) {
 561  E :    DCHECK_NE(static_cast<crashdata::Dictionary*>(nullptr), dict);
 562    :  
 563    :    // Any new parameter added to the parameters structure should also be added
 564    :    // here.
 565    :    static_assert(14 == ::common::kAsanParametersVersion,
 566    :                  "Pointers in the params must be linked up here.");
 567    :    crashdata::Dictionary* param_dict = crashdata::DictAddDict("asan-parameters",
 568  E :                                                               dict);
 569  E :    DCHECK_NE(static_cast<crashdata::Dictionary*>(nullptr), param_dict);
 570    :    crashdata::LeafSetUInt(error_info.asan_parameters.quarantine_size,
 571  E :                           crashdata::DictAddLeaf("quarantine-size", param_dict));
 572    :    crashdata::LeafSetUInt(error_info.asan_parameters.trailer_padding_size,
 573    :                           crashdata::DictAddLeaf("trailer-padding-size",
 574  E :                                                  param_dict));
 575    :    crashdata::LeafSetUInt(error_info.asan_parameters.quarantine_block_size,
 576    :                           crashdata::DictAddLeaf("quarantine-block-size",
 577  E :                                                  param_dict));
 578    :    crashdata::LeafSetUInt(error_info.asan_parameters.check_heap_on_failure,
 579    :                           crashdata::DictAddLeaf("check-heap-on-failure",
 580  E :                                                  param_dict));
 581    :    crashdata::LeafSetUInt(error_info.asan_parameters.enable_zebra_block_heap,
 582    :                           crashdata::DictAddLeaf("enable-zebra-block-heap",
 583  E :                                                  param_dict));
 584    :    crashdata::LeafSetUInt(error_info.asan_parameters.enable_large_block_heap,
 585    :                           crashdata::DictAddLeaf("enable-large-block-heap",
 586  E :                                                  param_dict));
 587    :    crashdata::LeafSetUInt(error_info.asan_parameters.enable_allocation_filter,
 588    :                           crashdata::DictAddLeaf("enable-allocation-filter",
 589  E :                                                  param_dict));
 590    :    crashdata::LeafSetReal(error_info.asan_parameters.allocation_guard_rate,
 591    :                           crashdata::DictAddLeaf("allocation-guard-rate",
 592  E :                                                  param_dict));
 593    :    crashdata::LeafSetUInt(error_info.asan_parameters.zebra_block_heap_size,
 594    :                           crashdata::DictAddLeaf("zebra-block-heap-size",
 595  E :                                                  param_dict));
 596    :    crashdata::LeafSetReal(
 597    :        error_info.asan_parameters.zebra_block_heap_quarantine_ratio,
 598  E :        crashdata::DictAddLeaf("zebra-block-heap-quarantine-ratio", param_dict));
 599    :    crashdata::LeafSetUInt(error_info.asan_parameters.large_allocation_threshold,
 600    :                           crashdata::DictAddLeaf("large-allocation-threshold",
 601  E :                                                  param_dict));
 602    :    crashdata::LeafSetReal(
 603    :        error_info.asan_parameters.quarantine_flood_fill_rate,
 604  E :        crashdata::DictAddLeaf("quarantine-flood-fill-rate", param_dict));
 605  E :  }
 606    :  
 607    :  }  // namespace
 608    :  
 609    :  // TODO(chrisha): Only emit information that makes sense for the given error
 610    :  //                type. For example, wild-access errors have no associated
 611    :  //                block information.
 612    :  void PopulateErrorInfo(const Shadow* shadow,
 613    :                         const AsanErrorInfo& error_info,
 614    :                         crashdata::Value* value,
 615  E :                         MemoryRanges* memory_ranges) {
 616  E :    DCHECK_NE(static_cast<Shadow*>(nullptr), shadow);
 617  E :    DCHECK_NE(static_cast<crashdata::Value*>(nullptr), value);
 618    :  
 619    :    // Create a single outermost dictionary.
 620  E :    crashdata::Dictionary* dict = ValueGetDict(value);
 621  E :    DCHECK_NE(static_cast<crashdata::Dictionary*>(nullptr), dict);
 622    :  
 623    :    crashdata::LeafGetAddress(crashdata::DictAddLeaf("location", dict))
 624  E :        ->set_address(CastAddress(error_info.location));
 625    :    crashdata::LeafSetUInt(error_info.crash_stack_id,
 626  E :                           crashdata::DictAddLeaf("crash-stack-id", dict));
 627  E :    if (error_info.block_info.header != nullptr) {
 628    :      // Include the block contents only if the block isn't too large. This tries
 629    :      // to reflect the cap on crash server minidump sizes.
 630    :      // TODO(chrisha): This decision should be made higher up the stack, and not
 631    :      // here.
 632  E :      bool include_block_info = error_info.block_info.user_size < 100 * 1024;
 633    :      PopulateBlockInfo(shadow, error_info.block_info, include_block_info,
 634    :                        crashdata::DictAddValue("block-info", dict),
 635  E :                        memory_ranges);
 636    :    }
 637    :    crashdata::LeafGetString(crashdata::DictAddLeaf("error-type", dict))
 638  E :        ->assign(ErrorInfoAccessTypeToStr(error_info.error_type));
 639    :    AccessModeToString(
 640    :        error_info.access_mode,
 641  E :        crashdata::LeafGetString(crashdata::DictAddLeaf("access-mode", dict)));
 642    :    crashdata::LeafSetUInt(error_info.access_size,
 643  E :                           crashdata::DictAddLeaf("access-size", dict));
 644    :  
 645  E :    PopulateShadowMemoryBlob(shadow, error_info, dict, memory_ranges);
 646  E :    PopulatePageBitsBlob(shadow, error_info, dict, memory_ranges);
 647    :  
 648    :    // Send information about corruption.
 649    :    crashdata::LeafSetUInt(error_info.heap_is_corrupt,
 650  E :                           crashdata::DictAddLeaf("heap-is-corrupt", dict));
 651    :    crashdata::LeafSetUInt(error_info.corrupt_range_count,
 652  E :                           crashdata::DictAddLeaf("corrupt-range-count", dict));
 653    :    crashdata::LeafSetUInt(error_info.corrupt_block_count,
 654  E :                           crashdata::DictAddLeaf("corrupt-block-count", dict));
 655  E :    if (error_info.corrupt_ranges_reported > 0) {
 656    :      crashdata::ValueList* list = crashdata::ValueGetValueList(
 657  E :          crashdata::DictAddValue("corrupt-ranges", dict));
 658  E :      for (size_t i = 0; i < error_info.corrupt_ranges_reported; ++i) {
 659    :        PopulateCorruptBlockRange(shadow, error_info.corrupt_ranges[i],
 660  E :                                  list->add_values(), memory_ranges);
 661  E :      }
 662    :    }
 663  E :    PopulateAsanParameters(error_info, dict);
 664  E :  }
 665    :  
 666    :  }  // namespace asan
 667    :  }  // namespace agent

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