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