1/*
2 * Copyright (C) 2013-2017 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27
28#include "RefLogger.h"
29#include "Utilities.h"
30#include <wtf/MainThread.h>
31#include <wtf/NeverDestroyed.h>
32#include <wtf/RefCounted.h>
33#include <wtf/RefPtr.h>
34#include <wtf/RunLoop.h>
35#include <wtf/ThreadSafeRefCounted.h>
36#include <wtf/Threading.h>
37
38namespace TestWebKitAPI {
39
40TEST(WTF_RefPtr, Basic)
41{
42 DerivedRefLogger a("a");
43
44 RefPtr<RefLogger> empty;
45 EXPECT_EQ(nullptr, empty.get());
46
47 {
48 RefPtr<RefLogger> ptr(&a);
49 EXPECT_EQ(&a, ptr.get());
50 EXPECT_EQ(&a, &*ptr);
51 EXPECT_EQ(&a.name, &ptr->name);
52 }
53 EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
54
55 {
56 RefPtr<RefLogger> ptr = &a;
57 EXPECT_EQ(&a, ptr.get());
58 }
59 EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
60
61 {
62 RefPtr<RefLogger> p1 = &a;
63 RefPtr<RefLogger> p2(p1);
64 EXPECT_EQ(&a, p1.get());
65 EXPECT_EQ(&a, p2.get());
66 }
67 EXPECT_STREQ("ref(a) ref(a) deref(a) deref(a) ", takeLogStr().c_str());
68
69 {
70 RefPtr<RefLogger> p1 = &a;
71 RefPtr<RefLogger> p2 = p1;
72 EXPECT_EQ(&a, p1.get());
73 EXPECT_EQ(&a, p2.get());
74 }
75 EXPECT_STREQ("ref(a) ref(a) deref(a) deref(a) ", takeLogStr().c_str());
76
77 {
78 RefPtr<RefLogger> p1 = &a;
79 RefPtr<RefLogger> p2 = WTFMove(p1);
80 EXPECT_EQ(nullptr, p1.get());
81 EXPECT_EQ(&a, p2.get());
82 }
83 EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
84
85 {
86 RefPtr<RefLogger> p1 = &a;
87 RefPtr<RefLogger> p2(WTFMove(p1));
88 EXPECT_EQ(nullptr, p1.get());
89 EXPECT_EQ(&a, p2.get());
90 }
91 EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
92
93 {
94 RefPtr<DerivedRefLogger> p1 = &a;
95 RefPtr<RefLogger> p2 = p1;
96 EXPECT_EQ(&a, p1.get());
97 EXPECT_EQ(&a, p2.get());
98 }
99 EXPECT_STREQ("ref(a) ref(a) deref(a) deref(a) ", takeLogStr().c_str());
100
101 {
102 RefPtr<DerivedRefLogger> p1 = &a;
103 RefPtr<RefLogger> p2 = WTFMove(p1);
104 EXPECT_EQ(nullptr, p1.get());
105 EXPECT_EQ(&a, p2.get());
106 }
107 EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
108
109 {
110 RefPtr<RefLogger> ptr(&a);
111 EXPECT_EQ(&a, ptr.get());
112 ptr = nullptr;
113 EXPECT_EQ(nullptr, ptr.get());
114 }
115 EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
116}
117
118TEST(WTF_RefPtr, AssignPassRefToRefPtr)
119{
120 DerivedRefLogger a("a");
121 {
122 Ref<RefLogger> passRef(a);
123 RefPtr<RefLogger> ptr = WTFMove(passRef);
124 EXPECT_EQ(&a, ptr.get());
125 }
126 EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
127}
128
129TEST(WTF_RefPtr, Adopt)
130{
131 DerivedRefLogger a("a");
132
133 RefPtr<RefLogger> empty;
134 EXPECT_EQ(nullptr, empty.get());
135
136 {
137 RefPtr<RefLogger> ptr(adoptRef(&a));
138 EXPECT_EQ(&a, ptr.get());
139 EXPECT_EQ(&a, &*ptr);
140 EXPECT_EQ(&a.name, &ptr->name);
141 }
142 EXPECT_STREQ("deref(a) ", takeLogStr().c_str());
143
144 {
145 RefPtr<RefLogger> ptr = adoptRef(&a);
146 EXPECT_EQ(&a, ptr.get());
147 }
148 EXPECT_STREQ("deref(a) ", takeLogStr().c_str());
149}
150
151TEST(WTF_RefPtr, Assignment)
152{
153 DerivedRefLogger a("a");
154 RefLogger b("b");
155 DerivedRefLogger c("c");
156
157 {
158 RefPtr<RefLogger> p1(&a);
159 RefPtr<RefLogger> p2(&b);
160 EXPECT_EQ(&a, p1.get());
161 EXPECT_EQ(&b, p2.get());
162 log() << "| ";
163 p1 = p2;
164 EXPECT_EQ(&b, p1.get());
165 EXPECT_EQ(&b, p2.get());
166 log() << "| ";
167 }
168 EXPECT_STREQ("ref(a) ref(b) | ref(b) deref(a) | deref(b) deref(b) ", takeLogStr().c_str());
169
170 {
171 RefPtr<RefLogger> ptr(&a);
172 EXPECT_EQ(&a, ptr.get());
173 log() << "| ";
174 ptr = &b;
175 EXPECT_EQ(&b, ptr.get());
176 log() << "| ";
177 }
178 EXPECT_STREQ("ref(a) | ref(b) deref(a) | deref(b) ", takeLogStr().c_str());
179
180 {
181 RefPtr<RefLogger> ptr(&a);
182 EXPECT_EQ(&a, ptr.get());
183 log() << "| ";
184 ptr = adoptRef(&b);
185 EXPECT_EQ(&b, ptr.get());
186 log() << "| ";
187 }
188 EXPECT_STREQ("ref(a) | deref(a) | deref(b) ", takeLogStr().c_str());
189
190 {
191 RefPtr<RefLogger> ptr(&a);
192 EXPECT_EQ(&a, ptr.get());
193 ptr = nullptr;
194 EXPECT_EQ(nullptr, ptr.get());
195 }
196 EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
197
198 {
199 RefPtr<RefLogger> p1(&a);
200 RefPtr<RefLogger> p2(&b);
201 EXPECT_EQ(&a, p1.get());
202 EXPECT_EQ(&b, p2.get());
203 log() << "| ";
204 p1 = WTFMove(p2);
205 EXPECT_EQ(&b, p1.get());
206 EXPECT_EQ(nullptr, p2.get());
207 log() << "| ";
208 }
209 EXPECT_STREQ("ref(a) ref(b) | deref(a) | deref(b) ", takeLogStr().c_str());
210
211 {
212 RefPtr<RefLogger> p1(&a);
213 RefPtr<DerivedRefLogger> p2(&c);
214 EXPECT_EQ(&a, p1.get());
215 EXPECT_EQ(&c, p2.get());
216 log() << "| ";
217 p1 = p2;
218 EXPECT_EQ(&c, p1.get());
219 EXPECT_EQ(&c, p2.get());
220 log() << "| ";
221 }
222 EXPECT_STREQ("ref(a) ref(c) | ref(c) deref(a) | deref(c) deref(c) ", takeLogStr().c_str());
223
224 {
225 RefPtr<RefLogger> ptr(&a);
226 EXPECT_EQ(&a, ptr.get());
227 log() << "| ";
228 ptr = &c;
229 EXPECT_EQ(&c, ptr.get());
230 log() << "| ";
231 }
232 EXPECT_STREQ("ref(a) | ref(c) deref(a) | deref(c) ", takeLogStr().c_str());
233
234 {
235 RefPtr<RefLogger> ptr(&a);
236 EXPECT_EQ(&a, ptr.get());
237 log() << "| ";
238 ptr = adoptRef(&c);
239 EXPECT_EQ(&c, ptr.get());
240 log() << "| ";
241 }
242 EXPECT_STREQ("ref(a) | deref(a) | deref(c) ", takeLogStr().c_str());
243
244 {
245 RefPtr<RefLogger> p1(&a);
246 RefPtr<DerivedRefLogger> p2(&c);
247 EXPECT_EQ(&a, p1.get());
248 EXPECT_EQ(&c, p2.get());
249 log() << "| ";
250 p1 = WTFMove(p2);
251 EXPECT_EQ(&c, p1.get());
252 EXPECT_EQ(nullptr, p2.get());
253 log() << "| ";
254 }
255 EXPECT_STREQ("ref(a) ref(c) | deref(a) | deref(c) ", takeLogStr().c_str());
256
257 {
258 RefPtr<RefLogger> ptr(&a);
259 EXPECT_EQ(&a, ptr.get());
260 log() << "| ";
261#if COMPILER(CLANG)
262#pragma clang diagnostic push
263#pragma clang diagnostic ignored "-Wunknown-pragmas"
264#pragma clang diagnostic ignored "-Wunknown-warning-option"
265#pragma clang diagnostic ignored "-Wself-assign-overloaded"
266#endif
267 ptr = ptr;
268#if COMPILER(CLANG)
269#pragma clang diagnostic pop
270#endif
271 EXPECT_EQ(&a, ptr.get());
272 log() << "| ";
273 }
274 EXPECT_STREQ("ref(a) | ref(a) deref(a) | deref(a) ", takeLogStr().c_str());
275
276 {
277 RefPtr<RefLogger> ptr(&a);
278 EXPECT_EQ(&a, ptr.get());
279#if COMPILER(CLANG)
280#pragma clang diagnostic push
281#pragma clang diagnostic ignored "-Wunknown-pragmas"
282#pragma clang diagnostic ignored "-Wself-move"
283#endif
284 ptr = WTFMove(ptr);
285#if COMPILER(CLANG)
286#pragma clang diagnostic pop
287#endif
288 EXPECT_EQ(&a, ptr.get());
289 }
290 EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
291}
292
293TEST(WTF_RefPtr, Swap)
294{
295 RefLogger a("a");
296 RefLogger b("b");
297
298 {
299 RefPtr<RefLogger> p1(&a);
300 RefPtr<RefLogger> p2(&b);
301 log() << "| ";
302 EXPECT_EQ(&a, p1.get());
303 EXPECT_EQ(&b, p2.get());
304 p1.swap(p2);
305 EXPECT_EQ(&b, p1.get());
306 EXPECT_EQ(&a, p2.get());
307 log() << "| ";
308 }
309 EXPECT_STREQ("ref(a) ref(b) | | deref(a) deref(b) ", takeLogStr().c_str());
310
311 {
312 RefPtr<RefLogger> p1(&a);
313 RefPtr<RefLogger> p2(&b);
314 log() << "| ";
315 EXPECT_EQ(&a, p1.get());
316 EXPECT_EQ(&b, p2.get());
317 std::swap(p1, p2);
318 EXPECT_EQ(&b, p1.get());
319 EXPECT_EQ(&a, p2.get());
320 log() << "| ";
321 }
322 EXPECT_STREQ("ref(a) ref(b) | | deref(a) deref(b) ", takeLogStr().c_str());
323}
324
325TEST(WTF_RefPtr, ReleaseNonNull)
326{
327 RefLogger a("a");
328
329 {
330 RefPtr<RefLogger> refPtr = &a;
331 RefPtr<RefLogger> ref = refPtr.releaseNonNull();
332 }
333
334 EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
335}
336
337TEST(WTF_RefPtr, Release)
338{
339 DerivedRefLogger a("a");
340 RefLogger b("b");
341 DerivedRefLogger c("c");
342
343 {
344 RefPtr<RefLogger> p1 = &a;
345 RefPtr<RefLogger> p2 = WTFMove(p1);
346 EXPECT_EQ(nullptr, p1.get());
347 EXPECT_EQ(&a, p2.get());
348 }
349 EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
350
351 {
352 RefPtr<RefLogger> p1 = &a;
353 RefPtr<RefLogger> p2(WTFMove(p1));
354 EXPECT_EQ(nullptr, p1.get());
355 EXPECT_EQ(&a, p2.get());
356 }
357 EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
358
359 {
360 RefPtr<DerivedRefLogger> p1 = &a;
361 RefPtr<RefLogger> p2 = WTFMove(p1);
362 EXPECT_EQ(nullptr, p1.get());
363 EXPECT_EQ(&a, p2.get());
364 }
365 EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
366
367 {
368 RefPtr<RefLogger> p1(&a);
369 RefPtr<RefLogger> p2(&b);
370 EXPECT_EQ(&a, p1.get());
371 EXPECT_EQ(&b, p2.get());
372 log() << "| ";
373 p1 = WTFMove(p2);
374 EXPECT_EQ(&b, p1.get());
375 EXPECT_EQ(nullptr, p2.get());
376 log() << "| ";
377 }
378 EXPECT_STREQ("ref(a) ref(b) | deref(a) | deref(b) ", takeLogStr().c_str());
379
380 {
381 RefPtr<RefLogger> p1(&a);
382 RefPtr<DerivedRefLogger> p2(&c);
383 EXPECT_EQ(&a, p1.get());
384 EXPECT_EQ(&c, p2.get());
385 log() << "| ";
386 p1 = WTFMove(p2);
387 EXPECT_EQ(&c, p1.get());
388 EXPECT_EQ(nullptr, p2.get());
389 log() << "| ";
390 }
391 EXPECT_STREQ("ref(a) ref(c) | deref(a) | deref(c) ", takeLogStr().c_str());
392}
393
394RefPtr<RefLogger> f1(RefLogger& logger)
395{
396 return RefPtr<RefLogger>(&logger);
397}
398
399TEST(WTF_RefPtr, ReturnValue)
400{
401 DerivedRefLogger a("a");
402
403 {
404 f1(a);
405 }
406 EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
407
408 {
409 auto ptr = f1(a);
410 }
411 EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
412}
413
414struct ConstRefCounted : RefCounted<ConstRefCounted> {
415 static Ref<ConstRefCounted> create() { return adoptRef(*new ConstRefCounted); }
416};
417
418const ConstRefCounted& returnConstRefCountedRef()
419{
420 static NeverDestroyed<ConstRefCounted> instance;
421 return instance.get();
422}
423ConstRefCounted& returnRefCountedRef()
424{
425 static NeverDestroyed<ConstRefCounted> instance;
426 return instance.get();
427}
428
429TEST(WTF_RefPtr, Const)
430{
431 // This test passes if it compiles without an error.
432 auto a = ConstRefCounted::create();
433 Ref<const ConstRefCounted> b = WTFMove(a);
434 RefPtr<const ConstRefCounted> c = b.ptr();
435 Ref<const ConstRefCounted> d = returnConstRefCountedRef();
436 RefPtr<const ConstRefCounted> e = &returnConstRefCountedRef();
437 RefPtr<ConstRefCounted> f = ConstRefCounted::create();
438 RefPtr<const ConstRefCounted> g = f;
439 RefPtr<const ConstRefCounted> h(f);
440 Ref<const ConstRefCounted> i(returnRefCountedRef());
441}
442
443struct RefPtrCheckingRefLogger : RefLogger {
444 RefPtrCheckingRefLogger(const char* name);
445 void ref();
446 void deref();
447 const RefPtr<RefPtrCheckingRefLogger>* slotToCheck { nullptr };
448};
449
450RefPtrCheckingRefLogger::RefPtrCheckingRefLogger(const char* name)
451 : RefLogger { name }
452{
453}
454
455static const char* loggerName(const RefPtr<RefPtrCheckingRefLogger>& pointer)
456{
457 return pointer ? &pointer->name : "null";
458}
459
460void RefPtrCheckingRefLogger::ref()
461{
462 if (slotToCheck)
463 log() << "slot=" << loggerName(*slotToCheck) << " ";
464 RefLogger::ref();
465}
466
467void RefPtrCheckingRefLogger::deref()
468{
469 if (slotToCheck)
470 log() << "slot=" << loggerName(*slotToCheck) << " ";
471 RefLogger::deref();
472}
473
474TEST(WTF_RefPtr, AssignBeforeDeref)
475{
476 RefPtrCheckingRefLogger a("a");
477 RefPtrCheckingRefLogger b("b");
478
479 {
480 RefPtr<RefPtrCheckingRefLogger> p1(&a);
481 RefPtr<RefPtrCheckingRefLogger> p2(&b);
482 EXPECT_EQ(&a, p1.get());
483 EXPECT_EQ(&b, p2.get());
484 log() << "| ";
485 a.slotToCheck = &p1;
486 b.slotToCheck = &p1;
487 p1 = p2;
488 a.slotToCheck = nullptr;
489 b.slotToCheck = nullptr;
490 EXPECT_EQ(&b, p1.get());
491 EXPECT_EQ(&b, p2.get());
492 log() << "| ";
493 }
494 EXPECT_STREQ("ref(a) ref(b) | slot=a ref(b) slot=b deref(a) | deref(b) deref(b) ", takeLogStr().c_str());
495
496 {
497 RefPtr<RefPtrCheckingRefLogger> ptr(&a);
498 EXPECT_EQ(&a, ptr.get());
499 log() << "| ";
500 a.slotToCheck = &ptr;
501 b.slotToCheck = &ptr;
502 ptr = &b;
503 a.slotToCheck = nullptr;
504 b.slotToCheck = nullptr;
505 EXPECT_EQ(&b, ptr.get());
506 log() << "| ";
507 }
508 EXPECT_STREQ("ref(a) | slot=a ref(b) slot=b deref(a) | deref(b) ", takeLogStr().c_str());
509
510 {
511 RefPtr<RefPtrCheckingRefLogger> ptr(&a);
512 EXPECT_EQ(&a, ptr.get());
513 a.slotToCheck = &ptr;
514 ptr = nullptr;
515 a.slotToCheck = nullptr;
516 EXPECT_EQ(nullptr, ptr.get());
517 }
518 EXPECT_STREQ("ref(a) slot=null deref(a) ", takeLogStr().c_str());
519
520 {
521 RefPtr<RefPtrCheckingRefLogger> p1(&a);
522 RefPtr<RefPtrCheckingRefLogger> p2(&b);
523 EXPECT_EQ(&a, p1.get());
524 EXPECT_EQ(&b, p2.get());
525 log() << "| ";
526 a.slotToCheck = &p1;
527 b.slotToCheck = &p1;
528 p1 = WTFMove(p2);
529 a.slotToCheck = nullptr;
530 b.slotToCheck = nullptr;
531 EXPECT_EQ(&b, p1.get());
532 EXPECT_EQ(nullptr, p2.get());
533 log() << "| ";
534 }
535 EXPECT_STREQ("ref(a) ref(b) | slot=b deref(a) | deref(b) ", takeLogStr().c_str());
536}
537
538TEST(WTF_RefPtr, ReleaseNonNullBeforeDeref)
539{
540 RefPtrCheckingRefLogger a("a");
541
542 {
543 RefPtr<RefPtrCheckingRefLogger> refPtr = &a;
544 a.slotToCheck = &refPtr;
545 refPtr.releaseNonNull();
546 a.slotToCheck = nullptr;
547 }
548
549 EXPECT_STREQ("ref(a) slot=null deref(a) ", takeLogStr().c_str());
550}
551
552// FIXME: Enable these tests once Win platform supports TestWebKitAPI::Util::run
553#if! PLATFORM(WIN)
554
555static bool done;
556static bool isDestroyedInMainThread;
557struct ThreadSafeRefCountedObject : ThreadSafeRefCounted<ThreadSafeRefCountedObject> {
558 static Ref<ThreadSafeRefCountedObject> create() { return adoptRef(*new ThreadSafeRefCountedObject); }
559
560 ~ThreadSafeRefCountedObject()
561 {
562 isDestroyedInMainThread = isMainThread();
563 done = true;
564 }
565};
566
567struct MainThreadSafeRefCountedObject : ThreadSafeRefCounted<MainThreadSafeRefCountedObject, WTF::DestructionThread::Main> {
568 static Ref<MainThreadSafeRefCountedObject> create() { return adoptRef(*new MainThreadSafeRefCountedObject); }
569
570 ~MainThreadSafeRefCountedObject()
571 {
572 isDestroyedInMainThread = isMainThread();
573 done = true;
574 }
575};
576
577TEST(WTF_RefPtr, ReleaseInNonMainThread)
578{
579 done = false;
580 Thread::create("", [object = ThreadSafeRefCountedObject::create()] { });
581 TestWebKitAPI::Util::run(&done);
582
583 EXPECT_FALSE(isDestroyedInMainThread);
584}
585
586TEST(WTF_RefPtr, ReleaseInNonMainThreadDestroyInMainThread)
587{
588 RunLoop::initializeMainRunLoop();
589 done = false;
590 Thread::create("", [object = MainThreadSafeRefCountedObject::create()] { });
591 TestWebKitAPI::Util::run(&done);
592
593 EXPECT_TRUE(isDestroyedInMainThread);
594}
595
596#endif
597
598} // namespace TestWebKitAPI
599