• 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 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