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

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
92.5%1361470.C++test

Line-by-line coverage:

   1    :  // Copyright 2013 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    :  #ifndef SYZYGY_AGENT_ASAN_UNITTEST_UTIL_H_
  16    :  #define SYZYGY_AGENT_ASAN_UNITTEST_UTIL_H_
  17    :  
  18    :  #include <string>
  19    :  #include <utility>
  20    :  #include <vector>
  21    :  
  22    :  #include "base/bind.h"
  23    :  #include "base/files/file_util.h"
  24    :  #include "base/files/scoped_temp_dir.h"
  25    :  #include "base/memory/ref_counted.h"
  26    :  #include "base/strings/string_piece.h"
  27    :  #include "gmock/gmock.h"
  28    :  #include "gtest/gtest.h"
  29    :  #include "syzygy/agent/asan/block.h"
  30    :  #include "syzygy/agent/asan/error_info.h"
  31    :  #include "syzygy/agent/asan/heap.h"
  32    :  #include "syzygy/agent/asan/logger.h"
  33    :  #include "syzygy/agent/asan/memory_notifier.h"
  34    :  #include "syzygy/agent/asan/page_protection_helpers.h"
  35    :  #include "syzygy/agent/asan/runtime.h"
  36    :  #include "syzygy/agent/asan/shadow.h"
  37    :  #include "syzygy/agent/asan/stack_capture_cache.h"
  38    :  #include "syzygy/agent/asan/memory_notifiers/null_memory_notifier.h"
  39    :  #include "syzygy/agent/common/stack_capture.h"
  40    :  #include "syzygy/core/address.h"
  41    :  #include "syzygy/core/address_space.h"
  42    :  #include "syzygy/core/unittest_util.h"
  43    :  #include "syzygy/trace/agent_logger/agent_logger.h"
  44    :  #include "syzygy/trace/agent_logger/agent_logger_rpc_impl.h"
  45    :  
  46    :  namespace testing {
  47    :  
  48    :  using agent::asan::AsanErrorInfo;
  49    :  using agent::asan::memory_notifiers::NullMemoryNotifier;
  50    :  using agent::asan::Shadow;
  51    :  using agent::asan::StackCaptureCache;
  52    :  
  53    :  // The default name of the runtime library DLL.
  54    :  extern const wchar_t kSyzyAsanRtlDll[];
  55    :  
  56    :  // A unittest fixture that sets up a OnExceptionCallback for use with
  57    :  // BlockInfoFromMemory and BlockGetHeaderFromBody. This is the base fixture
  58    :  // class for all ASAN-related test fixtures declared in this file.
  59    :  class LenientOnExceptionCallbackTest : public testing::Test {
  60    :   public:
  61  E :    MOCK_METHOD1(OnExceptionCallback, void(EXCEPTION_POINTERS*));
  62    :  
  63  E :    void SetUp() override {
  64  E :      testing::Test::SetUp();
  65    :      agent::asan::SetOnExceptionCallback(
  66    :          base::Bind(&LenientOnExceptionCallbackTest::OnExceptionCallback,
  67  E :                     base::Unretained(this)));
  68  E :    }
  69    :  
  70  E :    void TearDown() override {
  71  E :      agent::asan::ClearOnExceptionCallback();
  72  E :      testing::Test::TearDown();
  73  E :    }
  74    :  };
  75    :  typedef testing::StrictMock<LenientOnExceptionCallbackTest>
  76    :      OnExceptionCallbackTest;
  77    :  
  78    :  // A unittest fixture that ensures that an Asan logger instance is up and
  79    :  // running for the duration of the test. Output is captured to a file so that
  80    :  // its contents can be read after the test if necessary.
  81    :  class TestWithAsanLogger : public OnExceptionCallbackTest {
  82    :   public:
  83    :    TestWithAsanLogger();
  84    :  
  85    :    // @name testing::Test overrides.
  86    :    // @{
  87    :    void SetUp() override;
  88    :    void TearDown() override;
  89    :    // @}
  90    :  
  91    :    // @name Accessors.
  92    :    // @{
  93    :    const std::wstring& instance_id() const { return instance_id_; }
  94    :    const base::FilePath& log_file_path() const { return log_file_path_; }
  95    :    const base::FilePath& temp_dir() const { return temp_dir_.path(); }
  96    :    // @}
  97    :  
  98    :    bool LogContains(const base::StringPiece& message);
  99    :  
 100    :    // Delete the temporary file used for the logging and its directory.
 101    :    void DeleteTempFileAndDirectory();
 102    :  
 103    :    // Starts the logger process.
 104    :    void StartLogger();
 105    :  
 106    :    // Stops the logger process.
 107    :    void StopLogger();
 108    :  
 109    :    // Reset the log contents.
 110    :    void ResetLog();
 111    :  
 112    :    // Appends @p instance to the RPC logger instance environment variable.
 113    :    void AppendToLoggerEnv(const std::string &instance);
 114    :  
 115    :   private:
 116    :    // The instance ID used by the running logger instance.
 117    :    std::wstring instance_id_;
 118    :  
 119    :    // The path to the log file where the the logger instance will write.
 120    :    base::FilePath log_file_path_;
 121    :  
 122    :    // Status of the logger process.
 123    :    bool logger_running_;
 124    :  
 125    :    // A temporary directory into which the log file will be written.
 126    :    base::ScopedTempDir temp_dir_;
 127    :  
 128    :    // The contents of the log. These are read by calling LogContains.
 129    :    bool log_contents_read_;
 130    :    std::string log_contents_;
 131    :  
 132    :    // Value of the logger instance environment variable before SetUp.
 133    :    std::string old_logger_env_;
 134    :  
 135    :    // Redirection files for the logger.
 136    :    base::ScopedFILE logger_stdin_file_;
 137    :    base::ScopedFILE logger_stdout_file_;
 138    :    base::ScopedFILE logger_stderr_file_;
 139    :  };
 140    :  
 141    :  // Shorthand for discussing all the asan runtime functions.
 142    :  #define ASAN_RTL_FUNCTIONS(F)  \
 143    :      F(WINAPI, HANDLE, GetProcessHeap, (), ())  \
 144    :      F(WINAPI, HANDLE, HeapCreate,  \
 145    :        (DWORD options, SIZE_T initial_size, SIZE_T maximum_size),  \
 146    :        (options, initial_size, maximum_size))  \
 147    :      F(WINAPI, BOOL, HeapDestroy,  \
 148    :        (HANDLE heap), (heap))  \
 149    :      F(WINAPI, LPVOID, HeapAlloc,  \
 150    :        (HANDLE heap, DWORD flags, SIZE_T bytes), (heap, flags, bytes))  \
 151    :      F(WINAPI, LPVOID, HeapReAlloc,  \
 152    :        (HANDLE heap, DWORD flags, LPVOID mem, SIZE_T bytes),  \
 153    :        (heap, flags, mem, bytes))  \
 154    :      F(WINAPI, BOOL, HeapFree,  \
 155    :        (HANDLE heap, DWORD flags, LPVOID mem), (heap, flags, mem))  \
 156    :      F(WINAPI, SIZE_T, HeapSize,  \
 157    :        (HANDLE heap, DWORD flags, LPCVOID mem), (heap, flags, mem))  \
 158    :      F(WINAPI, BOOL, HeapValidate,  \
 159    :        (HANDLE heap, DWORD flags, LPCVOID mem), (heap, flags, mem))  \
 160    :      F(WINAPI, SIZE_T, HeapCompact,  \
 161    :        (HANDLE heap, DWORD flags), (heap, flags))  \
 162    :      F(WINAPI, BOOL, HeapLock, (HANDLE heap), (heap))  \
 163    :      F(WINAPI, BOOL, HeapUnlock, (HANDLE heap), (heap))  \
 164    :      F(WINAPI, BOOL, HeapWalk,  \
 165    :        (HANDLE heap, LPPROCESS_HEAP_ENTRY entry), (heap, entry))  \
 166    :      F(WINAPI, BOOL, HeapSetInformation,  \
 167    :        (HANDLE heap, HEAP_INFORMATION_CLASS info_class,  \
 168    :         PVOID info, SIZE_T info_length),  \
 169    :        (heap, info_class, info, info_length))  \
 170    :      F(WINAPI, BOOL, HeapQueryInformation,  \
 171    :        (HANDLE heap, HEAP_INFORMATION_CLASS info_class,  \
 172    :         PVOID info, SIZE_T info_length, PSIZE_T return_length),  \
 173    :        (heap, info_class, info, info_length, return_length))  \
 174    :      F(WINAPI, void, SetCallBack,  \
 175    :        (void (*callback)(AsanErrorInfo* error_info)),  \
 176    :        (callback))  \
 177    :      F(_cdecl, void*, memcpy,  \
 178    :        (void* destination, const void* source,  size_t num),  \
 179    :        (destination, source, num))  \
 180    :      F(_cdecl, void*, memmove,  \
 181    :        (void* destination, const void* source, size_t num),  \
 182    :        (destination, source, num))  \
 183    :      F(_cdecl, void*, memset, (void* ptr, int value, size_t num),  \
 184    :        (ptr, value, num))  \
 185    :      F(_cdecl, const void*, memchr, (const void* ptr, int value, size_t num),  \
 186    :        (ptr, value, num))  \
 187    :      F(_cdecl, size_t, strcspn, (const char* str1, const char* str2),  \
 188    :        (str1, str2))  \
 189    :      F(_cdecl, size_t, strlen, (const char* str), (str))  \
 190    :      F(_cdecl, const char*, strrchr, (const char* str, int character),  \
 191    :        (str, character))  \
 192    :      F(_cdecl, const wchar_t*, wcsrchr, (const wchar_t* str, int character),  \
 193    :        (str, character))  \
 194    :      F(_cdecl, const wchar_t*, wcschr, (const wchar_t* str, int character),  \
 195    :        (str, character))  \
 196    :      F(_cdecl, int, strcmp, (const char* str1, const char* str2),  \
 197    :        (str1, str2))  \
 198    :      F(_cdecl, const char*, strpbrk, (const char* str1, const char* str2),  \
 199    :        (str1, str2))  \
 200    :      F(_cdecl, const char*, strstr, (const char* str1, const char* str2),  \
 201    :        (str1, str2))  \
 202    :      F(_cdecl, const wchar_t*, wcsstr, (const wchar_t* str1,  \
 203    :        const wchar_t* str2), (str1, str2))  \
 204    :      F(_cdecl, size_t, strspn, (const char* str1, const char* str2),  \
 205    :        (str1, str2))  \
 206    :      F(_cdecl, char*, strncpy,  \
 207    :        (char* destination, const char* source, size_t num),  \
 208    :        (destination, source, num))  \
 209    :      F(_cdecl, char*, strncat,  \
 210    :        (char* destination, const char* source, size_t num),  \
 211    :        (destination, source, num))  \
 212    :      F(WINAPI, BOOL, ReadFile,  \
 213    :        (HANDLE file_handle, LPVOID buffer, DWORD bytes_to_read,  \
 214    :         LPDWORD bytes_read, LPOVERLAPPED overlapped),  \
 215    :        (file_handle, buffer, bytes_to_read, bytes_read, overlapped))  \
 216    :      F(WINAPI, BOOL, WriteFile,  \
 217    :        (HANDLE file_handle, LPCVOID buffer, DWORD bytes_to_write,  \
 218    :         LPDWORD bytes_written, LPOVERLAPPED overlapped),  \
 219    :        (file_handle, buffer, bytes_to_write, bytes_written, overlapped))  \
 220    :      F(_cdecl, void, SetInterceptorCallback, (void (*callback)()), (callback))  \
 221    :      F(WINAPI, agent::asan::AsanRuntime*, GetActiveRuntime, (), ())  \
 222    :      F(WINAPI, void, SetAllocationFilterFlag, (), ())  \
 223    :      F(WINAPI, void, ClearAllocationFilterFlag, (), ())
 224    :  
 225    :  // Declare pointer types for the intercepted functions.
 226    :  #define DECLARE_ASAN_FUNCTION_PTR(convention, ret, name, args, argnames) \
 227    :    typedef ret (convention* name##FunctionPtr)args;
 228    :  ASAN_RTL_FUNCTIONS(DECLARE_ASAN_FUNCTION_PTR)
 229    :  #undef DECLARE_ASAN_FUNCTION_PTR
 230    :  
 231    :  class TestAsanRtl : public testing::TestWithAsanLogger {
 232    :   public:
 233  E :    TestAsanRtl() : asan_rtl_(NULL), heap_(NULL) {
 234  E :    }
 235    :  
 236  E :    void SetUp() override {
 237  E :      testing::TestWithAsanLogger::SetUp();
 238    :  
 239    :      // Load the Asan runtime library.
 240    :      base::FilePath asan_rtl_path =
 241  E :          testing::GetExeRelativePath(L"syzyasan_rtl.dll");
 242  E :      asan_rtl_ = ::LoadLibrary(asan_rtl_path.value().c_str());
 243  E :      ASSERT_TRUE(asan_rtl_ != NULL);
 244    :  
 245    :      // Load all the functions and assert that we find them.
 246    :  #define LOAD_ASAN_FUNCTION(convention, ret, name, args, argnames)  \
 247    :      name##Function = reinterpret_cast<name##FunctionPtr>(  \
 248    :          ::GetProcAddress(asan_rtl_, "asan_" #name));  \
 249    :      ASSERT_TRUE(name##Function != NULL);
 250    :  
 251  E :      ASAN_RTL_FUNCTIONS(LOAD_ASAN_FUNCTION)
 252    :  
 253    :  #undef LOAD_ASAN_FUNCTION
 254    :  
 255  E :      heap_ = HeapCreateFunction(0, 0, 0);
 256  E :      ASSERT_TRUE(heap_ != NULL);
 257    :  
 258  E :      agent::asan::AsanRuntime* runtime = GetActiveRuntimeFunction();
 259  E :      ASSERT_NE(reinterpret_cast<agent::asan::AsanRuntime*>(NULL), runtime);
 260    :      // Disable the heap checking as this really slows down the unittests.
 261  E :      runtime->params().check_heap_on_failure = false;
 262  E :    }
 263    :  
 264  E :    void TearDown() override {
 265  E :      if (heap_ != NULL) {
 266  E :        HeapDestroyFunction(heap_);
 267  E :        heap_ = NULL;
 268    :      }
 269    :  
 270  E :      if (asan_rtl_ != NULL) {
 271  E :        ::FreeLibrary(asan_rtl_);
 272  E :        asan_rtl_ = NULL;
 273    :      }
 274    :  
 275  E :      testing::TestWithAsanLogger::TearDown();
 276  E :    }
 277    :  
 278  E :    HANDLE heap() { return heap_; }
 279    :  
 280    :    // Declare pointers to intercepted functions.
 281    :  #define DECLARE_FUNCTION_PTR_VARIABLE(convention, ret, name, args, argnames)  \
 282    :      static name##FunctionPtr name##Function;
 283    :    ASAN_RTL_FUNCTIONS(DECLARE_FUNCTION_PTR_VARIABLE)
 284    :  #undef DECLARE_FUNCTION_PTR_VARIABLE
 285    :  
 286    :    // Define versions of all of the functions that expect an error to be thrown
 287    :    // by the AsanErrorCallback, and in turn raise an exception if the underlying
 288    :    // function didn't fail.
 289    :  #define DECLARE_FAILING_FUNCTION(convention, ret, name, args, argnames)  \
 290    :      static void name##FunctionFailing args;
 291    :    ASAN_RTL_FUNCTIONS(DECLARE_FAILING_FUNCTION)
 292    :  #undef DECLARE_FAILING_FUNCTION
 293    :  
 294    :   protected:
 295    :    // The AsanAsan runtime module to test.
 296    :    HMODULE asan_rtl_;
 297    :  
 298    :    // Scratch heap handle valid from SetUp to TearDown.
 299    :    HANDLE heap_;
 300    :  };
 301    :  
 302    :  // A helper struct to be passed as a destructor of Asan scoped allocation.
 303    :  struct AsanDeleteHelper {
 304  E :    explicit AsanDeleteHelper(TestAsanRtl* asan_rtl)
 305    :        : asan_rtl_(asan_rtl) {
 306  E :    }
 307    :  
 308  E :    void operator()(void* ptr) {
 309  E :      asan_rtl_->HeapFreeFunction(asan_rtl_->heap(), 0, ptr);
 310  E :    }
 311    :    TestAsanRtl* asan_rtl_;
 312    :  };
 313    :  
 314    :  // A scoped_ptr specialization for the Asan allocations.
 315    :  template <typename T>
 316    :  class ScopedAsanAlloc : public scoped_ptr<T, AsanDeleteHelper> {
 317    :   public:
 318    :    explicit ScopedAsanAlloc(TestAsanRtl* asan_rtl)
 319    :        : scoped_ptr(NULL, AsanDeleteHelper(asan_rtl)) {
 320    :    }
 321    :  
 322  E :    ScopedAsanAlloc(TestAsanRtl* asan_rtl, size_t size)
 323    :        : scoped_ptr(NULL, AsanDeleteHelper(asan_rtl)) {
 324  E :      Allocate(asan_rtl, size);
 325  E :    }
 326    :  
 327  E :    ScopedAsanAlloc(TestAsanRtl* asan_rtl, size_t size, const T* value)
 328    :        : scoped_ptr(NULL, AsanDeleteHelper(asan_rtl)) {
 329  E :      Allocate(asan_rtl, size);
 330  E :      ::memcpy(get(), value, size * sizeof(T));
 331  E :    }
 332    :  
 333    :    template <typename T2>
 334  E :    T2* GetAs() {
 335  E :      return reinterpret_cast<T2*>(get());
 336  E :    }
 337    :  
 338  E :    void Allocate(TestAsanRtl* asan_rtl, size_t size) {
 339  E :      ASSERT_TRUE(asan_rtl != NULL);
 340    :      reset(reinterpret_cast<T*>(
 341  E :          asan_rtl->HeapAllocFunction(asan_rtl->heap(), 0, size * sizeof(T))));
 342  E :      ::memset(get(), 0, size * sizeof(T));
 343  E :    }
 344    :  
 345    :    T operator[](int i) const {
 346    :      CHECK(get() != NULL);
 347    :      return get()[i];
 348    :    }
 349    :  
 350  E :    T& operator[](int i) {
 351  E :      CHECK(get() != NULL);
 352  E :      return get()[i];
 353  E :    }
 354    :  };
 355    :  
 356    :  // A unittest fixture that initializes an Asan runtime instance.
 357    :  class TestWithAsanRuntime : public OnExceptionCallbackTest {
 358    :   public:
 359  E :    TestWithAsanRuntime() {
 360  E :      runtime_ = new agent::asan::AsanRuntime();
 361  E :      owns_runtime_ = true;
 362  E :    }
 363    :  
 364  E :    explicit TestWithAsanRuntime(agent::asan::AsanRuntime* runtime)
 365    :        : runtime_(runtime), owns_runtime_(false) {
 366  E :      CHECK_NE(reinterpret_cast<agent::asan::AsanRuntime*>(NULL), runtime_);
 367  E :    }
 368    :  
 369  E :    ~TestWithAsanRuntime() {
 370  E :      CHECK_NE(reinterpret_cast<agent::asan::AsanRuntime*>(NULL), runtime_);
 371  E :      if (owns_runtime_)
 372  E :        delete runtime_;
 373  E :      runtime_ = NULL;
 374  E :    }
 375    :  
 376  E :    virtual void SetUp() override {
 377  E :      CHECK_NE(reinterpret_cast<agent::asan::AsanRuntime*>(NULL), runtime_);
 378  E :      testing::Test::SetUp();
 379  E :      runtime_->SetUp(L"");
 380  E :    }
 381    :  
 382  E :    virtual void TearDown() override {
 383  E :      CHECK_NE(reinterpret_cast<agent::asan::AsanRuntime*>(NULL), runtime_);
 384  E :      runtime_->TearDown();
 385  E :      testing::Test::TearDown();
 386  E :    }
 387    :  
 388    :   protected:
 389    :    // The runtime instance used by the tests.
 390    :    agent::asan::AsanRuntime* runtime_;
 391    :  
 392    :    // Indicates if we own the runtime instance.
 393    :    bool owns_runtime_;
 394    :  };
 395    :  
 396    :  // A unittest fixture to test the bookkeeping functions.
 397    :  struct FakeAsanBlock {
 398    :    static const size_t kMaxAlignmentLog = 13;
 399    :    static const size_t kMaxAlignment = 1 << kMaxAlignmentLog;
 400    :    // If we want to test the alignments up to 4096 we need a buffer of at least
 401    :    // 3 * 4096 bytes:
 402    :    // +--- 0 <= size < 4096 bytes---+---4096 bytes---+--4096 bytes--+
 403    :    // ^buffer                       ^aligned_buffer  ^user_pointer
 404    :    static const size_t kBufferSize = 3 * kMaxAlignment;
 405    :    static const uint8 kBufferHeaderValue = 0xAE;
 406    :    static const uint8 kBufferTrailerValue = 0xEA;
 407    :  
 408    :    FakeAsanBlock(Shadow* shadow,
 409    :                  size_t alloc_alignment_log,
 410    :                  StackCaptureCache* stack_cache);
 411    :  
 412    :    ~FakeAsanBlock();
 413    :  
 414    :    // Initialize an Asan block in the buffer.
 415    :    // @param alloc_size The user size of the Asan block.
 416    :    // @returns true on success, false otherwise.
 417    :    bool InitializeBlock(size_t alloc_size);
 418    :  
 419    :    // Ensures that this block has a valid block header.
 420    :    bool TestBlockMetadata();
 421    :  
 422    :    // Mark the current Asan block as quarantined.
 423    :    bool MarkBlockAsQuarantinedImpl(bool flood_filled);
 424    :  
 425    :    // Mark the current Asan block as quarantined.
 426    :    bool MarkBlockAsQuarantined();
 427    :  
 428    :    // Mark the current Asan block as quarantined and flooded.
 429    :    bool MarkBlockAsQuarantinedFlooded();
 430    :  
 431    :    // The buffer we use internally.
 432    :    uint8 buffer[kBufferSize];
 433    :  
 434    :    // The information about the block once it has been initialized.
 435    :    agent::asan::BlockInfo block_info;
 436    :  
 437    :    // The alignment of the current allocation.
 438    :    size_t alloc_alignment;
 439    :    size_t alloc_alignment_log;
 440    :  
 441    :    // The sizes of the different sub-structures in the buffer.
 442    :    size_t buffer_header_size;
 443    :    size_t buffer_trailer_size;
 444    :  
 445    :    // The pointers to the different sub-structures in the buffer.
 446    :    uint8* buffer_align_begin;
 447    :  
 448    :    // Indicate if the buffer has been initialized.
 449    :    bool is_initialized;
 450    :  
 451    :    // The shadow memory that will be modified.
 452    :    Shadow* shadow_;
 453    :  
 454    :    // The cache that will store the stack traces of this block.
 455    :    StackCaptureCache* stack_cache;
 456    :  };
 457    :  
 458    :  // A mock memory notifier. Useful when testing objects that have a memory
 459    :  // notifier dependency.
 460    :  class MockMemoryNotifier : public agent::asan::MemoryNotifierInterface {
 461    :   public:
 462    :    // Constructor.
 463  E :    MockMemoryNotifier() { }
 464    :  
 465    :    // Virtual destructor.
 466  E :    virtual ~MockMemoryNotifier() { }
 467    :  
 468    :    // @name MemoryNotifierInterface implementation.
 469    :    // @{
 470  E :    MOCK_METHOD2(NotifyInternalUse, void(const void*, size_t));
 471  E :    MOCK_METHOD2(NotifyFutureHeapUse, void(const void*, size_t));
 472  E :    MOCK_METHOD2(NotifyReturnedToOS, void(const void*, size_t));
 473    :    // @}
 474    :  
 475    :   private:
 476    :    DISALLOW_COPY_AND_ASSIGN(MockMemoryNotifier);
 477    :  };
 478    :  
 479    :  // A mock HeapInterface.
 480    :  class LenientMockHeap : public agent::asan::HeapInterface {
 481    :   public:
 482  E :    LenientMockHeap() { }
 483  E :    virtual ~LenientMockHeap() { }
 484  i :    MOCK_CONST_METHOD0(GetHeapType, agent::asan::HeapType());
 485  E :    MOCK_CONST_METHOD0(GetHeapFeatures, uint32());
 486  E :    MOCK_METHOD1(Allocate, void*(size_t));
 487  E :    MOCK_METHOD1(Free, bool(void*));
 488  i :    MOCK_METHOD1(IsAllocated, bool(const void*));
 489  i :    MOCK_METHOD1(GetAllocationSize, size_t(const void*));
 490  i :    MOCK_METHOD0(Lock, void());
 491  i :    MOCK_METHOD0(Unlock, void());
 492  i :    MOCK_METHOD0(TryLock, bool());
 493    :  };
 494    :  typedef testing::StrictMock<LenientMockHeap> MockHeap;
 495    :  
 496    :  typedef std::vector<agent::asan::AsanBlockInfo> AsanBlockInfoVector;
 497    :  typedef std::pair<agent::asan::AsanCorruptBlockRange, AsanBlockInfoVector>
 498    :      CorruptRangeInfo;
 499    :  typedef std::vector<CorruptRangeInfo> CorruptRangeVector;
 500    :  
 501    :  // A helper for testing SyzyAsan memory accessor instrumentation functions.
 502    :  class MemoryAccessorTester {
 503    :   public:
 504    :    typedef agent::asan::BadAccessKind BadAccessKind;
 505    :  
 506    :    enum IgnoreFlags {
 507    :      IGNORE_FLAGS
 508    :    };
 509    :    MemoryAccessorTester();
 510    :    explicit MemoryAccessorTester(IgnoreFlags ignore_flags);
 511    :    ~MemoryAccessorTester();
 512    :  
 513    :    // Checks that @p access_fn doesn't raise exceptions on access checking
 514    :    // @p ptr, and that @p access_fn doesn't modify any registers or flags
 515    :    // when executed.
 516    :    void CheckAccessAndCompareContexts(FARPROC access_fn, void* ptr);
 517    :  
 518    :    // Checks that @p access_fn generates @p bad_access_type on checking @p ptr.
 519    :    void AssertMemoryErrorIsDetected(
 520    :        FARPROC access_fn, void* ptr, BadAccessKind bad_access_type);
 521    :  
 522    :    enum StringOperationDirection {
 523    :      DIRECTION_FORWARD,
 524    :      DIRECTION_BACKWARD
 525    :    };
 526    :    // Checks that @p access_fn doesn't raise exceptions on access checking
 527    :    // for a given @p direction, @p src, @p dst and @p len.
 528    :    void CheckSpecialAccessAndCompareContexts(
 529    :        FARPROC access_fn, StringOperationDirection direction,
 530    :        void* dst, void* src, int len);
 531    :  
 532    :    // Checks that @p access_fn generates @p bad_access_type on access checking
 533    :    // for a given @p direction, @p src, @p dst and @p len.
 534    :    void ExpectSpecialMemoryErrorIsDetected(
 535    :        FARPROC access_fn, StringOperationDirection direction,
 536    :        bool expect_error, void* dst, void* src, int32 length,
 537    :        BadAccessKind bad_access_type);
 538    :  
 539    :    static void AsanErrorCallback(AsanErrorInfo* error_info);
 540    :  
 541  E :    void set_expected_error_type(BadAccessKind expected) {
 542  E :      expected_error_type_ = expected;
 543  E :    }
 544  E :    bool memory_error_detected() const { return memory_error_detected_; }
 545  E :    void set_memory_error_detected(bool memory_error_detected) {
 546  E :      memory_error_detected_ = memory_error_detected;
 547  E :    }
 548    :  
 549  E :    const AsanErrorInfo& last_error_info() const { return last_error_info_; }
 550  E :    const CorruptRangeVector& last_corrupt_ranges() const {
 551  E :      return last_corrupt_ranges_;
 552  E :    }
 553    :  
 554    :   private:
 555    :    void Initialize();
 556    :    void AsanErrorCallbackImpl(AsanErrorInfo* error_info);
 557    :  
 558    :    // This will be used in the asan callback to ensure that we detect the right
 559    :    // error.
 560    :    BadAccessKind expected_error_type_;
 561    :    // A flag used in asan callback to ensure that a memory error has been
 562    :    // detected.
 563    :    bool memory_error_detected_;
 564    :  
 565    :    // Indicates whether to ignore changes to the flags register.
 566    :    bool ignore_flags_;
 567    :  
 568    :    // The pre- and post-invocation contexts.
 569    :    CONTEXT context_before_hook_;
 570    :    CONTEXT context_after_hook_;
 571    :    // Context captured on error.
 572    :    CONTEXT error_context_;
 573    :  
 574    :    // The information about the last error.
 575    :    AsanErrorInfo last_error_info_;
 576    :    CorruptRangeVector last_corrupt_ranges_;
 577    :  
 578    :    // There shall be only one!
 579    :    static MemoryAccessorTester* instance_;
 580    :  };
 581    :  
 582    :  // A fixture class for testing memory interceptors.
 583    :  class TestMemoryInterceptors : public TestWithAsanLogger {
 584    :   public:
 585    :    // Redefine some enums for local use.
 586    :    enum AccessMode {
 587    :      AsanReadAccess = agent::asan::ASAN_READ_ACCESS,
 588    :      AsanWriteAccess = agent::asan::ASAN_WRITE_ACCESS,
 589    :      AsanUnknownAccess = agent::asan::ASAN_UNKNOWN_ACCESS,
 590    :    };
 591    :  
 592    :    struct InterceptFunction {
 593    :      void(*function)();
 594    :      size_t size;
 595    :    };
 596    :  
 597    :    struct StringInterceptFunction {
 598    :      void(*function)();
 599    :      size_t size;
 600    :      AccessMode dst_access_mode;
 601    :      AccessMode src_access_mode;
 602    :      bool uses_counter;
 603    :    };
 604    :  
 605    :    static const bool kCounterInit_ecx = true;
 606    :    static const bool kCounterInit_1 = false;
 607    :  
 608    :    TestMemoryInterceptors();
 609    :    void SetUp() override;
 610    :    void TearDown() override;
 611    :  
 612    :    template <size_t N>
 613  E :    void TestValidAccess(const InterceptFunction (&fns)[N]) {
 614  E :      TestValidAccess(fns, N);
 615  E :    }
 616    :    template <size_t N>
 617  E :    void TestValidAccessIgnoreFlags(const InterceptFunction (&fns)[N]) {
 618  E :      TestValidAccessIgnoreFlags(fns, N);
 619  E :    }
 620    :    template <size_t N>
 621  E :    void TestOverrunAccess(const InterceptFunction (&fns)[N]) {
 622  E :      TestOverrunAccess(fns, N);
 623  E :    }
 624    :    template <size_t N>
 625  E :    void TestOverrunAccessIgnoreFlags(const InterceptFunction (&fns)[N]) {
 626  E :      TestOverrunAccessIgnoreFlags(fns, N);
 627  E :    }
 628    :    template <size_t N>
 629  E :    void TestUnderrunAccess(const InterceptFunction (&fns)[N]) {
 630  E :      TestUnderrunAccess(fns, N);
 631  E :    }
 632    :    template <size_t N>
 633  E :    void TestUnderrunAccessIgnoreFlags(const InterceptFunction (&fns)[N]) {
 634  E :      TestUnderrunAccessIgnoreFlags(fns, N);
 635  E :    }
 636    :    template <size_t N>
 637  E :    void TestStringValidAccess(const StringInterceptFunction (&fns)[N]) {
 638  E :      TestStringValidAccess(fns, N);
 639  E :    }
 640    :    template <size_t N>
 641  E :    void TestStringOverrunAccess(const StringInterceptFunction (&fns)[N]) {
 642  E :      TestStringOverrunAccess(fns, N);
 643  E :    }
 644    :  
 645    :   protected:
 646    :    void TestValidAccess(const InterceptFunction* fns, size_t num_fns);
 647    :    void TestValidAccessIgnoreFlags(const InterceptFunction* fns,
 648    :                                    size_t num_fns);
 649    :    void TestOverrunAccess(const InterceptFunction* fns, size_t num_fns);
 650    :    void TestOverrunAccessIgnoreFlags(const InterceptFunction* fns,
 651    :                                      size_t num_fns);
 652    :    void TestUnderrunAccess(const InterceptFunction* fns, size_t num_fns);
 653    :    void TestUnderrunAccessIgnoreFlags(const InterceptFunction* fns,
 654    :                                       size_t num_fns);
 655    :    void TestStringValidAccess(
 656    :        const StringInterceptFunction* fns, size_t num_fns);
 657    :    void TestStringOverrunAccess(
 658    :        const StringInterceptFunction* fns, size_t num_fns);
 659    :  
 660    :    const size_t kAllocSize = 64;
 661    :  
 662    :    agent::asan::AsanRuntime asan_runtime_;
 663    :    HANDLE heap_;
 664    :  
 665    :    // Convenience allocs of kAllocSize. Valid from SetUp to TearDown.
 666    :    byte* src_;
 667    :    byte* dst_;
 668    :  };
 669    :  
 670    :  // A very lightweight dummy heap to be used in stress testing the
 671    :  // HeapAllocator. Lock and Unlock are noops, so this is not thread
 672    :  // safe.
 673    :  class DummyHeap : public agent::asan::HeapInterface {
 674    :   public:
 675  E :    virtual ~DummyHeap() { }
 676  i :    virtual agent::asan::HeapType GetHeapType() const {
 677  i :      return agent::asan::kUnknownHeapType;
 678  i :    }
 679  E :    virtual uint32 GetHeapFeatures() const { return 0; }
 680  E :    virtual void* Allocate(size_t bytes) { return ::malloc(bytes); }
 681  E :    virtual bool Free(void* alloc) { ::free(alloc); return true; }
 682  i :    virtual bool IsAllocated(const void* alloc) { return false; }
 683  i :    virtual size_t GetAllocationSize(const void* alloc) { return 0; }
 684  E :    virtual void Lock() { return; }
 685  E :    virtual void Unlock() { return; }
 686  E :    virtual bool TryLock() { return true; }
 687    :  };
 688    :  
 689    :  // Test read and write access.
 690    :  // Use carefully, since it will try to overwrite the value at @p address with 0.
 691    :  // @returns true if the address is readable and writable, false otherwise.
 692    :  bool IsAccessible(void* address);
 693    :  
 694    :  // Test read and write access.
 695    :  // Use carefully, since it will try to overwrite the value at @p address with 0.
 696    :  // @returns true if the address is neither readable nor writable,
 697    :  //     false otherwise.
 698    :  bool IsNotAccessible(void* address);
 699    :  
 700    :  // A scoped block access helper. Removes block protections when created via
 701    :  // BlockProtectNone, and restores them via BlockProtectAuto.
 702    :  // TODO(chrisha): Consider recording the fact the block protections on this
 703    :  //     block are being blocked in some synchronous manner. This will prevent
 704    :  //     the page protections from being added during the lifetime of this
 705    :  //     object.
 706    :  class ScopedBlockAccess {
 707    :   public:
 708    :    // Constructor. Unprotects the provided block.
 709    :    // @param block_info The block whose protections are to be modified.
 710    :    // @parma shadow The shadow memory to be updated.
 711  E :    explicit ScopedBlockAccess(const agent::asan::BlockInfo& block_info,
 712    :                               Shadow* shadow)
 713    :        : block_info_(block_info), shadow_(shadow) {
 714  E :      BlockProtectNone(block_info_, shadow_);
 715  E :    }
 716    :  
 717    :    // Destructor. Restores protections on the provided block.
 718  E :    ~ScopedBlockAccess() { BlockProtectAuto(block_info_, shadow_); }
 719    :  
 720    :   private:
 721    :    const agent::asan::BlockInfo& block_info_;
 722    :    Shadow* shadow_;
 723    :  };
 724    :  
 725    :  // A debugging shadow class. This keeps extra details in the form of an address
 726    :  // space with stack traces. This makes it much easier to track down
 727    :  // inconsistencies in the shadow memory.
 728    :  class DebugShadow : public Shadow {
 729    :   public:
 730    :    using ShadowMarker = agent::asan::ShadowMarker;
 731    :  
 732    :    DebugShadow() : Shadow() {
 733    :    }
 734    :  
 735    :    explicit DebugShadow(size_t length)
 736    :        : Shadow(length) {
 737    :    }
 738    :  
 739    :    ~DebugShadow() override {
 740    :      // If the shadow has been properly used it will be completely empty by the
 741    :      // time it is torn down.
 742    :      CHECK(shadow_address_space_.empty());
 743    :    }
 744    :  
 745    :   protected:
 746    :    // @name Shadow implementation.
 747    :    // @{
 748    :    void SetShadowMemory(
 749    :        const void* address, size_t length, ShadowMarker marker) override;
 750    :    void GetPointerAndSizeImpl(void const** self, size_t* size) const override;
 751    :    // @}
 752    :  
 753    :   private:
 754    :    using StackCapture = agent::common::StackCapture;
 755    :  
 756    :    // Holds details about a given range of shadow memory. Persists the
 757    :    // original size of a region, even if it is subsequently fragmented.
 758    :    struct Metadata {
 759    :      const void* address;
 760    :      size_t size;
 761    :      ShadowMarker marker;
 762    :      StackCapture stack_capture;
 763    :  
 764    :      // Explicitly enable copy and assignment.
 765    :      Metadata();
 766    :      Metadata(const void* address, size_t size, ShadowMarker marker);
 767    :      Metadata(const Metadata& rhs);
 768    :      Metadata& operator=(const Metadata& rhs);
 769    :    };
 770    :    using ShadowAddressSpace =
 771    :        core::AddressSpace<uintptr_t, size_t, Metadata>;
 772    :    using Range = ShadowAddressSpace::Range;
 773    :  
 774    :    // Ensure that the given range has been cleared from the address-space,
 775    :    // readying it for a subsequent insertion.
 776    :    void ClearIntersection(const void* addr, size_t size);
 777    :  
 778    :    // An alternative view of shadow memory. Accessible regions are not
 779    :    // displayed. Neighboring regions of the same type are merged.
 780    :    ShadowAddressSpace shadow_address_space_;
 781    :  };
 782    :  
 783    :  }  // namespace testing
 784    :  
 785    :  #endif  // SYZYGY_AGENT_ASAN_UNITTEST_UTIL_H_

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