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

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
98.3%1181200.C++test

Line-by-line coverage:

   1    :  // Copyright 2012 Google Inc.
   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    :  #include <windows.h>
  15    :  
  16    :  #include "base/compiler_specific.h"
  17    :  #include "base/logging.h"
  18    :  #include "base/rand_util.h"
  19    :  #include "base/debug/debugger.h"
  20    :  #include "gtest/gtest.h"
  21    :  #include "syzygy/agent/asan/asan_shadow.h"
  22    :  #include "syzygy/core/unittest_util.h"
  23    :  
  24    :  namespace agent {
  25    :  namespace asan {
  26    :  
  27    :  namespace {
  28    :  
  29    :  // Shorthand for discussing all the heap functions.
  30    :  #define HEAP_FUNCTIONS(F)  \
  31    :      F(HANDLE, HeapCreate,  \
  32    :        (DWORD options, SIZE_T initial_size, SIZE_T maximum_size))  \
  33    :      F(BOOL, HeapDestroy,   \
  34    :        (HANDLE heap))  \
  35    :      F(LPVOID, HeapAlloc,   \
  36    :        (HANDLE heap, DWORD flags, SIZE_T bytes))  \
  37    :      F(LPVOID, HeapReAlloc,  \
  38    :        (HANDLE heap, DWORD flags, LPVOID mem, SIZE_T bytes))  \
  39    :      F(BOOL, HeapFree,  \
  40    :        (HANDLE heap, DWORD flags, LPVOID mem))  \
  41    :      F(SIZE_T, HeapSize,  \
  42    :        (HANDLE heap, DWORD flags, LPCVOID mem))  \
  43    :      F(BOOL, HeapValidate,  \
  44    :        (HANDLE heap, DWORD flags, LPCVOID mem))  \
  45    :      F(SIZE_T, HeapCompact,  \
  46    :        (HANDLE heap, DWORD flags))  \
  47    :      F(BOOL, HeapLock, (HANDLE heap))  \
  48    :      F(BOOL, HeapUnlock, (HANDLE heap))  \
  49    :      F(BOOL, HeapWalk,  \
  50    :        (HANDLE heap, LPPROCESS_HEAP_ENTRY entry))  \
  51    :      F(BOOL, HeapSetInformation,  \
  52    :        (HANDLE heap, HEAP_INFORMATION_CLASS info_class,  \
  53    :         PVOID info, SIZE_T info_length))  \
  54    :      F(BOOL, HeapQueryInformation,  \
  55    :        (HANDLE heap, HEAP_INFORMATION_CLASS info_class,  \
  56    :         PVOID info, SIZE_T info_length, PSIZE_T return_length))  \
  57    :  
  58    :  #define DECLARE_HEAP_FUNCTION_PTR(ret, name, args) \
  59    :      typedef ret (WINAPI* name##FunctionPtr)args;
  60    :  
  61    :  HEAP_FUNCTIONS(DECLARE_HEAP_FUNCTION_PTR)
  62    :  
  63    :  #undef DECLARE_HEAP_FUNCTION_PTR
  64    :  
  65    :  class AsanRtlTest : public testing::Test {
  66    :   public:
  67  E :    AsanRtlTest() : asan_rtl_(NULL), heap_(NULL) {
  68  E :    }
  69    :  
  70  E :    void SetUp() OVERRIDE {
  71  E :      FilePath asan_rtl_path = testing::GetExeRelativePath(L"asan_rtl.dll");
  72  E :      asan_rtl_ = ::LoadLibrary(asan_rtl_path.value().c_str());
  73  E :      ASSERT_TRUE(asan_rtl_ != NULL);
  74    :  
  75    :      // Load all the functions and assert that we find them.
  76    :  #define LOAD_ASAN_FUNCTION(ret, name, args)  \
  77    :      name##Function = reinterpret_cast<name##FunctionPtr>(  \
  78    :          ::GetProcAddress(asan_rtl_, "asan_" #name));  \
  79    :      ASSERT_TRUE(name##Function != NULL);
  80    :  
  81  E :      HEAP_FUNCTIONS(LOAD_ASAN_FUNCTION)
  82    :  
  83    :  #undef LOAD_ASAN_FUNCTION
  84    :  
  85  E :      heap_ = HeapCreateFunction(0, 0, 0);
  86  E :      ASSERT_TRUE(heap_ != NULL);
  87  E :    }
  88    :  
  89  E :    void TearDown() OVERRIDE {
  90  E :      if (heap_ != NULL) {
  91  E :        HeapDestroyFunction(heap_);
  92  E :        heap_ = NULL;
  93    :      }
  94    :  
  95  E :      if (asan_rtl_ != NULL) {
  96  E :        ::FreeLibrary(asan_rtl_);
  97  E :        asan_rtl_ = NULL;
  98    :      }
  99  E :    }
 100    :  
 101    :   protected:
 102    :    // Arbitrary constant for all size limit.
 103    :    static const size_t kMaxAllocSize = 134584;
 104    :  
 105    :    // The ASAN runtime module to test.
 106    :    HMODULE asan_rtl_;
 107    :  
 108    :    // Scratch heap handle valid from SetUp to TearDown.
 109    :    HANDLE heap_;
 110    :  
 111    :    // Declare the function pointers.
 112    :  #define DECLARE_FUNCTION_PTR_VARIABLE(ret, name, args)  \
 113    :      static name##FunctionPtr AsanRtlTest::name##Function;
 114    :  
 115    :    HEAP_FUNCTIONS(DECLARE_FUNCTION_PTR_VARIABLE)
 116    :  
 117    :  #undef DECLARE_FUNCTION_PTR_VARIABLE
 118    :  };
 119    :  
 120    :  // Define the function pointers.
 121    :  #define DEFINE_FUNCTION_PTR_VARIABLE(ret, name, args)  \
 122    :      name##FunctionPtr AsanRtlTest::name##Function;
 123    :  
 124    :    HEAP_FUNCTIONS(DEFINE_FUNCTION_PTR_VARIABLE)
 125    :  
 126    :  #undef DEFINE_FUNCTION_PTR_VARIABLE
 127    :  
 128    :  } // namespace
 129    :  
 130  E :  TEST_F(AsanRtlTest, CreateDestroy) {
 131  E :    HANDLE heap = HeapCreateFunction(0, 0, 0);
 132  E :    ASSERT_TRUE(heap != NULL);
 133  E :    ASSERT_TRUE(HeapDestroyFunction(heap));
 134  E :  }
 135    :  
 136  E :  TEST_F(AsanRtlTest, Alloc) {
 137  E :    for (size_t size = 10; size < kMaxAllocSize; size = size * 5 + 123) {
 138  E :      void* mem = HeapAllocFunction(heap_, 0, size);
 139  E :      ASSERT_TRUE(mem != NULL);
 140  E :      memset(mem, '\0', size);
 141    :  
 142  E :      size_t new_size = size;
 143  E :      while (new_size == size)
 144  E :        new_size = base::RandInt(size / 2, size * 2);
 145    :  
 146  E :      void* new_mem = HeapReAllocFunction(heap_, 0, mem, new_size);
 147  E :      ASSERT_TRUE(new_mem != NULL);
 148  E :      ASSERT_NE(mem, new_mem);
 149    :  
 150  E :      ASSERT_TRUE(HeapFreeFunction(heap_, 0, new_mem));
 151  E :    }
 152  E :  }
 153    :  
 154  E :  TEST_F(AsanRtlTest, Size) {
 155  E :    for (size_t size = 10; size < kMaxAllocSize; size = size * 5 + 123) {
 156  E :      void* mem = HeapAllocFunction(heap_, 0, size);
 157  E :      ASSERT_TRUE(mem != NULL);
 158  E :      ASSERT_EQ(size, HeapSizeFunction(heap_, 0, mem));
 159  E :      ASSERT_TRUE(HeapFreeFunction(heap_, 0, mem));
 160  E :    }
 161  E :  }
 162    :  
 163  E :  TEST_F(AsanRtlTest, Validate) {
 164  E :    for (size_t size = 10; size < kMaxAllocSize; size = size * 5 + 123) {
 165  E :      void* mem = HeapAllocFunction(heap_, 0, size);
 166  E :      ASSERT_TRUE(mem != NULL);
 167  E :      ASSERT_TRUE(HeapValidateFunction(heap_, 0, mem));
 168  E :      ASSERT_TRUE(HeapFreeFunction(heap_, 0, mem));
 169  E :    }
 170  E :  }
 171    :  
 172  E :  TEST_F(AsanRtlTest, Compact) {
 173    :    // Compact should return a non-zero size.
 174  E :    ASSERT_LT(0U, HeapCompactFunction(heap_, 0));
 175    :  
 176    :    // TODO(siggi): It may not be possible to allocate the size returned due
 177    :    //     to padding - fix and test.
 178  E :  }
 179    :  
 180  E :  TEST_F(AsanRtlTest, LockUnlock) {
 181    :    // We can't really test these, aside from not crashing.
 182  E :    ASSERT_TRUE(HeapLockFunction(heap_));
 183  E :    ASSERT_TRUE(HeapUnlockFunction(heap_));
 184  E :  }
 185    :  
 186  E :  TEST_F(AsanRtlTest, Walk) {
 187    :    // We assume at least two entries to walk through.
 188  E :    PROCESS_HEAP_ENTRY entry = {};
 189  E :    ASSERT_TRUE(HeapWalkFunction(heap_, &entry));
 190  E :    ASSERT_TRUE(HeapWalkFunction(heap_, &entry));
 191  E :  }
 192    :  
 193  E :  TEST_F(AsanRtlTest, SetQueryInformation) {
 194  E :    ULONG compat_flag = -1;
 195  E :    unsigned long ret = 0;
 196    :    // Get the current value of the compat flag.
 197    :    ASSERT_TRUE(
 198    :        HeapQueryInformationFunction(heap_, HeapCompatibilityInformation,
 199  E :                                     &compat_flag, sizeof(compat_flag), &ret));
 200  E :    ASSERT_EQ(sizeof(compat_flag), ret);
 201  E :    ASSERT_TRUE(compat_flag != -1);
 202    :  
 203    :    // Put the heap in LFH, which should always succeed, except when a debugger
 204    :    // is attached. When a debugger is attached, the heap is wedged in certain
 205    :    // debug settings.
 206  E :    if (base::debug::BeingDebugged()) {
 207  i :      LOG(WARNING) << "Can't test HeapProxy::SetInformation under debugger.";
 208  i :      return;
 209    :    }
 210    :  
 211  E :    compat_flag = 2;
 212    :    ASSERT_TRUE(
 213    :        HeapSetInformationFunction(heap_, HeapCompatibilityInformation,
 214  E :                                   &compat_flag, sizeof(compat_flag)));
 215  E :  }
 216    :  
 217    :  namespace {
 218    :  
 219    :  // The access check function invoked by the below.
 220    :  FARPROC check_access_fn = NULL;
 221    :  
 222    :  void __declspec(naked) CheckAccessAndCaptureContexts(CONTEXT* before,
 223    :                                                       CONTEXT* after,
 224  E :                                                       void* ptr) {
 225    :    __asm {
 226    :      // Capture the CPU context before calling the access check function.
 227  E :      push dword ptr[esp + 0x4]
 228  E :      call dword ptr[RtlCaptureContext]
 229    :  
 230    :      // Restore EAX, which is stomped by RtlCaptureContext.
 231  E :      mov eax, dword ptr[esp + 0x4]
 232  E :      mov eax, dword ptr[eax + CONTEXT.Eax]
 233    :  
 234    :      // Push eax as we're required to do by the custom calling convention.
 235  E :      push eax
 236    :      // Ptr is the pointer to check.
 237  E :      mov eax, dword ptr[esp + 0x10]
 238    :      // Call through.
 239  E :      call dword ptr[check_access_fn + 0]
 240    :  
 241    :      // Capture the CPU context after calling the access check function.
 242  E :      push dword ptr[esp + 0x8]
 243  E :      call dword ptr[RtlCaptureContext]
 244    :  
 245  E :      ret
 246    :    }
 247    :  }
 248    :  
 249  E :  void CheckAccessAndCompareContexts(void* ptr) {
 250  E :    CONTEXT before = {};
 251  E :    CONTEXT after = {};
 252    :  
 253  E :    CheckAccessAndCaptureContexts(&before, &after, ptr);
 254    :  
 255  E :    EXPECT_EQ(before.SegGs, after.SegGs);
 256  E :    EXPECT_EQ(before.SegFs, after.SegFs);
 257  E :    EXPECT_EQ(before.SegEs, after.SegEs);
 258  E :    EXPECT_EQ(before.SegDs, after.SegDs);
 259    :  
 260  E :    EXPECT_EQ(before.Edi, after.Edi);
 261  E :    EXPECT_EQ(before.Esi, after.Esi);
 262  E :    EXPECT_EQ(before.Ebx, after.Ebx);
 263  E :    EXPECT_EQ(before.Edx, after.Edx);
 264  E :    EXPECT_EQ(before.Ecx, after.Ecx);
 265  E :    EXPECT_EQ(before.Eax, after.Eax);
 266    :  
 267  E :    EXPECT_EQ(before.Ebp, after.Ebp);
 268  E :    EXPECT_EQ(before.Eip, after.Eip);
 269  E :    EXPECT_EQ(before.SegCs, after.SegCs);
 270  E :    EXPECT_EQ(before.EFlags, after.EFlags);
 271  E :    EXPECT_EQ(before.Esp, after.Esp);
 272  E :    EXPECT_EQ(before.SegSs, after.SegSs);
 273  E :  }
 274    :  
 275    :  }  // namespace
 276    :  
 277  E :  TEST_F(AsanRtlTest, asan_check_access) {
 278  E :    check_access_fn = ::GetProcAddress(asan_rtl_, "asan_check_access");
 279  E :    ASSERT_TRUE(check_access_fn != NULL);
 280    :  
 281    :    // Run through access checking an allocation that's larger than our
 282    :    // block size (8), but not a multiple thereof to exercise all paths
 283    :    // in the access check function (save for the failure path).
 284  E :    const size_t kAllocSize = 13;
 285    :    uint8* mem = reinterpret_cast<uint8*>(
 286  E :        HeapAllocFunction(heap_, 0, kAllocSize));
 287  E :    ASSERT_TRUE(mem != NULL);
 288    :  
 289  E :    for (size_t i = 0; i < kAllocSize; ++i) {
 290  E :      ASSERT_NO_FATAL_FAILURE(CheckAccessAndCompareContexts(mem + i));
 291  E :    }
 292    :  
 293  E :    ASSERT_TRUE(HeapFreeFunction(heap_, 0, mem));
 294  E :  }
 295    :  
 296    :  } // namespace asan
 297    :  } // namespace agent

Coverage information generated Thu Sep 06 11:30:46 2012.