1 : // Copyright 2014 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/quarantines/size_limited_quarantine.h"
16 :
17 : #include "gmock/gmock.h"
18 : #include "gtest/gtest.h"
19 :
20 : namespace agent {
21 : namespace asan {
22 : namespace quarantines {
23 :
24 : // A dummy lightweight object for storing in a quarantine under test.
25 : // This is outside of the anonymous namespace to keep gmock happy.
26 : struct DummyObject {
27 : size_t size;
28 :
29 : DummyObject() : size(0) { }
30 E : explicit DummyObject(size_t size) : size(size) { }
31 E : DummyObject(const DummyObject& o) : size(o.size) { } // NOLINT
32 : };
33 :
34 E : std::ostream& operator<<(std::ostream& os, const DummyObject& o) {
35 E : os << "DummyObject(size=" << o.size << ")";
36 E : return os;
37 E : }
38 :
39 E : bool operator==(const DummyObject& o1, const DummyObject& o2) {
40 E : return o1.size == o2.size;
41 E : }
42 :
43 : namespace {
44 :
45 : struct DummyObjectSizeFunctor {
46 E : size_t operator()(const DummyObject& o) {
47 E : return o.size;
48 E : }
49 : };
50 :
51 : typedef std::vector<DummyObject> DummyObjectVector;
52 :
53 : class TestQuarantine
54 : : public SizeLimitedQuarantineImpl<DummyObject, DummyObjectSizeFunctor> {
55 : public:
56 E : TestQuarantine() { }
57 E : virtual ~TestQuarantine() { }
58 :
59 : protected:
60 : // @name SizeLimitedQuarantine interface.
61 : // @{
62 E : bool PushImpl(const DummyObject& o) {
63 E : objects_.push_back(o);
64 E : return true;
65 E : }
66 :
67 E : bool PopImpl(DummyObject* o) {
68 E : DCHECK_NE(static_cast<DummyObject*>(NULL), o);
69 E : DCHECK(!objects_.empty());
70 E : *o = objects_.back();
71 E : objects_.pop_back();
72 E : return true;
73 E : }
74 :
75 E : void EmptyImpl(DummyObjectVector* os) {
76 E : DCHECK_NE(static_cast<DummyObjectVector*>(NULL), os);
77 E : os->swap(objects_);
78 E : }
79 :
80 i : size_t GetLockIdImpl(const DummyObject& o) { return 0; }
81 i : void LockImpl(size_t lock_id) {}
82 i : void UnlockImpl(size_t lock_id) {}
83 : // @}
84 :
85 : DummyObjectVector objects_;
86 : };
87 :
88 : } // namespace
89 :
90 E : TEST(SizeLimitedQuarantineTest, ConstructorsSettersAndGetters) {
91 E : TestQuarantine q;
92 E : EXPECT_EQ(TestQuarantine::kUnboundedSize, q.max_object_size());
93 E : EXPECT_EQ(TestQuarantine::kUnboundedSize, q.max_quarantine_size());
94 E : EXPECT_EQ(0u, q.GetSizeForTesting());
95 E : EXPECT_EQ(0u, q.GetCountForTesting());
96 :
97 E : q.set_max_object_size(100);
98 E : EXPECT_EQ(100u, q.max_object_size());
99 :
100 E : q.set_max_quarantine_size(1000);
101 E : EXPECT_EQ(1000u, q.max_quarantine_size());
102 E : }
103 :
104 E : TEST(SizeLimitedQuarantineTest, NoSizeLimit) {
105 E : TestQuarantine q;
106 E : for (size_t i = 0; i < 1000; ++i) {
107 E : q.Push(DummyObject(i * 1000));
108 E : EXPECT_EQ(i + 1, q.GetCountForTesting());
109 E : }
110 E : }
111 :
112 E : TEST(SizeLimitedQuarantineTest, MaxObjectSizeEnforced) {
113 E : TestQuarantine q;
114 E : q.set_max_object_size(10);
115 E : for (size_t i = 1; i < 20; ++i) {
116 E : if (i <= 10) {
117 E : EXPECT_TRUE(q.Push(DummyObject(i)).push_successful);
118 E : EXPECT_EQ(i, q.GetCountForTesting());
119 E : } else {
120 E : EXPECT_FALSE(q.Push(DummyObject(i)).push_successful);
121 E : EXPECT_EQ(10u, q.GetCountForTesting());
122 : }
123 E : }
124 E : }
125 :
126 E : TEST(SizeLimitedQuarantineTest, InvariantEnforced) {
127 E : TestQuarantine q;
128 E : DummyObject o(10);
129 :
130 E : q.set_max_quarantine_size(15);
131 :
132 E : EXPECT_TRUE(q.Push(o).push_successful);
133 E : EXPECT_EQ(10u, q.GetSizeForTesting());
134 E : EXPECT_EQ(1u, q.GetCountForTesting());
135 :
136 E : EXPECT_FALSE(q.Pop(&o).pop_successful);
137 E : EXPECT_EQ(10u, q.GetSizeForTesting());
138 E : EXPECT_EQ(1u, q.GetCountForTesting());
139 :
140 E : EXPECT_TRUE(q.Push(o).push_successful);
141 E : EXPECT_EQ(20u, q.GetSizeForTesting());
142 E : EXPECT_EQ(2u, q.GetCountForTesting());
143 :
144 E : EXPECT_TRUE(q.Pop(&o).pop_successful);
145 E : EXPECT_EQ(10u, q.GetSizeForTesting());
146 E : EXPECT_EQ(1u, q.GetCountForTesting());
147 :
148 E : EXPECT_FALSE(q.Pop(&o).pop_successful);
149 E : EXPECT_EQ(10u, q.GetSizeForTesting());
150 E : EXPECT_EQ(1u, q.GetCountForTesting());
151 E : }
152 :
153 E : TEST(SizeLimitedQuarantineTest, EmptyWorks) {
154 E : TestQuarantine q;
155 E : DummyObject o(10);
156 :
157 E : EXPECT_TRUE(q.Push(o).push_successful);
158 E : EXPECT_TRUE(q.Push(o).push_successful);
159 E : EXPECT_TRUE(q.Push(o).push_successful);
160 E : EXPECT_EQ(30u, q.GetSizeForTesting());
161 E : EXPECT_EQ(3u, q.GetCountForTesting());
162 :
163 E : DummyObjectVector os;
164 E : q.Empty(&os);
165 :
166 E : EXPECT_THAT(os, testing::ElementsAre(o, o, o));
167 E : }
168 :
169 E : TEST(SizeLimitedQuarantineTest, GetQuarantineColor) {
170 E : const size_t kMaxSize = 1000;
171 E : const size_t kOverbudgetSize = 10;
172 :
173 E : TestQuarantine q;
174 E : q.set_max_quarantine_size(kMaxSize);
175 E : q.SetOverbudgetSize(kOverbudgetSize);
176 :
177 : // Test all values to make sure they fit in the right color.
178 E : int i = 0;
179 E : for (; i <= q.GetMaxSizeForColorForTesting(TrimColor::GREEN); i++)
180 E : EXPECT_EQ(TrimColor::GREEN, q.GetQuarantineColor(i));
181 :
182 E : for (; i <= q.GetMaxSizeForColorForTesting(TrimColor::YELLOW); i++)
183 E : EXPECT_EQ(TrimColor::YELLOW, q.GetQuarantineColor(i));
184 :
185 E : for (; i <= q.GetMaxSizeForColorForTesting(TrimColor::RED); i++)
186 E : EXPECT_EQ(TrimColor::RED, q.GetQuarantineColor(i));
187 :
188 : // Testing all the Black values would take too long, so only test the first
189 : // few.
190 E : for (; i < q.GetMaxSizeForColorForTesting(TrimColor::RED) * 2; i++)
191 E : EXPECT_EQ(TrimColor::BLACK, q.GetQuarantineColor(i));
192 E : }
193 :
194 E : TEST(SizeLimitedQuarantineTest, GetMaxSizeForColorForTesting) {
195 E : const size_t kMaxQuarantineSize = 1000;
196 E : const size_t kOverbudgetSize = 2048;
197 :
198 E : TestQuarantine q;
199 E : q.set_max_quarantine_size(kMaxQuarantineSize);
200 :
201 : // There should only be two limits by default.
202 E : EXPECT_EQ(q.GetMaxSizeForColorForTesting(TrimColor::GREEN),
203 E : q.GetMaxSizeForColorForTesting(TrimColor::YELLOW));
204 E : EXPECT_EQ(q.GetMaxSizeForColorForTesting(TrimColor::YELLOW),
205 E : q.GetMaxSizeForColorForTesting(TrimColor::RED));
206 E : EXPECT_LT(q.GetMaxSizeForColorForTesting(TrimColor::RED),
207 E : q.GetMaxSizeForColorForTesting(TrimColor::BLACK));
208 :
209 E : q.SetOverbudgetSize(kOverbudgetSize);
210 : // Yellow is set at the max size.
211 E : EXPECT_EQ(kMaxQuarantineSize,
212 E : q.GetMaxSizeForColorForTesting(TrimColor::YELLOW));
213 : // There should be 4 limits now that an overbudget size is set.
214 E : EXPECT_LT(q.GetMaxSizeForColorForTesting(TrimColor::GREEN),
215 E : q.GetMaxSizeForColorForTesting(TrimColor::YELLOW));
216 E : EXPECT_LT(q.GetMaxSizeForColorForTesting(TrimColor::YELLOW),
217 E : q.GetMaxSizeForColorForTesting(TrimColor::RED));
218 E : EXPECT_LT(q.GetMaxSizeForColorForTesting(TrimColor::RED),
219 E : q.GetMaxSizeForColorForTesting(TrimColor::BLACK));
220 E : }
221 :
222 E : TEST(SizeLimitedQuarantineTest, SetOverbudgetSize) {
223 E : const size_t kMaxQuarantineSize = 10 * 1024;
224 E : const size_t kMinBudgetSize = 1024;
225 E : TestQuarantine q;
226 E : q.set_max_quarantine_size(kMaxQuarantineSize);
227 E : EXPECT_EQ(0, q.GetOverbudgetSizeForTesting());
228 :
229 : // Min is 1k.
230 E : q.SetOverbudgetSize(kMinBudgetSize - 1);
231 E : EXPECT_EQ(kMinBudgetSize, q.GetOverbudgetSizeForTesting());
232 E : q.SetOverbudgetSize(0);
233 :
234 : // Max is max_quarantine_size/2.
235 E : q.SetOverbudgetSize(kMaxQuarantineSize);
236 E : EXPECT_EQ(kMaxQuarantineSize / 2, q.GetOverbudgetSizeForTesting());
237 E : q.SetOverbudgetSize(0);
238 :
239 E : q.SetOverbudgetSize(kMinBudgetSize * 2);
240 E : EXPECT_EQ(kMinBudgetSize * 2, q.GetOverbudgetSizeForTesting());
241 :
242 E : q.SetOverbudgetSize(0);
243 E : EXPECT_EQ(0, q.GetOverbudgetSizeForTesting());
244 E : }
245 :
246 : } // namespace quarantines
247 : } // namespace asan
248 : } // namespace agent
|