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