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