1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <stdint.h>
6
7 #include "base/at_exit.h"
8 #include "base/memory/aligned_memory.h"
9 #include "base/memory/singleton.h"
10 #include "testing/gtest/include/gtest/gtest.h"
11
12 namespace base {
13 namespace {
14
15 static_assert(DefaultSingletonTraits<int>::kRegisterAtExit == true,
16 "object must be deleted on process exit");
17
18 typedef void (*CallbackFunc)();
19
20 template <size_t alignment>
21 class AlignedData {
22 public:
23 AlignedData() = default;
24 ~AlignedData() = default;
25 alignas(alignment) char data_[alignment];
26 };
27
28 class IntSingleton {
29 public:
GetInstance()30 static IntSingleton* GetInstance() {
31 return Singleton<IntSingleton>::get();
32 }
33
34 int value_;
35 };
36
37 class Init5Singleton {
38 public:
39 struct Trait;
40
GetInstance()41 static Init5Singleton* GetInstance() {
42 return Singleton<Init5Singleton, Trait>::get();
43 }
44
45 int value_;
46 };
47
48 struct Init5Singleton::Trait : public DefaultSingletonTraits<Init5Singleton> {
Newbase::__anon2f1763790111::Init5Singleton::Trait49 static Init5Singleton* New() {
50 Init5Singleton* instance = new Init5Singleton();
51 instance->value_ = 5;
52 return instance;
53 }
54 };
55
SingletonInt()56 int* SingletonInt() {
57 return &IntSingleton::GetInstance()->value_;
58 }
59
SingletonInt5()60 int* SingletonInt5() {
61 return &Init5Singleton::GetInstance()->value_;
62 }
63
64 template <typename Type>
65 struct CallbackTrait : public DefaultSingletonTraits<Type> {
Deletebase::__anon2f1763790111::CallbackTrait66 static void Delete(Type* instance) {
67 if (instance->callback_)
68 (instance->callback_)();
69 DefaultSingletonTraits<Type>::Delete(instance);
70 }
71 };
72
73 class CallbackSingleton {
74 public:
CallbackSingleton()75 CallbackSingleton() : callback_(nullptr) {}
76 CallbackFunc callback_;
77 };
78
79 class CallbackSingletonWithNoLeakTrait : public CallbackSingleton {
80 public:
81 struct Trait : public CallbackTrait<CallbackSingletonWithNoLeakTrait> { };
82
CallbackSingletonWithNoLeakTrait()83 CallbackSingletonWithNoLeakTrait() : CallbackSingleton() { }
84
GetInstance()85 static CallbackSingletonWithNoLeakTrait* GetInstance() {
86 return Singleton<CallbackSingletonWithNoLeakTrait, Trait>::get();
87 }
88 };
89
90 class CallbackSingletonWithLeakTrait : public CallbackSingleton {
91 public:
92 struct Trait : public CallbackTrait<CallbackSingletonWithLeakTrait> {
93 static const bool kRegisterAtExit = false;
94 };
95
CallbackSingletonWithLeakTrait()96 CallbackSingletonWithLeakTrait() : CallbackSingleton() { }
97
GetInstance()98 static CallbackSingletonWithLeakTrait* GetInstance() {
99 return Singleton<CallbackSingletonWithLeakTrait, Trait>::get();
100 }
101 };
102
103 class CallbackSingletonWithStaticTrait : public CallbackSingleton {
104 public:
105 struct Trait;
106
CallbackSingletonWithStaticTrait()107 CallbackSingletonWithStaticTrait() : CallbackSingleton() { }
108
GetInstance()109 static CallbackSingletonWithStaticTrait* GetInstance() {
110 return Singleton<CallbackSingletonWithStaticTrait, Trait>::get();
111 }
112 };
113
114 struct CallbackSingletonWithStaticTrait::Trait
115 : public StaticMemorySingletonTraits<CallbackSingletonWithStaticTrait> {
Deletebase::__anon2f1763790111::CallbackSingletonWithStaticTrait::Trait116 static void Delete(CallbackSingletonWithStaticTrait* instance) {
117 if (instance->callback_)
118 (instance->callback_)();
119 StaticMemorySingletonTraits<CallbackSingletonWithStaticTrait>::Delete(
120 instance);
121 }
122 };
123
124 template <class Type>
125 class AlignedTestSingleton {
126 public:
127 AlignedTestSingleton() = default;
128 ~AlignedTestSingleton() = default;
GetInstance()129 static AlignedTestSingleton* GetInstance() {
130 return Singleton<AlignedTestSingleton,
131 StaticMemorySingletonTraits<AlignedTestSingleton>>::get();
132 }
133
134 Type type_;
135 };
136
137
SingletonNoLeak(CallbackFunc CallOnQuit)138 void SingletonNoLeak(CallbackFunc CallOnQuit) {
139 CallbackSingletonWithNoLeakTrait::GetInstance()->callback_ = CallOnQuit;
140 }
141
SingletonLeak(CallbackFunc CallOnQuit)142 void SingletonLeak(CallbackFunc CallOnQuit) {
143 CallbackSingletonWithLeakTrait::GetInstance()->callback_ = CallOnQuit;
144 }
145
GetLeakySingleton()146 CallbackFunc* GetLeakySingleton() {
147 return &CallbackSingletonWithLeakTrait::GetInstance()->callback_;
148 }
149
DeleteLeakySingleton()150 void DeleteLeakySingleton() {
151 DefaultSingletonTraits<CallbackSingletonWithLeakTrait>::Delete(
152 CallbackSingletonWithLeakTrait::GetInstance());
153 }
154
SingletonStatic(CallbackFunc CallOnQuit)155 void SingletonStatic(CallbackFunc CallOnQuit) {
156 CallbackSingletonWithStaticTrait::GetInstance()->callback_ = CallOnQuit;
157 }
158
GetStaticSingleton()159 CallbackFunc* GetStaticSingleton() {
160 CallbackSingletonWithStaticTrait* instance =
161 CallbackSingletonWithStaticTrait::GetInstance();
162 if (instance == nullptr) {
163 return nullptr;
164 } else {
165 return &instance->callback_;
166 }
167 }
168
169 class SingletonTest : public testing::Test {
170 public:
171 SingletonTest() = default;
172
SetUp()173 void SetUp() override {
174 non_leak_called_ = false;
175 leaky_called_ = false;
176 static_called_ = false;
177 }
178
179 protected:
VerifiesCallbacks()180 void VerifiesCallbacks() {
181 EXPECT_TRUE(non_leak_called_);
182 EXPECT_FALSE(leaky_called_);
183 EXPECT_TRUE(static_called_);
184 non_leak_called_ = false;
185 leaky_called_ = false;
186 static_called_ = false;
187 }
188
VerifiesCallbacksNotCalled()189 void VerifiesCallbacksNotCalled() {
190 EXPECT_FALSE(non_leak_called_);
191 EXPECT_FALSE(leaky_called_);
192 EXPECT_FALSE(static_called_);
193 non_leak_called_ = false;
194 leaky_called_ = false;
195 static_called_ = false;
196 }
197
CallbackNoLeak()198 static void CallbackNoLeak() {
199 non_leak_called_ = true;
200 }
201
CallbackLeak()202 static void CallbackLeak() {
203 leaky_called_ = true;
204 }
205
CallbackStatic()206 static void CallbackStatic() {
207 static_called_ = true;
208 }
209
210 private:
211 static bool non_leak_called_;
212 static bool leaky_called_;
213 static bool static_called_;
214 };
215
216 bool SingletonTest::non_leak_called_ = false;
217 bool SingletonTest::leaky_called_ = false;
218 bool SingletonTest::static_called_ = false;
219
TEST_F(SingletonTest,Basic)220 TEST_F(SingletonTest, Basic) {
221 int* singleton_int;
222 int* singleton_int_5;
223 CallbackFunc* leaky_singleton;
224 CallbackFunc* static_singleton;
225
226 {
227 ShadowingAtExitManager sem;
228 {
229 singleton_int = SingletonInt();
230 }
231 // Ensure POD type initialization.
232 EXPECT_EQ(*singleton_int, 0);
233 *singleton_int = 1;
234
235 EXPECT_EQ(singleton_int, SingletonInt());
236 EXPECT_EQ(*singleton_int, 1);
237
238 {
239 singleton_int_5 = SingletonInt5();
240 }
241 // Is default initialized to 5.
242 EXPECT_EQ(*singleton_int_5, 5);
243
244 SingletonNoLeak(&CallbackNoLeak);
245 SingletonLeak(&CallbackLeak);
246 SingletonStatic(&CallbackStatic);
247 static_singleton = GetStaticSingleton();
248 leaky_singleton = GetLeakySingleton();
249 EXPECT_TRUE(leaky_singleton);
250 }
251
252 // Verify that only the expected callback has been called.
253 VerifiesCallbacks();
254 // Delete the leaky singleton.
255 DeleteLeakySingleton();
256
257 // The static singleton can't be acquired post-atexit.
258 EXPECT_EQ(nullptr, GetStaticSingleton());
259
260 {
261 ShadowingAtExitManager sem;
262 // Verifiy that the variables were reset.
263 {
264 singleton_int = SingletonInt();
265 EXPECT_EQ(*singleton_int, 0);
266 }
267 {
268 singleton_int_5 = SingletonInt5();
269 EXPECT_EQ(*singleton_int_5, 5);
270 }
271 {
272 // Resurrect the static singleton, and assert that it
273 // still points to the same (static) memory.
274 CallbackSingletonWithStaticTrait::Trait::ResurrectForTesting();
275 EXPECT_EQ(GetStaticSingleton(), static_singleton);
276 }
277 }
278 // The leaky singleton shouldn't leak since SingletonLeak has not been called.
279 VerifiesCallbacksNotCalled();
280 }
281
TEST_F(SingletonTest,Alignment)282 TEST_F(SingletonTest, Alignment) {
283 // Create some static singletons with increasing sizes and alignment
284 // requirements. By ordering this way, the linker will need to do some work to
285 // ensure proper alignment of the static data.
286 AlignedTestSingleton<int32_t>* align4 =
287 AlignedTestSingleton<int32_t>::GetInstance();
288 AlignedTestSingleton<AlignedData<32>>* align32 =
289 AlignedTestSingleton<AlignedData<32>>::GetInstance();
290 AlignedTestSingleton<AlignedData<128>>* align128 =
291 AlignedTestSingleton<AlignedData<128>>::GetInstance();
292 AlignedTestSingleton<AlignedData<4096>>* align4096 =
293 AlignedTestSingleton<AlignedData<4096>>::GetInstance();
294
295 EXPECT_TRUE(IsAligned(align4, 4));
296 EXPECT_TRUE(IsAligned(align32, 32));
297 EXPECT_TRUE(IsAligned(align128, 128));
298 EXPECT_TRUE(IsAligned(align4096, 4096));
299 }
300
301 } // namespace
302 } // namespace base
303