• 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 "base/memory/weak_ptr.h"
6 
7 #include <string>
8 
9 #include "base/bind.h"
10 #include "base/debug/leak_annotations.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/synchronization/waitable_event.h"
14 #include "base/threading/thread.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 
17 namespace base {
18 namespace {
19 
20 template <class T>
21 class OffThreadObjectCreator {
22  public:
NewObject()23   static T* NewObject() {
24     T* result;
25     {
26       Thread creator_thread("creator_thread");
27       creator_thread.Start();
28       creator_thread.message_loop()->PostTask(
29           FROM_HERE,
30           base::Bind(OffThreadObjectCreator::CreateObject, &result));
31     }
32     DCHECK(result);  // We synchronized on thread destruction above.
33     return result;
34   }
35  private:
CreateObject(T ** result)36   static void CreateObject(T** result) {
37     *result = new T;
38   }
39 };
40 
41 struct Base {
42   std::string member;
43 };
44 struct Derived : public Base {};
45 
46 struct TargetBase {};
47 struct Target : public TargetBase, public SupportsWeakPtr<Target> {};
48 struct DerivedTarget : public Target {};
49 struct Arrow {
50   WeakPtr<Target> target;
51 };
52 struct TargetWithFactory : public Target {
TargetWithFactorybase::__anon86d82c370111::TargetWithFactory53   TargetWithFactory() : factory(this) {}
54   WeakPtrFactory<Target> factory;
55 };
56 
57 // Helper class to create and destroy weak pointer copies
58 // and delete objects on a background thread.
59 class BackgroundThread : public Thread {
60  public:
BackgroundThread()61   BackgroundThread() : Thread("owner_thread") {}
62 
~BackgroundThread()63   virtual ~BackgroundThread() {
64     Stop();
65   }
66 
CreateArrowFromTarget(Arrow ** arrow,Target * target)67   void CreateArrowFromTarget(Arrow** arrow, Target* target) {
68     WaitableEvent completion(true, false);
69     message_loop()->PostTask(
70         FROM_HERE,
71         base::Bind(&BackgroundThread::DoCreateArrowFromTarget,
72                    arrow, target, &completion));
73     completion.Wait();
74   }
75 
CreateArrowFromArrow(Arrow ** arrow,const Arrow * other)76   void CreateArrowFromArrow(Arrow** arrow, const Arrow* other) {
77     WaitableEvent completion(true, false);
78     message_loop()->PostTask(
79         FROM_HERE,
80         base::Bind(&BackgroundThread::DoCreateArrowFromArrow,
81                    arrow, other, &completion));
82     completion.Wait();
83   }
84 
DeleteTarget(Target * object)85   void DeleteTarget(Target* object) {
86     WaitableEvent completion(true, false);
87     message_loop()->PostTask(
88         FROM_HERE,
89         base::Bind(&BackgroundThread::DoDeleteTarget, object, &completion));
90     completion.Wait();
91   }
92 
CopyAndAssignArrow(Arrow * object)93   void CopyAndAssignArrow(Arrow* object) {
94     WaitableEvent completion(true, false);
95     message_loop()->PostTask(
96         FROM_HERE,
97         base::Bind(&BackgroundThread::DoCopyAndAssignArrow,
98                    object, &completion));
99     completion.Wait();
100   }
101 
CopyAndAssignArrowBase(Arrow * object)102   void CopyAndAssignArrowBase(Arrow* object) {
103     WaitableEvent completion(true, false);
104     message_loop()->PostTask(
105         FROM_HERE,
106         base::Bind(&BackgroundThread::DoCopyAndAssignArrowBase,
107                    object, &completion));
108     completion.Wait();
109   }
110 
DeleteArrow(Arrow * object)111   void DeleteArrow(Arrow* object) {
112     WaitableEvent completion(true, false);
113     message_loop()->PostTask(
114         FROM_HERE,
115         base::Bind(&BackgroundThread::DoDeleteArrow, object, &completion));
116     completion.Wait();
117   }
118 
DeRef(const Arrow * arrow)119   Target* DeRef(const Arrow* arrow) {
120     WaitableEvent completion(true, false);
121     Target* result = NULL;
122     message_loop()->PostTask(
123         FROM_HERE,
124         base::Bind(&BackgroundThread::DoDeRef, arrow, &result, &completion));
125     completion.Wait();
126     return result;
127   }
128 
129  protected:
DoCreateArrowFromArrow(Arrow ** arrow,const Arrow * other,WaitableEvent * completion)130   static void DoCreateArrowFromArrow(Arrow** arrow,
131                                      const Arrow* other,
132                                      WaitableEvent* completion) {
133     *arrow = new Arrow;
134     **arrow = *other;
135     completion->Signal();
136   }
137 
DoCreateArrowFromTarget(Arrow ** arrow,Target * target,WaitableEvent * completion)138   static void DoCreateArrowFromTarget(Arrow** arrow,
139                                       Target* target,
140                                       WaitableEvent* completion) {
141     *arrow = new Arrow;
142     (*arrow)->target = target->AsWeakPtr();
143     completion->Signal();
144   }
145 
DoDeRef(const Arrow * arrow,Target ** result,WaitableEvent * completion)146   static void DoDeRef(const Arrow* arrow,
147                       Target** result,
148                       WaitableEvent* completion) {
149     *result = arrow->target.get();
150     completion->Signal();
151   }
152 
DoDeleteTarget(Target * object,WaitableEvent * completion)153   static void DoDeleteTarget(Target* object, WaitableEvent* completion) {
154     delete object;
155     completion->Signal();
156   }
157 
DoCopyAndAssignArrow(Arrow * object,WaitableEvent * completion)158   static void DoCopyAndAssignArrow(Arrow* object, WaitableEvent* completion) {
159     // Copy constructor.
160     Arrow a = *object;
161     // Assignment operator.
162     *object = a;
163     completion->Signal();
164   }
165 
DoCopyAndAssignArrowBase(Arrow * object,WaitableEvent * completion)166   static void DoCopyAndAssignArrowBase(
167       Arrow* object,
168       WaitableEvent* completion) {
169     // Copy constructor.
170     WeakPtr<TargetBase> b = object->target;
171     // Assignment operator.
172     WeakPtr<TargetBase> c;
173     c = object->target;
174     completion->Signal();
175   }
176 
DoDeleteArrow(Arrow * object,WaitableEvent * completion)177   static void DoDeleteArrow(Arrow* object, WaitableEvent* completion) {
178     delete object;
179     completion->Signal();
180   }
181 };
182 
183 }  // namespace
184 
TEST(WeakPtrFactoryTest,Basic)185 TEST(WeakPtrFactoryTest, Basic) {
186   int data;
187   WeakPtrFactory<int> factory(&data);
188   WeakPtr<int> ptr = factory.GetWeakPtr();
189   EXPECT_EQ(&data, ptr.get());
190 }
191 
TEST(WeakPtrFactoryTest,Comparison)192 TEST(WeakPtrFactoryTest, Comparison) {
193   int data;
194   WeakPtrFactory<int> factory(&data);
195   WeakPtr<int> ptr = factory.GetWeakPtr();
196   WeakPtr<int> ptr2 = ptr;
197   EXPECT_EQ(ptr.get(), ptr2.get());
198 }
199 
TEST(WeakPtrFactoryTest,OutOfScope)200 TEST(WeakPtrFactoryTest, OutOfScope) {
201   WeakPtr<int> ptr;
202   EXPECT_EQ(NULL, ptr.get());
203   {
204     int data;
205     WeakPtrFactory<int> factory(&data);
206     ptr = factory.GetWeakPtr();
207   }
208   EXPECT_EQ(NULL, ptr.get());
209 }
210 
TEST(WeakPtrFactoryTest,Multiple)211 TEST(WeakPtrFactoryTest, Multiple) {
212   WeakPtr<int> a, b;
213   {
214     int data;
215     WeakPtrFactory<int> factory(&data);
216     a = factory.GetWeakPtr();
217     b = factory.GetWeakPtr();
218     EXPECT_EQ(&data, a.get());
219     EXPECT_EQ(&data, b.get());
220   }
221   EXPECT_EQ(NULL, a.get());
222   EXPECT_EQ(NULL, b.get());
223 }
224 
TEST(WeakPtrFactoryTest,MultipleStaged)225 TEST(WeakPtrFactoryTest, MultipleStaged) {
226   WeakPtr<int> a;
227   {
228     int data;
229     WeakPtrFactory<int> factory(&data);
230     a = factory.GetWeakPtr();
231     {
232       WeakPtr<int> b = factory.GetWeakPtr();
233     }
234     EXPECT_TRUE(NULL != a.get());
235   }
236   EXPECT_EQ(NULL, a.get());
237 }
238 
TEST(WeakPtrFactoryTest,Dereference)239 TEST(WeakPtrFactoryTest, Dereference) {
240   Base data;
241   data.member = "123456";
242   WeakPtrFactory<Base> factory(&data);
243   WeakPtr<Base> ptr = factory.GetWeakPtr();
244   EXPECT_EQ(&data, ptr.get());
245   EXPECT_EQ(data.member, (*ptr).member);
246   EXPECT_EQ(data.member, ptr->member);
247 }
248 
TEST(WeakPtrFactoryTest,UpCast)249 TEST(WeakPtrFactoryTest, UpCast) {
250   Derived data;
251   WeakPtrFactory<Derived> factory(&data);
252   WeakPtr<Base> ptr = factory.GetWeakPtr();
253   ptr = factory.GetWeakPtr();
254   EXPECT_EQ(ptr.get(), &data);
255 }
256 
TEST(WeakPtrTest,SupportsWeakPtr)257 TEST(WeakPtrTest, SupportsWeakPtr) {
258   Target target;
259   WeakPtr<Target> ptr = target.AsWeakPtr();
260   EXPECT_EQ(&target, ptr.get());
261 }
262 
TEST(WeakPtrTest,DerivedTarget)263 TEST(WeakPtrTest, DerivedTarget) {
264   DerivedTarget target;
265   WeakPtr<DerivedTarget> ptr = AsWeakPtr(&target);
266   EXPECT_EQ(&target, ptr.get());
267 }
268 
TEST(WeakPtrTest,InvalidateWeakPtrs)269 TEST(WeakPtrTest, InvalidateWeakPtrs) {
270   int data;
271   WeakPtrFactory<int> factory(&data);
272   WeakPtr<int> ptr = factory.GetWeakPtr();
273   EXPECT_EQ(&data, ptr.get());
274   EXPECT_TRUE(factory.HasWeakPtrs());
275   factory.InvalidateWeakPtrs();
276   EXPECT_EQ(NULL, ptr.get());
277   EXPECT_FALSE(factory.HasWeakPtrs());
278 }
279 
TEST(WeakPtrTest,HasWeakPtrs)280 TEST(WeakPtrTest, HasWeakPtrs) {
281   int data;
282   WeakPtrFactory<int> factory(&data);
283   {
284     WeakPtr<int> ptr = factory.GetWeakPtr();
285     EXPECT_TRUE(factory.HasWeakPtrs());
286   }
287   EXPECT_FALSE(factory.HasWeakPtrs());
288 }
289 
TEST(WeakPtrTest,ObjectAndWeakPtrOnDifferentThreads)290 TEST(WeakPtrTest, ObjectAndWeakPtrOnDifferentThreads) {
291   // Test that it is OK to create an object that supports WeakPtr on one thread,
292   // but use it on another.  This tests that we do not trip runtime checks that
293   // ensure that a WeakPtr is not used by multiple threads.
294   scoped_ptr<Target> target(OffThreadObjectCreator<Target>::NewObject());
295   WeakPtr<Target> weak_ptr = target->AsWeakPtr();
296   EXPECT_EQ(target.get(), weak_ptr.get());
297 }
298 
TEST(WeakPtrTest,WeakPtrInitiateAndUseOnDifferentThreads)299 TEST(WeakPtrTest, WeakPtrInitiateAndUseOnDifferentThreads) {
300   // Test that it is OK to create an object that has a WeakPtr member on one
301   // thread, but use it on another.  This tests that we do not trip runtime
302   // checks that ensure that a WeakPtr is not used by multiple threads.
303   scoped_ptr<Arrow> arrow(OffThreadObjectCreator<Arrow>::NewObject());
304   Target target;
305   arrow->target = target.AsWeakPtr();
306   EXPECT_EQ(&target, arrow->target.get());
307 }
308 
TEST(WeakPtrTest,MoveOwnershipImplicitly)309 TEST(WeakPtrTest, MoveOwnershipImplicitly) {
310   // Move object ownership to another thread by releasing all weak pointers
311   // on the original thread first, and then establish WeakPtr on a different
312   // thread.
313   BackgroundThread background;
314   background.Start();
315 
316   Target* target = new Target();
317   {
318     WeakPtr<Target> weak_ptr = target->AsWeakPtr();
319     // Main thread deletes the WeakPtr, then the thread ownership of the
320     // object can be implicitly moved.
321   }
322   Arrow* arrow;
323 
324   // Background thread creates WeakPtr(and implicitly owns the object).
325   background.CreateArrowFromTarget(&arrow, target);
326   EXPECT_EQ(background.DeRef(arrow), target);
327 
328   {
329     // Main thread creates another WeakPtr, but this does not trigger implicitly
330     // thread ownership move.
331     Arrow arrow;
332     arrow.target = target->AsWeakPtr();
333 
334     // The new WeakPtr is owned by background thread.
335     EXPECT_EQ(target, background.DeRef(&arrow));
336   }
337 
338   // Target can only be deleted on background thread.
339   background.DeleteTarget(target);
340   background.DeleteArrow(arrow);
341 }
342 
TEST(WeakPtrTest,MoveOwnershipOfUnreferencedObject)343 TEST(WeakPtrTest, MoveOwnershipOfUnreferencedObject) {
344   BackgroundThread background;
345   background.Start();
346 
347   Arrow* arrow;
348   {
349     Target target;
350     // Background thread creates WeakPtr.
351     background.CreateArrowFromTarget(&arrow, &target);
352 
353     // Bind to background thread.
354     EXPECT_EQ(&target, background.DeRef(arrow));
355 
356     // Release the only WeakPtr.
357     arrow->target.reset();
358 
359     // Now we should be able to create a new reference from this thread.
360     arrow->target = target.AsWeakPtr();
361 
362     // Re-bind to main thread.
363     EXPECT_EQ(&target, arrow->target.get());
364 
365     // And the main thread can now delete the target.
366   }
367 
368   delete arrow;
369 }
370 
TEST(WeakPtrTest,MoveOwnershipAfterInvalidate)371 TEST(WeakPtrTest, MoveOwnershipAfterInvalidate) {
372   BackgroundThread background;
373   background.Start();
374 
375   Arrow arrow;
376   scoped_ptr<TargetWithFactory> target(new TargetWithFactory);
377 
378   // Bind to main thread.
379   arrow.target = target->factory.GetWeakPtr();
380   EXPECT_EQ(target.get(), arrow.target.get());
381 
382   target->factory.InvalidateWeakPtrs();
383   EXPECT_EQ(NULL, arrow.target.get());
384 
385   arrow.target = target->factory.GetWeakPtr();
386   // Re-bind to background thread.
387   EXPECT_EQ(target.get(), background.DeRef(&arrow));
388 
389   // And the background thread can now delete the target.
390   background.DeleteTarget(target.release());
391 }
392 
TEST(WeakPtrTest,MainThreadRefOutlivesBackgroundThreadRef)393 TEST(WeakPtrTest, MainThreadRefOutlivesBackgroundThreadRef) {
394   // Originating thread has a WeakPtr that outlives others.
395   // - Main thread creates a WeakPtr
396   // - Background thread creates a WeakPtr copy from the one in main thread
397   // - Destruct the WeakPtr on background thread
398   // - Destruct the WeakPtr on main thread
399   BackgroundThread background;
400   background.Start();
401 
402   Target target;
403   Arrow arrow;
404   arrow.target = target.AsWeakPtr();
405 
406   Arrow* arrow_copy;
407   background.CreateArrowFromArrow(&arrow_copy, &arrow);
408   EXPECT_EQ(arrow_copy->target.get(), &target);
409   background.DeleteArrow(arrow_copy);
410 }
411 
TEST(WeakPtrTest,BackgroundThreadRefOutlivesMainThreadRef)412 TEST(WeakPtrTest, BackgroundThreadRefOutlivesMainThreadRef) {
413   // Originating thread drops all references before another thread.
414   // - Main thread creates a WeakPtr and passes copy to background thread
415   // - Destruct the pointer on main thread
416   // - Destruct the pointer on background thread
417   BackgroundThread background;
418   background.Start();
419 
420   Target target;
421   Arrow* arrow_copy;
422   {
423     Arrow arrow;
424     arrow.target = target.AsWeakPtr();
425     background.CreateArrowFromArrow(&arrow_copy, &arrow);
426   }
427   EXPECT_EQ(arrow_copy->target.get(), &target);
428   background.DeleteArrow(arrow_copy);
429 }
430 
TEST(WeakPtrTest,OwnerThreadDeletesObject)431 TEST(WeakPtrTest, OwnerThreadDeletesObject) {
432   // Originating thread invalidates WeakPtrs while its held by other thread.
433   // - Main thread creates WeakPtr and passes Copy to background thread
434   // - Object gets destroyed on main thread
435   //   (invalidates WeakPtr on background thread)
436   // - WeakPtr gets destroyed on Thread B
437   BackgroundThread background;
438   background.Start();
439   Arrow* arrow_copy;
440   {
441     Target target;
442     Arrow arrow;
443     arrow.target = target.AsWeakPtr();
444     background.CreateArrowFromArrow(&arrow_copy, &arrow);
445   }
446   EXPECT_EQ(NULL, arrow_copy->target.get());
447   background.DeleteArrow(arrow_copy);
448 }
449 
TEST(WeakPtrTest,NonOwnerThreadCanCopyAndAssignWeakPtr)450 TEST(WeakPtrTest, NonOwnerThreadCanCopyAndAssignWeakPtr) {
451   // Main thread creates a Target object.
452   Target target;
453   // Main thread creates an arrow referencing the Target.
454   Arrow *arrow = new Arrow();
455   arrow->target = target.AsWeakPtr();
456 
457   // Background can copy and assign arrow (as well as the WeakPtr inside).
458   BackgroundThread background;
459   background.Start();
460   background.CopyAndAssignArrow(arrow);
461   background.DeleteArrow(arrow);
462 }
463 
TEST(WeakPtrTest,NonOwnerThreadCanCopyAndAssignWeakPtrBase)464 TEST(WeakPtrTest, NonOwnerThreadCanCopyAndAssignWeakPtrBase) {
465   // Main thread creates a Target object.
466   Target target;
467   // Main thread creates an arrow referencing the Target.
468   Arrow *arrow = new Arrow();
469   arrow->target = target.AsWeakPtr();
470 
471   // Background can copy and assign arrow's WeakPtr to a base class WeakPtr.
472   BackgroundThread background;
473   background.Start();
474   background.CopyAndAssignArrowBase(arrow);
475   background.DeleteArrow(arrow);
476 }
477 
TEST(WeakPtrTest,NonOwnerThreadCanDeleteWeakPtr)478 TEST(WeakPtrTest, NonOwnerThreadCanDeleteWeakPtr) {
479   // Main thread creates a Target object.
480   Target target;
481   // Main thread creates an arrow referencing the Target.
482   Arrow* arrow = new Arrow();
483   arrow->target = target.AsWeakPtr();
484 
485   // Background can delete arrow (as well as the WeakPtr inside).
486   BackgroundThread background;
487   background.Start();
488   background.DeleteArrow(arrow);
489 }
490 
491 #if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) && GTEST_HAS_DEATH_TEST
492 
TEST(WeakPtrDeathTest,WeakPtrCopyDoesNotChangeThreadBinding)493 TEST(WeakPtrDeathTest, WeakPtrCopyDoesNotChangeThreadBinding) {
494   // The default style "fast" does not support multi-threaded tests
495   // (introduces deadlock on Linux).
496   ::testing::FLAGS_gtest_death_test_style = "threadsafe";
497 
498   BackgroundThread background;
499   background.Start();
500 
501   // Main thread creates a Target object.
502   Target target;
503   // Main thread creates an arrow referencing the Target.
504   Arrow arrow;
505   arrow.target = target.AsWeakPtr();
506 
507   // Background copies the WeakPtr.
508   Arrow* arrow_copy;
509   background.CreateArrowFromArrow(&arrow_copy, &arrow);
510 
511   // The copy is still bound to main thread so I can deref.
512   EXPECT_EQ(arrow.target.get(), arrow_copy->target.get());
513 
514   // Although background thread created the copy, it can not deref the copied
515   // WeakPtr.
516   ASSERT_DEATH(background.DeRef(arrow_copy), "");
517 
518   background.DeleteArrow(arrow_copy);
519 }
520 
TEST(WeakPtrDeathTest,NonOwnerThreadDereferencesWeakPtrAfterReference)521 TEST(WeakPtrDeathTest, NonOwnerThreadDereferencesWeakPtrAfterReference) {
522   // The default style "fast" does not support multi-threaded tests
523   // (introduces deadlock on Linux).
524   ::testing::FLAGS_gtest_death_test_style = "threadsafe";
525 
526   // Main thread creates a Target object.
527   Target target;
528 
529   // Main thread creates an arrow referencing the Target (so target's
530   // thread ownership can not be implicitly moved).
531   Arrow arrow;
532   arrow.target = target.AsWeakPtr();
533   arrow.target.get();
534 
535   // Background thread tries to deref target, which violates thread ownership.
536   BackgroundThread background;
537   background.Start();
538   ASSERT_DEATH(background.DeRef(&arrow), "");
539 }
540 
TEST(WeakPtrDeathTest,NonOwnerThreadDeletesWeakPtrAfterReference)541 TEST(WeakPtrDeathTest, NonOwnerThreadDeletesWeakPtrAfterReference) {
542   // The default style "fast" does not support multi-threaded tests
543   // (introduces deadlock on Linux).
544   ::testing::FLAGS_gtest_death_test_style = "threadsafe";
545 
546   scoped_ptr<Target> target(new Target());
547 
548   // Main thread creates an arrow referencing the Target.
549   Arrow arrow;
550   arrow.target = target->AsWeakPtr();
551 
552   // Background thread tries to deref target, binding it to the thread.
553   BackgroundThread background;
554   background.Start();
555   background.DeRef(&arrow);
556 
557   // Main thread deletes Target, violating thread binding.
558   ASSERT_DEATH(target.reset(), "");
559 
560   // |target.reset()| died so |target| still holds the object, so we
561   // must pass it to the background thread to teardown.
562   background.DeleteTarget(target.release());
563 }
564 
TEST(WeakPtrDeathTest,NonOwnerThreadDeletesObjectAfterReference)565 TEST(WeakPtrDeathTest, NonOwnerThreadDeletesObjectAfterReference) {
566   // The default style "fast" does not support multi-threaded tests
567   // (introduces deadlock on Linux).
568   ::testing::FLAGS_gtest_death_test_style = "threadsafe";
569 
570   scoped_ptr<Target> target(new Target());
571 
572   // Main thread creates an arrow referencing the Target, and references it, so
573   // that it becomes bound to the thread.
574   Arrow arrow;
575   arrow.target = target->AsWeakPtr();
576   arrow.target.get();
577 
578   // Background thread tries to delete target, volating thread binding.
579   BackgroundThread background;
580   background.Start();
581   ASSERT_DEATH(background.DeleteTarget(target.release()), "");
582 }
583 
TEST(WeakPtrDeathTest,NonOwnerThreadReferencesObjectAfterDeletion)584 TEST(WeakPtrDeathTest, NonOwnerThreadReferencesObjectAfterDeletion) {
585   // The default style "fast" does not support multi-threaded tests
586   // (introduces deadlock on Linux).
587   ::testing::FLAGS_gtest_death_test_style = "threadsafe";
588 
589   scoped_ptr<Target> target(new Target());
590 
591   // Main thread creates an arrow referencing the Target.
592   Arrow arrow;
593   arrow.target = target->AsWeakPtr();
594 
595   // Background thread tries to delete target, binding the object to the thread.
596   BackgroundThread background;
597   background.Start();
598   background.DeleteTarget(target.release());
599 
600   // Main thread attempts to dereference the target, violating thread binding.
601   ASSERT_DEATH(arrow.target.get(), "");
602 }
603 
604 #endif
605 
606 }  // namespace base
607