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
|