1 /*
2 * Copyright (c) Facebook, Inc. and its affiliates.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <folly/memory/not_null.h>
18
19 #include <memory>
20 #include <strstream>
21 #include <unordered_set>
22
23 #include <folly/portability/GTest.h>
24
25 using namespace folly;
26
27 namespace {
28 struct Base {
29 virtual ~Base() = default;
30 };
31 struct Derived : public Base {};
32 struct Derived2 : public Base {};
33
34 struct my_deleter {
my_deleter__anon0a86a4a20111::my_deleter35 explicit my_deleter(int* counter) : counter_(counter) {}
operator ()__anon0a86a4a20111::my_deleter36 void operator()(int* ptr) {
37 (*counter_)++;
38 delete ptr;
39 }
40 int* counter_;
41 };
42 } // namespace
43
44 template <typename PtrT>
nullify(not_null<PtrT> & nn)45 void nullify(not_null<PtrT>& nn) {
46 // Super bad practice, but useful for testing.
47 const_cast<PtrT&>(nn.unwrap()) = nullptr;
48 }
49
50 template <typename T>
51 struct Wrapper {
52 template <typename U>
WrapperWrapper53 /* implicit */ Wrapper(U&& u) : t(std::forward<U>(u)) {}
54
55 T t;
56 };
57
TEST(nn,is_not_null)58 TEST(nn, is_not_null) {
59 static_assert(detail::is_not_null_v<void> == false, "is_not_null failure");
60 static_assert(detail::is_not_null_v<int> == false, "is_not_null failure");
61 static_assert(detail::is_not_null_v<int*> == false, "is_not_null failure");
62 static_assert(
63 detail::is_not_null_v<const int* const> == false, "is_not_null failure");
64 static_assert(
65 detail::is_not_null_v<not_null<int*>> == true, "is_not_null failure");
66 static_assert(
67 detail::is_not_null_v<const not_null<int*>&> == true,
68 "is_not_null failure");
69 static_assert(
70 detail::is_not_null_v<not_null<int*>&&> == true, "is_not_null failure");
71 }
72
73 template <typename To, typename From>
ctor_throws(From && from)74 bool ctor_throws(From&& from) {
75 try {
76 not_null<To> nn(std::forward<From>(from));
77 EXPECT_TRUE(nn);
78 } catch (std::invalid_argument&) {
79 return true;
80 }
81 return false;
82 }
83
TEST(nn,ctor_exception)84 TEST(nn, ctor_exception) {
85 Derived* dp = nullptr;
86
87 Derived d;
88 not_null<Derived*> nnd(&d);
89 nullify(nnd);
90
91 EXPECT_TRUE(ctor_throws<Derived*>(dp));
92 EXPECT_TRUE(ctor_throws<Base*>(dp));
93 EXPECT_TRUE(ctor_throws<Base*>(std::move(dp)));
94
95 // Copy/move constructor never throws
96 EXPECT_FALSE(ctor_throws<Derived*>(nnd));
97 EXPECT_FALSE((ctor_throws<Derived*, const not_null<Derived*>&>(nnd)));
98
99 // Converting constructor fails in debug mode
100 #ifndef NDEBUG
101 EXPECT_DEATH(not_null<Base*> nb1(nnd), "not_null internal pointer is null");
102 EXPECT_DEATH(
103 not_null<Base*> nb2(std::move(nnd)), "not_null internal pointer is null");
104 #else
105 EXPECT_FALSE(ctor_throws<Base*>(nnd));
106 EXPECT_FALSE(ctor_throws<Base*>(std::move(nnd)));
107 #endif
108 }
109
TEST(nn,ctor_conversion)110 TEST(nn, ctor_conversion) {
111 int* p = new int(7);
112 not_null_unique_ptr<int> a(p);
113 not_null_shared_ptr<int> b(std::move(a));
114 EXPECT_EQ(*b, 7);
115 }
116
TEST(nn,explicit_construction)117 TEST(nn, explicit_construction) {
118 int* i = new int(7);
119
120 // Can explicitly construct a unique_ptr from a raw pointer...
121 not_null_unique_ptr<int> a(i);
122 EXPECT_EQ(*a, 7);
123 // ...but not implicitly; the following code does not (and should not)
124 // compile.
125 #if 0
126 int* j = new int(8);
127 auto f = [](not_null_unique_ptr<int>) {};
128 f(j);
129 #endif
130 }
131
TEST(nn,dereferencing)132 TEST(nn, dereferencing) {
133 not_null_unique_ptr<std::vector<int>> nn =
134 std::make_unique<std::vector<int>>();
135
136 nn->push_back(2);
137 EXPECT_EQ((*nn)[0], 2);
138 }
139
TEST(nn,bool_cast)140 TEST(nn, bool_cast) {
141 int i = 7;
142 not_null<int*> nn(&i);
143 if (nn) {
144 } else {
145 EXPECT_FALSE(true);
146 }
147 if (!nn) {
148 EXPECT_FALSE(true);
149 }
150 }
151
TEST(nn,ptr_casting)152 TEST(nn, ptr_casting) {
153 int i = 7;
154 not_null<int*> nn(&i);
155 auto f = [](int* p) { *p = 8; };
156 f(nn);
157 EXPECT_EQ(i, 8);
158 }
159
TEST(nn,conversion_casting)160 TEST(nn, conversion_casting) {
161 Derived d;
162 not_null<Derived*> nnd(&d);
163 auto f = [&](Base* b) { EXPECT_EQ(&d, b); };
164 f(nnd);
165 }
166
TEST(nn,move_casting)167 TEST(nn, move_casting) {
168 not_null<std::unique_ptr<Derived>> nnd = std::make_unique<Derived>();
169 auto f = [](std::unique_ptr<Base>) {};
170 f(std::move(nnd));
171
172 #ifdef NDEBUG
173 // use-after-move is disallowed, but possible
174 EXPECT_EQ(nnd.unwrap(), nullptr);
175 #else
176 EXPECT_DEATH(nnd.unwrap(), "not_null internal pointer is null");
177 #endif
178 }
179
180 // If there are multiple ways to convert, not_null's casting operator should
181 // yield. If the casting operator did not yield, then Wrapper could either be
182 // implicitly constructed from not_null, or not_null could be casted to Wrapper,
183 // leading to a compiler error for ambiguity.
TEST(nn,multi_cast)184 TEST(nn, multi_cast) {
185 int i = 5;
186 not_null<int*> nn(&i);
187 auto f = [](Wrapper<not_null<int*>> w) { EXPECT_EQ(*w.t, 5); };
188
189 const auto& cnn = nn;
190 f(cnn);
191
192 f(std::move(nn));
193 }
194
TEST(nn,unwrap)195 TEST(nn, unwrap) {
196 not_null_unique_ptr<int> nn = std::make_unique<int>(7);
197 auto f = [](const std::unique_ptr<int>& u_i) { return *u_i; };
198 auto g = [](std::unique_ptr<int>&& u_i) { return *u_i; };
199 EXPECT_EQ(f(nn.unwrap()), 7);
200 EXPECT_EQ(g(std::move(nn).unwrap()), 7);
201
202 // Because g accepts an rvalue-reference, rather than a value, and does not
203 // move-from the argument, nn.unwrap() is still valid.
204 EXPECT_NE(nn.unwrap(), nullptr);
205 }
206
207 /**
208 * not_null_unique_ptr API tests
209 */
TEST(nn_up,deleter)210 TEST(nn_up, deleter) {
211 int counter = 0;
212 {
213 not_null_unique_ptr<int, my_deleter> a(new int(5), my_deleter(&counter));
214 auto d = a.get_deleter();
215 EXPECT_EQ(d.counter_, &counter);
216 }
217 EXPECT_EQ(counter, 1);
218 }
219
TEST(nn_up,reset)220 TEST(nn_up, reset) {
221 not_null_unique_ptr<int> a(new int(5));
222 int* i = new int(6);
223
224 a.reset(i);
225 EXPECT_EQ(*a, 6);
226 }
227
TEST(nn_up,swap)228 TEST(nn_up, swap) {
229 not_null_unique_ptr<int> a(new int(5));
230 not_null_unique_ptr<int> b(new int(6));
231
232 a.swap(b);
233 EXPECT_EQ(*a, 6);
234 EXPECT_EQ(*b, 5);
235 }
236
TEST(nn_up,get)237 TEST(nn_up, get) {
238 int* i = new int(5);
239 not_null_unique_ptr<int> a(i);
240 int* p = a.get();
241 EXPECT_EQ(p, i);
242
243 auto g = a.get();
244 static_assert(
245 detail::is_not_null_v<decltype(g)>, "get() does not return not_null");
246 }
247
TEST(nn_up,assignment)248 TEST(nn_up, assignment) {
249 not_null_unique_ptr<int> nnup(new int(5));
250 auto up = std::make_unique<int>(6);
251
252 nnup = std::move(up);
253 EXPECT_EQ(*nnup, 6);
254 }
255
256 /**
257 * not_null_shared_ptr API tests
258 */
TEST(nn_sp,deleter)259 TEST(nn_sp, deleter) {
260 int counter = 0;
261 {
262 not_null_shared_ptr<int> nnsp(new int(5), my_deleter(&counter));
263
264 auto* deleter = get_deleter<my_deleter>(nnsp);
265 EXPECT_EQ(deleter->counter_, &counter);
266 }
267 EXPECT_EQ(counter, 1);
268
269 // Also test that the first argument can be a not_null pointer.
270 {
271 not_null<int*> nnp(new int(6));
272 not_null_shared_ptr<int> nnsp(nnp, my_deleter(&counter));
273 auto* deleter = get_deleter<my_deleter>(nnsp);
274 EXPECT_EQ(deleter->counter_, &counter);
275 }
276 EXPECT_EQ(counter, 2);
277 }
278
TEST(nn_sp,aliasing)279 TEST(nn_sp, aliasing) {
280 auto sp = std::make_shared<int>(5);
281 int i = 6;
282 not_null_shared_ptr<int> nnsp1(sp, &i);
283 int j = 7;
284 not_null_shared_ptr<int> nnsp2(nnsp1, &j);
285
286 EXPECT_EQ(*sp, 5);
287 EXPECT_EQ(*nnsp1, 6);
288 EXPECT_EQ(*nnsp2, 7);
289 EXPECT_EQ(sp.use_count(), 3);
290 EXPECT_EQ(nnsp1.use_count(), 3);
291 EXPECT_EQ(nnsp2.use_count(), 3);
292
293 // The move-aliasing-constructor is a c++20 API, and falls back to the const&
294 // API without c++20 support. Cannot therefore test use_count().
295 not_null_shared_ptr<int> nnsp3(std::move(sp), &i);
296 EXPECT_EQ(*nnsp3, 6);
297 not_null_shared_ptr<int> nnsp4(std::move(nnsp1), &j);
298 EXPECT_EQ(*nnsp4, 7);
299 }
300
TEST(nn_sp,null_aliasing)301 TEST(nn_sp, null_aliasing) {
302 int* i = new int(5);
303 int* j = new int(6);
304 std::shared_ptr<int> sp1;
305 std::shared_ptr<int> sp2(sp1, i);
306 ASSERT_NE(sp2.get(), nullptr);
307 EXPECT_EQ(*sp2, 5);
308 EXPECT_EQ(sp2.use_count(), 0);
309
310 not_null_shared_ptr<int> nnsp(sp1, j);
311 EXPECT_EQ(*nnsp, 6);
312 EXPECT_EQ(nnsp.use_count(), 0);
313
314 // Null-aliased pointers do not get deleted.
315 delete j;
316 delete i;
317 }
318
TEST(nn_sp,assignment)319 TEST(nn_sp, assignment) {
320 not_null_shared_ptr<int> nnsp(new int(5));
321 auto& ret = nnsp = std::make_unique<int>(6);
322 EXPECT_EQ(*nnsp, 6);
323 static_assert(
324 std::is_same<decltype(ret), not_null_shared_ptr<int>&>::value,
325 "operator= wrong return type");
326 }
327
TEST(nn_sp,reset)328 TEST(nn_sp, reset) {
329 not_null_shared_ptr<int> nnsp(new int(5));
330 not_null<int*> nnp1(new int(6));
331
332 nnsp.reset(nnp1);
333 EXPECT_EQ(*nnsp, 6);
334
335 int* n = nullptr;
336 EXPECT_THROW(nnsp.reset(n), std::invalid_argument);
337 EXPECT_EQ(*nnsp, 6); // Strong exception guarantee.
338
339 int counter = 0;
340 nnsp.reset(new int(7), my_deleter(&counter));
341 EXPECT_EQ(*nnsp, 7);
342 not_null<int*> nnp2(new int(8));
343 nnsp.reset(nnp2);
344 EXPECT_EQ(counter, 1);
345 }
346
TEST(nn_sp,swap)347 TEST(nn_sp, swap) {
348 not_null_shared_ptr<int> a(new int(5));
349 not_null_shared_ptr<int> b(new int(6));
350
351 a.swap(b);
352 EXPECT_EQ(*a, 6);
353 EXPECT_EQ(*b, 5);
354 }
355
TEST(nn_sp,get)356 TEST(nn_sp, get) {
357 not_null_shared_ptr<int> nnsp(new int(5));
358 auto p = nnsp.get();
359 EXPECT_EQ(*p, 5);
360 EXPECT_EQ(*nnsp, 5);
361 static_assert(
362 std::is_same_v<decltype(p), not_null<int*>>, "wrong return type");
363 }
364
TEST(nn_sp,use_count)365 TEST(nn_sp, use_count) {
366 not_null_shared_ptr<int> nnsp1(new int(5));
367 EXPECT_EQ(nnsp1.use_count(), 1);
368 {
369 not_null_shared_ptr<int> nnsp2(nnsp1);
370 EXPECT_EQ(nnsp1.use_count(), 2);
371 EXPECT_EQ(nnsp2.use_count(), 2);
372 }
373 EXPECT_EQ(nnsp1.use_count(), 1);
374 }
375
TEST(nn_sp,owner_before)376 TEST(nn_sp, owner_before) {
377 not_null_shared_ptr<int> nnsp1(new int(5));
378 not_null_shared_ptr<int> nnsp2(new int(6));
379 auto sp = std::make_shared<int>(7);
380
381 auto f = [](const auto& p1, const auto& p2, bool same) {
382 bool cmp1 = p1.owner_before(p2);
383 bool cmp2 = p2.owner_before(p1);
384
385 if (same) {
386 EXPECT_FALSE(cmp1);
387 EXPECT_FALSE(cmp2);
388 } else {
389 EXPECT_NE(cmp1, cmp2);
390 }
391 };
392
393 f(nnsp1, nnsp1, /* same */ true);
394 f(nnsp1, nnsp2, /* same */ false);
395 nnsp1.owner_before(sp); // compiles
396 }
397
398 /**
399 * Non-member not_null helpers.
400 */
TEST(nn_helper,maker)401 TEST(nn_helper, maker) {
402 auto nnu = make_not_null_unique<int>(7);
403 EXPECT_EQ(*nnu, 7);
404
405 auto nns = make_not_null_shared<int>(8);
406 EXPECT_EQ(*nns, 8);
407 }
408
TEST(nn,cmp_correctness)409 TEST(nn, cmp_correctness) {
410 int* a = new int(6);
411 int* b = new int(7);
412
413 not_null<int*> nna = a;
414 not_null<int*> nnb = b;
415
416 #define FB_NOT_NULL_CHECK_OP(op) \
417 do { \
418 bool cmp1 = a op b; \
419 bool cmp2 = nna op nnb; \
420 EXPECT_EQ(cmp1, cmp2); \
421 bool self1 = a op a; \
422 bool self2 = nna op nna; \
423 EXPECT_EQ(self1, self2); \
424 } while (0)
425
426 FB_NOT_NULL_CHECK_OP(==);
427 FB_NOT_NULL_CHECK_OP(!=);
428 FB_NOT_NULL_CHECK_OP(<);
429 FB_NOT_NULL_CHECK_OP(<=);
430 FB_NOT_NULL_CHECK_OP(>);
431 FB_NOT_NULL_CHECK_OP(>=);
432
433 delete b;
434 delete a;
435 }
436
TEST(nn,cmp_types)437 TEST(nn, cmp_types) {
438 int i = 5;
439 int* p = &i;
440 int* j = new int(6);
441 not_null<int*> nnp(j);
442
443 EXPECT_TRUE(nnp == nnp);
444 EXPECT_FALSE(nnp == p);
445 EXPECT_FALSE(p == nnp);
446 EXPECT_FALSE(nnp == nullptr);
447 EXPECT_FALSE(nullptr == nnp);
448
449 delete j;
450 }
451
TEST(nn_helper,output)452 TEST(nn_helper, output) {
453 not_null_shared_ptr<int> nn(new int(5));
454
455 std::stringstream ss1, ss2;
456 ss1 << nn;
457 ss2 << nn.unwrap();
458 auto s1 = ss1.str();
459 auto s2 = ss2.str();
460 EXPECT_EQ(s1, s2);
461 EXPECT_NE(s2, "");
462 }
463
TEST(nn_helper,casting)464 TEST(nn_helper, casting) {
465 not_null_shared_ptr<Derived> nnd(new Derived());
466
467 auto s = static_pointer_cast<Base>(nnd);
468 EXPECT_EQ(s.get(), nnd.get());
469 static_assert(
470 std::is_same_v<decltype(s), not_null_shared_ptr<Base>>, "wrong cast");
471
472 auto d1 = dynamic_pointer_cast<Derived>(s);
473 EXPECT_EQ(d1.get(), nnd.get());
474 static_assert(
475 std::is_same_v<decltype(d1), std::shared_ptr<Derived>>, "wrong cast");
476 auto d2 = dynamic_pointer_cast<Derived2>(s);
477 EXPECT_EQ(d2.get(), nullptr);
478 static_assert(
479 std::is_same_v<decltype(d2), std::shared_ptr<Derived2>>, "wrong cast");
480
481 auto c = const_pointer_cast<const Derived>(nnd);
482 EXPECT_EQ(c.get(), nnd.get());
483 static_assert(
484 std::is_same_v<decltype(c), not_null_shared_ptr<const Derived>>,
485 "wrong cast");
486
487 auto r = reinterpret_pointer_cast<Base>(nnd);
488 EXPECT_EQ(r.get(), nnd.get());
489 static_assert(
490 std::is_same_v<decltype(r), not_null_shared_ptr<Base>>, "wrong cast");
491 }
492
TEST(nn,hash)493 TEST(nn, hash) {
494 int* i = new int(5);
495 {
496 std::unordered_set<not_null<int*>> s;
497 s.emplace(i);
498 }
499 delete i;
500 }
501
TEST(nn,null_deleter)502 TEST(nn, null_deleter) {
503 int* j = new int(6);
504 try {
505 not_null_unique_ptr<int, void (*)(int*)> nnui(j, nullptr);
506 } catch (std::invalid_argument&) {
507 delete j;
508 return;
509 }
510 EXPECT_FALSE(true);
511 }
512
513 template <typename Aliased>
testAliasedSharedPtrNullOwner()514 void testAliasedSharedPtrNullOwner() {
515 int* p = new int(7);
516
517 {
518 std::shared_ptr<int> sp; // null
519 Aliased aliased_sp(sp, p);
520
521 // Despite having a null owner, the pointer is valid.
522 EXPECT_EQ(*aliased_sp, *p);
523 *p = 8;
524 EXPECT_EQ(*aliased_sp, *p);
525 }
526
527 // ASAN will abort if aliased_sp deleted p.
528 EXPECT_EQ(*p, 8);
529 delete p;
530 }
531
TEST(nn_sp,null_aliased_shared_ptr)532 TEST(nn_sp, null_aliased_shared_ptr) {
533 // It is legal to construct an aliased shared_ptr with a null owner.
534 // Verify that this is so for regular shared_ptr.
535 testAliasedSharedPtrNullOwner<std::shared_ptr<int>>();
536
537 // It works for std::shared_ptr, so should also work for not_null_shared_ptr.
538 testAliasedSharedPtrNullOwner<not_null_shared_ptr<int>>();
539 }
540
TEST(nn_sp,pointer_cast_check)541 TEST(nn_sp, pointer_cast_check) {
542 auto nnd = make_not_null_shared<Derived>();
543
544 auto nnb1 = static_pointer_cast<Base>(nnd);
545 EXPECT_EQ(nnb1.use_count(), 2);
546 EXPECT_EQ(nnd.get(), nnb1.get());
547
548 nullify(nnd);
549 #ifndef NDEBUG
550 EXPECT_DEATH(
551 static_pointer_cast<Base>(nnd), "not_null internal pointer is null");
552 #else
553 auto nnb2 = static_pointer_cast<Base>(nnd);
554 EXPECT_EQ(nnb2.get(), nullptr);
555 #endif
556 }
557
558 class MyAllocator : public std::allocator<int> {
559 public:
MyAllocator(int * count)560 explicit MyAllocator(int* count) : count_(count) {}
561
562 template <typename... Args>
allocate(Args &&...args)563 int* allocate(Args&&... args) {
564 ++*count_;
565 Alloc alloc;
566 return AllocTraits::allocate(alloc, std::forward<Args>(args)...);
567 }
568
569 template <typename U, typename... Args>
construct(U * p,Args &&...args)570 void construct(U* p, Args&&... args) {
571 ++*count_;
572 Alloc alloc;
573 AllocTraits::construct(alloc, p, std::forward<Args>(args)...);
574 }
575
576 public:
577 using Alloc = std::allocator<int>;
578 using AllocTraits = std::allocator_traits<Alloc>;
579 using value_type = AllocTraits::value_type;
580
581 using pointer = AllocTraits::pointer;
582 using const_pointer = AllocTraits::const_pointer;
583 using reference = value_type&;
584 using const_reference = value_type const&;
585 using size_type = AllocTraits::size_type;
586 using difference_type = AllocTraits::difference_type;
587
588 using propagate_on_container_move_assignment =
589 AllocTraits::propagate_on_container_move_assignment;
590 #if __cplusplus <= 202001L
591 using Alloc::is_always_equal;
592 using Alloc::rebind;
593 #else
594 using is_always_equal = AllocTraits::is_always_equal;
595 template <class U>
596 struct rebind {
597 using other = std::allocator<U>;
598 };
599 #endif
600
601 private:
602 int* count_;
603 };
TEST(nn_sp,allocate_shared)604 TEST(nn_sp, allocate_shared) {
605 int count = 0;
606 auto nnsp = allocate_not_null_shared<int>(MyAllocator(&count), 7);
607 EXPECT_EQ(*nnsp, 7);
608 EXPECT_EQ(count, 1);
609 }
610