Coverage for /Syzygy/refinery/detectors/lfh_entry_detector_unittest.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
0.0%0092.C++test

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    :  #include "syzygy/refinery/detectors/lfh_entry_detector.h"
  16    :  
  17    :  #include <vector>
  18    :  
  19    :  #include "gtest/gtest.h"
  20    :  #include "syzygy/refinery/unittest_util.h"
  21    :  #include "syzygy/refinery/detectors/unittest_util.h"
  22    :  
  23  m :  namespace refinery {
  24    :  
  25  m :  namespace {
  26    :  
  27  m :  class LFHEntryDetectorTest : public testing::LFHDetectorTest {
  28  m :   protected:
  29    :    // TODO(siggi): This code is 32 bit heap specific - amend this for 64 bit
  30    :    //     heap support.
  31  m :    void ResetTestData(size_t byte_size) {
  32    :      // Set with 0x80 as that signals "lfh entry" at certain byte positions.
  33  m :      test_data_.assign(byte_size, 0x80);
  34  m :    }
  35    :  
  36  m :    void WriteSubseg(size_t byte_offset, uintptr_t subseg_code) {
  37  m :      ASSERT_LT(byte_offset + sizeof(subseg_code), test_data_.size());
  38  m :      void* dst_addr = &test_data_.at(byte_offset);
  39  m :      subseg_code ^= (testing::ToAddress(dst_addr) >> 3);
  40    :  
  41  m :      ::memcpy(dst_addr, &subseg_code, sizeof(subseg_code));
  42  m :    }
  43    :  
  44  m :    void DetectTestData(LFHEntryDetector::LFHEntryRuns* found_runs) {
  45  m :      ASSERT_TRUE(found_runs);
  46    :  
  47  m :      LFHEntryDetector detector;
  48  m :      ASSERT_TRUE(detector.Init(repo().get(), bit_source()));
  49  m :      ASSERT_TRUE(detector.Detect(
  50  m :          AddressRange(testing::ToAddress(&test_data_.at(0)), test_data_.size()),
  51  m :          found_runs));
  52  m :    }
  53    :  
  54  m :   private:
  55  m :    std::vector<uint8_t> test_data_;
  56  m :  };
  57    :  
  58  m :  }  // namespace
  59    :  
  60  m :  TEST_F(LFHEntryDetectorTest, InitSuccess) {
  61  m :    LFHEntryDetector detector;
  62    :  
  63  m :    ASSERT_TRUE(detector.Init(repo().get(), bit_source()));
  64  m :    ASSERT_TRUE(detector.entry_type());
  65  m :  }
  66    :  
  67  m :  TEST_F(LFHEntryDetectorTest, FailsOnEmptyTypeRepo) {
  68  m :    LFHEntryDetector detector;
  69    :  
  70  m :    scoped_refptr<TypeRepository> empty_type_repo = new TypeRepository;
  71  m :    ASSERT_FALSE(detector.Init(empty_type_repo.get(), bit_source()));
  72  m :    ASSERT_FALSE(detector.entry_type());
  73  m :  }
  74    :  
  75  m :  TEST_F(LFHEntryDetectorTest, Detect) {
  76  m :    if (testing::IsAppVerifierActive()) {
  77  m :      LOG(WARNING) << "LFHEntryDetectorTest.Detect is incompatible with AV.";
  78  m :      return;
  79  m :    }
  80    :  
  81  m :    LFHEntryDetector detector;
  82    :  
  83  m :    ASSERT_TRUE(detector.Init(repo().get(), bit_source()));
  84    :  
  85  m :    const size_t kBlockSize = 17;
  86    :    // Allocate blocks until we get an LFH bucket.
  87  m :    Address bucket = AllocateLFHBucket(kBlockSize);
  88  m :    if (bucket == 0) {
  89  m :      LOG(ERROR) << "Couldn't find an LFH bucket - is AppVerifier enabled?";
  90  m :      return;
  91  m :    }
  92    :  
  93    :    // Form a range covering the LFH bucket start and perform detection on it.
  94  m :    AddressRange range(bucket - 256, 1024);
  95  m :    LFHEntryDetector::LFHEntryRuns found_runs;
  96  m :    ASSERT_TRUE(detector.Detect(range, &found_runs));
  97    :  
  98  m :    ASSERT_LE(1, found_runs.size());
  99    :  
 100  m :    bool suitable_size_found = false;
 101  m :    for (const auto& found_run : found_runs) {
 102  m :      ASSERT_NE(0U, found_run.entries_found);
 103  m :      ASSERT_LE(found_run.entry_distance_bytes * (found_run.entries_found - 1),
 104  m :                found_run.last_entry - found_run.first_entry);
 105  m :      ASSERT_NE(0U, found_run.size_votes);
 106  m :      ASSERT_GT(found_run.entries_found, found_run.size_votes);
 107    :  
 108    :      // Technically it's possible for the subsegment mask to be zero, but this
 109    :      // at least tests that it's set with a 1/2^32 odds of flaking.
 110  m :      ASSERT_NE(0ULL, found_run.subsegment_code);
 111    :  
 112  m :      const size_t kEntrySize = 8;
 113  m :      if (found_run.entry_distance_bytes > kBlockSize + kEntrySize)
 114  m :        suitable_size_found = true;
 115    :  
 116  m :      AddressRange found_span(found_run.first_entry,
 117  m :                              found_run.last_entry - found_run.first_entry);
 118  m :      ASSERT_TRUE(found_span.IsValid());
 119    :      // All found spans should be contained within the range we constrain the
 120    :      // search to.
 121  m :      ASSERT_TRUE(range.Contains(found_span));
 122  m :    }
 123    :  
 124  m :    ASSERT_TRUE(suitable_size_found);
 125  m :  }
 126    :  
 127  m :  TEST_F(LFHEntryDetectorTest, VotingPicksMinimumDistance) {
 128    :    // Make some test data.
 129  m :    ResetTestData(1024);
 130    :  
 131  m :    const uintptr_t kSubsegCode = 0xCAFEBABE;
 132  m :    WriteSubseg(16 * 1, kSubsegCode);
 133  m :    WriteSubseg(16 * 2, kSubsegCode);
 134  m :    WriteSubseg(16 * 4, kSubsegCode);
 135    :  
 136  m :    LFHEntryDetector::LFHEntryRuns found_runs;
 137  m :    ASSERT_NO_FATAL_FAILURE(DetectTestData(&found_runs));
 138    :  
 139  m :    ASSERT_EQ(1U, found_runs.size());
 140  m :    EXPECT_EQ(kSubsegCode, found_runs[0].subsegment_code);
 141    :    // The smaller size should have been selected.
 142  m :    EXPECT_EQ(16, found_runs[0].entry_distance_bytes);
 143    :  
 144  m :    ResetTestData(1024);
 145    :  
 146    :    // Now try starting with the larger span.
 147  m :    WriteSubseg(16 * 1, kSubsegCode);
 148  m :    WriteSubseg(16 * 3, kSubsegCode);
 149  m :    WriteSubseg(16 * 4, kSubsegCode);
 150    :  
 151  m :    ASSERT_NO_FATAL_FAILURE(DetectTestData(&found_runs));
 152  m :    ASSERT_EQ(1U, found_runs.size());
 153  m :    EXPECT_EQ(kSubsegCode, found_runs[0].subsegment_code);
 154    :    // The smaller size should have been selected.
 155  m :    EXPECT_EQ(16, found_runs[0].entry_distance_bytes);
 156  m :  }
 157    :  
 158  m :  }  // namespace refinery

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