tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

TestWeakPtr.cpp (4348B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "mozilla/WeakPtr.h"
      8 
      9 using mozilla::SupportsWeakPtr;
     10 using mozilla::WeakPtr;
     11 
     12 static char IamB[] = "B";
     13 static char IamC[] = "C";
     14 static char IamD[] = "D";
     15 
     16 class B : public SupportsWeakPtr {
     17 public:
     18  char const* whoAmI() const { return IamB; }
     19 };
     20 
     21 // To have a class C support weak pointers, inherit from SupportsWeakPtr.
     22 class C : public SupportsWeakPtr {
     23 public:
     24  int mNum;
     25 
     26  C() : mNum(0) {}
     27 
     28  ~C() {
     29    // Setting mNum in the destructor allows us to test against use-after-free
     30    // below
     31    mNum = 0xDEAD;
     32  }
     33 
     34  char const* whoAmI() const { return IamC; }
     35 
     36  void act() {}
     37 
     38  bool isConst() { return false; }
     39 
     40  bool isConst() const { return true; }
     41 };
     42 
     43 // Derived from a class that supports weakptr, but doesn't implement itself
     44 // To check upcast works as expected
     45 class D : public B {
     46 public:
     47  char const* whoAmI() const { return IamD; }
     48 };
     49 
     50 bool isConst(C*) { return false; }
     51 
     52 bool isConst(const C*) { return true; }
     53 
     54 int main() {
     55  C* c1 = new C;
     56  MOZ_RELEASE_ASSERT(c1->mNum == 0);
     57 
     58  // Get weak pointers to c1. The first time,
     59  // a reference-counted WeakReference object is created that
     60  // can live beyond the lifetime of 'c1'. The WeakReference
     61  // object will be notified of 'c1's destruction.
     62  WeakPtr<C> w1 = c1;
     63  // Test a weak pointer for validity before using it.
     64  MOZ_RELEASE_ASSERT(w1);
     65  MOZ_RELEASE_ASSERT(w1 == c1);
     66  w1->mNum = 1;
     67  w1->act();
     68 
     69  // Test taking another WeakPtr<C> to c1
     70  WeakPtr<C> w2 = c1;
     71  MOZ_RELEASE_ASSERT(w2);
     72  MOZ_RELEASE_ASSERT(w2 == c1);
     73  MOZ_RELEASE_ASSERT(w2 == w1);
     74  MOZ_RELEASE_ASSERT(w2->mNum == 1);
     75 
     76  // Test a WeakPtr<const C>
     77  WeakPtr<const C> w3const = c1;
     78  MOZ_RELEASE_ASSERT(w3const);
     79  MOZ_RELEASE_ASSERT(w3const == c1);
     80  MOZ_RELEASE_ASSERT(w3const == w1);
     81  MOZ_RELEASE_ASSERT(w3const == w2);
     82  MOZ_RELEASE_ASSERT(w3const->mNum == 1);
     83 
     84  // Test const-correctness of operator-> and operator T*
     85  MOZ_RELEASE_ASSERT(!w1->isConst());
     86  MOZ_RELEASE_ASSERT(w3const->isConst());
     87  MOZ_RELEASE_ASSERT(!isConst(w1));
     88  MOZ_RELEASE_ASSERT(isConst(w3const));
     89 
     90  // Test that when a WeakPtr is destroyed, it does not destroy the object that
     91  // it points to, and it does not affect other WeakPtrs pointing to the same
     92  // object (e.g. it does not destroy the WeakReference object).
     93  {
     94    WeakPtr<C> w4local = c1;
     95    MOZ_RELEASE_ASSERT(w4local == c1);
     96  }
     97  // Now w4local has gone out of scope. If that had destroyed c1, then the
     98  // following would fail for sure (see C::~C()).
     99  MOZ_RELEASE_ASSERT(c1->mNum == 1);
    100  // Check that w4local going out of scope hasn't affected other WeakPtr's
    101  // pointing to c1
    102  MOZ_RELEASE_ASSERT(w1 == c1);
    103  MOZ_RELEASE_ASSERT(w2 == c1);
    104 
    105  // Now construct another C object and test changing what object a WeakPtr
    106  // points to
    107  C* c2 = new C;
    108  c2->mNum = 2;
    109  MOZ_RELEASE_ASSERT(w2->mNum == 1);  // w2 was pointing to c1
    110  w2 = c2;
    111  MOZ_RELEASE_ASSERT(w2);
    112  MOZ_RELEASE_ASSERT(w2 == c2);
    113  MOZ_RELEASE_ASSERT(w2 != c1);
    114  MOZ_RELEASE_ASSERT(w2 != w1);
    115  MOZ_RELEASE_ASSERT(w2->mNum == 2);
    116 
    117  // Destroying the underlying object clears weak pointers to it.
    118  // It should not affect pointers that are not currently pointing to it.
    119  delete c1;
    120  MOZ_RELEASE_ASSERT(!w1, "Deleting an object should clear WeakPtr's to it.");
    121  MOZ_RELEASE_ASSERT(!w3const,
    122                     "Deleting an object should clear WeakPtr's to it.");
    123  MOZ_RELEASE_ASSERT(w2,
    124                     "Deleting an object should not clear WeakPtr that are not "
    125                     "pointing to it.");
    126 
    127  delete c2;
    128  MOZ_RELEASE_ASSERT(!w2, "Deleting an object should clear WeakPtr's to it.");
    129 
    130  // Check that we correctly upcast to the base class supporting weakptr
    131  D* d = new D;
    132  WeakPtr<B> db = d;
    133 
    134  // You should be able to use WeakPtr<D> even if it's a base class which
    135  // implements SupportsWeakPtr.
    136  WeakPtr<D> weakd = d;
    137 
    138  MOZ_RELEASE_ASSERT(db->whoAmI() == IamB);
    139  MOZ_RELEASE_ASSERT(weakd.get() == db.get());
    140 
    141  delete d;
    142 
    143  MOZ_RELEASE_ASSERT(!db);
    144  MOZ_RELEASE_ASSERT(!weakd);
    145 }