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

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

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