tor-browser

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

TestUniquePtr.cpp (13222B)


      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 file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include <stddef.h>
      8 
      9 #include <memory>  // For unique_ptr
     10 #include <type_traits>
     11 #include <utility>
     12 
     13 #include "mozilla/Assertions.h"
     14 #include "mozilla/UniquePtr.h"
     15 #include "mozilla/UniquePtrExtensions.h"
     16 #include "mozilla/Vector.h"
     17 
     18 using mozilla::DefaultDelete;
     19 using mozilla::MakeUnique;
     20 using mozilla::UniqueFreePtr;
     21 using mozilla::UniquePtr;
     22 using mozilla::Vector;
     23 
     24 #define CHECK(c)                                  \
     25  do {                                            \
     26    bool cond = !!(c);                            \
     27    MOZ_RELEASE_ASSERT(cond, "Test failed: " #c); \
     28  } while (false)
     29 
     30 typedef UniquePtr<int> NewInt;
     31 static_assert(sizeof(NewInt) == sizeof(int*), "stored most efficiently");
     32 
     33 static size_t gADestructorCalls = 0;
     34 
     35 struct A {
     36 public:
     37  A() : mX(0) {}
     38  virtual ~A() { gADestructorCalls++; }
     39 
     40  int mX;
     41 };
     42 
     43 static size_t gBDestructorCalls = 0;
     44 
     45 struct B : public A {
     46 public:
     47  B() : mY(1) {}
     48  ~B() { gBDestructorCalls++; }
     49 
     50  int mY;
     51 };
     52 
     53 typedef UniquePtr<A> UniqueA;
     54 typedef UniquePtr<B, UniqueA::deleter_type> UniqueB;  // permit interconversion
     55 
     56 static_assert(sizeof(UniqueA) == sizeof(A*), "stored most efficiently");
     57 static_assert(sizeof(UniqueB) == sizeof(B*), "stored most efficiently");
     58 
     59 struct DeleterSubclass : UniqueA::deleter_type {};
     60 
     61 typedef UniquePtr<B, DeleterSubclass> UniqueC;
     62 static_assert(sizeof(UniqueC) == sizeof(B*), "stored most efficiently");
     63 
     64 static UniqueA ReturnUniqueA() { return UniqueA(new B); }
     65 
     66 static UniqueA ReturnLocalA() {
     67  UniqueA a(new A);
     68  return a;
     69 }
     70 
     71 static void TestDeleterType() {
     72  // Make sure UniquePtr will use its deleter's pointer type if it defines one.
     73  typedef int* Ptr;
     74  struct Deleter {
     75    typedef Ptr pointer;
     76    Deleter() = default;
     77    void operator()(int* p) { delete p; }
     78  };
     79  UniquePtr<Ptr, Deleter> u(new int, Deleter());
     80 }
     81 
     82 static bool TestDefaultFreeGuts() {
     83  static_assert(std::is_same_v<NewInt::deleter_type, DefaultDelete<int> >,
     84                "weird deleter?");
     85 
     86  NewInt n1(new int);
     87  CHECK(n1);
     88  CHECK(n1.get() != nullptr);
     89 
     90  n1 = nullptr;
     91  CHECK(!n1);
     92  CHECK(n1.get() == nullptr);
     93 
     94  int* p1 = new int;
     95  n1.reset(p1);
     96  CHECK(n1);
     97  NewInt n2(std::move(n1));
     98  CHECK(!n1);
     99  CHECK(n1.get() == nullptr);
    100  CHECK(n2.get() == p1);
    101 
    102  std::swap(n1, n2);
    103  CHECK(n1.get() == p1);
    104  CHECK(n2.get() == nullptr);
    105 
    106  n1.swap(n2);
    107  CHECK(n1.get() == nullptr);
    108  CHECK(n2.get() == p1);
    109  delete n2.release();
    110 
    111  CHECK(n1.get() == nullptr);
    112  CHECK(n2 == nullptr);
    113  CHECK(nullptr == n2);
    114 
    115  int* p2 = new int;
    116  int* p3 = new int;
    117  n1.reset(p2);
    118  n2.reset(p3);
    119  CHECK(n1.get() == p2);
    120  CHECK(n2.get() == p3);
    121 
    122  n1.swap(n2);
    123  CHECK(n2 != nullptr);
    124  CHECK(nullptr != n2);
    125  CHECK(n2.get() == p2);
    126  CHECK(n1.get() == p3);
    127 
    128  UniqueA a1;
    129  CHECK(a1 == nullptr);
    130  a1.reset(new A);
    131  CHECK(gADestructorCalls == 0);
    132  CHECK(a1->mX == 0);
    133 
    134  B* bp1 = new B;
    135  bp1->mX = 5;
    136  CHECK(gBDestructorCalls == 0);
    137  a1.reset(bp1);
    138  CHECK(gADestructorCalls == 1);
    139  CHECK(a1->mX == 5);
    140  a1.reset(nullptr);
    141  CHECK(gADestructorCalls == 2);
    142  CHECK(gBDestructorCalls == 1);
    143 
    144  B* bp2 = new B;
    145  UniqueB b1(bp2);
    146  UniqueA a2(nullptr);
    147  a2 = std::move(b1);
    148  CHECK(gADestructorCalls == 2);
    149  CHECK(gBDestructorCalls == 1);
    150 
    151  UniqueA a3(std::move(a2));
    152  a3 = nullptr;
    153  CHECK(gADestructorCalls == 3);
    154  CHECK(gBDestructorCalls == 2);
    155 
    156  B* bp3 = new B;
    157  bp3->mX = 42;
    158  UniqueB b2(bp3);
    159  UniqueA a4(std::move(b2));
    160  CHECK(b2.get() == nullptr);
    161  CHECK((*a4).mX == 42);
    162  CHECK(gADestructorCalls == 3);
    163  CHECK(gBDestructorCalls == 2);
    164 
    165  UniqueA a5(new A);
    166  UniqueB b3(new B);
    167  a5 = std::move(b3);
    168  CHECK(gADestructorCalls == 4);
    169  CHECK(gBDestructorCalls == 2);
    170 
    171  ReturnUniqueA();
    172  CHECK(gADestructorCalls == 5);
    173  CHECK(gBDestructorCalls == 3);
    174 
    175  ReturnLocalA();
    176  CHECK(gADestructorCalls == 6);
    177  CHECK(gBDestructorCalls == 3);
    178 
    179  UniqueA a6(ReturnLocalA());
    180  a6 = nullptr;
    181  CHECK(gADestructorCalls == 7);
    182  CHECK(gBDestructorCalls == 3);
    183 
    184  UniqueC c1(new B);
    185  UniqueA a7(new B);
    186  a7 = std::move(c1);
    187  CHECK(gADestructorCalls == 8);
    188  CHECK(gBDestructorCalls == 4);
    189 
    190  c1.reset(new B);
    191 
    192  UniqueA a8(std::move(c1));
    193  CHECK(gADestructorCalls == 8);
    194  CHECK(gBDestructorCalls == 4);
    195 
    196  // These smart pointers still own B resources.
    197  CHECK(a4);
    198  CHECK(a5);
    199  CHECK(a7);
    200  CHECK(a8);
    201  return true;
    202 }
    203 
    204 static bool TestDefaultFree() {
    205  CHECK(TestDefaultFreeGuts());
    206  CHECK(gADestructorCalls == 12);
    207  CHECK(gBDestructorCalls == 8);
    208  return true;
    209 }
    210 
    211 static size_t FreeClassCounter = 0;
    212 
    213 struct FreeClass {
    214 public:
    215  FreeClass() = default;
    216 
    217  void operator()(int* aPtr) {
    218    FreeClassCounter++;
    219    delete aPtr;
    220  }
    221 };
    222 
    223 typedef UniquePtr<int, FreeClass> NewIntCustom;
    224 static_assert(sizeof(NewIntCustom) == sizeof(int*), "stored most efficiently");
    225 
    226 static bool TestFreeClass() {
    227  CHECK(FreeClassCounter == 0);
    228  {
    229    NewIntCustom n1(new int);
    230    CHECK(FreeClassCounter == 0);
    231  }
    232  CHECK(FreeClassCounter == 1);
    233 
    234  NewIntCustom n2;
    235  {
    236    NewIntCustom n3(new int);
    237    CHECK(FreeClassCounter == 1);
    238    n2 = std::move(n3);
    239  }
    240  CHECK(FreeClassCounter == 1);
    241  n2 = nullptr;
    242  CHECK(FreeClassCounter == 2);
    243 
    244  n2.reset(nullptr);
    245  CHECK(FreeClassCounter == 2);
    246  n2.reset(new int);
    247  n2.reset();
    248  CHECK(FreeClassCounter == 3);
    249 
    250  NewIntCustom n4(new int, FreeClass());
    251  CHECK(FreeClassCounter == 3);
    252  n4.reset(new int);
    253  CHECK(FreeClassCounter == 4);
    254  n4.reset();
    255  CHECK(FreeClassCounter == 5);
    256 
    257  FreeClass f;
    258  NewIntCustom n5(new int, f);
    259  CHECK(FreeClassCounter == 5);
    260  int* p = n5.release();
    261  CHECK(FreeClassCounter == 5);
    262  delete p;
    263 
    264  return true;
    265 }
    266 
    267 typedef UniquePtr<int, DefaultDelete<int>&> IntDeleterRef;
    268 typedef UniquePtr<A, DefaultDelete<A>&> ADeleterRef;
    269 typedef UniquePtr<B, DefaultDelete<A>&> BDeleterRef;
    270 
    271 static_assert(sizeof(IntDeleterRef) > sizeof(int*),
    272              "has to be heavier than an int* to store the reference");
    273 static_assert(sizeof(ADeleterRef) > sizeof(A*),
    274              "has to be heavier than an A* to store the reference");
    275 static_assert(sizeof(BDeleterRef) > sizeof(int*),
    276              "has to be heavier than a B* to store the reference");
    277 
    278 static bool TestReferenceDeleterGuts() {
    279  DefaultDelete<int> delInt;
    280  IntDeleterRef id1(new int, delInt);
    281 
    282  IntDeleterRef id2(std::move(id1));
    283  CHECK(id1 == nullptr);
    284  CHECK(nullptr != id2);
    285  CHECK(&id1.get_deleter() == &id2.get_deleter());
    286 
    287  IntDeleterRef id3(std::move(id2));
    288 
    289  DefaultDelete<A> delA;
    290  ADeleterRef a1(new A, delA);
    291  a1.reset(nullptr);
    292  a1.reset(new B);
    293  a1 = nullptr;
    294 
    295  BDeleterRef b1(new B, delA);
    296  a1 = std::move(b1);
    297 
    298  BDeleterRef b2(new B, delA);
    299 
    300  ADeleterRef a2(std::move(b2));
    301 
    302  return true;
    303 }
    304 
    305 static bool TestReferenceDeleter() {
    306  gADestructorCalls = 0;
    307  gBDestructorCalls = 0;
    308 
    309  CHECK(TestReferenceDeleterGuts());
    310 
    311  CHECK(gADestructorCalls == 4);
    312  CHECK(gBDestructorCalls == 3);
    313 
    314  gADestructorCalls = 0;
    315  gBDestructorCalls = 0;
    316  return true;
    317 }
    318 
    319 struct Free {
    320  void operator()(void* aPtr) { free(aPtr); }
    321 };
    322 
    323 static size_t DeleteIntFunctionCallCount = 0;
    324 struct DeleteIntFunction {
    325  void operator()(void* aPtr) {
    326    DeleteIntFunctionCallCount++;
    327    delete[] static_cast<int*>(aPtr);
    328  }
    329 };
    330 
    331 static void SetMallocedInt(UniquePtr<int, Free>& aPtr, int aI) {
    332  int* newPtr = static_cast<int*>(malloc(sizeof(int)));
    333  *newPtr = aI;
    334  aPtr.reset(newPtr);
    335 }
    336 
    337 static UniquePtr<int, Free> MallocedInt(int aI) {
    338  UniquePtr<int, Free> ptr(static_cast<int*>(malloc(sizeof(int))), Free{});
    339  *ptr = aI;
    340  return ptr;
    341 }
    342 static bool TestFunctionReferenceDeleter() {
    343  // Look for allocator mismatches and leaks to verify these bits
    344  UniquePtr<int, Free> i1(MallocedInt(17));
    345  CHECK(*i1 == 17);
    346 
    347  SetMallocedInt(i1, 42);
    348  CHECK(*i1 == 42);
    349 
    350  // These bits use a custom deleter so we can instrument deletion.
    351  {
    352    UniquePtr<int, DeleteIntFunction> i2 =
    353        UniquePtr<int, DeleteIntFunction>(new int[42], DeleteIntFunction{});
    354    CHECK(DeleteIntFunctionCallCount == 0);
    355 
    356    i2.reset(new int[76]);
    357    CHECK(DeleteIntFunctionCallCount == 1);
    358  }
    359 
    360  CHECK(DeleteIntFunctionCallCount == 2);
    361 
    362  return true;
    363 }
    364 
    365 template <typename T>
    366 struct AppendNullptrTwice {
    367  AppendNullptrTwice() = default;
    368 
    369  bool operator()(Vector<T>& vec) {
    370    CHECK(vec.append(nullptr));
    371    CHECK(vec.append(nullptr));
    372    return true;
    373  }
    374 };
    375 
    376 static size_t AAfter;
    377 static size_t BAfter;
    378 
    379 static bool TestVectorGuts() {
    380  Vector<UniqueA> vec;
    381  CHECK(vec.append(new B));
    382  CHECK(vec.append(new A));
    383  CHECK(AppendNullptrTwice<UniqueA>()(vec));
    384  CHECK(vec.append(new B));
    385 
    386  size_t initialLength = vec.length();
    387 
    388  UniqueA* begin = vec.begin();
    389  bool appendA = true;
    390  do {
    391    CHECK(appendA ? vec.append(new A) : vec.append(new B));
    392    appendA = !appendA;
    393  } while (begin == vec.begin());
    394 
    395  size_t numAppended = vec.length() - initialLength;
    396 
    397  BAfter = numAppended / 2;
    398  AAfter = numAppended - numAppended / 2;
    399 
    400  CHECK(gADestructorCalls == 0);
    401  CHECK(gBDestructorCalls == 0);
    402  return true;
    403 }
    404 
    405 static bool TestVector() {
    406  gADestructorCalls = 0;
    407  gBDestructorCalls = 0;
    408 
    409  CHECK(TestVectorGuts());
    410 
    411  CHECK(gADestructorCalls == 3 + AAfter + BAfter);
    412  CHECK(gBDestructorCalls == 2 + BAfter);
    413  return true;
    414 }
    415 
    416 typedef UniquePtr<int[]> IntArray;
    417 static_assert(sizeof(IntArray) == sizeof(int*), "stored most efficiently");
    418 
    419 static bool TestArray() {
    420  static_assert(std::is_same_v<IntArray::deleter_type, DefaultDelete<int[]> >,
    421                "weird deleter?");
    422 
    423  IntArray n1(new int[5]);
    424  CHECK(n1);
    425  CHECK(n1.get() != nullptr);
    426 
    427  n1 = nullptr;
    428  CHECK(!n1);
    429  CHECK(n1.get() == nullptr);
    430 
    431  int* p1 = new int[42];
    432  n1.reset(p1);
    433  CHECK(n1);
    434  IntArray n2(std::move(n1));
    435  CHECK(!n1);
    436  CHECK(n1.get() == nullptr);
    437  CHECK(n2.get() == p1);
    438 
    439  std::swap(n1, n2);
    440  CHECK(n1.get() == p1);
    441  CHECK(n2.get() == nullptr);
    442 
    443  n1.swap(n2);
    444  CHECK(n1.get() == nullptr);
    445  CHECK(n2.get() == p1);
    446  delete[] n2.release();
    447 
    448  CHECK(n1.get() == nullptr);
    449  CHECK(n2.get() == nullptr);
    450 
    451  int* p2 = new int[7];
    452  int* p3 = new int[42];
    453  n1.reset(p2);
    454  n2.reset(p3);
    455  CHECK(n1.get() == p2);
    456  CHECK(n2.get() == p3);
    457 
    458  n1.swap(n2);
    459  CHECK(n2.get() == p2);
    460  CHECK(n1.get() == p3);
    461 
    462  n1 = std::move(n2);
    463  CHECK(n1.get() == p2);
    464  n1 = std::move(n2);
    465  CHECK(n1.get() == nullptr);
    466 
    467  UniquePtr<A[]> a1(new A[17]);
    468  static_assert(sizeof(a1) == sizeof(A*), "stored most efficiently");
    469 
    470  UniquePtr<A[]> a2(new A[5], DefaultDelete<A[]>());
    471  a2.reset(nullptr);
    472  a2.reset(new A[17]);
    473  a2 = nullptr;
    474 
    475  UniquePtr<A[]> a3(nullptr);
    476  a3.reset(new A[7]);
    477 
    478  return true;
    479 }
    480 
    481 struct Q {
    482  Q() = default;
    483  Q(const Q&) = default;
    484 
    485  Q(Q&, char) {}
    486 
    487  template <typename T>
    488  Q(Q, T&&, int) {}
    489 
    490  Q(int, long, double, void*) {}
    491 };
    492 
    493 static int randomInt() { return 4; }
    494 
    495 static bool TestMakeUnique() {
    496  UniquePtr<int> a1(MakeUnique<int>());
    497  UniquePtr<long> a2(MakeUnique<long>(4));
    498 
    499  // no args, easy
    500  UniquePtr<Q> q0(MakeUnique<Q>());
    501 
    502  // temporary bound to const lval ref
    503  UniquePtr<Q> q1(MakeUnique<Q>(Q()));
    504 
    505  // passing through a non-const lval ref
    506  UniquePtr<Q> q2(MakeUnique<Q>(*q1, 'c'));
    507 
    508  // pass by copying, forward a temporary, pass by value
    509  UniquePtr<Q> q3(MakeUnique<Q>(Q(), UniquePtr<int>(), randomInt()));
    510 
    511  // various type mismatching to test "fuzzy" forwarding
    512  UniquePtr<Q> q4(MakeUnique<Q>('s', 66LL, 3.141592654, &q3));
    513 
    514  UniquePtr<char[]> c1(MakeUnique<char[]>(5));
    515 
    516  return true;
    517 }
    518 
    519 static bool TestVoid() {
    520  // UniquePtr<void> supports all operations except operator*() and
    521  // operator->().
    522  UniqueFreePtr<void> p1(malloc(1));
    523  UniqueFreePtr<void> p2;
    524 
    525  auto x = p1.get();
    526  CHECK(x != nullptr);
    527  CHECK((std::is_same_v<decltype(x), void*>));
    528 
    529  p2.reset(p1.release());
    530  CHECK(p1.get() == nullptr);
    531  CHECK(p2.get() != nullptr);
    532 
    533  p1 = std::move(p2);
    534  CHECK(p1);
    535  CHECK(!p2);
    536 
    537  p1.swap(p2);
    538  CHECK(!p1);
    539  CHECK(p2);
    540 
    541  p2 = nullptr;
    542  CHECK(!p2);
    543 
    544  return true;
    545 }
    546 
    547 static bool TestTempPtrToSetter() {
    548  static int sFooRefcount = 0;
    549  struct Foo {
    550    Foo() { sFooRefcount += 1; }
    551 
    552    ~Foo() { sFooRefcount -= 1; }
    553  };
    554 
    555  const auto AllocByOutvar = [](Foo** out) -> bool {
    556    *out = new Foo;
    557    return true;
    558  };
    559 
    560  {
    561    UniquePtr<Foo> f;
    562    (void)AllocByOutvar(mozilla::TempPtrToSetter(&f));
    563    CHECK(sFooRefcount == 1);
    564  }
    565  CHECK(sFooRefcount == 0);
    566 
    567  {
    568    std::unique_ptr<Foo> f;
    569    (void)AllocByOutvar(mozilla::TempPtrToSetter(&f));
    570    CHECK(sFooRefcount == 1);
    571  }
    572  CHECK(sFooRefcount == 0);
    573 
    574  return true;
    575 }
    576 
    577 int main() {
    578  TestDeleterType();
    579 
    580  if (!TestDefaultFree()) {
    581    return 1;
    582  }
    583  if (!TestFreeClass()) {
    584    return 1;
    585  }
    586  if (!TestReferenceDeleter()) {
    587    return 1;
    588  }
    589  if (!TestFunctionReferenceDeleter()) {
    590    return 1;
    591  }
    592  if (!TestVector()) {
    593    return 1;
    594  }
    595  if (!TestArray()) {
    596    return 1;
    597  }
    598  if (!TestMakeUnique()) {
    599    return 1;
    600  }
    601  if (!TestVoid()) {
    602    return 1;
    603  }
    604  if (!TestTempPtrToSetter()) {
    605    return 1;
    606  }
    607  return 0;
    608 }