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

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
100.0%990.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    :  // Implements HeapProxy, a class that wraps Win32 heap allocations but adds
  16    :  // heap/tail redzones.
  17    :  
  18    :  #ifndef SYZYGY_AGENT_ASAN_ASAN_HEAP_H_
  19    :  #define SYZYGY_AGENT_ASAN_ASAN_HEAP_H_
  20    :  
  21    :  #include <windows.h>  // NOLINT
  22    :  
  23    :  #include "base/logging.h"
  24    :  #include "base/string_piece.h"
  25    :  #include "base/debug/stack_trace.h"
  26    :  #include "base/synchronization/lock.h"
  27    :  #include "syzygy/agent/asan/stack_capture_cache.h"
  28    :  #include "syzygy/agent/common/dlist.h"
  29    :  
  30    :  namespace agent {
  31    :  namespace asan {
  32    :  
  33    :  // Forward declaration.
  34    :  class AsanLogger;
  35    :  class StackCapture;
  36    :  class StackCaptureCache;
  37    :  struct AsanErrorInfo;
  38    :  
  39    :  // An helper function to send a command to Windbg. Windbg should first receive
  40    :  // the ".ocommand ASAN" command to treat those messages as commands.
  41    :  // TODO(sebmarchand): Move this function and the following one to the
  42    :  //     AsanRuntime class once it's ready.
  43    :  void ASANDbgCmd(const wchar_t* fmt, ...);
  44    :  
  45    :  // An helper function to print a message to Windbg's console.
  46    :  void ASANDbgMessage(const wchar_t* fmt, ...);
  47    :  
  48    :  // Makes like a Win32 heap manager heap, but adds a redzone before and after
  49    :  // each allocation and maintains a quarantine list of freed blocks.
  50    :  class HeapProxy {
  51    :   public:
  52    :    // The different memory access modes that we can encounter.
  53    :    enum AccessMode {
  54    :      ASAN_READ_ACCESS,
  55    :      ASAN_WRITE_ACCESS,
  56    :      ASAN_UNKNOWN_ACCESS
  57    :    };
  58    :  
  59    :    // Enumeration of the different kinds of bad heap accesses that we can
  60    :    // encounter.
  61    :    enum BadAccessKind {
  62    :      UNKNOWN_BAD_ACCESS,
  63    :      WILD_ACCESS,
  64    :      USE_AFTER_FREE,
  65    :      HEAP_BUFFER_OVERFLOW,
  66    :      HEAP_BUFFER_UNDERFLOW,
  67    :    };
  68    :  
  69    :    // The different types of error we can encounter.
  70    :    static const char* kHeapUseAfterFree;
  71    :    static const char* kHeapBufferUnderFlow;
  72    :    static const char* kHeapBufferOverFlow;
  73    :    static const char* kAttemptingDoubleFree;
  74    :    static const char* kWildAccess;
  75    :    static const char* kHeapUnknownError;
  76    :  
  77    :    // The sleep time (in milliseconds) used to approximate the CPU frequency.
  78    :    // Exposed for testing.
  79    :    static const size_t kSleepTimeForApproximatingCPUFrequency = 100;
  80    :  
  81    :    HeapProxy(StackCaptureCache* cache, AsanLogger* logger);
  82    :    ~HeapProxy();
  83    :  
  84    :    // @name Cast to/from HANDLE.
  85    :    // @{
  86    :    static HANDLE ToHandle(HeapProxy* proxy);
  87    :    static HeapProxy* FromHandle(HANDLE heap);
  88    :    // @}
  89    :  
  90    :    // @name Heap interface.
  91    :    // @{
  92    :    bool Create(DWORD options,
  93    :                size_t initial_size,
  94    :                size_t maximum_size);
  95    :    bool Destroy();
  96    :    void* Alloc(DWORD flags, size_t bytes);
  97    :    void* ReAlloc(DWORD flags, void* mem, size_t bytes);
  98    :    bool Free(DWORD flags, void* mem);
  99    :    size_t Size(DWORD flags, const void* mem);
 100    :    bool Validate(DWORD flags, const void* mem);
 101    :    size_t Compact(DWORD flags);
 102    :    bool Lock();
 103    :    bool Unlock();
 104    :    bool Walk(PROCESS_HEAP_ENTRY* entry);
 105    :    bool SetInformation(HEAP_INFORMATION_CLASS info_class,
 106    :                        void* info,
 107    :                        size_t info_length);
 108    :    bool QueryInformation(HEAP_INFORMATION_CLASS info_class,
 109    :                          void* info,
 110    :                          size_t info_length,
 111    :                          unsigned long* return_length);
 112    :    // @}
 113    :  
 114    :    // Report a bad access to the heap.
 115    :    // @param addr The red-zoned address causing a bad access.
 116    :    // @param context The context at which the access occurred.
 117    :    // @param stack The stack capture at the point of error.
 118    :    // @param access_mode The kind of the access (read or write).
 119    :    // @param access_size The size of the access (in bytes).
 120    :    // @param bad_access_info Will receive the information about this access.
 121    :    // @returns true if the address belongs to a memory block, false otherwise.
 122    :    bool OnBadAccess(const void* addr,
 123    :                     const CONTEXT& context,
 124    :                     const StackCapture& stack,
 125    :                     AccessMode access_mode,
 126    :                     size_t access_size,
 127    :                     AsanErrorInfo* bad_access_info);
 128    :  
 129    :    // Report a wild access to the memory; this can either be an access to an
 130    :    // internal structure or an access to the upper memory (over the 2GB limit).
 131    :    // @param addr The address causing an error.
 132    :    // @param context The context at which the access occurred.
 133    :    // @param stack The stack capture at the point of error.
 134    :    // @param access_mode The kind of the access (read or write).
 135    :    // @param access_size The size of the access (in bytes).
 136    :    void ReportWildAccess(const void* addr,
 137    :                          const CONTEXT& context,
 138    :                          const StackCapture& stack,
 139    :                          AccessMode access_mode,
 140    :                          size_t access_size);
 141    :  
 142    :    // @name Cast to/from HANDLE.
 143    :    // @{
 144    :    static LIST_ENTRY* ToListEntry(HeapProxy* proxy);
 145    :    static HeapProxy* FromListEntry(LIST_ENTRY* list_entry);
 146    :    // @}
 147    :  
 148    :    // Set the default max size of the quarantine of a heap proxy.
 149    :    // @param quarantine_max_size The maximum size of the quarantine list, in
 150    :    //     bytes.
 151  E :    static void set_default_quarantine_max_size(size_t quarantine_max_size) {
 152  E :      default_quarantine_max_size_ = quarantine_max_size;
 153  E :    }
 154    :  
 155    :    // Get the default max size of the quarantine of a heap proxy.
 156  E :    static size_t default_quarantine_max_size() {
 157  E :      return default_quarantine_max_size_;
 158  E :    }
 159    :  
 160    :    // Set the max size of the quarantine of a heap proxy. If the current size of
 161    :    // the quarantine is greater than this new max size then the extra blocks are
 162    :    // removed from the quarantine.
 163    :    // @param quarantine_max_size The maximum size of the quarantine list, in
 164    :    //     bytes.
 165    :    void SetQuarantineMaxSize(size_t quarantine_max_size);
 166    :  
 167    :    // Get the max size of the quarantine of a heap proxy.
 168  E :    size_t quarantine_max_size() {
 169  E :      return quarantine_max_size_;
 170  E :    }
 171    :  
 172    :    // Static initialization of HeapProxy context.
 173    :    static void Init();
 174    :  
 175    :    // Returns a string describing a bad access kind.
 176    :    static const char* AccessTypeToStr(BadAccessKind bad_access_kind);
 177    :  
 178    :   protected:
 179    :    enum BlockState {
 180    :      ALLOCATED,
 181    :      FREED,
 182    :      QUARANTINED,
 183    :    };
 184    :  
 185    :    // Every allocated block starts with a BlockHeader...
 186    :    struct BlockHeader {
 187    :      size_t magic_number : 24;
 188    :      BlockState state : 8;
 189    :      size_t block_size;
 190    :      const StackCapture* alloc_stack;
 191    :      DWORD alloc_tid;
 192    :    };
 193    :    COMPILE_ASSERT((sizeof(BlockHeader) & 7) == 0,
 194    :                   asan_block_header_not_multiple_of_8_bytes);
 195    :    COMPILE_ASSERT(sizeof(BlockHeader) == 16, asan_block_header_too_big);
 196    :  
 197    :    // ... and ends with a BlockTrailer.
 198    :    #pragma pack(push, 4)
 199    :    struct BlockTrailer {
 200    :      uint64 free_timestamp;
 201    :      const StackCapture* free_stack;
 202    :      DWORD free_tid;
 203    :      // Free blocks are linked together.
 204    :      BlockHeader* next_free_block;
 205    :    };
 206    :    #pragma pack(pop)
 207    :    COMPILE_ASSERT(sizeof(BlockTrailer) == 20, asan_block_trailer_too_big);
 208    :  
 209    :    // Magic number to identify the beginning of a block header.
 210    :    static const size_t kBlockHeaderSignature = 0xCA80E7;
 211    :  
 212    :    // Returns the block header for an alloc.
 213    :    BlockHeader* ToBlockHeader(const void* alloc);
 214    :  
 215    :    // Returns the block trailer for a block header.
 216    :    BlockTrailer* GetBlockTrailer(const BlockHeader* header);
 217    :  
 218    :    // Returns alloc for a block.
 219    :    uint8* ToAlloc(BlockHeader* block);
 220    :  
 221    :    // Find the memory block containing @p addr.
 222    :    // @returns a pointer to this memory block in case of success, NULL otherwise.
 223    :    BlockHeader* FindAddressBlock(const void* addr);
 224    :  
 225    :    // Give the type of a bad heap access corresponding to an address.
 226    :    // @param addr The address causing a bad heap access.
 227    :    // @param header The header of the block containing this address.
 228    :    BadAccessKind GetBadAccessKind(const void* addr, BlockHeader* header);
 229    :  
 230    :    // Calculates the underlying allocation size for a requested
 231    :    // allocation of @p bytes.
 232    :    static size_t GetAllocSize(size_t bytes);
 233    :  
 234    :    // Quarantines @p block and flushes quarantine overage.
 235    :    void QuarantineBlock(BlockHeader* block);
 236    :  
 237    :    // If the quarantine size is over quarantine_max_size_, trim it down until
 238    :    // it's below the limit.
 239    :    void TrimQuarantine();
 240    :  
 241    :    // Get the information about an address belonging to a memory block. This
 242    :    // function will output the relative position of this address inside a block
 243    :    // and the bounds of this block.
 244    :    // @param addr The address for which we want information.
 245    :    // @param header The block containing the address.
 246    :    // @param bad_access_kind The kind of bad access corresponding to this
 247    :    //     address.
 248    :    // @param bad_access_info Will receive the information about this access.
 249    :    void ReportAddressInformation(const void* addr,
 250    :                                  BlockHeader* header,
 251    :                                  BadAccessKind bad_access_kind,
 252    :                                  AsanErrorInfo* bad_access_info);
 253    :  
 254    :    // Low-level ASAN reporting function. This function dumps the stack,
 255    :    // optionally including an extra (free-form) description of the address
 256    :    // being accessed when the error occurred.
 257    :    // @param bug_descr The description of the error.
 258    :    // @param addr The address causing an error.
 259    :    // @param context The context at which the access occurred.
 260    :    // @param stack The stack capture at the point of error.
 261    :    // @param bad_access_kind The kind of error.
 262    :    // @param access_mode The mode of the access (read or write).
 263    :    // @param access_size The size of the access (in bytes).
 264    :    void ReportAsanErrorBase(const char* bug_descr,
 265    :                             const void* addr,
 266    :                             const CONTEXT& context,
 267    :                             const StackCapture& stack,
 268    :                             BadAccessKind bad_access_kind,
 269    :                             AccessMode access_mode,
 270    :                             size_t access_size);
 271    :  
 272    :    // Report an ASAN error, automatically including information about the
 273    :    // address being accessed when the error occurred.
 274    :    // @param bug_descr The description of the error.
 275    :    // @param addr The address causing an error.
 276    :    // @param context The context at which the access occurred.
 277    :    // @param stack The stack capture at the point of error.
 278    :    // @param bad_access_kind The kind of error.
 279    :    // @param header The header of the block containing this address.
 280    :    // @param access_mode The kind of the access (read or write).
 281    :    // @param access_size The size of the access (in bytes).
 282    :    // @param bad_access_info Will receive the information about this access.
 283    :    void ReportAsanError(const char* bug_descr,
 284    :                         const void* addr,
 285    :                         const CONTEXT& context,
 286    :                         const StackCapture& stack,
 287    :                         BadAccessKind bad_access_kind,
 288    :                         BlockHeader* header,
 289    :                         AccessMode access_mode,
 290    :                         size_t access_size,
 291    :                         AsanErrorInfo* bad_access_info);
 292    :  
 293    :    // Returns the time since the block @p header was freed (in microseconds).
 294    :    uint64 GetTimeSinceFree(const BlockHeader* header);
 295    :  
 296    :    // Arbitrarily keep 16 megabytes of quarantine per heap by default.
 297    :    static const size_t kDefaultQuarantineMaxSize_ = 16 * 1024 * 1024;
 298    :  
 299    :    // Default max size of blocks in quarantine (in bytes).
 300    :    static size_t default_quarantine_max_size_;
 301    :  
 302    :    // The number of CPU cycles per microsecond on the current machine.
 303    :    static double cpu_cycles_per_us_;
 304    :  
 305    :    // The underlying heap we delegate to.
 306    :    HANDLE heap_;
 307    :  
 308    :    // A repository of unique stack captures recorded on alloc and free.
 309    :    StackCaptureCache* const stack_cache_;
 310    :  
 311    :    // The logger to use when an error occurs.
 312    :    AsanLogger* const logger_;
 313    :  
 314    :    // Protects concurrent access to HeapProxy internals.
 315    :    base::Lock lock_;
 316    :  
 317    :    // Points to the head of the quarantine queue.
 318    :    BlockHeader* head_;  // Under lock_.
 319    :  
 320    :    // Points to the tail of the quarantine queue.
 321    :    BlockHeader* tail_;  // Under lock_.
 322    :  
 323    :    // Total size of blocks in quarantine.
 324    :    size_t quarantine_size_;  // Under lock_.
 325    :  
 326    :    // Max size of blocks in quarantine.
 327    :    size_t quarantine_max_size_;  // Under lock_.
 328    :  
 329    :    // The entry linking to us.
 330    :    LIST_ENTRY list_entry_;
 331    :  };
 332    :  
 333    :  }  // namespace asan
 334    :  }  // namespace agent
 335    :  
 336    :  #endif  // SYZYGY_AGENT_ASAN_ASAN_HEAP_H_

Coverage information generated Thu Jul 04 09:34:53 2013.