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

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
100.0%2252250.C++test

Line-by-line coverage:

   1    :  // Copyright 2012 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    :  #include "syzygy/agent/asan/stack_capture_cache.h"
  16    :  
  17    :  #include "base/memory/scoped_ptr.h"
  18    :  #include "gtest/gtest.h"
  19    :  #include "syzygy/agent/asan/asan_logger.h"
  20    :  
  21    :  namespace agent {
  22    :  namespace asan {
  23    :  
  24    :  namespace {
  25    :  
  26    :  using agent::common::StackCapture;
  27    :  
  28    :  class TestStackCaptureCache : public StackCaptureCache {
  29    :   public:
  30  E :    explicit TestStackCaptureCache(AsanLogger* logger)
  31    :        : StackCaptureCache(logger) {
  32  E :    }
  33  E :    TestStackCaptureCache(AsanLogger* logger, size_t max_num_frames)
  34    :        : StackCaptureCache(logger, max_num_frames) {
  35  E :    }
  36    :  
  37    :    using StackCaptureCache::Statistics;
  38    :  
  39  E :    void GetStatistics(Statistics* s) {
  40  E :      DCHECK(s != NULL);
  41  E :      base::AutoLock auto_lock(stats_lock_);
  42  E :      GetStatisticsUnlocked(s);
  43  E :    }
  44    :  
  45  E :    CachePage* current_page() { return current_page_; }
  46    :  
  47    :   private:
  48    :    using StackCaptureCache::current_page_;
  49    :  };
  50    :  
  51    :  class StackCaptureCacheTest : public testing::Test {
  52    :   public:
  53  E :    void SetUp() OVERRIDE {
  54    :      // Setup the "global" state.
  55  E :      StackCapture::Init();
  56  E :      StackCaptureCache::Init();
  57  E :    }
  58    :  };
  59    :  
  60    :  }  // namespace
  61    :  
  62  E :  TEST_F(StackCaptureCacheTest, CachePageTest) {
  63    :    static const size_t kFrameCounts[] =
  64    :        { 5, 10, 30, StackCapture::kMaxNumFrames };
  65    :  
  66  E :    for (size_t i = 0; i < arraysize(kFrameCounts); ++i) {
  67  E :      size_t max_num_frames = kFrameCounts[i];
  68    :      scoped_ptr<TestStackCaptureCache::CachePage> page(
  69  E :          new TestStackCaptureCache::CachePage(NULL));
  70    :  
  71    :      // Ensure that returning a page works.
  72  E :      EXPECT_EQ(0u, page->bytes_used());
  73  E :      StackCapture* s1 = page->GetNextStackCapture(max_num_frames);
  74  E :      ASSERT_TRUE(s1 != NULL);
  75  E :      EXPECT_EQ(max_num_frames, s1->max_num_frames());
  76  E :      EXPECT_EQ(s1->Size(), page->bytes_used());
  77  E :      page->ReturnStackCapture(s1);
  78  E :      EXPECT_EQ(0u, page->bytes_used());
  79    :  
  80    :      // Reallocating should get us the same page as the one we just returned.
  81  E :      StackCapture* s2 = page->GetNextStackCapture(max_num_frames);
  82  E :      EXPECT_EQ(s1, s2);
  83    :  
  84    :      // Figure out how many more allocations the page should give us.
  85  E :      size_t bytes_left = page->bytes_left();
  86  E :      size_t allocations_left = bytes_left / s2->Size();
  87    :  
  88    :      // Ensure we get exactly that many.
  89  E :      for (size_t j = 0; j < allocations_left; ++j) {
  90  E :        EXPECT_TRUE(page->GetNextStackCapture(max_num_frames) != NULL);
  91  E :      }
  92    :  
  93    :      // And no more than that.
  94  E :      EXPECT_TRUE(page->GetNextStackCapture(max_num_frames) == NULL);
  95  E :    }
  96  E :  }
  97    :  
  98  E :  TEST_F(StackCaptureCacheTest, SaveStackTrace) {
  99  E :    AsanLogger logger;
 100  E :    TestStackCaptureCache cache(&logger);
 101  E :    EXPECT_EQ(StackCapture::kMaxNumFrames, cache.max_num_frames());
 102    :  
 103    :    // Capture a stack trace.
 104  E :    ULONG stack_id = 0;
 105  E :    void* frames[StackCapture::kMaxNumFrames] = { 0 };
 106    :    size_t num_frames = ::CaptureStackBackTrace(
 107  E :        0, StackCapture::kMaxNumFrames, frames, &stack_id);
 108    :  
 109    :    // We should be able to save the captures stack trace.
 110  E :    const StackCapture* s1 = cache.SaveStackTrace(stack_id, frames, num_frames);
 111  E :    ASSERT_TRUE(s1 != NULL);
 112  E :    EXPECT_EQ(num_frames, s1->max_num_frames());
 113    :  
 114    :    // We should get a pointer to the initial stack capture object if we attempt
 115    :    // to save the same trace again.
 116  E :    const StackCapture* s2 = cache.SaveStackTrace(stack_id, frames, num_frames);
 117  E :    EXPECT_EQ(s1, s2);
 118    :  
 119    :    // Capture a new stack trace.
 120    :    num_frames = ::CaptureStackBackTrace(
 121  E :        0, StackCapture::kMaxNumFrames, frames, &stack_id);
 122    :  
 123    :    // We should get a pointer to a new stack capture object when we attempt
 124    :    // to save a different trace.
 125  E :    const StackCapture* s3 = cache.SaveStackTrace(stack_id, frames, num_frames);
 126  E :    EXPECT_NE(s1, s3);
 127  E :    EXPECT_EQ(num_frames, s3->max_num_frames());
 128  E :  }
 129    :  
 130  E :  TEST_F(StackCaptureCacheTest, RestrictedStackTraces) {
 131  E :    AsanLogger logger;
 132  E :    TestStackCaptureCache cache(&logger, 20);
 133  E :    EXPECT_EQ(20u, cache.max_num_frames());
 134    :  
 135    :    // Capture a stack trace.
 136  E :    ULONG stack_id = 0;
 137  E :    void* frames[StackCapture::kMaxNumFrames] = { 0 };
 138    :    size_t num_frames = ::CaptureStackBackTrace(
 139  E :        0, StackCapture::kMaxNumFrames, frames, &stack_id);
 140    :  
 141    :    // We should be able to save the captures stack trace.
 142  E :    const StackCapture* s1 = cache.SaveStackTrace(stack_id, frames, num_frames);
 143  E :    ASSERT_TRUE(s1 != NULL);
 144  E :    EXPECT_EQ(num_frames, s1->max_num_frames());
 145    :  
 146    :    // We should get a pointer to the initial stack capture object if we attempt
 147    :    // to save the same trace again.
 148  E :    const StackCapture* s2 = cache.SaveStackTrace(stack_id, frames, num_frames);
 149  E :    EXPECT_EQ(s1, s2);
 150    :  
 151    :    // Capture a new stack trace.
 152    :    num_frames = ::CaptureStackBackTrace(
 153  E :        0, StackCapture::kMaxNumFrames, frames, &stack_id);
 154    :  
 155    :    // We should get a pointer to a new stack capture object when we attempt
 156    :    // to save a different trace.
 157  E :    const StackCapture* s3 = cache.SaveStackTrace(stack_id, frames, num_frames);
 158  E :    EXPECT_NE(s1, s3);
 159  E :    EXPECT_EQ(num_frames, s1->max_num_frames());
 160  E :  }
 161    :  
 162  E :  TEST_F(StackCaptureCacheTest, MaxNumFrames) {
 163  E :    AsanLogger logger;
 164  E :    TestStackCaptureCache cache(&logger);
 165  E :    size_t max_num_frames = cache.max_num_frames() + 1;
 166  E :    cache.set_max_num_frames(max_num_frames);
 167  E :    ASSERT_EQ(max_num_frames, cache.max_num_frames());
 168  E :  }
 169    :  
 170  E :  TEST_F(StackCaptureCacheTest, ReclaimedStackCapture) {
 171  E :    AsanLogger logger;
 172  E :    TestStackCaptureCache cache(&logger);
 173    :  
 174    :    // Grab a stack capture and insert it.
 175  E :    StackCapture stack_capture;
 176  E :    stack_capture.InitFromStack();
 177  E :    const StackCapture* s1 = cache.SaveStackTrace(stack_capture);
 178  E :    ASSERT_TRUE(s1 != NULL);
 179    :  
 180    :    // Grab another one and insert it.
 181  E :    stack_capture.InitFromStack();
 182  E :    const StackCapture* s2 = cache.SaveStackTrace(stack_capture);
 183  E :    ASSERT_TRUE(s2 != NULL);
 184    :  
 185    :    // Return the first one.
 186  E :    cache.ReleaseStackTrace(s1);
 187    :  
 188    :    // Grab another one and insert it.
 189  E :    stack_capture.InitFromStack();
 190  E :    const StackCapture* s3 = cache.SaveStackTrace(stack_capture);
 191  E :    ASSERT_TRUE(s3 != NULL);
 192    :  
 193    :    // We expect this third one to have been reclaimed.
 194  E :    EXPECT_EQ(s1, s3);
 195  E :  }
 196    :  
 197  E :  TEST_F(StackCaptureCacheTest, Statistics) {
 198  E :    AsanLogger logger;
 199  E :    TestStackCaptureCache cache(&logger);
 200  E :    cache.set_compression_reporting_period(1U);
 201  E :    TestStackCaptureCache::Statistics s = {};
 202    :  
 203  E :    cache.GetStatistics(&s);
 204  E :    EXPECT_EQ(0u, s.cached);
 205  E :    EXPECT_EQ(0u, s.saturated);
 206  E :    EXPECT_EQ(0u, s.unreferenced);
 207  E :    EXPECT_EQ(0u, s.requested);
 208  E :    EXPECT_EQ(0u, s.allocated);
 209  E :    EXPECT_EQ(0u, s.references);
 210  E :    EXPECT_EQ(0u, s.frames_stored);
 211  E :    EXPECT_EQ(0u, s.frames_alive);
 212  E :    EXPECT_EQ(0u, s.frames_dead);
 213    :  
 214    :    // Grab a stack capture and insert it.
 215  E :    StackCapture stack_capture;
 216  E :    stack_capture.InitFromStack();
 217  E :    const StackCapture* s1 = cache.SaveStackTrace(stack_capture);
 218  E :    ASSERT_TRUE(s1 != NULL);
 219  E :    size_t s1_frames = s1->num_frames();
 220  E :    cache.GetStatistics(&s);
 221  E :    EXPECT_EQ(1u, s.cached);
 222  E :    EXPECT_EQ(0u, s.saturated);
 223  E :    EXPECT_EQ(0u, s.unreferenced);
 224  E :    EXPECT_EQ(1u, s.requested);
 225  E :    EXPECT_EQ(1u, s.allocated);
 226  E :    EXPECT_EQ(1u, s.references);
 227  E :    EXPECT_EQ(s1_frames, s.frames_stored);
 228  E :    EXPECT_EQ(s1_frames, s.frames_alive);
 229  E :    EXPECT_EQ(0u, s.frames_dead);
 230    :  
 231    :    // Reinsert the same stack. We expect to get the same pointer back.
 232  E :    const StackCapture* s2 = cache.SaveStackTrace(stack_capture);
 233  E :    ASSERT_TRUE(s2 != NULL);
 234  E :    cache.GetStatistics(&s);
 235  E :    EXPECT_EQ(s1, s2);
 236  E :    EXPECT_EQ(1u, s.cached);
 237  E :    EXPECT_EQ(0u, s.saturated);
 238  E :    EXPECT_EQ(0u, s.unreferenced);
 239  E :    EXPECT_EQ(2u, s.requested);
 240  E :    EXPECT_EQ(1u, s.allocated);
 241  E :    EXPECT_EQ(2u, s.references);
 242  E :    EXPECT_EQ(2 * s1_frames, s.frames_stored);
 243  E :    EXPECT_EQ(s1_frames, s.frames_alive);
 244  E :    EXPECT_EQ(0u, s.frames_dead);
 245    :  
 246    :    // Insert a new stack.
 247  E :    stack_capture.InitFromStack();
 248  E :    const StackCapture* s3 = cache.SaveStackTrace(stack_capture);
 249  E :    ASSERT_TRUE(s3 != NULL);
 250  E :    size_t s3_frames = s3->num_frames();
 251  E :    cache.GetStatistics(&s);
 252  E :    EXPECT_EQ(2u, s.cached);
 253  E :    EXPECT_EQ(0u, s.saturated);
 254  E :    EXPECT_EQ(0u, s.unreferenced);
 255  E :    EXPECT_EQ(3u, s.requested);
 256  E :    EXPECT_EQ(2u, s.allocated);
 257  E :    EXPECT_EQ(3u, s.references);
 258  E :    EXPECT_EQ(2 * s1_frames + s3_frames, s.frames_stored);
 259  E :    EXPECT_EQ(s1_frames + s3_frames, s.frames_alive);
 260  E :    EXPECT_EQ(0u, s.frames_dead);
 261    :  
 262    :    // Return the first stack. This should decrement the total reference count.
 263  E :    cache.ReleaseStackTrace(s1);
 264  E :    s1 = NULL;
 265  E :    cache.GetStatistics(&s);
 266  E :    EXPECT_EQ(2u, s.cached);
 267  E :    EXPECT_EQ(0u, s.saturated);
 268  E :    EXPECT_EQ(0u, s.unreferenced);
 269  E :    EXPECT_EQ(3u, s.requested);
 270  E :    EXPECT_EQ(2u, s.allocated);
 271  E :    EXPECT_EQ(2u, s.references);
 272  E :    EXPECT_EQ(s1_frames + s3_frames, s.frames_stored);
 273  E :    EXPECT_EQ(s1_frames + s3_frames, s.frames_alive);
 274  E :    EXPECT_EQ(0u, s.frames_dead);
 275    :  
 276    :    // Return the 2nd stack. This should decrement the reference count, and leave
 277    :    // a stack unreferenced (and its frames dead).
 278  E :    cache.ReleaseStackTrace(s2);
 279  E :    s2 = NULL;
 280  E :    cache.GetStatistics(&s);
 281  E :    EXPECT_EQ(1u, s.cached);
 282  E :    EXPECT_EQ(0u, s.saturated);
 283  E :    EXPECT_EQ(1u, s.unreferenced);
 284  E :    EXPECT_EQ(3u, s.requested);
 285  E :    EXPECT_EQ(2u, s.allocated);
 286  E :    EXPECT_EQ(1u, s.references);
 287  E :    EXPECT_EQ(s3_frames, s.frames_stored);
 288  E :    EXPECT_EQ(s3_frames, s.frames_alive);
 289  E :    EXPECT_EQ(s1_frames, s.frames_dead);
 290    :  
 291    :    // Insert the 3rd stack over and over again. We'll eventually saturate the
 292    :    // reference counter and it'll be a permanent part of the cache.
 293  E :    size_t kEnoughTimesToSaturate = StackCapture::kMaxRefCount;
 294  E :    for (size_t i = 0; i < kEnoughTimesToSaturate; ++i) {
 295  E :      const StackCapture* s4 = cache.SaveStackTrace(stack_capture);
 296  E :      ASSERT_TRUE(s4 != NULL);
 297  E :      EXPECT_EQ(s3, s4);
 298  E :    }
 299  E :    cache.GetStatistics(&s);
 300  E :    EXPECT_EQ(1u, s.cached);
 301  E :    EXPECT_EQ(1u, s.saturated);
 302  E :    EXPECT_EQ(1u, s.unreferenced);
 303  E :    EXPECT_EQ(3u + kEnoughTimesToSaturate, s.requested);
 304  E :    EXPECT_EQ(2u, s.allocated);
 305  E :    EXPECT_EQ(1u + kEnoughTimesToSaturate, s.references);
 306  E :    EXPECT_EQ((1u + kEnoughTimesToSaturate) * s3_frames, s.frames_stored);
 307  E :    EXPECT_EQ(s3_frames, s.frames_alive);
 308  E :    EXPECT_EQ(s1_frames, s.frames_dead);
 309    :  
 310    :    // Return the 3rd stack as many times as it was referenced. It should still
 311    :    // be saturated. None of its frames should be stored (there are no active
 312    :    // references), but it should still be 'alive' as it remains in the cache.
 313  E :    for (size_t i = 0; i < kEnoughTimesToSaturate + 1; ++i)
 314  E :      cache.ReleaseStackTrace(s3);
 315  E :    s3 = NULL;
 316  E :    cache.GetStatistics(&s);
 317  E :    EXPECT_EQ(1u, s.cached);
 318  E :    EXPECT_EQ(1u, s.saturated);
 319  E :    EXPECT_EQ(1u, s.unreferenced);
 320  E :    EXPECT_EQ(3u + kEnoughTimesToSaturate, s.requested);
 321  E :    EXPECT_EQ(2u, s.allocated);
 322  E :    EXPECT_EQ(0u, s.references);
 323  E :    EXPECT_EQ(0u, s.frames_stored);
 324  E :    EXPECT_EQ(s3_frames, s.frames_alive);
 325  E :    EXPECT_EQ(s1_frames, s.frames_dead);
 326  E :  }
 327    :  
 328  E :  TEST_F(StackCaptureCacheTest, CachePagesArePoisoned) {
 329    :    scoped_ptr<TestStackCaptureCache::CachePage> page(
 330  E :        new TestStackCaptureCache::CachePage(NULL));
 331  E :    void* cache_page_ptr = reinterpret_cast<void*>(page.get());
 332  E :    EXPECT_FALSE(Shadow::IsAccessible(cache_page_ptr));
 333  E :    page.reset(NULL);
 334  E :    EXPECT_TRUE(Shadow::IsAccessible(cache_page_ptr));
 335  E :  }
 336    :  
 337  E :  TEST_F(StackCaptureCacheTest, StackCapturePointerIsValid) {
 338  E :    AsanLogger logger;
 339  E :    TestStackCaptureCache cache(&logger);
 340    :  
 341    :    // Capture and save a stack trace.
 342  E :    ULONG stack_id = 0;
 343  E :    void* frames[StackCapture::kMaxNumFrames] = { 0 };
 344    :    size_t num_frames = ::CaptureStackBackTrace(
 345  E :        0, StackCapture::kMaxNumFrames, frames, &stack_id);
 346  E :    const StackCapture* s1 = cache.SaveStackTrace(stack_id, frames, num_frames);
 347  E :    ASSERT_TRUE(s1 != NULL);
 348    :  
 349    :    // This pointer should be valid.
 350  E :    EXPECT_TRUE(cache.StackCapturePointerIsValid(s1));
 351    :  
 352    :    // An address after the current page should be invalid.
 353    :    const StackCapture* invalid_stack_capture_1 =
 354    :        reinterpret_cast<const StackCapture*>(cache.current_page()->data() +
 355  E :            cache.current_page()->data_size());
 356  E :    EXPECT_FALSE(cache.StackCapturePointerIsValid(invalid_stack_capture_1));
 357    :  
 358    :    // An address before the current page should be invalid.
 359    :    const StackCapture* invalid_stack_capture_2 =
 360  E :        reinterpret_cast<const StackCapture*>(cache.current_page()->data() - 1);
 361  E :    EXPECT_FALSE(cache.StackCapturePointerIsValid(invalid_stack_capture_2));
 362    :  
 363    :    // A null pointer should be invalid.
 364    :    EXPECT_FALSE(cache.StackCapturePointerIsValid(
 365  E :        reinterpret_cast<const StackCapture*>(NULL)));
 366  E :  }
 367    :  
 368    :  }  // namespace asan
 369    :  }  // namespace agent

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