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

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
98.8%1661680.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/runtime.h"
  16    :  
  17    :  #include <map>
  18    :  
  19    :  #include "base/bind.h"
  20    :  #include "base/bits.h"
  21    :  #include "base/command_line.h"
  22    :  #include "base/environment.h"
  23    :  #include "base/memory/scoped_ptr.h"
  24    :  #include "base/strings/string_number_conversions.h"
  25    :  #include "base/strings/utf_string_conversions.h"
  26    :  #include "gtest/gtest.h"
  27    :  #include "syzygy/agent/asan/unittest_util.h"
  28    :  
  29    :  namespace agent {
  30    :  namespace asan {
  31    :  
  32    :  namespace {
  33    :  
  34    :  using agent::asan::AsanErrorInfo;
  35    :  
  36    :  // Derived classes to expose protected members for unit-testing.
  37    :  class TestBlockHeapManager : public heap_managers::BlockHeapManager {
  38    :   public:
  39    :    using heap_managers::BlockHeapManager::enable_page_protections_;
  40    :  };
  41    :  
  42    :  class TestAsanRuntime : public AsanRuntime {
  43    :   public:
  44    :    using AsanRuntime::GenerateRandomFeatureSet;
  45    :    using AsanRuntime::PropagateParams;
  46    :    using AsanRuntime::enable_kasko_;
  47    :    using AsanRuntime::enabled_features_;
  48    :    using AsanRuntime::heap_manager_;
  49    :  };
  50    :  
  51    :  class AsanRuntimeTest : public testing::TestWithAsanLogger {
  52    :   public:
  53    :    typedef testing::TestWithAsanLogger Super;
  54    :  
  55  E :    AsanRuntimeTest() : current_command_line_(base::CommandLine::NO_PROGRAM) {}
  56    :  
  57  E :    void SetUp() override {
  58  E :      Super::SetUp();
  59    :  
  60  E :      env_.reset(base::Environment::Create());
  61  E :      ASSERT_TRUE(env_.get() != NULL);
  62  E :      env_->UnSetVar(::common::kSyzyAsanOptionsEnvVar);
  63    :  
  64    :      // Setup the "global" state.
  65  E :      common::StackCapture::Init();
  66  E :      StackCaptureCache::Init();
  67  E :    }
  68    :  
  69  E :    void TearDown() override {
  70    :      // Clear the environment so other tests aren't affected.
  71  E :      env_->UnSetVar(::common::kSyzyAsanOptionsEnvVar);
  72    :  
  73  E :      Super::TearDown();
  74  E :    }
  75    :  
  76    :    // The test runtime instance.
  77    :    TestAsanRuntime asan_runtime_;
  78    :  
  79    :    // The value of the command-line that we want to test.
  80    :    base::CommandLine current_command_line_;
  81    :  
  82    :    // The process environment.
  83    :    scoped_ptr<base::Environment> env_;
  84    :  };
  85    :  
  86    :  bool callback_called = false;
  87    :  AsanErrorInfo callback_error_info = {};
  88    :  
  89    :  // A simple callback that change the value of a boolean to indicate that it has
  90    :  // been called.
  91  E :  void TestCallback(AsanErrorInfo* error_info) {
  92  E :    callback_called = true;
  93  E :    callback_error_info = *error_info;
  94  E :  }
  95    :  
  96    :  }  // namespace
  97    :  
  98  E :  TEST_F(AsanRuntimeTest, SetUpAndTearDown) {
  99    :    ASSERT_NO_FATAL_FAILURE(
 100  E :        asan_runtime_.SetUp(current_command_line_.GetCommandLineString()));
 101    :    // Make sure the singleton pointer matches the runtime we created.
 102    :    ASSERT_EQ(reinterpret_cast<AsanRuntime*>(&asan_runtime_),
 103  E :              AsanRuntime::runtime());
 104  E :    ASSERT_NO_FATAL_FAILURE(asan_runtime_.TearDown());
 105  E :  }
 106    :  
 107  E :  TEST_F(AsanRuntimeTest, ThreadIdCache) {
 108    :    ASSERT_NO_FATAL_FAILURE(
 109  E :        asan_runtime_.SetUp(current_command_line_.GetCommandLineString()));
 110    :  
 111  E :    EXPECT_FALSE(asan_runtime_.ThreadIdIsValid(1234));
 112  E :    EXPECT_FALSE(asan_runtime_.ThreadIdIsValid(5678));
 113  E :    asan_runtime_.AddThreadId(1234);
 114  E :    EXPECT_TRUE(asan_runtime_.ThreadIdIsValid(1234));
 115  E :    EXPECT_FALSE(asan_runtime_.ThreadIdIsValid(5678));
 116  E :    asan_runtime_.AddThreadId(5678);
 117  E :    EXPECT_TRUE(asan_runtime_.ThreadIdIsValid(1234));
 118  E :    EXPECT_TRUE(asan_runtime_.ThreadIdIsValid(5678));
 119    :  
 120  E :    ASSERT_NO_FATAL_FAILURE(asan_runtime_.TearDown());
 121  E :  }
 122    :  
 123  E :  TEST_F(AsanRuntimeTest, OnError) {
 124    :    ASSERT_NO_FATAL_FAILURE(
 125  E :        asan_runtime_.SetUp(current_command_line_.GetCommandLineString()));
 126    :  
 127    :    // Disable the heap checking as this really slows down the unittests.
 128  E :    asan_runtime_.params().check_heap_on_failure = false;
 129  E :    asan_runtime_.SetErrorCallBack(base::Bind(&TestCallback));
 130  E :    callback_called = false;
 131  E :    AsanErrorInfo bad_access_info = {};
 132  E :    RtlCaptureContext(&bad_access_info.context);
 133  E :    asan_runtime_.OnError(&bad_access_info);
 134  E :    ASSERT_TRUE(callback_called);
 135  E :    ASSERT_NO_FATAL_FAILURE(asan_runtime_.TearDown());
 136  E :    ::common::AsanParameters params = asan_runtime_.params();
 137    :    EXPECT_EQ(0u, ::memcmp(&params, &(callback_error_info.asan_parameters),
 138  E :                           sizeof(::common::AsanParameters)));
 139  E :  }
 140    :  
 141  E :  TEST_F(AsanRuntimeTest, SetCompressionReportingPeriod) {
 142    :    ASSERT_EQ(StackCaptureCache::GetDefaultCompressionReportingPeriod(),
 143  E :              StackCaptureCache::compression_reporting_period());
 144    :  
 145    :    size_t new_period =
 146  E :        StackCaptureCache::GetDefaultCompressionReportingPeriod() + 1024;
 147  E :    std::string new_period_str = base::UintToString(new_period);
 148    :    current_command_line_.AppendSwitchASCII(
 149  E :        ::common::kParamReportingPeriod, new_period_str);
 150    :  
 151    :    ASSERT_NO_FATAL_FAILURE(
 152  E :        asan_runtime_.SetUp(current_command_line_.GetCommandLineString()));
 153    :    // Ensure that the compression reporting period has been modified.
 154  E :    EXPECT_EQ(new_period, StackCaptureCache::compression_reporting_period());
 155  E :    ASSERT_NO_FATAL_FAILURE(asan_runtime_.TearDown());
 156  E :  }
 157    :  
 158  E :  TEST_F(AsanRuntimeTest, SetBottomFramesToSkip) {
 159  E :    size_t frames_to_skip = common::StackCapture::bottom_frames_to_skip() + 1;
 160  E :    std::string new_frames_to_skip_str = base::UintToString(frames_to_skip);
 161    :    current_command_line_.AppendSwitchASCII(
 162  E :        ::common::kParamBottomFramesToSkip, new_frames_to_skip_str);
 163    :  
 164    :    ASSERT_NO_FATAL_FAILURE(
 165  E :        asan_runtime_.SetUp(current_command_line_.GetCommandLineString()));
 166  E :    EXPECT_EQ(frames_to_skip, common::StackCapture::bottom_frames_to_skip());
 167  E :    ASSERT_NO_FATAL_FAILURE(asan_runtime_.TearDown());
 168  E :  }
 169    :  
 170  E :  TEST_F(AsanRuntimeTest, SetDisableBreakpad) {
 171  E :    current_command_line_.AppendSwitch(::common::kParamDisableBreakpadReporting);
 172    :  
 173    :    ASSERT_NO_FATAL_FAILURE(
 174  E :        asan_runtime_.SetUp(current_command_line_.GetCommandLineString()));
 175  E :    EXPECT_TRUE(asan_runtime_.params().disable_breakpad_reporting);
 176  E :    ASSERT_NO_FATAL_FAILURE(asan_runtime_.TearDown());
 177  E :  }
 178    :  
 179  E :  TEST_F(AsanRuntimeTest, SetExitOnFailure) {
 180  E :    current_command_line_.AppendSwitch(::common::kParamExitOnFailure);
 181    :  
 182    :    ASSERT_NO_FATAL_FAILURE(
 183  E :        asan_runtime_.SetUp(current_command_line_.GetCommandLineString()));
 184  E :    EXPECT_TRUE(asan_runtime_.params().exit_on_failure);
 185  E :    ASSERT_NO_FATAL_FAILURE(asan_runtime_.TearDown());
 186  E :  }
 187    :  
 188  E :  TEST_F(AsanRuntimeTest, ExitOnFailure) {
 189    :    // This test always fails under a debugger, due to strangeness in how
 190    :    // gtest death tests work.
 191  E :    if (base::debug::BeingDebugged()) {
 192  i :      LOG(WARNING) << "Skipping this test under debugger.";
 193  i :      return;
 194    :    }
 195    :  
 196  E :    current_command_line_.AppendSwitch(::common::kParamExitOnFailure);
 197    :  
 198    :    ASSERT_NO_FATAL_FAILURE(
 199  E :        asan_runtime_.SetUp(current_command_line_.GetCommandLineString()));
 200    :  
 201  E :    EXPECT_TRUE(asan_runtime_.params().exit_on_failure);
 202  E :    AsanErrorInfo bad_access_info = {};
 203  E :    RtlCaptureContext(&bad_access_info.context);
 204    :  
 205    :    // We need to delete the files and directory created by this unittest because
 206    :    // the EXPECT_EXIT macro will clone the process and this new process will exit
 207    :    // after the call to OnError, without calling the destructor of this class
 208    :    // (who takes care of deleting the temporary files/directories).
 209  E :    DeleteTempFileAndDirectory();
 210    :  
 211    :    // Disable the heap checking as this really slows down the unittests.
 212  E :    asan_runtime_.params().check_heap_on_failure = false;
 213    :    EXPECT_EXIT(asan_runtime_.OnError(&bad_access_info),
 214  E :                ::testing::ExitedWithCode(EXIT_FAILURE), "");
 215    :  
 216  E :    ASSERT_NO_FATAL_FAILURE(asan_runtime_.TearDown());
 217  E :  }
 218    :  
 219  E :  TEST_F(AsanRuntimeTest, IgnoredStackIds) {
 220  E :    std::string ignored_stack_ids = "0x1;0X7E577E57;0xCAFEBABE;0xffffffff";
 221    :    current_command_line_.AppendSwitchASCII(
 222  E :        ::common::kParamIgnoredStackIds, ignored_stack_ids);
 223    :  
 224    :    ASSERT_NO_FATAL_FAILURE(
 225  E :        asan_runtime_.SetUp(current_command_line_.GetCommandLineString()));
 226    :  
 227    :    EXPECT_THAT(asan_runtime_.params().ignored_stack_ids_set,
 228  E :                testing::ElementsAre(0x1, 0x7E577E57, 0xCAFEBABE, 0xFFFFFFFF));
 229  E :    ASSERT_NO_FATAL_FAILURE(asan_runtime_.TearDown());
 230  E :  }
 231    :  
 232  E :  TEST_F(AsanRuntimeTest, HeapIdIsValid) {
 233    :    ASSERT_NO_FATAL_FAILURE(
 234  E :        asan_runtime_.SetUp(current_command_line_.GetCommandLineString()));
 235    :  
 236  E :    EXPECT_FALSE(asan_runtime_.HeapIdIsValid(0xDEADBEEF));
 237  E :    EXPECT_TRUE(asan_runtime_.HeapIdIsValid(asan_runtime_.GetProcessHeap()));
 238    :  
 239  E :    ASSERT_NO_FATAL_FAILURE(asan_runtime_.TearDown());
 240  E :  }
 241    :  
 242  E :  TEST_F(AsanRuntimeTest, GetHeapType) {
 243    :    ASSERT_NO_FATAL_FAILURE(
 244  E :        asan_runtime_.SetUp(current_command_line_.GetCommandLineString()));
 245    :  
 246  E :    HeapManagerInterface::HeapId heap_id = asan_runtime_.GetProcessHeap();
 247  E :    EXPECT_EQ(kWinHeap, asan_runtime_.GetHeapType(heap_id));
 248    :  
 249  E :    ASSERT_NO_FATAL_FAILURE(asan_runtime_.TearDown());
 250  E :  }
 251    :  
 252  E :  TEST_F(AsanRuntimeTest, GenerateRandomFeatureSet) {
 253    :    ASSERT_NO_FATAL_FAILURE(
 254  E :        asan_runtime_.SetUp(current_command_line_.GetCommandLineString()));
 255    :  
 256  E :    const size_t kIterations = 10000;
 257    :  
 258  E :    std::map<size_t, size_t> feature_group_frequency;
 259    :    const size_t kFeatureMaskBitCount =
 260  E :        static_cast<size_t>(base::bits::Log2Floor(ASAN_FEATURE_MAX));
 261  E :    std::vector<size_t> feature_activation_count(kFeatureMaskBitCount, 0);
 262    :  
 263  E :    for (size_t i = 0; i < kIterations; ++i) {
 264  E :      AsanFeatureSet feature_group = asan_runtime_.GenerateRandomFeatureSet();
 265  E :      ASSERT_LT(feature_group, ASAN_FEATURE_MAX);
 266    :      if (feature_group_frequency.find(feature_group) !=
 267  E :          feature_group_frequency.end()) {
 268  E :        feature_group_frequency[feature_group]++;
 269  E :      } else {
 270  E :        feature_group_frequency[feature_group] = 0;
 271    :      }
 272    :      TestBlockHeapManager* test_block_heap_manager =
 273  E :          static_cast<TestBlockHeapManager*>(asan_runtime_.heap_manager_.get());
 274  E :      if (test_block_heap_manager->enable_page_protections_) {
 275    :        feature_activation_count[base::bits::Log2Floor(
 276  E :            ASAN_FEATURE_ENABLE_PAGE_PROTECTIONS)]++;
 277    :      }
 278  E :      if (asan_runtime_.params().enable_large_block_heap) {
 279    :        feature_activation_count[base::bits::Log2Floor(
 280  E :            ASAN_FEATURE_ENABLE_LARGE_BLOCK_HEAP)]++;
 281    :      }
 282  E :      if (asan_runtime_.enable_kasko_) {
 283    :        feature_activation_count[base::bits::Log2Floor(
 284  E :            ASAN_FEATURE_ENABLE_KASKO)]++;
 285    :      }
 286  E :    }
 287    :  
 288  E :    size_t number_of_disabled_features = 0;
 289  E :    for (size_t i = 0; i < sizeof(kAsanDisabledFeatureMask); ++i) {
 290  E :      if ((kAsanDisabledFeatureMask & (1 << i)) == 0)
 291  E :        number_of_disabled_features++;
 292  E :    }
 293    :  
 294    :    // This could theoretically fail, but that would imply an extremely bad
 295    :    // implementation of the underlying random number generator. We expect a
 296    :    // standard deviation of 1 / 8 * sqrt(10000 * 7) = 33. A 10% margin is
 297    :    // 1000 / 33 = 30 standard deviations. For |z| > 30, the p-value is < 0.00001
 298    :    // and can be considered as insignificant.
 299    :    const size_t kExpectedCount =
 300  E :      kIterations / (ASAN_FEATURE_MAX >> number_of_disabled_features);
 301  E :    const size_t kErrorMargin = kExpectedCount / 10;
 302  E :    for (const auto& iter : feature_group_frequency) {
 303  E :      EXPECT_LT(kExpectedCount - kErrorMargin, iter.second);
 304  E :      EXPECT_GT(kExpectedCount + kErrorMargin, iter.second);
 305  E :    }
 306    :  
 307    :    // Every feature has a 50% chance of being turned on, so we expect a standard
 308    :    // deviation of sqrt(10000 * 0.5 * (1 - 0.5)) = 50. So with a 10% margin we're
 309    :    // at 20 standard deviations. For |z| > 30, the p-value is < 0.0001 and can
 310    :    // be considered as insignificant.
 311  E :    const size_t kExpectedFeatureFrequency = kIterations / 2;
 312    :    const size_t kExpectedFeatureFrequencyErrorMargin =
 313  E :        kExpectedFeatureFrequency / 10;
 314  E :    for (size_t i = 0; i < feature_activation_count.size(); ++i) {
 315  E :      if ((kAsanDisabledFeatureMask & (1 << i)) != 0) {
 316    :        EXPECT_LT(
 317    :            kExpectedFeatureFrequency - kExpectedFeatureFrequencyErrorMargin,
 318  E :            feature_activation_count[i]);
 319    :        EXPECT_GT(
 320    :            kExpectedFeatureFrequency + kExpectedFeatureFrequencyErrorMargin,
 321  E :            feature_activation_count[i]);
 322  E :      } else {
 323  E :        EXPECT_EQ(0U, feature_activation_count[i]);
 324    :      }
 325  E :    }
 326    :  
 327  E :    ASSERT_NO_FATAL_FAILURE(asan_runtime_.TearDown());
 328  E :  }
 329    :  
 330  E :  TEST_F(AsanRuntimeTest, OnErrorSaveEnabledFeatureList) {
 331  E :    asan_runtime_.params().feature_randomization = true;
 332    :    ASSERT_NO_FATAL_FAILURE(
 333  E :        asan_runtime_.SetUp(current_command_line_.GetCommandLineString()));
 334    :  
 335    :    // Disable the heap checking as this really slows down the unittests.
 336  E :    asan_runtime_.params().check_heap_on_failure = false;
 337  E :    asan_runtime_.SetErrorCallBack(base::Bind(&TestCallback));
 338  E :    callback_called = false;
 339  E :    callback_error_info.feature_set = ASAN_FEATURE_MAX;
 340  E :    AsanErrorInfo bad_access_info = {};
 341  E :    RtlCaptureContext(&bad_access_info.context);
 342    :    AsanFeatureSet expected_feature_set = static_cast<AsanFeatureSet>(
 343  E :        ASAN_FEATURE_ENABLE_KASKO | ASAN_FEATURE_ENABLE_LARGE_BLOCK_HEAP);
 344  E :    asan_runtime_.enabled_features_ = expected_feature_set;
 345  E :    asan_runtime_.OnError(&bad_access_info);
 346  E :    EXPECT_TRUE(callback_called);
 347  E :    EXPECT_EQ(expected_feature_set, callback_error_info.feature_set);
 348  E :    ASSERT_NO_FATAL_FAILURE(asan_runtime_.TearDown());
 349  E :  }
 350    :  
 351    :  }  // namespace asan
 352    :  }  // namespace agent

Coverage information generated Thu Jan 14 17:40:38 2016.