Coverage for /Syzygy/agent/memprof/memprof_harness.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
0.0%0077.C++source

Line-by-line coverage:

   1    :  // Copyright 2015 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    :  // A minimal test harness that invokes all of the functions that are observed
  16    :  // by the memory profiler. The harness also uses threading so that the traces
  17    :  // produced by profiling this harness put the grinder through its paces.
  18    :  //
  19    :  // The output of the grinder should look like the following (with a minimal set
  20    :  // of dependencies drawn as arrows):
  21    :  //
  22    :  //     WorkerThread1                       WorkerThread2
  23    :  //     -------------                       -------------
  24    :  //  0: create heap 0                       create heap 3
  25    :  //  1: create alloc 0 on heap 0            create alloc 3 on heap 3
  26    :  //  2: create heap 1 --------------------> create alloc 4 on heap 1
  27    :  //  3: create alloc 1 on heap 1 ---------> get size of alloc 1 on heap 1
  28    :  //  4: create alloc 2 on heap 1            realloc alloc 1 on heap 1
  29    :  //  5: free alloc 2 on heap 1 -----+       free alloc 1 on heap 1
  30    :  //  6: set info on heap 2          |       free alloc 4 on heap 1
  31    :  //  7: free alloc 0 on heap 0      +-----> destroy heap 1
  32    :  //  8: destroy heap 0                      free alloc 3 on heap 3
  33    :  //  9:                                     destroy heap 3
  34    :  //
  35    :  // The mutexes ensure that the sequence of events happens as follows:
  36    :  //
  37    :  // Phase 0: Thread1: 0, 1, 2, 3, 4
  38    :  // Phase 1: Thread2: 0, 1, 2, 3, 4, 5, 6
  39    :  // Phase 2: Thread1: 5, 6, 7, 8
  40    :  // Phase 3: Thread2: 7, 8, 9
  41    :  
  42    :  #include <assert.h>
  43    :  #include <windows.h>
  44    :  
  45  m :  namespace {
  46    :  
  47    :  // Mutex synchronizing access to shared_heap and shared_alloc.
  48  m :  HANDLE shared_mutex = nullptr;
  49    :  
  50    :  // The current 'phase'. This is used to coordinate the sequence of events
  51    :  // across the two threads. This is necessary to ensure the dependencies are
  52    :  // exactly as wanted, without unintentional dependencies caused by allocation
  53    :  // reuse in a heap. Modified under |shared_mutex|.
  54  m :  size_t phase = 0;
  55    :  
  56    :  // Heap that has shared use across two threads. Modified under |shared_mutex|.
  57  m :  HANDLE shared_heap = nullptr;
  58    :  
  59    :  // Allocation that has shared use across two threads. Allocated from
  60    :  // shared_heap. Modified under |shared_mutex|.
  61  m :  void* shared_alloc = nullptr;
  62    :  
  63    :  // Helper function for acquiring |shared_mutex| on the current thread and in
  64    :  // the desired phase.
  65  m :  void AcquireMutex(size_t desired_phase) {
  66  m :    while (true) {
  67  m :      while (::WaitForSingleObject(shared_mutex, INFINITE) != WAIT_OBJECT_0) {}
  68  m :      if (desired_phase == phase)
  69  m :        return;
  70  m :      ::ReleaseMutex(shared_mutex);
  71  m :      ::Sleep(10);
  72  m :    }
  73  m :  }
  74    :  
  75    :  // Releases the mutex and increments the phase.
  76  m :  void ReleaseMutex() {
  77  m :    ++phase;
  78  m :    ::ReleaseMutex(shared_mutex);
  79  m :  }
  80    :  
  81    :  // Body of the first worker thread. This thread is responsible for creating the
  82    :  // shared heap and allocation.
  83  m :  DWORD WINAPI WorkerThread1Main(LPVOID param) {
  84  m :    AcquireMutex(0);
  85  m :    assert(shared_heap == nullptr);
  86  m :    assert(shared_alloc == nullptr);
  87    :  
  88    :    // Allocate a heap and a buffer on this thread.
  89  m :    HANDLE heap = ::HeapCreate(0, 0, 0);                     // 0
  90  m :    void* alloc1 = ::HeapAlloc(heap, HEAP_ZERO_MEMORY, 42);  // 1
  91    :  
  92  m :    shared_heap = ::HeapCreate(0, 0, 0);                  // 2
  93  m :    shared_alloc = ::HeapAlloc(shared_heap, 0, 1 << 20);  // 3
  94    :  
  95  m :    void* alloc2 = ::HeapAlloc(shared_heap, 0, 16);  // 4
  96    :  
  97  m :    ReleaseMutex();
  98  m :    AcquireMutex(2);
  99    :  
 100  m :    ::HeapFree(shared_heap, 0, alloc2);              // 5
 101    :  
 102    :    // Tinker with the process heap a bit.
 103  m :    HANDLE process_heap = ::GetProcessHeap();
 104  m :    ::HeapSetInformation(process_heap, HeapEnableTerminationOnCorruption,  // 6
 105  m :                         0, 0);
 106    :  
 107    :    // Free the allocation and heap made on this thread.
 108  m :    ::HeapFree(heap, 0, alloc1);  // 7
 109  m :    alloc1 = nullptr;
 110  m :    ::HeapDestroy(heap);  // 8
 111  m :    heap = nullptr;
 112    :  
 113  m :    ReleaseMutex();
 114    :  
 115  m :    return 0;
 116  m :  }
 117    :  
 118    :  // Body of the second worker thread. This thread is responsible for releasing
 119    :  // the shared heap and allocation.
 120  m :  DWORD WINAPI WorkerThread2Main(LPVOID param) {
 121  m :    AcquireMutex(1);
 122  m :    assert(shared_heap != nullptr);
 123  m :    assert(shared_alloc != nullptr);
 124    :  
 125    :    // Allocate a heap and a buffer on this thread.
 126  m :    HANDLE heap = ::HeapCreate(0, 0, 0);                       // 0
 127  m :    void* alloc1 = ::HeapAlloc(heap, HEAP_ZERO_MEMORY, 1024);  // 1
 128    :  
 129    :    // Create an allocation on this thread that is only used on this thread,
 130    :    // but which references the shared heap.
 131  m :    HANDLE alloc2 = ::HeapAlloc(shared_heap, 0, 347);  // 2
 132    :  
 133    :    // Query and then free the shared allocation.
 134  m :    ::HeapSize(shared_heap, 0, shared_alloc);                         // 3
 135  m :    shared_alloc = ::HeapReAlloc(shared_heap, 0, shared_alloc, 500);  // 4
 136  m :    ::HeapFree(shared_heap, 0, shared_alloc);                         // 5
 137  m :    shared_alloc = nullptr;
 138    :  
 139    :    // Free the shared_heap allocation made on this thread.
 140  m :    ::HeapFree(shared_heap, 0, alloc2);  // 6
 141    :  
 142  m :    ReleaseMutex();
 143  m :    AcquireMutex(3);
 144    :  
 145    :    // Free the shared heap.
 146  m :    ::HeapDestroy(shared_heap);  // 7
 147  m :    shared_heap = nullptr;
 148    :  
 149  m :    ::HeapFree(heap, 0, alloc1);  // 8
 150  m :    alloc1 = nullptr;
 151  m :    ::HeapDestroy(heap);  // 9
 152  m :    heap = nullptr;
 153    :  
 154  m :    ::ReleaseMutex(shared_mutex);
 155    :  
 156  m :    return 0;
 157  m :  }
 158    :  
 159  m :  }  // namespace
 160    :  
 161  m :  int main(int argc, const char* const* argv) {
 162    :    // The controlled tests (with known expectations) are run on independent
 163    :    // threads. This keeps them separated from the CRT code that runs on the main
 164    :    // thread and which we don't directly control.
 165    :  
 166    :    // Create a mutex not owned by anyone.
 167  m :    shared_mutex = ::CreateMutex(NULL, FALSE, NULL);
 168    :  
 169    :    // Run the two threads simultaneously and wait for them both to finish.
 170  m :    DWORD worker_thread_1_id = 0;
 171  m :    HANDLE worker_thread_1 = ::CreateThread(nullptr, 0, WorkerThread1Main,
 172  m :                                            nullptr, 0, &worker_thread_1_id);
 173  m :    DWORD worker_thread_2_id = 0;
 174  m :    HANDLE worker_thread_2 = ::CreateThread(nullptr, 0, WorkerThread2Main,
 175  m :                                            nullptr, 0, &worker_thread_2_id);
 176  m :    ::WaitForSingleObject(worker_thread_1, INFINITE);
 177  m :    ::WaitForSingleObject(worker_thread_2, INFINITE);
 178    :  
 179    :    // Destroy the mutex.
 180  m :    ::CloseHandle(shared_mutex);
 181    :  
 182  m :    return 0;
 183  m :  }

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