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