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