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

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
92.7%1401510.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  E :      agent::asan::SetOnExceptionCallback(
  66    :          base::Bind(&LenientOnExceptionCallbackTest::OnExceptionCallback,
  67    :                     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, size_t, strnlen, (const char* str, size_t max_len),  \
 191    :        (str, max_len))  \
 192    :      F(_cdecl, const char*, strrchr, (const char* str, int character),  \
 193    :        (str, character))  \
 194    :      F(_cdecl, const wchar_t*, wcsrchr, (const wchar_t* str, int character),  \
 195    :        (str, character))  \
 196    :      F(_cdecl, const wchar_t*, wcschr, (const wchar_t* str, int character),  \
 197    :        (str, character))  \
 198    :      F(_cdecl, int, strcmp, (const char* str1, const char* str2),  \
 199    :        (str1, str2))  \
 200    :      F(_cdecl, const char*, strpbrk, (const char* str1, const char* str2),  \
 201    :        (str1, str2))  \
 202    :      F(_cdecl, const char*, strstr, (const char* str1, const char* str2),  \
 203    :        (str1, str2))  \
 204    :      F(_cdecl, size_t, wcsnlen, (const wchar_t* str, size_t max_len),  \
 205    :        (str, max_len))  \
 206    :      F(_cdecl, const wchar_t*, wcsstr, (const wchar_t* str1,  \
 207    :        const wchar_t* str2), (str1, str2))  \
 208    :      F(_cdecl, size_t, strspn, (const char* str1, const char* str2),  \
 209    :        (str1, str2))  \
 210    :      F(_cdecl, char*, strncpy,  \
 211    :        (char* destination, const char* source, size_t num),  \
 212    :        (destination, source, num))  \
 213    :      F(_cdecl, char*, strncat,  \
 214    :        (char* destination, const char* source, size_t num),  \
 215    :        (destination, source, num))  \
 216    :      F(WINAPI, BOOL, ReadFile,  \
 217    :        (HANDLE file_handle, LPVOID buffer, DWORD bytes_to_read,  \
 218    :         LPDWORD bytes_read, LPOVERLAPPED overlapped),  \
 219    :        (file_handle, buffer, bytes_to_read, bytes_read, overlapped))  \
 220    :      F(WINAPI, BOOL, WriteFile,  \
 221    :        (HANDLE file_handle, LPCVOID buffer, DWORD bytes_to_write,  \
 222    :         LPDWORD bytes_written, LPOVERLAPPED overlapped),  \
 223    :        (file_handle, buffer, bytes_to_write, bytes_written, overlapped))  \
 224    :      F(_cdecl, void, SetInterceptorCallback, (void (*callback)()), (callback))  \
 225    :      F(WINAPI, agent::asan::AsanRuntime*, GetActiveRuntime, (), ())  \
 226    :      F(WINAPI, void, SetAllocationFilterFlag, (), ())  \
 227    :      F(WINAPI, void, ClearAllocationFilterFlag, (), ())
 228    :  
 229    :  // Declare pointer types for the intercepted functions.
 230    :  #define DECLARE_ASAN_FUNCTION_PTR(convention, ret, name, args, argnames) \
 231    :    typedef ret (convention* name##FunctionPtr)args;
 232    :  ASAN_RTL_FUNCTIONS(DECLARE_ASAN_FUNCTION_PTR)
 233    :  #undef DECLARE_ASAN_FUNCTION_PTR
 234    :  
 235    :  class TestAsanRtl : public testing::TestWithAsanLogger {
 236    :   public:
 237  E :    TestAsanRtl() : asan_rtl_(NULL), heap_(NULL) {
 238  E :    }
 239    :  
 240  E :    void SetUp() override {
 241  E :      testing::TestWithAsanLogger::SetUp();
 242    :  
 243    :      // Load the Asan runtime library.
 244    :      base::FilePath asan_rtl_path =
 245  E :          testing::GetExeRelativePath(L"syzyasan_rtl.dll");
 246  E :      asan_rtl_ = ::LoadLibrary(asan_rtl_path.value().c_str());
 247  E :      ASSERT_TRUE(asan_rtl_ != NULL);
 248    :  
 249    :      // Load all the functions and assert that we find them.
 250    :  #define LOAD_ASAN_FUNCTION(convention, ret, name, args, argnames)  \
 251    :      name##Function = reinterpret_cast<name##FunctionPtr>(  \
 252    :          ::GetProcAddress(asan_rtl_, "asan_" #name));  \
 253    :      ASSERT_TRUE(name##Function != NULL);
 254    :  
 255  E :      ASAN_RTL_FUNCTIONS(LOAD_ASAN_FUNCTION)
 256    :  
 257    :  #undef LOAD_ASAN_FUNCTION
 258    :  
 259  E :      heap_ = HeapCreateFunction(0, 0, 0);
 260  E :      ASSERT_TRUE(heap_ != NULL);
 261    :  
 262  E :      agent::asan::AsanRuntime* runtime = GetActiveRuntimeFunction();
 263  E :      ASSERT_NE(reinterpret_cast<agent::asan::AsanRuntime*>(NULL), runtime);
 264    :      // Disable the heap checking as this really slows down the unittests.
 265  E :      runtime->params().check_heap_on_failure = false;
 266  E :    }
 267    :  
 268  E :    void TearDown() override {
 269  E :      if (heap_ != NULL) {
 270  E :        HeapDestroyFunction(heap_);
 271  E :        heap_ = NULL;
 272    :      }
 273    :  
 274  E :      if (asan_rtl_ != NULL) {
 275  E :        ::FreeLibrary(asan_rtl_);
 276  E :        asan_rtl_ = NULL;
 277    :      }
 278    :  
 279  E :      testing::TestWithAsanLogger::TearDown();
 280  E :    }
 281    :  
 282  E :    HANDLE heap() { return heap_; }
 283    :  
 284    :    // Declare pointers to intercepted functions.
 285    :  #define DECLARE_FUNCTION_PTR_VARIABLE(convention, ret, name, args, argnames)  \
 286    :      static name##FunctionPtr name##Function;
 287    :    ASAN_RTL_FUNCTIONS(DECLARE_FUNCTION_PTR_VARIABLE)
 288    :  #undef DECLARE_FUNCTION_PTR_VARIABLE
 289    :  
 290    :    // Define versions of all of the functions that expect an error to be thrown
 291    :    // by the AsanErrorCallback, and in turn raise an exception if the underlying
 292    :    // function didn't fail.
 293    :  #define DECLARE_FAILING_FUNCTION(convention, ret, name, args, argnames)  \
 294    :      static void name##FunctionFailing args;
 295    :    ASAN_RTL_FUNCTIONS(DECLARE_FAILING_FUNCTION)
 296    :  #undef DECLARE_FAILING_FUNCTION
 297    :  
 298    :   protected:
 299    :    // The AsanAsan runtime module to test.
 300    :    HMODULE asan_rtl_;
 301    :  
 302    :    // Scratch heap handle valid from SetUp to TearDown.
 303    :    HANDLE heap_;
 304    :  };
 305    :  
 306    :  // A helper struct to be passed as a destructor of Asan scoped allocation.
 307    :  struct AsanDeleteHelper {
 308  E :    explicit AsanDeleteHelper(TestAsanRtl* asan_rtl)
 309  E :        : asan_rtl_(asan_rtl) {
 310  E :    }
 311    :  
 312  E :    void operator()(void* ptr) {
 313  E :      asan_rtl_->HeapFreeFunction(asan_rtl_->heap(), 0, ptr);
 314  E :    }
 315    :    TestAsanRtl* asan_rtl_;
 316    :  };
 317    :  
 318    :  // A std::unique_ptr specialization for the Asan allocations.
 319    :  template <typename T>
 320    :  class ScopedAsanAlloc : public std::unique_ptr<T, AsanDeleteHelper> {
 321    :   public:
 322    :    explicit ScopedAsanAlloc(TestAsanRtl* asan_rtl)
 323    :        : std::unique_ptr<T, AsanDeleteHelper>(NULL, AsanDeleteHelper(asan_rtl)) {
 324    :    }
 325    :  
 326    :    ScopedAsanAlloc(TestAsanRtl* asan_rtl, size_t size)
 327  E :        : std::unique_ptr<T, AsanDeleteHelper>(NULL, AsanDeleteHelper(asan_rtl)) {
 328  E :      Allocate(asan_rtl, size);
 329  E :    }
 330    :  
 331    :    ScopedAsanAlloc(TestAsanRtl* asan_rtl, size_t size, const T* value)
 332  E :        : std::unique_ptr<T, AsanDeleteHelper>(NULL, AsanDeleteHelper(asan_rtl)) {
 333  E :      Allocate(asan_rtl, size);
 334  E :      ::memcpy(get(), value, size * sizeof(T));
 335  E :    }
 336    :  
 337    :    template <typename T2>
 338  E :    T2* GetAs() {
 339  E :      return reinterpret_cast<T2*>(get());
 340  E :    }
 341    :  
 342  E :    void Allocate(TestAsanRtl* asan_rtl, size_t size) {
 343  E :      ASSERT_TRUE(asan_rtl != NULL);
 344  E :      reset(reinterpret_cast<T*>(
 345    :          asan_rtl->HeapAllocFunction(asan_rtl->heap(), 0, size * sizeof(T))));
 346  E :      ::memset(get(), 0, size * sizeof(T));
 347  E :    }
 348    :  
 349    :    T operator[](int i) const {
 350    :      CHECK(get() != NULL);
 351    :      return get()[i];
 352    :    }
 353    :  
 354  E :    T& operator[](int i) {
 355  E :      CHECK(get() != NULL);
 356  E :      return get()[i];
 357  E :    }
 358    :  };
 359    :  
 360    :  // A unittest fixture that initializes an Asan runtime instance.
 361    :  class TestWithAsanRuntime : public OnExceptionCallbackTest {
 362    :   public:
 363  E :    TestWithAsanRuntime() {
 364  E :      runtime_ = new agent::asan::AsanRuntime();
 365  E :      owns_runtime_ = true;
 366  E :    }
 367    :  
 368  E :    explicit TestWithAsanRuntime(agent::asan::AsanRuntime* runtime)
 369  E :        : runtime_(runtime), owns_runtime_(false) {
 370  E :      CHECK_NE(reinterpret_cast<agent::asan::AsanRuntime*>(NULL), runtime_);
 371  E :    }
 372    :  
 373  E :    ~TestWithAsanRuntime() {
 374  E :      CHECK_NE(reinterpret_cast<agent::asan::AsanRuntime*>(NULL), runtime_);
 375  E :      if (owns_runtime_)
 376  E :        delete runtime_;
 377  E :      runtime_ = NULL;
 378  E :    }
 379    :  
 380  E :    void SetUp() override {
 381  E :      CHECK_NE(reinterpret_cast<agent::asan::AsanRuntime*>(NULL), runtime_);
 382  E :      testing::Test::SetUp();
 383  E :      runtime_->SetUp(L"");
 384  E :    }
 385    :  
 386  E :    void TearDown() override {
 387  E :      CHECK_NE(reinterpret_cast<agent::asan::AsanRuntime*>(NULL), runtime_);
 388  E :      runtime_->TearDown();
 389  E :      testing::Test::TearDown();
 390  E :    }
 391    :  
 392    :   protected:
 393    :    // The runtime instance used by the tests.
 394    :    agent::asan::AsanRuntime* runtime_;
 395    :  
 396    :    // Indicates if we own the runtime instance.
 397    :    bool owns_runtime_;
 398    :  };
 399    :  
 400    :  // A unittest fixture to test the bookkeeping functions.
 401    :  struct FakeAsanBlock {
 402    :    static const size_t kMaxAlignmentLog = 13;
 403    :    static const size_t kMaxAlignment = 1 << kMaxAlignmentLog;
 404    :    // If we want to test the alignments up to 4096 we need a buffer of at least
 405    :    // 3 * 4096 bytes:
 406    :    // +--- 0 <= size < 4096 bytes---+---4096 bytes---+--4096 bytes--+
 407    :    // ^buffer                       ^aligned_buffer  ^user_pointer
 408    :    static const size_t kBufferSize = 3 * kMaxAlignment;
 409    :    static const uint8_t kBufferHeaderValue = 0xAE;
 410    :    static const uint8_t kBufferTrailerValue = 0xEA;
 411    :  
 412    :    FakeAsanBlock(Shadow* shadow,
 413    :                  size_t alloc_alignment_log,
 414    :                  StackCaptureCache* stack_cache);
 415    :  
 416    :    ~FakeAsanBlock();
 417    :  
 418    :    // Initialize an Asan block in the buffer.
 419    :    // @param alloc_size The user size of the Asan block.
 420    :    // @returns true on success, false otherwise.
 421    :    bool InitializeBlock(size_t alloc_size);
 422    :  
 423    :    // Ensures that this block has a valid block header.
 424    :    bool TestBlockMetadata();
 425    :  
 426    :    // Mark the current Asan block as quarantined.
 427    :    bool MarkBlockAsQuarantinedImpl(bool flood_filled);
 428    :  
 429    :    // Mark the current Asan block as quarantined.
 430    :    bool MarkBlockAsQuarantined();
 431    :  
 432    :    // Mark the current Asan block as quarantined and flooded.
 433    :    bool MarkBlockAsQuarantinedFlooded();
 434    :  
 435    :    // The buffer we use internally.
 436    :    uint8_t buffer[kBufferSize];
 437    :  
 438    :    // The information about the block once it has been initialized.
 439    :    agent::asan::BlockInfo block_info;
 440    :  
 441    :    // The alignment of the current allocation.
 442    :    size_t alloc_alignment;
 443    :    size_t alloc_alignment_log;
 444    :  
 445    :    // The sizes of the different sub-structures in the buffer.
 446    :    size_t buffer_header_size;
 447    :    size_t buffer_trailer_size;
 448    :  
 449    :    // The pointers to the different sub-structures in the buffer.
 450    :    uint8_t* buffer_align_begin;
 451    :  
 452    :    // Indicate if the buffer has been initialized.
 453    :    bool is_initialized;
 454    :  
 455    :    // The shadow memory that will be modified.
 456    :    Shadow* shadow_;
 457    :  
 458    :    // The cache that will store the stack traces of this block.
 459    :    StackCaptureCache* stack_cache;
 460    :  };
 461    :  
 462    :  // A mock memory notifier. Useful when testing objects that have a memory
 463    :  // notifier dependency.
 464    :  class MockMemoryNotifier : public agent::asan::MemoryNotifierInterface {
 465    :   public:
 466    :    // Constructor.
 467  E :    MockMemoryNotifier() { }
 468    :  
 469    :    // Virtual destructor.
 470  E :    virtual ~MockMemoryNotifier() { }
 471    :  
 472    :    // @name MemoryNotifierInterface implementation.
 473    :    // @{
 474  E :    MOCK_METHOD2(NotifyInternalUse, void(const void*, size_t));
 475  E :    MOCK_METHOD2(NotifyFutureHeapUse, void(const void*, size_t));
 476  E :    MOCK_METHOD2(NotifyReturnedToOS, void(const void*, size_t));
 477    :    // @}
 478    :  
 479    :   private:
 480    :    DISALLOW_COPY_AND_ASSIGN(MockMemoryNotifier);
 481    :  };
 482    :  
 483    :  // A mock HeapInterface.
 484    :  class LenientMockHeap : public agent::asan::HeapInterface {
 485    :   public:
 486  E :    LenientMockHeap() { }
 487  E :    virtual ~LenientMockHeap() { }
 488  i :    MOCK_CONST_METHOD0(GetHeapType, agent::asan::HeapType());
 489  E :    MOCK_CONST_METHOD0(GetHeapFeatures, uint32_t());
 490  E :    MOCK_METHOD1(Allocate, void*(size_t));
 491  E :    MOCK_METHOD1(Free, bool(void*));
 492  i :    MOCK_METHOD1(IsAllocated, bool(const void*));
 493  i :    MOCK_METHOD1(GetAllocationSize, size_t(const void*));
 494  i :    MOCK_METHOD0(Lock, void());
 495  i :    MOCK_METHOD0(Unlock, void());
 496  i :    MOCK_METHOD0(TryLock, bool());
 497    :  };
 498    :  typedef testing::StrictMock<LenientMockHeap> MockHeap;
 499    :  
 500    :  typedef std::vector<agent::asan::AsanBlockInfo> AsanBlockInfoVector;
 501    :  typedef std::pair<agent::asan::AsanCorruptBlockRange, AsanBlockInfoVector>
 502    :      CorruptRangeInfo;
 503    :  typedef std::vector<CorruptRangeInfo> CorruptRangeVector;
 504    :  
 505    :  // A helper for testing SyzyAsan memory accessor instrumentation functions.
 506    :  class MemoryAccessorTester {
 507    :   public:
 508    :    typedef agent::asan::BadAccessKind BadAccessKind;
 509    :  
 510    :    enum IgnoreFlags {
 511    :      IGNORE_FLAGS
 512    :    };
 513    :    MemoryAccessorTester();
 514    :    explicit MemoryAccessorTester(IgnoreFlags ignore_flags);
 515    :    ~MemoryAccessorTester();
 516    :  
 517    :    // Checks that @p access_fn doesn't raise exceptions on access checking
 518    :    // @p ptr, and that @p access_fn doesn't modify any registers or flags
 519    :    // when executed.
 520    :    void CheckAccessAndCompareContexts(FARPROC access_fn, void* ptr);
 521    :  
 522    :    // Checks that @p access_fn generates @p bad_access_type on checking @p ptr.
 523    :    void AssertMemoryErrorIsDetected(
 524    :        FARPROC access_fn, void* ptr, BadAccessKind bad_access_type);
 525    :  
 526    :    enum StringOperationDirection {
 527    :      DIRECTION_FORWARD,
 528    :      DIRECTION_BACKWARD
 529    :    };
 530    :    // Checks that @p access_fn doesn't raise exceptions on access checking
 531    :    // for a given @p direction, @p src, @p dst and @p len.
 532    :    void CheckSpecialAccessAndCompareContexts(
 533    :        FARPROC access_fn, StringOperationDirection direction,
 534    :        void* dst, void* src, int len);
 535    :  
 536    :    // Checks that @p access_fn generates @p bad_access_type on access checking
 537    :    // for a given @p direction, @p src, @p dst and @p len.
 538    :    void ExpectSpecialMemoryErrorIsDetected(FARPROC access_fn,
 539    :                                            StringOperationDirection direction,
 540    :                                            bool expect_error,
 541    :                                            void* dst,
 542    :                                            void* src,
 543    :                                            int32_t length,
 544    :                                            BadAccessKind bad_access_type);
 545    :  
 546    :    static void AsanErrorCallback(AsanErrorInfo* error_info);
 547    :  
 548  E :    void set_expected_error_type(BadAccessKind expected) {
 549  E :      expected_error_type_ = expected;
 550  E :    }
 551  E :    bool memory_error_detected() const { return memory_error_detected_; }
 552  E :    void set_memory_error_detected(bool memory_error_detected) {
 553  E :      memory_error_detected_ = memory_error_detected;
 554  E :    }
 555    :  
 556  E :    const AsanErrorInfo& last_error_info() const { return last_error_info_; }
 557  E :    const CorruptRangeVector& last_corrupt_ranges() const {
 558  E :      return last_corrupt_ranges_;
 559  E :    }
 560    :  
 561    :   private:
 562    :    void Initialize();
 563    :    void AsanErrorCallbackImpl(AsanErrorInfo* error_info);
 564    :  
 565    :    // This will be used in the asan callback to ensure that we detect the right
 566    :    // error.
 567    :    BadAccessKind expected_error_type_;
 568    :    // A flag used in asan callback to ensure that a memory error has been
 569    :    // detected.
 570    :    bool memory_error_detected_;
 571    :  
 572    :    // Indicates whether to ignore changes to the flags register.
 573    :    bool ignore_flags_;
 574    :  
 575    :    // The pre- and post-invocation contexts.
 576    :    CONTEXT context_before_hook_;
 577    :    CONTEXT context_after_hook_;
 578    :    // Context captured on error.
 579    :    CONTEXT error_context_;
 580    :  
 581    :    // The information about the last error.
 582    :    AsanErrorInfo last_error_info_;
 583    :    CorruptRangeVector last_corrupt_ranges_;
 584    :  
 585    :    // There shall be only one!
 586    :    static MemoryAccessorTester* instance_;
 587    :  };
 588    :  
 589    :  // A fixture class for testing memory interceptors.
 590    :  class TestMemoryInterceptors : public TestWithAsanLogger {
 591    :   public:
 592    :    // Redefine some enums for local use.
 593    :    enum AccessMode {
 594    :      AsanReadAccess = agent::asan::ASAN_READ_ACCESS,
 595    :      AsanWriteAccess = agent::asan::ASAN_WRITE_ACCESS,
 596    :      AsanUnknownAccess = agent::asan::ASAN_UNKNOWN_ACCESS,
 597    :    };
 598    :  
 599    :    struct InterceptFunction {
 600    :      void(*function)();
 601    :      size_t size;
 602    :    };
 603    :  
 604    :    struct StringInterceptFunction {
 605    :      void(*function)();
 606    :      size_t size;
 607    :      AccessMode dst_access_mode;
 608    :      AccessMode src_access_mode;
 609    :      bool uses_counter;
 610    :    };
 611    :  
 612    :    static const bool kCounterInit_ecx = true;
 613    :    static const bool kCounterInit_1 = false;
 614    :  
 615    :    TestMemoryInterceptors();
 616    :    void SetUp() override;
 617    :    void TearDown() override;
 618    :  
 619    :    template <size_t N>
 620  E :    void TestValidAccess(const InterceptFunction (&fns)[N]) {
 621  E :      TestValidAccess(fns, N);
 622  E :    }
 623    :    template <size_t N>
 624  E :    void TestValidAccessIgnoreFlags(const InterceptFunction (&fns)[N]) {
 625  E :      TestValidAccessIgnoreFlags(fns, N);
 626  E :    }
 627    :    template <size_t N>
 628  E :    void TestOverrunAccess(const InterceptFunction (&fns)[N]) {
 629  E :      TestOverrunAccess(fns, N);
 630  E :    }
 631    :    template <size_t N>
 632  E :    void TestOverrunAccessIgnoreFlags(const InterceptFunction (&fns)[N]) {
 633  E :      TestOverrunAccessIgnoreFlags(fns, N);
 634  E :    }
 635    :    template <size_t N>
 636  E :    void TestUnderrunAccess(const InterceptFunction (&fns)[N]) {
 637  E :      TestUnderrunAccess(fns, N);
 638  E :    }
 639    :    template <size_t N>
 640  E :    void TestUnderrunAccessIgnoreFlags(const InterceptFunction (&fns)[N]) {
 641  E :      TestUnderrunAccessIgnoreFlags(fns, N);
 642  E :    }
 643    :    template <size_t N>
 644  E :    void TestStringValidAccess(const StringInterceptFunction (&fns)[N]) {
 645  E :      TestStringValidAccess(fns, N);
 646  E :    }
 647    :    template <size_t N>
 648  E :    void TestStringOverrunAccess(const StringInterceptFunction (&fns)[N]) {
 649  E :      TestStringOverrunAccess(fns, N);
 650  E :    }
 651    :  
 652    :   protected:
 653    :    void TestValidAccess(const InterceptFunction* fns, size_t num_fns);
 654    :    void TestValidAccessIgnoreFlags(const InterceptFunction* fns,
 655    :                                    size_t num_fns);
 656    :    void TestOverrunAccess(const InterceptFunction* fns, size_t num_fns);
 657    :    void TestOverrunAccessIgnoreFlags(const InterceptFunction* fns,
 658    :                                      size_t num_fns);
 659    :    void TestUnderrunAccess(const InterceptFunction* fns, size_t num_fns);
 660    :    void TestUnderrunAccessIgnoreFlags(const InterceptFunction* fns,
 661    :                                       size_t num_fns);
 662    :    void TestStringValidAccess(
 663    :        const StringInterceptFunction* fns, size_t num_fns);
 664    :    void TestStringOverrunAccess(
 665    :        const StringInterceptFunction* fns, size_t num_fns);
 666    :  
 667  E :    const size_t kAllocSize = 64;
 668    :  
 669    :    agent::asan::AsanRuntime asan_runtime_;
 670    :    HANDLE heap_;
 671    :  
 672    :    // Convenience allocs of kAllocSize. Valid from SetUp to TearDown.
 673    :    byte* src_;
 674    :    byte* dst_;
 675    :  };
 676    :  
 677    :  // A very lightweight dummy heap to be used in stress testing the
 678    :  // HeapAllocator. Lock and Unlock are noops, so this is not thread
 679    :  // safe.
 680    :  class DummyHeap : public agent::asan::HeapInterface {
 681    :   public:
 682  E :    virtual ~DummyHeap() { }
 683  i :    virtual agent::asan::HeapType GetHeapType() const {
 684  i :      return agent::asan::kUnknownHeapType;
 685  i :    }
 686  E :    virtual uint32_t GetHeapFeatures() const { return 0; }
 687  E :    virtual void* Allocate(size_t bytes) { return ::malloc(bytes); }
 688  E :    virtual bool Free(void* alloc) { ::free(alloc); return true; }
 689  i :    virtual bool IsAllocated(const void* alloc) { return false; }
 690  i :    virtual size_t GetAllocationSize(const void* alloc) { return 0; }
 691  E :    virtual void Lock() { return; }
 692  E :    virtual void Unlock() { return; }
 693  E :    virtual bool TryLock() { return true; }
 694    :  };
 695    :  
 696    :  // Test read and write access.
 697    :  // Use carefully, since it will try to overwrite the value at @p address with 0.
 698    :  // @returns true if the address is readable and writable, false otherwise.
 699    :  bool IsAccessible(void* address);
 700    :  
 701    :  // Test read and write access.
 702    :  // Use carefully, since it will try to overwrite the value at @p address with 0.
 703    :  // @returns true if the address is neither readable nor writable,
 704    :  //     false otherwise.
 705    :  bool IsNotAccessible(void* address);
 706    :  
 707    :  // A scoped block access helper. Removes block protections when created via
 708    :  // BlockProtectNone, and restores them via BlockProtectAuto.
 709    :  // TODO(chrisha): Consider recording the fact the block protections on this
 710    :  //     block are being blocked in some synchronous manner. This will prevent
 711    :  //     the page protections from being added during the lifetime of this
 712    :  //     object.
 713    :  class ScopedBlockAccess {
 714    :   public:
 715    :    // Constructor. Unprotects the provided block.
 716    :    // @param block_info The block whose protections are to be modified.
 717    :    // @parma shadow The shadow memory to be updated.
 718  E :    explicit ScopedBlockAccess(const agent::asan::BlockInfo& block_info,
 719    :                               Shadow* shadow)
 720  E :        : block_info_(block_info), shadow_(shadow) {
 721  E :      BlockProtectNone(block_info_, shadow_);
 722  E :    }
 723    :  
 724    :    // Destructor. Restores protections on the provided block.
 725  E :    ~ScopedBlockAccess() { BlockProtectAuto(block_info_, shadow_); }
 726    :  
 727    :   private:
 728    :    const agent::asan::BlockInfo& block_info_;
 729    :    Shadow* shadow_;
 730    :  };
 731    :  
 732    :  // A debugging shadow class. This keeps extra details in the form of an address
 733    :  // space with stack traces. This makes it much easier to track down
 734    :  // inconsistencies in the shadow memory.
 735    :  class DebugShadow : public Shadow {
 736    :   public:
 737    :    using ShadowMarker = agent::asan::ShadowMarker;
 738    :  
 739    :    DebugShadow() : Shadow() {
 740    :    }
 741    :  
 742    :    explicit DebugShadow(size_t length)
 743    :        : Shadow(length) {
 744    :    }
 745    :  
 746    :    ~DebugShadow() override {
 747    :      // If the shadow has been properly used it will be completely empty by the
 748    :      // time it is torn down.
 749    :      CHECK(shadow_address_space_.empty());
 750    :    }
 751    :  
 752    :   protected:
 753    :    // @name Shadow implementation.
 754    :    // @{
 755    :    void SetShadowMemory(
 756    :        const void* address, size_t length, ShadowMarker marker) override;
 757    :    void GetPointerAndSizeImpl(void const** self, size_t* size) const override;
 758    :    // @}
 759    :  
 760    :   private:
 761    :    using StackCapture = agent::common::StackCapture;
 762    :  
 763    :    // Holds details about a given range of shadow memory. Persists the
 764    :    // original size of a region, even if it is subsequently fragmented.
 765    :    struct Metadata {
 766    :      const void* address;
 767    :      size_t size;
 768    :      ShadowMarker marker;
 769    :      StackCapture stack_capture;
 770    :  
 771    :      // Explicitly enable copy and assignment.
 772    :      Metadata();
 773    :      Metadata(const void* address, size_t size, ShadowMarker marker);
 774    :      Metadata(const Metadata& rhs);
 775    :      Metadata& operator=(const Metadata& rhs);
 776    :    };
 777    :    using ShadowAddressSpace =
 778    :        core::AddressSpace<uintptr_t, size_t, Metadata>;
 779    :    using Range = ShadowAddressSpace::Range;
 780    :  
 781    :    // Ensure that the given range has been cleared from the address-space,
 782    :    // readying it for a subsequent insertion.
 783    :    void ClearIntersection(const void* addr, size_t size);
 784    :  
 785    :    // An alternative view of shadow memory. Accessible regions are not
 786    :    // displayed. Neighboring regions of the same type are merged.
 787    :    ShadowAddressSpace shadow_address_space_;
 788    :  };
 789    :  
 790    :  }  // namespace testing
 791    :  
 792    :  #endif  // SYZYGY_AGENT_ASAN_UNITTEST_UTIL_H_

Coverage information generated Fri Jul 29 11:00:21 2016.