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