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

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
91.6%3163450.C++source

Line-by-line coverage:

   1    :  // Copyright 2012 Google Inc. All Rights Reserved.
   2    :  //
   3    :  // Licensed under the Apache License, Version 2.0 (the "License");
   4    :  // you may not use this file except in compliance with the License.
   5    :  // You may obtain a copy of the License at
   6    :  //
   7    :  //     http://www.apache.org/licenses/LICENSE-2.0
   8    :  //
   9    :  // Unless required by applicable law or agreed to in writing, software
  10    :  // distributed under the License is distributed on an "AS IS" BASIS,
  11    :  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12    :  // See the License for the specific language governing permissions and
  13    :  // limitations under the License.
  14    :  
  15    :  #include "syzygy/agent/asan/asan_heap.h"
  16    :  
  17    :  #include "base/logging.h"
  18    :  #include "base/stringprintf.h"
  19    :  #include "base/sys_string_conversions.h"
  20    :  #include "base/debug/stack_trace.h"
  21    :  #include "syzygy/agent/asan/asan_logger.h"
  22    :  #include "syzygy/agent/asan/asan_shadow.h"
  23    :  
  24    :  namespace agent {
  25    :  namespace asan {
  26    :  namespace {
  27    :  
  28    :  typedef StackCapture::StackId StackId;
  29    :  
  30    :  // Redzone size allocated at the start of every heap block.
  31    :  const size_t kRedZoneSize = 32U;
  32    :  
  33    :  // Utility class which implements an auto lock for a HeapProxy.
  34    :  class HeapLocker {
  35    :   public:
  36  E :    explicit HeapLocker(HeapProxy* const heap) : heap_(heap) {
  37  E :      DCHECK(heap != NULL);
  38  E :      if (!heap->Lock()) {
  39  i :        LOG(ERROR) << "Unable to lock the heap.";
  40    :      }
  41  E :    }
  42    :  
  43  E :    ~HeapLocker() {
  44  E :      DCHECK(heap_ != NULL);
  45  E :      if (!heap_->Unlock()) {
  46  i :        LOG(ERROR) << "Unable to lock the heap.";
  47    :      }
  48  E :    }
  49    :  
  50    :   private:
  51    :    HeapProxy* const heap_;
  52    :  
  53    :    DISALLOW_COPY_AND_ASSIGN(HeapLocker);
  54    :  };
  55    :  
  56    :  }  // namespace
  57    :  
  58    :  // Arbitrarily keep 16 megabytes of quarantine per heap by default.
  59    :  size_t HeapProxy::default_quarantine_max_size_ = 16 * 1024 * 1024;
  60    :  
  61  E :  void ASANDbgCmd(const wchar_t* fmt, ...) {
  62    :    // The string should start with "ASAN" to be interpreted by the debugger as a
  63    :    // command.
  64  E :    std::wstring command_wstring = L"ASAN ";
  65    :    va_list args;
  66  E :    va_start(args, fmt);
  67    :  
  68    :    // Append the actual command to the wstring.
  69  E :    base::StringAppendV(&command_wstring, fmt, args);
  70    :  
  71    :    // Append "; g" to make sure that the debugger continue its execution after
  72    :    // executing this command. This is needed because when the .ocommand function
  73    :    // is used under Windbg the debugger will break on OutputDebugString.
  74  E :    command_wstring.append(L"; g");
  75    :  
  76  E :    OutputDebugString(command_wstring.c_str());
  77  E :  }
  78    :  
  79  E :  void ASANDbgMessage(const wchar_t* fmt, ...) {
  80    :    // Prepend the message with the .echo command so it'll be printed into the
  81    :    // debugger's console.
  82  E :    std::wstring message_wstring = L".echo ";
  83    :    va_list args;
  84  E :    va_start(args, fmt);
  85    :  
  86    :    // Append the actual message to the wstring.
  87  E :    base::StringAppendV(&message_wstring, fmt, args);
  88    :  
  89    :    // Treat the message as a command to print it.
  90  E :    ASANDbgCmd(message_wstring.c_str());
  91  E :  }
  92    :  
  93    :  // Switch to the caller's context and print its stack trace in Windbg.
  94  E :  void ASANDbgPrintContext(const CONTEXT& context) {
  95  E :    ASANDbgMessage(L"Caller's context (%p) and stack trace:", &context);
  96  E :    ASANDbgCmd(L".cxr %p; kv", reinterpret_cast<uint32>(&context));
  97  E :  }
  98    :  
  99    :  HeapProxy::HeapProxy(StackCaptureCache* stack_cache, AsanLogger* logger)
 100    :      : heap_(NULL),
 101    :        stack_cache_(stack_cache),
 102    :        logger_(logger),
 103    :        head_(NULL),
 104    :        tail_(NULL),
 105    :        quarantine_size_(0),
 106  E :        quarantine_max_size_(0) {
 107  E :    DCHECK(stack_cache != NULL);
 108  E :    DCHECK(logger != NULL);
 109  E :  }
 110    :  
 111  E :  HeapProxy::~HeapProxy() {
 112  E :    if (heap_ != NULL)
 113  i :      Destroy();
 114    :  
 115  E :    DCHECK(heap_ == NULL);
 116  E :  }
 117    :  
 118  E :  HANDLE HeapProxy::ToHandle(HeapProxy* proxy) {
 119  E :    DCHECK(proxy != NULL);
 120  E :    return proxy;
 121  E :  }
 122    :  
 123  E :  HeapProxy* HeapProxy::FromHandle(HANDLE heap) {
 124  E :    DCHECK(heap != NULL);
 125  E :    return reinterpret_cast<HeapProxy*>(heap);
 126  E :  }
 127    :  
 128    :  bool HeapProxy::Create(DWORD options,
 129    :                         size_t initial_size,
 130  E :                         size_t maximum_size) {
 131  E :    DCHECK(heap_ == NULL);
 132    :    COMPILE_ASSERT(sizeof(HeapProxy::BlockHeader) <= kRedZoneSize,
 133    :                   asan_block_header_too_big);
 134    :  
 135  E :    set_quarantine_max_size(default_quarantine_max_size_);
 136    :  
 137  E :    HANDLE heap_new = ::HeapCreate(options, initial_size, maximum_size);
 138  E :    if (heap_new == NULL)
 139  E :      return false;
 140    :  
 141  E :    heap_ = heap_new;
 142    :  
 143  E :    return true;
 144  E :  }
 145    :  
 146  E :  bool HeapProxy::Destroy() {
 147  E :    DCHECK(heap_ != NULL);
 148    :  
 149    :    // Flush the quarantine.
 150  E :    set_quarantine_max_size(0);
 151    :  
 152  E :    if (::HeapDestroy(heap_)) {
 153  E :      heap_ = NULL;
 154  E :      return true;
 155    :    }
 156    :  
 157  i :    return false;
 158  E :  }
 159    :  
 160  E :  void* HeapProxy::Alloc(DWORD flags, size_t bytes) {
 161  E :    DCHECK(heap_ != NULL);
 162    :  
 163  E :    size_t alloc_size = GetAllocSize(bytes);
 164    :    BlockHeader* block =
 165  E :        reinterpret_cast<BlockHeader*>(::HeapAlloc(heap_, flags, alloc_size));
 166    :  
 167  E :    if (block == NULL)
 168  i :      return NULL;
 169    :  
 170    :    // Poison head and tail zones, and un-poison alloc.
 171  E :    size_t header_size = kRedZoneSize;
 172  E :    size_t trailer_size = alloc_size - kRedZoneSize - bytes;
 173  E :    memset(block, 0xCC, header_size);
 174  E :    Shadow::Poison(block, kRedZoneSize, Shadow::kHeapLeftRedzone);
 175    :  
 176    :    // Capture the current stack. InitFromStack is inlined to preserve the
 177    :    // greatest number of stack frames.
 178  E :    StackCapture stack;
 179  E :    stack.InitFromStack();
 180    :  
 181    :    // Initialize the block fields.
 182  E :    block->magic_number = kBlockHeaderSignature;
 183  E :    block->size = bytes;
 184  E :    block->state = ALLOCATED;
 185  E :    block->alloc_stack = stack_cache_->SaveStackTrace(stack);
 186  E :    block->free_stack = NULL;
 187    :  
 188  E :    uint8* block_alloc = ToAlloc(block);
 189  E :    Shadow::Unpoison(block_alloc, bytes);
 190    :  
 191  E :    memset(block_alloc + bytes, 0xCD, trailer_size);
 192  E :    Shadow::Poison(block_alloc + bytes, trailer_size, Shadow::kHeapRightRedzone);
 193    :  
 194  E :    return block_alloc;
 195  E :  }
 196    :  
 197  E :  void* HeapProxy::ReAlloc(DWORD flags, void* mem, size_t bytes) {
 198  E :    DCHECK(heap_ != NULL);
 199    :  
 200  E :    void *new_mem = Alloc(flags, bytes);
 201  E :    if (new_mem != NULL && mem != NULL)
 202  E :      memcpy(new_mem, mem, std::min(bytes, Size(0, mem)));
 203    :  
 204  E :    if (mem)
 205  E :      Free(flags, mem);
 206    :  
 207  E :    return new_mem;
 208  E :  }
 209    :  
 210  E :  bool HeapProxy::Free(DWORD flags, void* mem) {
 211  E :    DCHECK(heap_ != NULL);
 212  E :    BlockHeader* block = ToBlock(mem);
 213    :    // The standard allows to call free on a null pointer. ToBlock returns null if
 214    :    // the given pointer is null so we return true here.
 215  E :    if (block == NULL)
 216  i :      return true;
 217    :  
 218    :    // Capture the current stack.
 219  E :    StackCapture stack;
 220  E :    stack.InitFromStack();
 221    :  
 222  E :    if (block->state != ALLOCATED) {
 223    :      // We're not supposed to see another kind of block here, the FREED state
 224    :      // is only applied to block after invalidating their magic number and freed
 225    :      // them.
 226  E :      DCHECK(block->state == QUARANTINED);
 227    :  
 228    :      BadAccessKind bad_access_kind =
 229  E :          GetBadAccessKind(static_cast<const uint8*>(mem), block);
 230  E :      DCHECK_NE(UNKNOWN_BAD_ACCESS, bad_access_kind);
 231    :  
 232  E :      CONTEXT context = {};
 233  E :      ::RtlCaptureContext(&context);
 234    :  
 235    :      ReportAsanError("attempting double-free", static_cast<const uint8*>(mem),
 236    :                      context, stack, bad_access_kind, block,
 237  E :                      ASAN_UNKNOWN_ACCESS, 0);
 238    :  
 239  E :      return false;
 240    :    }
 241    :  
 242  E :    block->free_stack = stack_cache_->SaveStackTrace(stack);
 243  E :    DCHECK(ToAlloc(block) == mem);
 244    :  
 245    :    // If the size of the allocation is zero then we shouldn't check the shadow
 246    :    // memory as it'll only contain the red-zone for the head and tail of this
 247    :    // block.
 248  E :    if (block->size != 0 && !Shadow::IsAccessible(ToAlloc(block)))
 249  i :      return false;
 250  E :    QuarantineBlock(block);
 251  E :    return true;
 252  E :  }
 253    :  
 254  E :  size_t HeapProxy::Size(DWORD flags, const void* mem) {
 255  E :    DCHECK(heap_ != NULL);
 256  E :    BlockHeader* block = ToBlock(mem);
 257  E :    if (block == NULL)
 258  i :      return -1;
 259    :  
 260  E :    return block->size;
 261  E :  }
 262    :  
 263  E :  bool HeapProxy::Validate(DWORD flags, const void* mem) {
 264  E :    DCHECK(heap_ != NULL);
 265  E :    return ::HeapValidate(heap_, flags, ToBlock(mem)) == TRUE;
 266  E :  }
 267    :  
 268  E :  size_t HeapProxy::Compact(DWORD flags) {
 269  E :    DCHECK(heap_ != NULL);
 270  E :    return ::HeapCompact(heap_, flags);
 271  E :  }
 272    :  
 273  E :  bool HeapProxy::Lock() {
 274  E :    DCHECK(heap_ != NULL);
 275  E :    return ::HeapLock(heap_) == TRUE;
 276  E :  }
 277    :  
 278  E :  bool HeapProxy::Unlock() {
 279  E :    DCHECK(heap_ != NULL);
 280  E :    return ::HeapUnlock(heap_) == TRUE;
 281  E :  }
 282    :  
 283  E :  bool HeapProxy::Walk(PROCESS_HEAP_ENTRY* entry) {
 284  E :    DCHECK(heap_ != NULL);
 285  E :    return ::HeapWalk(heap_, entry) == TRUE;
 286  E :  }
 287    :  
 288    :  bool HeapProxy::SetInformation(HEAP_INFORMATION_CLASS info_class,
 289    :                                 void* info,
 290  E :                                 size_t info_length) {
 291  E :    DCHECK(heap_ != NULL);
 292  E :    return ::HeapSetInformation(heap_, info_class, info, info_length) == TRUE;
 293  E :  }
 294    :  
 295    :  bool HeapProxy::QueryInformation(HEAP_INFORMATION_CLASS info_class,
 296    :                                   void* info,
 297    :                                   size_t info_length,
 298  E :                                   unsigned long* return_length) {
 299  E :    DCHECK(heap_ != NULL);
 300    :    return ::HeapQueryInformation(heap_,
 301    :                                  info_class,
 302    :                                  info,
 303    :                                  info_length,
 304  E :                                  return_length) == TRUE;
 305  E :  }
 306    :  
 307  E :  void HeapProxy::set_quarantine_max_size(size_t quarantine_max_size) {
 308  E :    base::AutoLock lock(lock_);
 309  E :    quarantine_max_size_ = quarantine_max_size;
 310    :  
 311  E :    while (quarantine_size_ > quarantine_max_size_)
 312  E :      PopQuarantineUnlocked();
 313  E :  }
 314    :  
 315  E :  void HeapProxy::PopQuarantineUnlocked() {
 316  E :    DCHECK(head_ != NULL && tail_ != NULL);
 317    :    // The caller should have locked the quarantine.
 318  E :    lock_.AssertAcquired();
 319    :  
 320  E :    FreeBlockHeader* free_block = head_;
 321  E :    head_ = free_block->next;
 322  E :    if (head_ == NULL)
 323  E :      tail_ = NULL;
 324    :  
 325  E :    size_t alloc_size = GetAllocSize(free_block->size);
 326  E :    Shadow::Unpoison(free_block, alloc_size);
 327  E :    free_block->state = FREED;
 328  E :    free_block->magic_number = ~kBlockHeaderSignature;
 329  E :    free_block->alloc_stack = NULL;
 330  E :    free_block->free_stack = NULL;
 331    :  
 332  E :    DCHECK_NE(kBlockHeaderSignature, free_block->magic_number);
 333  E :    ::HeapFree(heap_, 0, free_block);
 334    :  
 335  E :    DCHECK_GE(quarantine_size_, alloc_size);
 336  E :    quarantine_size_ -= alloc_size;
 337  E :  }
 338    :  
 339  E :  void HeapProxy::QuarantineBlock(BlockHeader* block) {
 340  E :    DCHECK(block != NULL);
 341  E :    base::AutoLock lock(lock_);
 342  E :    FreeBlockHeader* free_block = static_cast<FreeBlockHeader*>(block);
 343    :  
 344  E :    free_block->next = NULL;
 345  E :    if (tail_ != NULL) {
 346  E :      tail_->next = free_block;
 347  E :    } else {
 348  E :      DCHECK(head_ == NULL);
 349  E :      head_ = free_block;
 350    :    }
 351  E :    tail_ = free_block;
 352    :  
 353    :    // Poison the released alloc.
 354  E :    size_t alloc_size = GetAllocSize(free_block->size);
 355    :    // Trash the data in the block and poison it.
 356  E :    uint8* mem = ToAlloc(free_block);
 357  E :    memset(mem, 0xCC, free_block->size);
 358  E :    Shadow::MarkAsFreed(mem, free_block->size);
 359  E :    quarantine_size_ += alloc_size;
 360    :    // Mark the block as quarantined.
 361  E :    free_block->state = QUARANTINED;
 362    :  
 363    :    // Flush quarantine overage.
 364  E :    while (quarantine_size_ > quarantine_max_size_)
 365  E :      PopQuarantineUnlocked();
 366  E :  }
 367    :  
 368  E :  size_t HeapProxy::GetAllocSize(size_t bytes) {
 369  E :    bytes += kRedZoneSize;
 370  E :    return (bytes + kRedZoneSize + kRedZoneSize - 1) & ~(kRedZoneSize - 1);
 371  E :  }
 372    :  
 373  E :  HeapProxy::BlockHeader* HeapProxy::ToBlock(const void* alloc) {
 374  E :    if (alloc == NULL)
 375  i :      return NULL;
 376    :  
 377  E :    const uint8* mem = static_cast<const uint8*>(alloc);
 378    :    const BlockHeader* header =
 379  E :        reinterpret_cast<const BlockHeader*>(mem -kRedZoneSize);
 380  E :    if (header->magic_number != kBlockHeaderSignature) {
 381  i :      CONTEXT context = {};
 382  i :      ::RtlCaptureContext(&context);
 383    :  
 384  i :      StackCapture stack;
 385  i :      stack.InitFromStack();
 386    :  
 387  i :      if (!OnBadAccess(mem, context, stack, ASAN_UNKNOWN_ACCESS, 0)) {
 388  i :        ReportUnknownError(mem, context, stack, ASAN_UNKNOWN_ACCESS, 0);
 389  i :        Shadow::PrintShadowMemoryForAddress(alloc);
 390    :      }
 391  i :      return NULL;
 392    :    }
 393    :  
 394  E :    return const_cast<BlockHeader*>(header);
 395  E :  }
 396    :  
 397  E :  uint8* HeapProxy::ToAlloc(BlockHeader* block) {
 398  E :    DCHECK(block != NULL);
 399  E :    DCHECK_EQ(kBlockHeaderSignature, block->magic_number);
 400  E :    DCHECK(block->state == ALLOCATED || block->state == QUARANTINED);
 401    :  
 402  E :    uint8* mem = reinterpret_cast<uint8*>(block);
 403    :  
 404  E :    return mem + kRedZoneSize;
 405  E :  }
 406    :  
 407    :  void HeapProxy::ReportAddressInformation(const void* addr,
 408    :                                           BlockHeader* header,
 409  E :                                           BadAccessKind bad_access_kind) {
 410  E :    DCHECK(addr != NULL);
 411  E :    DCHECK(header != NULL);
 412  E :    uint8* block_alloc = ToAlloc(header);
 413  E :    int offset = 0;
 414  E :    char* offset_relativity = "";
 415  E :    switch (bad_access_kind) {
 416    :      case HEAP_BUFFER_OVERFLOW:
 417  E :        offset = static_cast<const uint8*>(addr) - block_alloc - header->size;
 418  E :        offset_relativity = "to the right";
 419  E :        break;
 420    :      case HEAP_BUFFER_UNDERFLOW:
 421  E :        offset = block_alloc - static_cast<const uint8*>(addr);
 422  E :        offset_relativity = "to the left";
 423  E :        break;
 424    :      case USE_AFTER_FREE:
 425  E :        offset = static_cast<const uint8*>(addr) - block_alloc;
 426  E :        offset_relativity = "inside";
 427  E :        break;
 428    :      default:
 429  i :        NOTREACHED() << "Error trying to dump address information.";
 430    :    }
 431    :  
 432    :    logger_->Write(base::StringPrintf(
 433    :        "0x%08X is located %d bytes %s of %d-bytes region [0x%08X,0x%08X)\n",
 434    :        addr,
 435    :        offset,
 436    :        offset_relativity,
 437    :        header->size,
 438    :        block_alloc,
 439  E :        block_alloc + header->size));
 440  E :    if (header->free_stack != NULL) {
 441    :      std::string message = base::StringPrintf(
 442  E :          "freed here (stack_id=0x%08X):\n", header->free_stack->stack_id());
 443    :      logger_->WriteWithStackTrace(message,
 444    :                                   header->free_stack->frames(),
 445  E :                                   header->free_stack->num_frames());
 446  E :    }
 447  E :    if (header->alloc_stack != NULL) {
 448    :      std::string message = base::StringPrintf(
 449    :          "previously allocated here (stack_id=0x%08X):\n",
 450  E :          header->alloc_stack->stack_id());
 451    :      logger_->WriteWithStackTrace(message,
 452    :                                   header->alloc_stack->frames(),
 453  E :                                   header->alloc_stack->num_frames());
 454  E :    }
 455    :  
 456  E :    std::string shadow_text;
 457  E :    Shadow::AppendShadowMemoryText(addr, &shadow_text);
 458  E :    logger_->Write(shadow_text);
 459  E :  }
 460    :  
 461    :  HeapProxy::BadAccessKind HeapProxy::GetBadAccessKind(const void* addr,
 462  E :                                                       BlockHeader* header) {
 463  E :    DCHECK(addr != NULL);
 464  E :    DCHECK(header != NULL);
 465    :  
 466  E :    BadAccessKind bad_access_kind = UNKNOWN_BAD_ACCESS;
 467    :  
 468  E :    if (header->state == QUARANTINED) {
 469    :      // At this point we can't know if this address belongs to this
 470    :      // quarantined block... If the block containing this address has been
 471    :      // moved from the quarantine list its memory space could have been re-used
 472    :      // and freed again (so having this block in the quarantine list don't
 473    :      // guarantee that this is the original block).
 474    :      // TODO(sebmarchand): Find a way to fix this bug.
 475  E :      bad_access_kind = USE_AFTER_FREE;
 476  E :    } else {
 477  E :      if (addr < (ToAlloc(header)))
 478  E :        bad_access_kind = HEAP_BUFFER_UNDERFLOW;
 479  E :      else if (addr >= (ToAlloc(header) + header->size))
 480  E :        bad_access_kind = HEAP_BUFFER_OVERFLOW;
 481    :    }
 482  E :    return bad_access_kind;
 483  E :  }
 484    :  
 485  E :  HeapProxy::BlockHeader* HeapProxy::FindAddressBlock(const void* addr) {
 486  E :    DCHECK(addr != NULL);
 487  E :    PROCESS_HEAP_ENTRY heap_entry = {};
 488  E :    memset(&heap_entry, 0, sizeof(heap_entry));
 489  E :    BlockHeader* header = NULL;
 490    :  
 491    :    // Walk through the heap to find the block containing @p addr.
 492  E :    HeapLocker heap_locker(this);
 493  E :    while (Walk(&heap_entry)) {
 494    :      uint8* entry_upper_bound =
 495  E :          static_cast<uint8*>(heap_entry.lpData) + heap_entry.cbData;
 496    :  
 497  E :      if (heap_entry.lpData <= addr && entry_upper_bound > addr) {
 498  E :        header = reinterpret_cast<BlockHeader*>(heap_entry.lpData);
 499    :        // Ensures that the block have been allocated by this proxy.
 500  E :        if (header->magic_number == kBlockHeaderSignature) {
 501  E :          DCHECK(header->state != FREED);
 502  E :          break;
 503  i :        } else {
 504  E :          header = NULL;
 505    :        }
 506    :      }
 507  E :    }
 508    :  
 509  E :    return header;
 510  E :  }
 511    :  
 512    :  bool HeapProxy::OnBadAccess(const void* addr,
 513    :                              const CONTEXT& context,
 514    :                              const StackCapture& stack,
 515    :                              AccessMode access_mode,
 516  E :                              size_t access_size) {
 517  E :    DCHECK(addr != NULL);
 518  E :    base::AutoLock lock(lock_);
 519  E :    BadAccessKind bad_access_kind = UNKNOWN_BAD_ACCESS;
 520  E :    BlockHeader* header = FindAddressBlock(addr);
 521    :  
 522  E :    if (header == NULL)
 523  i :      return false;
 524    :  
 525  E :    bad_access_kind = GetBadAccessKind(addr, header);
 526    :    // Get the bad access description if we've been able to determine its kind.
 527  E :    if (bad_access_kind != UNKNOWN_BAD_ACCESS) {
 528  E :      const char* bug_descr = AccessTypeToStr(bad_access_kind);
 529    :      ReportAsanError(bug_descr,
 530    :                      addr,
 531    :                      context,
 532    :                      stack,
 533    :                      bad_access_kind,
 534    :                      header,
 535    :                      access_mode,
 536  E :                      access_size);
 537  E :      return true;
 538    :    }
 539    :  
 540  i :    return false;
 541  E :  }
 542    :  
 543    :  void HeapProxy::ReportUnknownError(const void* addr,
 544    :                                     const CONTEXT& context,
 545    :                                     const StackCapture& stack,
 546    :                                     AccessMode access_mode,
 547  i :                                     size_t access_size) {
 548  i :    DCHECK(addr != NULL);
 549    :    ReportAsanErrorBase("unknown-crash",
 550    :                        addr,
 551    :                        context,
 552    :                        stack,
 553    :                        UNKNOWN_BAD_ACCESS,
 554    :                        access_mode,
 555  i :                        access_size);
 556    :  
 557  i :    ASANDbgPrintContext(context);
 558  i :  }
 559    :  
 560    :  void HeapProxy::ReportAsanError(const char* bug_descr,
 561    :                                  const void* addr,
 562    :                                  const CONTEXT& context,
 563    :                                  const StackCapture& stack,
 564    :                                  BadAccessKind bad_access_kind,
 565    :                                  BlockHeader* header,
 566    :                                  AccessMode access_mode,
 567  E :                                  size_t access_size) {
 568  E :    DCHECK(bug_descr != NULL);
 569  E :    DCHECK(addr != NULL);
 570  E :    DCHECK(header != NULL);
 571    :  
 572    :    ReportAsanErrorBase(bug_descr,
 573    :                        addr,
 574    :                        context,
 575    :                        stack,
 576    :                        bad_access_kind,
 577    :                        access_mode,
 578  E :                        access_size);
 579    :  
 580    :    // Print the Windbg information to display the allocation stack if present.
 581  E :    if (header->alloc_stack != NULL) {
 582  E :      ASANDbgMessage(L"Allocation stack trace:");
 583    :      ASANDbgCmd(L"dps %p l%d",
 584    :                 header->alloc_stack->frames(),
 585  E :                 header->alloc_stack->num_frames());
 586    :    }
 587    :  
 588    :    // Print the Windbg information to display the free stack if present.
 589  E :    if (header->free_stack != NULL) {
 590  E :      ASANDbgMessage(L"Free stack trace:");
 591    :      ASANDbgCmd(L"dps %p l%d",
 592    :                 header->free_stack->frames(),
 593  E :                 header->free_stack->num_frames());
 594    :    }
 595    :  
 596  E :    ReportAddressInformation(addr, header, bad_access_kind);
 597    :  
 598  E :    ASANDbgPrintContext(context);
 599  E :  }
 600    :  
 601    :  void HeapProxy::ReportAsanErrorBase(const char* bug_descr,
 602    :                                      const void* addr,
 603    :                                      const CONTEXT& context,
 604    :                                      const StackCapture& stack,
 605    :                                      BadAccessKind bad_access_kind,
 606    :                                      AccessMode access_mode,
 607  E :                                      size_t access_size) {
 608  E :    DCHECK(bug_descr != NULL);
 609  E :    DCHECK(addr != NULL);
 610    :  
 611    :    // Print the base of the Windbg help message.
 612    :    ASANDbgMessage(L"An Asan error has been found (%ls), here are the details:",
 613  E :                   base::SysUTF8ToWide(bug_descr).c_str());
 614    :  
 615    :    // TODO(sebmarchand): Print PC, BP and SP.
 616    :    std::string output(base::StringPrintf(
 617    :        "SyzyASAN error: %s on address 0x%08X (stack_id=0x%08X)\n",
 618  E :        bug_descr, addr, stack.stack_id()));
 619  E :    if (access_mode != ASAN_UNKNOWN_ACCESS) {
 620  E :      const char* access_mode_str = NULL;
 621  E :      if (access_mode == ASAN_READ_ACCESS)
 622  E :        access_mode_str = "READ";
 623  E :      else
 624  i :        access_mode_str = "WRITE";
 625    :      base::StringAppendF(&output,
 626    :                          "%s of size %d at 0x%08X\n",
 627    :                          access_mode_str,
 628  E :                          access_size);
 629    :    }
 630    :  
 631    :    // Log the failure and stack.
 632  E :    logger_->WriteWithContext(output, context);
 633  E :  }
 634    :  
 635  E :  const char* HeapProxy::AccessTypeToStr(BadAccessKind bad_access_kind) {
 636  E :    switch (bad_access_kind) {
 637    :      case USE_AFTER_FREE:
 638  E :        return "heap-use-after-free";
 639    :      case HEAP_BUFFER_UNDERFLOW:
 640  E :        return "heap-buffer-underflow";
 641    :      case HEAP_BUFFER_OVERFLOW:
 642  E :        return "heap-buffer-overflow";
 643    :      default:
 644  i :        NOTREACHED() << "Unexpected bad access kind.";
 645  i :        return NULL;
 646    :    }
 647  E :  }
 648    :  
 649  E :  LIST_ENTRY* HeapProxy::ToListEntry(HeapProxy* proxy) {
 650  E :    DCHECK(proxy != NULL);
 651  E :    return &proxy->list_entry_;
 652  E :  }
 653    :  
 654  E :  HeapProxy* HeapProxy::FromListEntry(LIST_ENTRY* list_entry) {
 655  E :    DCHECK(list_entry != NULL);
 656  E :    return CONTAINING_RECORD(list_entry, HeapProxy, list_entry_);
 657  E :  }
 658    :  
 659    :  }  // namespace asan
 660    :  }  // namespace agent

Coverage information generated Thu Mar 14 11:53:36 2013.