xref: /aosp_15_r20/external/pdfium/core/fxcrt/unowned_ptr_unittest.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
1 // Copyright 2017 The PDFium Authors
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 "core/fxcrt/unowned_ptr.h"
6 
7 #include <atomic>
8 #include <functional>
9 #include <memory>
10 #include <set>
11 #include <utility>
12 
13 #include "testing/gtest/include/gtest/gtest.h"
14 #include "third_party/base/containers/contains.h"
15 
16 #if defined(PDF_USE_PARTITION_ALLOC)
17 #include "base/allocator/partition_allocator/shim/allocator_shim_default_dispatch_to_partition_alloc.h"
18 #endif
19 
20 namespace fxcrt {
21 namespace {
22 
23 template <typename T, typename C = std::less<T>>
24 class NoLinearSearchSet : public std::set<T, C> {
25  public:
26   typename std::set<T, C>::iterator begin() noexcept = delete;
27   typename std::set<T, C>::const_iterator cbegin() const noexcept = delete;
28 };
29 
30 class Clink {
31  public:
32   UnownedPtr<Clink> next_ = nullptr;
33 };
34 
DeleteDangling()35 void DeleteDangling() {
36   auto ptr2 = std::make_unique<Clink>();
37   {
38     auto ptr1 = std::make_unique<Clink>();
39     ptr2->next_ = ptr1.get();
40   }
41 }
42 
AssignDangling()43 void AssignDangling() {
44   auto ptr2 = std::make_unique<Clink>();
45   {
46     auto ptr1 = std::make_unique<Clink>();
47     ptr2->next_ = ptr1.get();
48   }
49   ptr2->next_ = nullptr;
50 }
51 
ReleaseDangling()52 void ReleaseDangling() {
53   auto ptr2 = std::make_unique<Clink>();
54   {
55     auto ptr1 = std::make_unique<Clink>();
56     ptr2->next_ = ptr1.get();
57   }
58   ptr2->next_.ExtractAsDangling();
59 }
60 
61 }  // namespace
62 
TEST(UnownedPtr,DefaultCtor)63 TEST(UnownedPtr, DefaultCtor) {
64   UnownedPtr<Clink> ptr;
65   EXPECT_FALSE(ptr);
66 }
67 
TEST(UnownedPtr,NullptrCtor)68 TEST(UnownedPtr, NullptrCtor) {
69   UnownedPtr<Clink> ptr(nullptr);
70   EXPECT_FALSE(ptr);
71 }
72 
TEST(UnownedPtr,RawCtor)73 TEST(UnownedPtr, RawCtor) {
74   auto obj = std::make_unique<Clink>();
75   UnownedPtr<Clink> ptr(obj.get());
76   EXPECT_EQ(obj.get(), ptr);
77 }
78 
TEST(UnownedPtr,CopyCtor)79 TEST(UnownedPtr, CopyCtor) {
80   std::unique_ptr<Clink> obj = std::make_unique<Clink>();
81   UnownedPtr<Clink> ptr1(obj.get());
82   UnownedPtr<Clink> ptr2(ptr1);
83   EXPECT_EQ(obj.get(), ptr2);
84   EXPECT_EQ(obj.get(), ptr1);
85 }
86 
TEST(UnownedPtr,MoveCtor)87 TEST(UnownedPtr, MoveCtor) {
88   std::unique_ptr<Clink> obj = std::make_unique<Clink>();
89   UnownedPtr<Clink> ptr1(obj.get());
90   UnownedPtr<Clink> ptr2(std::move(ptr1));
91   EXPECT_EQ(obj.get(), ptr2);
92   EXPECT_FALSE(ptr1);
93 }
94 
TEST(UnownedPtr,CopyConversionCtor)95 TEST(UnownedPtr, CopyConversionCtor) {
96   std::unique_ptr<Clink> obj = std::make_unique<Clink>();
97   UnownedPtr<Clink> ptr1(obj.get());
98   UnownedPtr<const Clink> ptr2(ptr1);
99   EXPECT_EQ(obj.get(), ptr2);
100   EXPECT_EQ(obj.get(), ptr1);
101 }
102 
TEST(UnownedPtr,MoveConversionCtor)103 TEST(UnownedPtr, MoveConversionCtor) {
104   std::unique_ptr<Clink> obj = std::make_unique<Clink>();
105   UnownedPtr<Clink> ptr1(obj.get());
106   UnownedPtr<const Clink> ptr2(std::move(ptr1));
107   EXPECT_EQ(obj.get(), ptr2);
108   EXPECT_FALSE(ptr1);
109 }
110 
TEST(UnownedPtr,NullptrAssign)111 TEST(UnownedPtr, NullptrAssign) {
112   std::unique_ptr<Clink> obj = std::make_unique<Clink>();
113   UnownedPtr<Clink> ptr(obj.get());
114   ptr = nullptr;
115   EXPECT_FALSE(ptr);
116 }
117 
TEST(UnownedPtr,RawAssign)118 TEST(UnownedPtr, RawAssign) {
119   std::unique_ptr<Clink> obj = std::make_unique<Clink>();
120   UnownedPtr<Clink> ptr;
121   ptr = obj.get();
122   EXPECT_EQ(obj.get(), ptr);
123 }
124 
TEST(UnownedPtr,CopyAssign)125 TEST(UnownedPtr, CopyAssign) {
126   std::unique_ptr<Clink> obj = std::make_unique<Clink>();
127   UnownedPtr<Clink> ptr1(obj.get());
128   UnownedPtr<Clink> ptr2;
129   ptr2 = ptr1;
130   EXPECT_EQ(obj.get(), ptr1);
131   EXPECT_EQ(obj.get(), ptr2);
132 }
133 
TEST(UnownedPtr,MoveAssign)134 TEST(UnownedPtr, MoveAssign) {
135   std::unique_ptr<Clink> obj = std::make_unique<Clink>();
136   UnownedPtr<Clink> ptr1(obj.get());
137   UnownedPtr<Clink> ptr2;
138   ptr2 = std::move(ptr1);
139   EXPECT_FALSE(ptr1);
140   EXPECT_EQ(obj.get(), ptr2);
141 }
142 
TEST(UnownedPtr,CopyConversionAssign)143 TEST(UnownedPtr, CopyConversionAssign) {
144   std::unique_ptr<Clink> obj = std::make_unique<Clink>();
145   UnownedPtr<Clink> ptr1(obj.get());
146   UnownedPtr<const Clink> ptr2;
147   ptr2 = ptr1;
148   EXPECT_EQ(obj.get(), ptr1);
149   EXPECT_EQ(obj.get(), ptr2);
150 }
151 
TEST(UnownedPtr,MoveConversionAssign)152 TEST(UnownedPtr, MoveConversionAssign) {
153   std::unique_ptr<Clink> obj = std::make_unique<Clink>();
154   UnownedPtr<Clink> ptr1(obj.get());
155   UnownedPtr<const Clink> ptr2;
156   ptr2 = std::move(ptr1);
157   EXPECT_FALSE(ptr1);
158   EXPECT_EQ(obj.get(), ptr2);
159 }
160 
TEST(UnownedPtr,PtrOk)161 TEST(UnownedPtr, PtrOk) {
162   auto ptr1 = std::make_unique<Clink>();
163   {
164     auto ptr2 = std::make_unique<Clink>();
165     ptr2->next_ = ptr1.get();
166   }
167 }
168 
TEST(UnownedPtr,PtrNotOk)169 TEST(UnownedPtr, PtrNotOk) {
170 #if defined(UNOWNED_PTR_DANGLING_CHECKS)
171   EXPECT_DEATH(DeleteDangling(), "");
172 #else
173   DeleteDangling();
174 #endif
175 }
176 
TEST(UnownedPtr,AssignOk)177 TEST(UnownedPtr, AssignOk) {
178   auto ptr1 = std::make_unique<Clink>();
179   {
180     auto ptr2 = std::make_unique<Clink>();
181     ptr2->next_ = ptr1.get();
182     ptr2->next_ = nullptr;
183   }
184 }
185 
TEST(UnownedPtr,AssignNotOk)186 TEST(UnownedPtr, AssignNotOk) {
187 #if defined(UNOWNED_PTR_DANGLING_CHECKS)
188   EXPECT_DEATH(AssignDangling(), "");
189 #else
190   AssignDangling();
191 #endif
192 }
193 
TEST(UnownedPtr,ReleaseOk)194 TEST(UnownedPtr, ReleaseOk) {
195   auto ptr2 = std::make_unique<Clink>();
196   {
197     auto ptr1 = std::make_unique<Clink>();
198     ptr2->next_ = ptr1.get();
199     ptr2->next_.ExtractAsDangling();
200   }
201 }
202 
TEST(UnownedPtr,ReleaseNotOk)203 TEST(UnownedPtr, ReleaseNotOk) {
204 #if defined(UNOWNED_PTR_DANGLING_CHECKS)
205   EXPECT_DEATH(ReleaseDangling(), "");
206 #else
207   ReleaseDangling();
208 #endif
209 }
210 
TEST(UnownedPtr,OperatorEQ)211 TEST(UnownedPtr, OperatorEQ) {
212   int foo;
213   UnownedPtr<int> ptr1;
214   EXPECT_TRUE(ptr1 == ptr1);
215 
216   UnownedPtr<int> ptr2;
217   EXPECT_TRUE(ptr1 == ptr2);
218 
219   UnownedPtr<int> ptr3(&foo);
220   EXPECT_TRUE(&foo == ptr3);
221   EXPECT_TRUE(ptr3 == &foo);
222   EXPECT_FALSE(ptr1 == ptr3);
223 
224   ptr1 = &foo;
225   EXPECT_TRUE(ptr1 == ptr3);
226 }
227 
TEST(UnownedPtr,OperatorNE)228 TEST(UnownedPtr, OperatorNE) {
229   int foo;
230   UnownedPtr<int> ptr1;
231   EXPECT_FALSE(ptr1 != ptr1);
232 
233   UnownedPtr<int> ptr2;
234   EXPECT_FALSE(ptr1 != ptr2);
235 
236   UnownedPtr<int> ptr3(&foo);
237   EXPECT_FALSE(&foo != ptr3);
238   EXPECT_FALSE(ptr3 != &foo);
239   EXPECT_TRUE(ptr1 != ptr3);
240 
241   ptr1 = &foo;
242   EXPECT_FALSE(ptr1 != ptr3);
243 }
244 
TEST(UnownedPtr,OperatorLT)245 TEST(UnownedPtr, OperatorLT) {
246   int foos[2];
247   UnownedPtr<int> ptr1(&foos[0]);
248   UnownedPtr<int> ptr2(&foos[1]);
249 
250   EXPECT_FALSE(ptr1 < ptr1);
251   EXPECT_TRUE(ptr1 < ptr2);
252   EXPECT_FALSE(ptr2 < ptr1);
253 }
254 
TEST(UnownedPtr,TransparentCompare)255 TEST(UnownedPtr, TransparentCompare) {
256   int foos[2];
257   UnownedPtr<int> ptr1(&foos[0]);
258   UnownedPtr<int> ptr2(&foos[1]);
259   NoLinearSearchSet<UnownedPtr<int>, std::less<>> holder;
260   holder.insert(ptr1);
261   EXPECT_NE(holder.end(), holder.find(&foos[0]));
262   EXPECT_EQ(holder.end(), holder.find(&foos[1]));
263   EXPECT_TRUE(pdfium::Contains(holder, &foos[0]));
264   EXPECT_FALSE(pdfium::Contains(holder, &foos[1]));
265 }
266 
267 #if defined(PDF_USE_PARTITION_ALLOC)
268 #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && \
269     BUILDFLAG(HAS_64_BIT_POINTERS) && BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT)
270 
TEST(UnownedPtr,DanglingGetsQuarantined)271 TEST(UnownedPtr, DanglingGetsQuarantined) {
272   partition_alloc::PartitionRoot* root =
273       allocator_shim::internal::PartitionAllocMalloc::Allocator();
274   size_t original_byte_count =
275       root->total_size_of_brp_quarantined_bytes.load(std::memory_order_relaxed);
276 
277   auto ptr = std::make_unique<double>(4.0);
278   UnownedPtr<double> dangler = ptr.get();
279   EXPECT_EQ(
280       root->total_size_of_brp_quarantined_bytes.load(std::memory_order_relaxed),
281       original_byte_count);
282 
283   ptr.reset();
284   EXPECT_GE(
285       root->total_size_of_brp_quarantined_bytes.load(std::memory_order_relaxed),
286       original_byte_count + sizeof(double));
287 
288   dangler = nullptr;
289   EXPECT_EQ(
290       root->total_size_of_brp_quarantined_bytes.load(std::memory_order_relaxed),
291       original_byte_count);
292 }
293 
294 #endif  // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) ...
295 #endif  // PDF_USE_PARTITION_ALLOC
296 
297 }  // namespace fxcrt
298