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/asan_runtime.h"
16 :
17 : #include "base/bind.h"
18 : #include "base/command_line.h"
19 : #include "base/environment.h"
20 : #include "base/memory/scoped_ptr.h"
21 : #include "base/strings/string_number_conversions.h"
22 : #include "base/strings/utf_string_conversions.h"
23 : #include "gtest/gtest.h"
24 : #include "syzygy/agent/asan/unittest_util.h"
25 :
26 : namespace agent {
27 : namespace asan {
28 :
29 : namespace {
30 :
31 : using agent::asan::AsanErrorInfo;
32 :
33 : // A derived class to expose protected members for unit-testing.
34 : class TestAsanRuntime : public AsanRuntime {
35 : public:
36 : using AsanRuntime::PropagateParams;
37 : };
38 :
39 : class AsanRuntimeTest : public testing::TestWithAsanLogger {
40 : public:
41 : typedef testing::TestWithAsanLogger Super;
42 :
43 E : AsanRuntimeTest()
44 : : current_command_line_(CommandLine::NO_PROGRAM) {
45 E : }
46 :
47 E : void SetUp() OVERRIDE {
48 E : Super::SetUp();
49 :
50 E : env_.reset(base::Environment::Create());
51 E : ASSERT_TRUE(env_.get() != NULL);
52 E : env_->UnSetVar(::common::kSyzyAsanOptionsEnvVar);
53 :
54 : // Setup the "global" state.
55 E : common::StackCapture::Init();
56 E : StackCaptureCache::Init();
57 E : }
58 :
59 E : void TearDown() OVERRIDE {
60 : // Clear the environment so other tests aren't affected.
61 E : env_->UnSetVar(::common::kSyzyAsanOptionsEnvVar);
62 :
63 E : Super::TearDown();
64 E : }
65 :
66 : // The test runtime instance.
67 : TestAsanRuntime asan_runtime_;
68 :
69 : // The value of the command-line that we want to test.
70 : CommandLine current_command_line_;
71 :
72 : // The process environment.
73 : scoped_ptr<base::Environment> env_;
74 : };
75 :
76 : bool callback_called = false;
77 :
78 : // A simple callback that change the value of a boolean to indicate that it has
79 : // been called.
80 E : void TestCallback(AsanErrorInfo* error_info) {
81 E : callback_called = true;
82 E : }
83 :
84 : } // namespace
85 :
86 E : TEST_F(AsanRuntimeTest, SetUpAndTearDown) {
87 : ASSERT_NO_FATAL_FAILURE(
88 E : asan_runtime_.SetUp(current_command_line_.GetCommandLineString()));
89 : // Make sure the singleton pointer matches the runtime we created.
90 : ASSERT_EQ(reinterpret_cast<AsanRuntime*>(&asan_runtime_),
91 E : AsanRuntime::runtime());
92 E : ASSERT_NO_FATAL_FAILURE(asan_runtime_.TearDown());
93 E : }
94 :
95 E : TEST_F(AsanRuntimeTest, ThreadIdCache) {
96 : ASSERT_NO_FATAL_FAILURE(
97 E : asan_runtime_.SetUp(current_command_line_.GetCommandLineString()));
98 :
99 E : EXPECT_FALSE(asan_runtime_.ThreadIdIsValid(1234));
100 E : EXPECT_FALSE(asan_runtime_.ThreadIdIsValid(5678));
101 E : asan_runtime_.AddThreadId(1234);
102 E : EXPECT_TRUE(asan_runtime_.ThreadIdIsValid(1234));
103 E : EXPECT_FALSE(asan_runtime_.ThreadIdIsValid(5678));
104 E : asan_runtime_.AddThreadId(5678);
105 E : EXPECT_TRUE(asan_runtime_.ThreadIdIsValid(1234));
106 E : EXPECT_TRUE(asan_runtime_.ThreadIdIsValid(5678));
107 :
108 E : ASSERT_NO_FATAL_FAILURE(asan_runtime_.TearDown());
109 E : }
110 :
111 E : TEST_F(AsanRuntimeTest, OnError) {
112 : ASSERT_NO_FATAL_FAILURE(
113 E : asan_runtime_.SetUp(current_command_line_.GetCommandLineString()));
114 :
115 : // Disable the heap checking as this really slows down the unittests.
116 E : asan_runtime_.params().check_heap_on_failure = false;
117 E : asan_runtime_.SetErrorCallBack(base::Bind(&TestCallback));
118 E : callback_called = false;
119 E : AsanErrorInfo bad_access_info = {};
120 E : RtlCaptureContext(&bad_access_info.context);
121 E : asan_runtime_.OnError(&bad_access_info);
122 E : ASSERT_TRUE(callback_called);
123 E : ASSERT_NO_FATAL_FAILURE(asan_runtime_.TearDown());
124 E : }
125 :
126 E : TEST_F(AsanRuntimeTest, SetCompressionReportingPeriod) {
127 : ASSERT_EQ(StackCaptureCache::GetDefaultCompressionReportingPeriod(),
128 E : StackCaptureCache::compression_reporting_period());
129 :
130 : size_t new_period =
131 E : StackCaptureCache::GetDefaultCompressionReportingPeriod() + 1024;
132 E : std::string new_period_str = base::UintToString(new_period);
133 : current_command_line_.AppendSwitchASCII(
134 E : ::common::kParamReportingPeriod, new_period_str);
135 :
136 : ASSERT_NO_FATAL_FAILURE(
137 E : asan_runtime_.SetUp(current_command_line_.GetCommandLineString()));
138 : // Ensure that the compression reporting period has been modified.
139 E : EXPECT_EQ(new_period, StackCaptureCache::compression_reporting_period());
140 E : ASSERT_NO_FATAL_FAILURE(asan_runtime_.TearDown());
141 E : }
142 :
143 E : TEST_F(AsanRuntimeTest, SetBottomFramesToSkip) {
144 E : size_t frames_to_skip = common::StackCapture::bottom_frames_to_skip() + 1;
145 E : std::string new_frames_to_skip_str = base::UintToString(frames_to_skip);
146 : current_command_line_.AppendSwitchASCII(
147 E : ::common::kParamBottomFramesToSkip, new_frames_to_skip_str);
148 :
149 : ASSERT_NO_FATAL_FAILURE(
150 E : asan_runtime_.SetUp(current_command_line_.GetCommandLineString()));
151 E : EXPECT_EQ(frames_to_skip, common::StackCapture::bottom_frames_to_skip());
152 E : ASSERT_NO_FATAL_FAILURE(asan_runtime_.TearDown());
153 E : }
154 :
155 E : TEST_F(AsanRuntimeTest, SetDisableBreakpad) {
156 E : current_command_line_.AppendSwitch(::common::kParamDisableBreakpadReporting);
157 :
158 : ASSERT_NO_FATAL_FAILURE(
159 E : asan_runtime_.SetUp(current_command_line_.GetCommandLineString()));
160 E : EXPECT_TRUE(asan_runtime_.params().disable_breakpad_reporting);
161 E : ASSERT_NO_FATAL_FAILURE(asan_runtime_.TearDown());
162 E : }
163 :
164 E : TEST_F(AsanRuntimeTest, SetExitOnFailure) {
165 E : current_command_line_.AppendSwitch(::common::kParamExitOnFailure);
166 :
167 : ASSERT_NO_FATAL_FAILURE(
168 E : asan_runtime_.SetUp(current_command_line_.GetCommandLineString()));
169 E : EXPECT_TRUE(asan_runtime_.params().exit_on_failure);
170 E : ASSERT_NO_FATAL_FAILURE(asan_runtime_.TearDown());
171 E : }
172 :
173 E : TEST_F(AsanRuntimeTest, ExitOnFailure) {
174 : // This test always fails under a debugger, due to strangeness in how
175 : // gtest death tests work.
176 E : if (base::debug::BeingDebugged()) {
177 i : LOG(WARNING) << "Skipping this test under debugger.";
178 i : return;
179 : }
180 :
181 E : current_command_line_.AppendSwitch(::common::kParamExitOnFailure);
182 :
183 : ASSERT_NO_FATAL_FAILURE(
184 E : asan_runtime_.SetUp(current_command_line_.GetCommandLineString()));
185 :
186 E : EXPECT_TRUE(asan_runtime_.params().exit_on_failure);
187 E : AsanErrorInfo bad_access_info = {};
188 E : RtlCaptureContext(&bad_access_info.context);
189 :
190 : // We need to delete the files and directory created by this unittest because
191 : // the EXPECT_EXIT macro will clone the process and this new process will exit
192 : // after the call to OnError, without calling the destructor of this class
193 : // (who takes care of deleting the temporary files/directories).
194 E : DeleteTempFileAndDirectory();
195 :
196 : // Disable the heap checking as this really slows down the unittests.
197 E : asan_runtime_.params().check_heap_on_failure = false;
198 : EXPECT_EXIT(asan_runtime_.OnError(&bad_access_info),
199 E : ::testing::ExitedWithCode(EXIT_FAILURE), "");
200 :
201 E : ASSERT_NO_FATAL_FAILURE(asan_runtime_.TearDown());
202 E : }
203 :
204 E : TEST_F(AsanRuntimeTest, IgnoredStackIds) {
205 E : std::string ignored_stack_ids = "0x1;0X7E577E57;0xCAFEBABE;0xffffffff";
206 : current_command_line_.AppendSwitchASCII(
207 E : ::common::kParamIgnoredStackIds, ignored_stack_ids);
208 :
209 : ASSERT_NO_FATAL_FAILURE(
210 E : asan_runtime_.SetUp(current_command_line_.GetCommandLineString()));
211 :
212 : EXPECT_THAT(asan_runtime_.params().ignored_stack_ids_set,
213 E : testing::ElementsAre(0x1, 0x7E577E57, 0xCAFEBABE, 0xFFFFFFFF));
214 E : ASSERT_NO_FATAL_FAILURE(asan_runtime_.TearDown());
215 E : }
216 :
217 E : TEST_F(AsanRuntimeTest, HeapIdIsValid) {
218 : ASSERT_NO_FATAL_FAILURE(
219 E : asan_runtime_.SetUp(current_command_line_.GetCommandLineString()));
220 :
221 E : EXPECT_FALSE(asan_runtime_.HeapIdIsValid(0xDEADBEEF));
222 E : EXPECT_TRUE(asan_runtime_.HeapIdIsValid(asan_runtime_.GetProcessHeap()));
223 :
224 E : ASSERT_NO_FATAL_FAILURE(asan_runtime_.TearDown());
225 E : }
226 :
227 E : TEST_F(AsanRuntimeTest, GetHeapType) {
228 : ASSERT_NO_FATAL_FAILURE(
229 E : asan_runtime_.SetUp(current_command_line_.GetCommandLineString()));
230 :
231 E : HeapManagerInterface::HeapId heap_id = asan_runtime_.GetProcessHeap();
232 E : EXPECT_EQ(kCtMallocHeap, asan_runtime_.GetHeapType(heap_id));
233 :
234 E : ASSERT_NO_FATAL_FAILURE(asan_runtime_.TearDown());
235 E : }
236 :
237 : } // namespace asan
238 : } // namespace agent
|