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 }