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

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
91.4%3944310.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/block.h"
  16    :  
  17    :  #include <algorithm>
  18    :  
  19    :  #include "base/hash.h"
  20    :  #include "base/logging.h"
  21    :  #include "syzygy/agent/asan/asan_runtime.h"
  22    :  #include "syzygy/agent/asan/stack_capture_cache.h"
  23    :  #include "syzygy/common/align.h"
  24    :  
  25    :  namespace agent {
  26    :  namespace asan {
  27    :  
  28    :  namespace {
  29    :  
  30    :  using ::common::IsAligned;
  31    :  
  32    :  // Declares a function that returns the maximum value representable by
  33    :  // the given bitfield.
  34    :  #define DECLARE_GET_MAX_BITFIELD_VALUE_FUNCTION(Type, FieldName)   \
  35    :    size_t GetMaxValue ## Type ## _ ## FieldName() {  \
  36    :      Type t = {};  \
  37    :      t.FieldName = 0;  \
  38    :      --t.FieldName;  \
  39    :      size_t value = t.FieldName;  \
  40    :      return value;  \
  41    :    }
  42  E :  DECLARE_GET_MAX_BITFIELD_VALUE_FUNCTION(BlockHeader, body_size);
  43    :  #undef DECLARE_GET_MAX_BITFIELD_VALUE_FUNCTION
  44    :  
  45  E :  const size_t kMaxBlockHeaderBodySize = GetMaxValueBlockHeader_body_size();
  46    :  
  47  E :  void InitializeBlockHeader(BlockInfo* block_info) {
  48  E :    DCHECK_NE(static_cast<BlockInfo*>(NULL), block_info);
  49  E :    DCHECK_NE(static_cast<BlockHeader*>(NULL), block_info->header);
  50  E :    ::memset(block_info->header, 0, sizeof(BlockHeader));
  51  E :    block_info->header->magic = kBlockHeaderMagic;
  52  E :    block_info->header->is_nested = block_info->is_nested;
  53  E :    block_info->header->has_header_padding = block_info->header_padding_size > 0;
  54    :    block_info->header->has_excess_trailer_padding =
  55  E :        block_info->trailer_padding_size > sizeof(uint32);
  56  E :    block_info->header->state = ALLOCATED_BLOCK;
  57  E :    block_info->header->body_size = block_info->body_size;
  58  E :  }
  59    :  
  60  E :  void InitializeBlockHeaderPadding(BlockInfo* block_info) {
  61  E :    DCHECK_NE(static_cast<BlockInfo*>(NULL), block_info);
  62  E :    if (block_info->header_padding_size == 0)
  63  E :      return;
  64  E :    DCHECK(IsAligned(block_info->header_padding_size, kShadowRatio));
  65    :    DCHECK(IsAligned(block_info->header_padding_size,
  66  E :                     2 * sizeof(uint32)));
  67    :  
  68    :    ::memset(block_info->header_padding + sizeof(uint32),
  69    :             kBlockHeaderPaddingByte,
  70  E :             block_info->header_padding_size - 2 * sizeof(uint32));
  71  E :    uint32* head = reinterpret_cast<uint32*>(block_info->header_padding);
  72    :    uint32* tail = reinterpret_cast<uint32*>(
  73    :        block_info->header_padding + block_info->header_padding_size -
  74  E :            sizeof(uint32));
  75  E :    *head = block_info->header_padding_size;
  76  E :    *tail = block_info->header_padding_size;
  77  E :  }
  78    :  
  79  E :  void InitializeBlockTrailerPadding(BlockInfo* block_info) {
  80  E :    DCHECK_NE(static_cast<BlockInfo*>(NULL), block_info);
  81  E :    if (block_info->trailer_padding_size == 0)
  82  E :      return;
  83    :    ::memset(block_info->trailer_padding, kBlockTrailerPaddingByte,
  84  E :             block_info->trailer_padding_size);
  85  E :    if (block_info->trailer_padding_size > (kShadowRatio / 2)) {
  86    :      // This is guaranteed by kShadowRatio being >= 8, but we double check
  87    :      // for sanity's sake.
  88  E :      DCHECK_LE(sizeof(uint32), block_info->trailer_padding_size);
  89  E :      uint32* head = reinterpret_cast<uint32*>(block_info->trailer_padding);
  90  E :      *head = block_info->trailer_padding_size;
  91    :    }
  92  E :  }
  93    :  
  94  E :  void InitializeBlockTrailer(BlockInfo* block_info) {
  95  E :    DCHECK_NE(static_cast<BlockInfo*>(NULL), block_info);
  96  E :    ::memset(block_info->trailer, 0, sizeof(BlockTrailer));
  97  E :    block_info->trailer->alloc_ticks = ::GetTickCount();
  98  E :    block_info->trailer->alloc_tid = ::GetCurrentThreadId();
  99  E :  }
 100    :  
 101    :  // Combines the bits of a uint32 into the number of bits used to store the
 102    :  // block checksum.
 103  E :  uint32 CombineUInt32IntoBlockChecksum(uint32 val) {
 104  E :    uint32 checksum = 0;
 105  E :    while (val != 0) {
 106  E :      checksum ^= val;
 107  E :      val >>= kBlockHeaderChecksumBits;
 108  E :    }
 109  E :    checksum &= ((1 << kBlockHeaderChecksumBits) - 1);
 110  E :    return checksum;
 111  E :  }
 112    :  
 113    :  // An exception filter that catches access violations and out of bound accesses.
 114  E :  DWORD BadMemoryAccessFilter(EXCEPTION_POINTERS* e) {
 115    :    if (e->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION ||
 116  E :        e->ExceptionRecord->ExceptionCode == EXCEPTION_ARRAY_BOUNDS_EXCEEDED) {
 117  E :      return EXCEPTION_EXECUTE_HANDLER;
 118    :    }
 119  i :    return EXCEPTION_CONTINUE_SEARCH;
 120  E :  }
 121    :  
 122    :  bool BlockInfoFromMemoryImpl(const void* const_raw_block,
 123  E :                               CompactBlockInfo* block_info) {
 124  E :    DCHECK_NE(static_cast<void*>(NULL), const_raw_block);
 125  E :    DCHECK_NE(static_cast<CompactBlockInfo*>(NULL), block_info);
 126    :  
 127  E :    void* raw_block = const_cast<void*>(const_raw_block);
 128    :  
 129    :    // The raw_block header must be minimally aligned and begin with the expected
 130    :    // magic.
 131  E :    if (!IsAligned(reinterpret_cast<uint32>(raw_block), kShadowRatio))
 132  E :      return false;
 133  E :    BlockHeader* header = reinterpret_cast<BlockHeader*>(raw_block);
 134  E :    if (header->magic != kBlockHeaderMagic)
 135  E :      return false;
 136    :  
 137    :    // Parse the header padding if present.
 138  E :    uint32 header_padding_size = 0;
 139  E :    if (header->has_header_padding) {
 140  E :      uint8* padding = reinterpret_cast<uint8*>(header + 1);
 141  E :      uint32* head = reinterpret_cast<uint32*>(padding);
 142  E :      header_padding_size = *head;
 143  E :      if (header_padding_size < 2 * sizeof(uint32))
 144  E :        return false;
 145  E :      if (!IsAligned(header_padding_size, kShadowRatio))
 146  i :        return false;
 147    :      uint32* tail = reinterpret_cast<uint32*>(
 148  E :          padding + header_padding_size - sizeof(uint32));
 149  E :      if (*head != *tail)
 150  E :        return false;
 151    :    }
 152    :  
 153    :    // Parse the body.
 154  E :    uint8* body = reinterpret_cast<uint8*>(header + 1) + header_padding_size;
 155    :  
 156    :    // Parse the trailer padding.
 157  E :    uint32 trailer_padding_size = 0;
 158  E :    if (header->has_excess_trailer_padding) {
 159  E :      uint32* head = reinterpret_cast<uint32*>(body + header->body_size);
 160  E :      trailer_padding_size = *head;
 161  E :    } else if ((header->body_size % kShadowRatio) != (kShadowRatio / 2)) {
 162    :      trailer_padding_size = (kShadowRatio / 2) -
 163  E :          (header->body_size % (kShadowRatio / 2));
 164    :    }
 165    :  
 166    :    // Parse the trailer. The end of it must be 8 aligned.
 167    :    BlockTrailer* trailer = reinterpret_cast<BlockTrailer*>(
 168  E :        body + header->body_size + trailer_padding_size);
 169  E :    if (!IsAligned(reinterpret_cast<uint32>(trailer + 1), kShadowRatio))
 170  i :      return false;
 171    :  
 172  E :    block_info->block = reinterpret_cast<uint8*>(raw_block);
 173    :    block_info->block_size = reinterpret_cast<uint8*>(trailer + 1)
 174  E :        - reinterpret_cast<uint8*>(header);
 175  E :    block_info->header_size = sizeof(BlockHeader) + header_padding_size;
 176  E :    block_info->trailer_size = trailer_padding_size + sizeof(BlockTrailer);
 177  E :    block_info->is_nested = header->is_nested;
 178    :  
 179  E :    return true;
 180  E :  }
 181    :  
 182  E :  BlockHeader* BlockGetHeaderFromBodyImpl(const void* const_body) {
 183  E :    DCHECK_NE(static_cast<void*>(NULL), const_body);
 184    :  
 185  E :    void* body = const_cast<void*>(const_body);
 186    :  
 187    :    // The header must be appropriately aligned.
 188  E :    if (!IsAligned(reinterpret_cast<uint32>(body), kShadowRatio))
 189  E :      return NULL;
 190    :  
 191    :    // First assume that there is no padding, and check if a valid block header
 192    :    // is found there.
 193  E :    BlockHeader* header = reinterpret_cast<BlockHeader*>(body) - 1;
 194  E :    if (header->magic == kBlockHeaderMagic && header->has_header_padding == 0)
 195  E :      return header;
 196    :  
 197    :    // Otherwise assume there is padding. The padding must be formatted
 198    :    // correctly and have a valid length.
 199  E :    uint32* tail = reinterpret_cast<uint32*>(body) - 1;
 200  E :    if (*tail == 0 || !IsAligned(*tail, kShadowRatio))
 201  E :      return NULL;
 202  E :    uint32* head = (tail + 1) - ((*tail) / sizeof(uint32));
 203  E :    if (head > tail)
 204  E :      return NULL;
 205  E :    if (*head != *tail)
 206  E :      return NULL;
 207    :  
 208    :    // Expect there to be a valid block header.
 209  E :    header = reinterpret_cast<BlockHeader*>(head) - 1;
 210  E :    if (header->magic == kBlockHeaderMagic && header->has_header_padding == 1)
 211  E :      return header;
 212    :  
 213    :    // No valid block header was found before the provided body address.
 214  E :    return NULL;
 215  E :  }
 216    :  
 217    :  }  // namespace
 218    :  
 219    :  bool BlockPlanLayout(size_t chunk_size,
 220    :                       size_t alignment,
 221    :                       size_t size,
 222    :                       size_t min_left_redzone_size,
 223    :                       size_t min_right_redzone_size,
 224  E :                       BlockLayout* layout) {
 225  E :    DCHECK_LE(kShadowRatio, chunk_size);
 226  E :    DCHECK(::common::IsPowerOfTwo(chunk_size));
 227  E :    DCHECK_LE(kShadowRatio, alignment);
 228  E :    DCHECK_GE(chunk_size, alignment);
 229  E :    DCHECK(::common::IsPowerOfTwo(alignment));
 230    :  
 231    :    // Calculate minimum redzone sizes that respect the parameters.
 232    :    size_t left_redzone_size = ::common::AlignUp(
 233    :        std::max(min_left_redzone_size, sizeof(BlockHeader)),
 234  E :        alignment);
 235    :    size_t right_redzone_size = std::max(min_right_redzone_size,
 236  E :                                         sizeof(BlockTrailer));
 237    :  
 238    :    // Calculate the total size of the allocation.
 239    :    size_t total_size = ::common::AlignUp(
 240  E :        left_redzone_size + size + right_redzone_size, chunk_size);
 241    :  
 242  E :    if (total_size < size)
 243  E :      return false;
 244    :  
 245    :    // Now figure out the sizes of things such that the body of the allocation is
 246    :    // aligned as close as possible to the beginning of the right redzone while
 247    :    // respecting the body alignment requirements. This favors catching overflows
 248    :    // vs underflows when page protection mechanisms are active.
 249  E :    size_t body_trailer_size = size + right_redzone_size;
 250    :    size_t body_trailer_size_aligned = ::common::AlignUp(body_trailer_size,
 251  E :                                                         alignment);
 252  E :    size_t body_padding_size = body_trailer_size_aligned - body_trailer_size;
 253  E :    right_redzone_size += body_padding_size;
 254    :  
 255    :    // The left redzone takes up the rest of the space.
 256  E :    left_redzone_size = total_size - right_redzone_size - size;
 257    :  
 258    :    // Make sure the basic layout invariants are satisfied.
 259  E :    DCHECK_LE(min_left_redzone_size, left_redzone_size);
 260  E :    DCHECK_LE(min_right_redzone_size, right_redzone_size);
 261  E :    DCHECK_EQ(total_size, (left_redzone_size + size + right_redzone_size));
 262  E :    DCHECK(IsAligned(total_size, chunk_size));
 263  E :    DCHECK(IsAligned(left_redzone_size, alignment));
 264    :  
 265    :    // Fill out the layout structure.
 266  E :    layout->block_alignment = chunk_size;
 267  E :    layout->block_size = total_size;
 268  E :    layout->header_size = sizeof(BlockHeader);
 269  E :    layout->header_padding_size = left_redzone_size - sizeof(BlockHeader);
 270  E :    layout->body_size = size;
 271  E :    layout->trailer_padding_size = right_redzone_size - sizeof(BlockTrailer);
 272  E :    layout->trailer_size = sizeof(BlockTrailer);
 273  E :    return true;
 274  E :  }
 275    :  
 276    :  void BlockInitialize(const BlockLayout& layout,
 277    :                       void* allocation,
 278    :                       bool is_nested,
 279  E :                       BlockInfo* block_info) {
 280  E :    DCHECK_NE(static_cast<void*>(NULL), allocation);
 281    :    DCHECK(IsAligned(reinterpret_cast<uint32>(allocation),
 282  E :                     layout.block_alignment));
 283    :  
 284    :    // If no output structure is provided then use a local one. We need the data
 285    :    // locally, but the caller might not be interested in it.
 286  E :    BlockInfo local_block_info = {};
 287  E :    if (block_info == NULL) {
 288  i :      block_info = &local_block_info;
 289  i :    } else {
 290  E :      ::memset(block_info, 0, sizeof(BlockInfo));
 291    :    }
 292    :  
 293    :    // Get pointers to the various components of the block.
 294  E :    uint8* cursor = reinterpret_cast<uint8*>(allocation);
 295  E :    block_info->block = reinterpret_cast<uint8*>(cursor);
 296  E :    block_info->block_size = layout.block_size;
 297  E :    block_info->is_nested = is_nested;
 298  E :    block_info->header = reinterpret_cast<BlockHeader*>(cursor);
 299  E :    cursor += sizeof(BlockHeader);
 300  E :    block_info->header_padding = cursor;
 301  E :    cursor += layout.header_padding_size;
 302  E :    block_info->header_padding_size = layout.header_padding_size;
 303  E :    block_info->body = reinterpret_cast<uint8*>(cursor);
 304  E :    cursor += layout.body_size;
 305  E :    block_info->body_size = layout.body_size;
 306  E :    block_info->trailer_padding = cursor;
 307  E :    cursor += layout.trailer_padding_size;
 308  E :    block_info->trailer_padding_size = layout.trailer_padding_size;
 309  E :    block_info->trailer = reinterpret_cast<BlockTrailer*>(cursor);
 310    :  
 311    :    // Indicates if the block is nested.
 312  E :    block_info->is_nested = is_nested;
 313    :  
 314    :    // If the block information is being returned to the user then determine
 315    :    // the extents of whole pages within it.
 316  E :    if (block_info != &local_block_info)
 317  E :      BlockIdentifyWholePages(block_info);
 318    :  
 319    :    // Initialize the various portions of the memory. The body is not initialized
 320    :    // as this is an unnecessary performance hit.
 321  E :    InitializeBlockHeader(block_info);
 322  E :    InitializeBlockHeaderPadding(block_info);
 323  E :    InitializeBlockTrailerPadding(block_info);
 324  E :    InitializeBlockTrailer(block_info);
 325  E :  }
 326    :  
 327  i :  bool BlockInfoFromMemory(const void* raw_block, CompactBlockInfo* block_info) {
 328  i :    DCHECK_NE(static_cast<void*>(NULL), raw_block);
 329  i :    DCHECK_NE(static_cast<CompactBlockInfo*>(NULL), block_info);
 330    :  
 331  i :    __try {
 332    :      // As little code as possible is inside the body of the __try so that
 333    :      // our code coverage can instrument it.
 334  i :      bool result = BlockInfoFromMemoryImpl(raw_block, block_info);
 335  i :      return result;
 336  i :    } __except (BadMemoryAccessFilter(GetExceptionInformation())) {  // NOLINT
 337    :      // The block is either corrupt, or the pages are protected.
 338  i :      return false;
 339  i :    }
 340  i :  }
 341    :  
 342  E :  void ConvertBlockInfo(const CompactBlockInfo& compact, BlockInfo* expanded) {
 343  E :    expanded->block = compact.block;
 344  E :    expanded->block_size = compact.block_size;
 345  E :    expanded->header = reinterpret_cast<BlockHeader*>(compact.block);
 346  E :    expanded->header_padding_size = compact.header_size - sizeof(BlockHeader);
 347  E :    expanded->header_padding = compact.block + sizeof(BlockHeader);
 348  E :    expanded->body = compact.block + compact.header_size;
 349    :    expanded->body_size = compact.block_size - compact.header_size -
 350  E :        compact.trailer_size;
 351  E :    expanded->trailer_padding_size = compact.trailer_size - sizeof(BlockTrailer);
 352  E :    expanded->trailer_padding = expanded->body + expanded->body_size;
 353    :    expanded->trailer = reinterpret_cast<BlockTrailer*>(
 354  E :        expanded->trailer_padding + expanded->trailer_padding_size);
 355  E :    expanded->is_nested = compact.is_nested;
 356  E :    BlockIdentifyWholePages(expanded);
 357  E :  }
 358    :  
 359  E :  void ConvertBlockInfo(const BlockInfo& expanded, CompactBlockInfo* compact) {
 360  E :    DCHECK_NE(static_cast<CompactBlockInfo*>(nullptr), compact);
 361  E :    compact->block = expanded.block;
 362  E :    compact->block_size = expanded.block_size;
 363  E :    compact->header_size = sizeof(BlockHeader) + expanded.header_padding_size;
 364  E :    compact->trailer_size = sizeof(BlockTrailer) + expanded.trailer_padding_size;
 365  E :    compact->is_nested = expanded.is_nested;
 366  E :  }
 367    :  
 368  E :  bool BlockInfoFromMemory(const void* raw_block, BlockInfo* block_info) {
 369  E :    DCHECK_NE(static_cast<void*>(NULL), raw_block);
 370  E :    DCHECK_NE(static_cast<BlockInfo*>(NULL), block_info);
 371  E :    CompactBlockInfo compact = {};
 372  E :    if (!BlockInfoFromMemory(raw_block, &compact))
 373  E :      return false;
 374  E :    ConvertBlockInfo(compact, block_info);
 375  E :    return true;
 376  E :  }
 377    :  
 378  i :  BlockHeader* BlockGetHeaderFromBody(const void* body) {
 379  i :    DCHECK_NE(static_cast<void*>(NULL), body);
 380    :  
 381  i :    __try {
 382    :      // As little code as possible is inside the body of the __try so that
 383    :      // our code coverage can instrument it.
 384  i :      BlockHeader* header = BlockGetHeaderFromBodyImpl(body);
 385  i :      return header;
 386  i :    } __except (BadMemoryAccessFilter(GetExceptionInformation())) {  // NOLINT
 387    :      // The block is either corrupt, or the pages are protected.
 388  i :      return NULL;
 389  i :    }
 390  i :  }
 391    :  
 392  E :  uint32 BlockCalculateChecksum(const BlockInfo& block_info) {
 393    :    // It is much easier to calculate the checksum in place so this actually
 394    :    // causes the block to be modified, but restores the original value.
 395  E :    uint32 old_checksum = block_info.header->checksum;
 396  E :    block_info.header->checksum = 0;
 397  E :    BlockSetChecksum(block_info);
 398  E :    uint32 new_checksum = block_info.header->checksum;
 399  E :    block_info.header->checksum = old_checksum;
 400  E :    return new_checksum;
 401  E :  }
 402    :  
 403  E :  bool BlockChecksumIsValid(const BlockInfo& block_info) {
 404  E :    uint32 checksum = BlockCalculateChecksum(block_info);
 405  E :    if (checksum == block_info.header->checksum)
 406  E :      return true;
 407  E :    return false;
 408  E :  }
 409    :  
 410  E :  void BlockSetChecksum(const BlockInfo& block_info) {
 411  E :    block_info.header->checksum = 0;
 412    :  
 413  E :    uint32 checksum = 0;
 414  E :    switch (block_info.header->state) {
 415    :      case ALLOCATED_BLOCK: {
 416    :        // Only checksum the header and trailer regions.
 417    :        checksum = base::SuperFastHash(
 418    :            reinterpret_cast<const char*>(block_info.block),
 419  E :            block_info.body - block_info.block);
 420    :        checksum ^= base::SuperFastHash(
 421    :            reinterpret_cast<const char*>(block_info.trailer_padding),
 422    :            block_info.block + block_info.block_size -
 423  E :                block_info.trailer_padding);
 424  E :        break;
 425    :      }
 426    :  
 427    :      // The checksum is the calculated in the same way in these two cases.
 428    :      // Similary, the catch all default case is calculated in this way so as to
 429    :      // allow the hash to successfully be calculated even for a block with a
 430    :      // corrupt state.
 431    :      case QUARANTINED_BLOCK:
 432    :      case FREED_BLOCK:
 433    :      default: {
 434    :        checksum = base::SuperFastHash(
 435    :            reinterpret_cast<const char*>(block_info.block),
 436  E :            block_info.block_size);
 437    :        break;
 438    :      }
 439    :    }
 440    :  
 441  E :    checksum = CombineUInt32IntoBlockChecksum(checksum);
 442  E :    DCHECK_EQ(0u, checksum >> kBlockHeaderChecksumBits);
 443  E :    block_info.header->checksum = checksum;
 444  E :  }
 445    :  
 446    :  // Identifies whole pages in the given block_info.
 447  E :  void BlockIdentifyWholePages(BlockInfo* block_info) {
 448  E :    DCHECK_NE(static_cast<BlockInfo*>(NULL), block_info);
 449    :    static const size_t kPageInfoSize =
 450    :        FIELD_OFFSET(BlockInfo, is_nested) -
 451    :        FIELD_OFFSET(BlockInfo, block_pages);
 452    :  
 453  E :    if (block_info->block_size < GetPageSize()) {
 454  E :      ::memset(&block_info->block_pages, 0, kPageInfoSize);
 455  E :      return;
 456    :    }
 457    :  
 458  E :    uint32 alloc_start = reinterpret_cast<uint32>(block_info->block);
 459  E :    uint32 alloc_end = alloc_start + block_info->block_size;
 460  E :    alloc_start = ::common::AlignUp(alloc_start, GetPageSize());
 461  E :    alloc_end = ::common::AlignDown(alloc_end, GetPageSize());
 462  E :    if (alloc_start >= alloc_end) {
 463  E :      ::memset(&block_info->block_pages, 0, kPageInfoSize);
 464  E :      return;
 465    :    }
 466    :  
 467  E :    block_info->block_pages = reinterpret_cast<uint8*>(alloc_start);
 468  E :    block_info->block_pages_size = alloc_end - alloc_start;
 469    :  
 470  E :    uint32 left_redzone_end = reinterpret_cast<uint32>(block_info->body);
 471  E :    uint32 right_redzone_start = left_redzone_end + block_info->body_size;
 472  E :    left_redzone_end = ::common::AlignDown(left_redzone_end, GetPageSize());
 473  E :    right_redzone_start = ::common::AlignUp(right_redzone_start, GetPageSize());
 474    :  
 475  E :    if (alloc_start < left_redzone_end) {
 476  E :      block_info->left_redzone_pages = reinterpret_cast<uint8*>(alloc_start);
 477  E :      block_info->left_redzone_pages_size = left_redzone_end - alloc_start;
 478  E :    } else {
 479  E :      block_info->left_redzone_pages = nullptr;
 480  E :      block_info->left_redzone_pages_size = 0;
 481    :    }
 482    :  
 483  E :    if (right_redzone_start < alloc_end) {
 484    :      block_info->right_redzone_pages =
 485  E :          reinterpret_cast<uint8*>(right_redzone_start);
 486  E :      block_info->right_redzone_pages_size = alloc_end - right_redzone_start;
 487  E :    } else {
 488  E :      block_info->right_redzone_pages = nullptr;
 489  E :      block_info->right_redzone_pages_size = 0;
 490    :    }
 491  E :  }
 492    :  
 493    :  // This namespace contains helpers for block analysis.
 494    :  namespace {
 495    :  
 496    :  // Determines if a stack-capture pointer is valid by referring to the
 497    :  // stack-capture cache in the active runtime.
 498  E :  bool IsValidStackCapturePointer(const common::StackCapture* stack) {
 499  E :    if (stack == nullptr)
 500  E :      return false;
 501  E :    AsanRuntime* runtime = AsanRuntime::runtime();
 502  E :    DCHECK_NE(static_cast<AsanRuntime*>(nullptr), runtime);
 503  E :    StackCaptureCache* cache = runtime->stack_cache();
 504  E :    DCHECK_NE(static_cast<StackCaptureCache*>(nullptr), cache);
 505  E :    if (!cache->StackCapturePointerIsValid(stack))
 506  E :      return false;
 507  E :    return true;
 508  E :  }
 509    :  
 510    :  // Determines if a thread-id is valid by referring to the cache of thread-ids
 511    :  // in the runtime.
 512  E :  bool IsValidThreadId(uint32 thread_id) {
 513  E :    AsanRuntime* runtime = AsanRuntime::runtime();
 514  E :    DCHECK_NE(static_cast<AsanRuntime*>(nullptr), runtime);
 515  E :    if (!runtime->ThreadIdIsValid(thread_id))
 516  E :      return false;
 517  E :    return true;
 518  E :  }
 519    :  
 520    :  // Determines if timestamp is plausible by referring to the process start
 521    :  // time as recorded by the runtime.
 522  E :  bool IsValidTicks(uint32 ticks) {
 523  E :    uint32 end = ::GetTickCount();
 524  E :    AsanRuntime* runtime = AsanRuntime::runtime();
 525  E :    DCHECK_NE(static_cast<AsanRuntime*>(nullptr), runtime);
 526  E :    uint32 begin = runtime->starting_ticks();
 527  E :    if (ticks < begin || ticks > end)
 528  i :      return false;
 529  E :    return true;
 530  E :  }
 531    :  
 532    :  // Determines if a heap id is valid by referring to the runtime.
 533  E :  bool IsValidHeapId(uint32 heap_id) {
 534  E :    AsanRuntime* runtime = AsanRuntime::runtime();
 535  E :    DCHECK_NE(static_cast<AsanRuntime*>(nullptr), runtime);
 536  E :    if (!runtime->HeapIdIsValid(heap_id))
 537  E :      return false;
 538  E :    return true;
 539  E :  }
 540    :  
 541  E :  bool BlockHeaderIsConsistent(const BlockInfo& block_info) {
 542  E :    const BlockHeader* h = block_info.header;
 543  E :    if (h->magic != kBlockHeaderMagic)
 544  E :      return false;
 545  E :    if (static_cast<bool>(h->is_nested) != block_info.is_nested)
 546  i :      return false;
 547    :  
 548  E :    bool expect_header_padding = block_info.header_padding_size > 0;
 549  E :    if (static_cast<bool>(h->has_header_padding) != expect_header_padding)
 550  i :      return false;
 551    :  
 552    :    bool expect_excess_trailer_padding =
 553  E :        block_info.trailer_padding_size > (kShadowRatio / 2);
 554    :    if (static_cast<bool>(h->has_excess_trailer_padding) !=
 555  E :            expect_excess_trailer_padding) {
 556  i :      return false;
 557    :    }
 558    :  
 559  E :    if (h->state > FREED_BLOCK)
 560  E :      return false;
 561    :  
 562  E :    if (h->body_size != block_info.body_size)
 563  i :      return false;
 564    :  
 565    :    // There should always be a valid allocation stack trace.
 566  E :    if (!IsValidStackCapturePointer(h->alloc_stack))
 567  E :      return false;
 568    :  
 569    :    // The free stack should be empty if we're in the allocated state.
 570  E :    if (h->state == ALLOCATED_BLOCK) {
 571  E :      if (h->free_stack != nullptr)
 572  E :        return false;
 573  E :    } else {
 574    :      // Otherwise there should be a valid free stack.
 575  E :      if (!IsValidStackCapturePointer(h->free_stack))
 576  E :        return false;
 577    :    }
 578    :  
 579    :    // If there's no header padding then the block is valid.
 580  E :    if (block_info.header_padding_size == 0)
 581  E :      return true;
 582    :  
 583    :    // Analyze the block header padding.
 584    :    const uint32* head = reinterpret_cast<const uint32*>(
 585  E :        block_info.header_padding);
 586    :    const uint32* tail = reinterpret_cast<const uint32*>(
 587  E :        block_info.header_padding + block_info.header_padding_size) - 1;
 588  E :    if (*head != block_info.header_padding_size)
 589  i :      return false;
 590  E :    if (*tail != block_info.header_padding_size)
 591  E :      return false;
 592    :    static const uint32 kHeaderPaddingValue =
 593    :        (kBlockHeaderPaddingByte << 24) |
 594    :        (kBlockHeaderPaddingByte << 16) |
 595    :        (kBlockHeaderPaddingByte << 8) |
 596    :        kBlockHeaderPaddingByte;
 597  E :    for (++head; head < tail; ++head) {
 598  E :      if (*head != kHeaderPaddingValue)
 599  E :        return false;
 600  E :    }
 601    :  
 602  E :    return true;
 603  E :  }
 604    :  
 605    :  // Returns true if the trailer is self-consistent, false otherwise.
 606    :  // Via |cross_consistent| indicates whether or not the header and trailer
 607    :  // are consistent with respect to each other.
 608  E :  bool BlockTrailerIsConsistent(const BlockInfo& block_info) {
 609  E :    const BlockHeader* h = block_info.header;
 610  E :    const BlockTrailer* t = block_info.trailer;
 611    :  
 612    :    // The allocation data must always be set.
 613  E :    if (!IsValidThreadId(t->alloc_tid))
 614  E :      return false;
 615  E :    if (!IsValidTicks(t->alloc_ticks))
 616  i :      return false;
 617    :  
 618    :    // The free fields must both be set, or both be clear.
 619  E :    if (t->free_tid != 0 && t->free_ticks != 0) {
 620  E :      if (!IsValidThreadId(t->free_tid))
 621  i :        return false;
 622  E :      if (!IsValidTicks(t->free_ticks))
 623  i :        return false;
 624  E :    } else if (t->free_tid != 0 || t->free_ticks != 0) {
 625    :      // If one or the other is set then the trailer is inconsistent.
 626  i :      return false;
 627    :    }
 628    :  
 629    :    // The heap ID must always be set and be valid.
 630  E :    if (!IsValidHeapId(t->heap_id))
 631  E :      return false;
 632    :  
 633    :    // If there's no padding to check then we're done.
 634  E :    if (block_info.trailer_padding_size == 0)
 635  E :      return true;
 636    :  
 637  E :    const uint8* padding = block_info.trailer_padding;
 638  E :    size_t size = block_info.trailer_padding_size;
 639    :  
 640    :    // If we have excess trailer padding then check the encoded length.
 641  E :    if (size > (kShadowRatio / 2)) {
 642  E :      const uint32* length = reinterpret_cast<const uint32*>(padding);
 643  E :      if (*length != size)
 644  E :        return false;
 645  E :      padding += sizeof(uint32);
 646  E :      size -= sizeof(uint32);
 647    :    }
 648    :  
 649    :    // Check the remaining trailer padding to ensure it's appropriately
 650    :    // flood-filled.
 651  E :    while (size > 0) {
 652  E :      if (*padding != kBlockTrailerPaddingByte)
 653  E :        return false;
 654  E :      ++padding;
 655  E :      --size;
 656  E :    }
 657    :  
 658  E :    return true;
 659  E :  }
 660    :  
 661    :  // Returns true if the header and trailer are cross-consistent with
 662    :  // respect to each other.
 663  E :  bool BlockHeaderAndTrailerAreCrossConsistent(const BlockInfo& block_info) {
 664  E :    const BlockHeader* h = block_info.header;
 665  E :    const BlockTrailer* t = block_info.trailer;
 666    :  
 667  E :    if (h->state == ALLOCATED_BLOCK) {
 668  E :      if (t->free_tid != 0 || t->free_ticks != 0)
 669  i :        return false;
 670  E :    } else {
 671  E :      if (t->free_tid == 0 || t->free_ticks == 0)
 672  E :        return false;
 673    :    }
 674    :  
 675  E :    return true;
 676  E :  }
 677    :  
 678    :  }  // namespace
 679    :  
 680    :  void BlockAnalyze(const BlockInfo& block_info,
 681  E :                    BlockAnalysisResult* result) {
 682  E :    DCHECK_NE(static_cast<BlockAnalysisResult*>(nullptr), result);
 683    :  
 684  E :    result->block_state = kDataStateUnknown;
 685  E :    result->header_state = kDataStateUnknown;
 686  E :    result->body_state = kDataStateUnknown;
 687  E :    result->trailer_state = kDataStateUnknown;
 688    :  
 689  E :    if (BlockChecksumIsValid(block_info)) {
 690  E :      result->block_state = kDataIsClean;
 691  E :      result->header_state = kDataIsClean;
 692  E :      result->body_state = kDataIsClean;
 693  E :      result->trailer_state = kDataIsClean;
 694  E :      return;
 695    :    }
 696    :  
 697    :    // At this point it's known that the checksum is invalid, so some part
 698    :    // of the block is corrupt.
 699  E :    result->block_state = kDataIsCorrupt;
 700    :  
 701    :    // Either the header, the body or the trailer is invalid. We can't
 702    :    // ever exonerate the body contents, so at the very least its state
 703    :    // is unknown. Leave it set to unknown.
 704    :  
 705    :    // Check the header.
 706  E :    bool consistent_header = BlockHeaderIsConsistent(block_info);
 707  E :    if (!consistent_header) {
 708  E :      result->header_state = kDataIsCorrupt;
 709  E :    } else {
 710  E :      result->header_state = kDataIsClean;
 711    :    }
 712    :  
 713    :    // Check the trailer.
 714  E :    bool consistent_trailer = BlockTrailerIsConsistent(block_info);
 715  E :    if (!consistent_trailer) {
 716  E :      result->trailer_state = kDataIsCorrupt;
 717  E :    } else {
 718  E :      result->trailer_state = kDataIsClean;
 719    :    }
 720    :  
 721  E :    bool cross_consistent = BlockHeaderAndTrailerAreCrossConsistent(block_info);
 722  E :    if (consistent_header && consistent_trailer) {
 723  E :      if (cross_consistent) {
 724    :        // If both the header and trailer are fine and cross-consistent, then the
 725    :        // body must be corrupt.
 726  E :        result->body_state = kDataIsCorrupt;
 727  E :      } else {
 728    :        // If both the header and trailer are fine but not cross-consistent, then
 729    :        // one or both of them is corrupt but we can't tell. Mark everything as
 730    :        // doubtful.
 731  i :        result->header_state = kDataStateUnknown;
 732  i :        result->trailer_state = kDataStateUnknown;
 733    :      }
 734    :    }
 735  E :  }
 736    :  
 737    :  }  // namespace asan
 738    :  }  // namespace agent

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