The table head of test freshness page should not scroll with the page.
[WebKit-https.git] / Tools / TestWebKitAPI / Tests / WTF / PoisonedRef.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/Poisoned.h>
31 #include <wtf/RefPtr.h>
32
33 namespace TestWebKitAPI {
34
35 namespace {
36
37 uintptr_t g_poisonA;
38 uintptr_t g_poisonB;
39 uintptr_t g_poisonC;
40 uintptr_t g_poisonD;
41 uintptr_t g_poisonE;
42 uintptr_t g_poisonF;
43
44 using PoisonA = Poison<g_poisonA>;
45 using PoisonB = Poison<g_poisonB>;
46 using PoisonC = Poison<g_poisonC>;
47 using PoisonD = Poison<g_poisonD>;
48 using PoisonE = Poison<g_poisonE>;
49 using PoisonF = Poison<g_poisonF>;
50
51 static void initializePoisons()
52 {
53     static std::once_flag initializeOnceFlag;
54     std::call_once(initializeOnceFlag, [] {
55         g_poisonA = makePoison();
56         g_poisonB = makePoison();
57         g_poisonC = makePoison();
58         g_poisonD = makePoison();
59         g_poisonF = makePoison();
60         g_poisonF = makePoison();
61     });
62 }
63
64 } // namespace anonymous
65
66 TEST(WTF_PoisonedRef, Basic)
67 {
68     initializePoisons();
69
70     DerivedRefLogger a("a");
71
72     {
73         PoisonedRef<PoisonA, RefLogger> ref(a);
74         EXPECT_EQ(&a, ref.ptr());
75         EXPECT_EQ(&a.name, &ref->name);
76
77 #if ENABLE(POISON)
78         uintptr_t ptrBits;
79         std::memcpy(&ptrBits, &ref, sizeof(ptrBits));
80         ASSERT_TRUE(ptrBits != bitwise_cast<uintptr_t>(&a));
81         ASSERT_EQ(ptrBits, (Poisoned<PoisonA, RefLogger*>(&a).bits()));
82 #if ENABLE(POISON_ASSERTS)
83         ASSERT_TRUE((Poisoned<PoisonA, RefLogger*>::isPoisoned(ptrBits)));
84 #endif
85 #endif // ENABLE(POISON)
86     }
87     EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
88
89     {
90         PoisonedRef<PoisonB, RefLogger> ref(adoptRef(a));
91         EXPECT_EQ(&a, ref.ptr());
92         EXPECT_EQ(&a.name, &ref->name);
93     }
94     EXPECT_STREQ("deref(a) ", takeLogStr().c_str());
95 }
96
97 TEST(WTF_PoisonedRef, Assignment)
98 {
99     initializePoisons();
100
101     DerivedRefLogger a("a");
102     RefLogger b("b");
103     DerivedRefLogger c("c");
104
105     {
106         PoisonedRef<PoisonC, RefLogger> ref(a);
107         EXPECT_EQ(&a, ref.ptr());
108         log() << "| ";
109         ref = b;
110         EXPECT_EQ(&b, ref.ptr());
111         log() << "| ";
112     }
113     EXPECT_STREQ("ref(a) | ref(b) deref(a) | deref(b) ", takeLogStr().c_str());
114
115     {
116         PoisonedRef<PoisonD, RefLogger> ref(a);
117         EXPECT_EQ(&a, ref.ptr());
118         log() << "| ";
119         ref = c;
120         EXPECT_EQ(&c, ref.ptr());
121         log() << "| ";
122     }
123     EXPECT_STREQ("ref(a) | ref(c) deref(a) | deref(c) ", takeLogStr().c_str());
124
125     {
126         PoisonedRef<PoisonE, RefLogger> ref(a);
127         EXPECT_EQ(&a, ref.ptr());
128         log() << "| ";
129         ref = adoptRef(b);
130         EXPECT_EQ(&b, ref.ptr());
131         log() << "| ";
132     }
133     EXPECT_STREQ("ref(a) | deref(a) | deref(b) ", takeLogStr().c_str());
134
135     {
136         PoisonedRef<PoisonF, RefLogger> ref(a);
137         EXPECT_EQ(&a, ref.ptr());
138         log() << "| ";
139         ref = adoptRef(c);
140         EXPECT_EQ(&c, ref.ptr());
141         log() << "| ";
142     }
143     EXPECT_STREQ("ref(a) | deref(a) | deref(c) ", takeLogStr().c_str());
144 }
145
146 static PoisonedRef<PoisonB, RefLogger> passWithRef(PoisonedRef<PoisonC, RefLogger>&& reference)
147 {
148     return WTFMove(reference);
149 }
150
151 TEST(WTF_PoisonedRef, ReturnValue)
152 {
153     initializePoisons();
154
155     DerivedRefLogger a("a");
156     RefLogger b("b");
157     DerivedRefLogger c("c");
158
159     {
160         PoisonedRef<PoisonB, RefLogger> ref(passWithRef(PoisonedRef<PoisonC, RefLogger>(a)));
161         EXPECT_EQ(&a, ref.ptr());
162     }
163     EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
164
165     {
166         PoisonedRef<PoisonD, RefLogger> ref(a);
167         EXPECT_EQ(&a, ref.ptr());
168         log() << "| ";
169         ref = passWithRef(b);
170         EXPECT_EQ(&b, ref.ptr());
171         log() << "| ";
172     }
173     EXPECT_STREQ("ref(a) | ref(b) deref(a) | deref(b) ", takeLogStr().c_str());
174
175     {
176         PoisonedRefPtr<PoisonE, RefLogger> ptr(passWithRef(a));
177         EXPECT_EQ(&a, ptr.get());
178     }
179     EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
180
181     {
182         PoisonedRefPtr<PoisonF, DerivedRefLogger> ptr(&a);
183         PoisonedRefPtr<PoisonA, RefLogger> ptr2(WTFMove(ptr));
184         EXPECT_EQ(nullptr, ptr.get());
185         EXPECT_EQ(&a, ptr2.get());
186     }
187     EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
188
189     {
190         PoisonedRef<PoisonB, DerivedRefLogger> derivedReference(a);
191         PoisonedRef<PoisonC, RefLogger> baseReference(passWithRef(derivedReference.copyRef()));
192         EXPECT_EQ(&a, derivedReference.ptr());
193         EXPECT_EQ(&a, baseReference.ptr());
194     }
195     EXPECT_STREQ("ref(a) ref(a) deref(a) deref(a) ", takeLogStr().c_str());
196 }
197
198 TEST(WTF_PoisonedRef, Swap)
199 {
200     initializePoisons();
201
202     RefLogger a("a");
203     RefLogger b("b");
204
205     {
206         PoisonedRef<PoisonD, RefLogger> p1(a);
207         PoisonedRef<PoisonE, RefLogger> p2(b);
208         log() << "| ";
209         EXPECT_EQ(&a, p1.ptr());
210         EXPECT_EQ(&b, p2.ptr());
211         p1.swap(p2);
212         EXPECT_EQ(&b, p1.ptr());
213         EXPECT_EQ(&a, p2.ptr());
214         log() << "| ";
215     }
216     EXPECT_STREQ("ref(a) ref(b) | | deref(a) deref(b) ", takeLogStr().c_str());
217
218     {
219         PoisonedRef<PoisonF, RefLogger> p1(a);
220         PoisonedRef<PoisonA, RefLogger> p2(b);
221         log() << "| ";
222         EXPECT_EQ(&a, p1.ptr());
223         EXPECT_EQ(&b, p2.ptr());
224         swap(p1, p2);
225         EXPECT_EQ(&b, p1.ptr());
226         EXPECT_EQ(&a, p2.ptr());
227         log() << "| ";
228     }
229     EXPECT_STREQ("ref(a) ref(b) | | deref(a) deref(b) ", takeLogStr().c_str());
230
231     {
232         PoisonedRef<PoisonF, RefLogger> p1(a);
233         Ref<RefLogger> p2(b);
234         log() << "| ";
235         EXPECT_EQ(&a, p1.ptr());
236         EXPECT_EQ(&b, p2.ptr());
237         swap(p1, p2);
238         EXPECT_EQ(&b, p1.ptr());
239         EXPECT_EQ(&a, p2.ptr());
240         log() << "| ";
241     }
242     EXPECT_STREQ("ref(a) ref(b) | | deref(a) deref(b) ", takeLogStr().c_str());
243
244     {
245         PoisonedRef<PoisonF, RefLogger> p1(a);
246         Ref<RefLogger> p2(b);
247         log() << "| ";
248         EXPECT_EQ(&a, p1.ptr());
249         EXPECT_EQ(&b, p2.ptr());
250         p1.swap(p2);
251         EXPECT_EQ(&b, p1.ptr());
252         EXPECT_EQ(&a, p2.ptr());
253         log() << "| ";
254     }
255     EXPECT_STREQ("ref(a) ref(b) | | deref(a) deref(b) ", takeLogStr().c_str());
256 }
257
258 struct PoisonedRefCheckingRefLogger : RefLogger {
259     using Ref = PoisonedRef<PoisonB, PoisonedRefCheckingRefLogger>;
260
261     PoisonedRefCheckingRefLogger(const char* name);
262     void ref();
263     void deref();
264     const Ref* slotToCheck { nullptr };
265 };
266
267 struct DerivedPoisonedRefCheckingRefLogger : PoisonedRefCheckingRefLogger {
268     DerivedPoisonedRefCheckingRefLogger(const char* name);
269 };
270
271 PoisonedRefCheckingRefLogger::PoisonedRefCheckingRefLogger(const char* name)
272     : RefLogger { name }
273 {
274 }
275
276 void PoisonedRefCheckingRefLogger::ref()
277 {
278     if (slotToCheck)
279         log() << "slot=" << slotToCheck->get().name << " ";
280     RefLogger::ref();
281 }
282
283 void PoisonedRefCheckingRefLogger::deref()
284 {
285     if (slotToCheck)
286         log() << "slot=" << slotToCheck->get().name << " ";
287     RefLogger::deref();
288 }
289
290 DerivedPoisonedRefCheckingRefLogger::DerivedPoisonedRefCheckingRefLogger(const char* name)
291     : PoisonedRefCheckingRefLogger { name }
292 {
293 }
294
295 TEST(WTF_PoisonedRef, AssignBeforeDeref)
296 {
297     initializePoisons();
298
299     DerivedPoisonedRefCheckingRefLogger a("a");
300     PoisonedRefCheckingRefLogger b("b");
301     DerivedPoisonedRefCheckingRefLogger c("c");
302
303     {
304         PoisonedRefCheckingRefLogger::Ref ref(a);
305         EXPECT_EQ(&a, ref.ptr());
306         log() << "| ";
307         a.slotToCheck = &ref;
308         b.slotToCheck = &ref;
309         ref = b;
310         a.slotToCheck = nullptr;
311         b.slotToCheck = nullptr;
312         EXPECT_EQ(&b, ref.ptr());
313         log() << "| ";
314     }
315     EXPECT_STREQ("ref(a) | slot=a ref(b) slot=b deref(a) | deref(b) ", takeLogStr().c_str());
316
317     {
318         PoisonedRefCheckingRefLogger::Ref ref(a);
319         EXPECT_EQ(&a, ref.ptr());
320         log() << "| ";
321         a.slotToCheck = &ref;
322         c.slotToCheck = &ref;
323         ref = c;
324         a.slotToCheck = nullptr;
325         c.slotToCheck = nullptr;
326         EXPECT_EQ(&c, ref.ptr());
327         log() << "| ";
328     }
329     EXPECT_STREQ("ref(a) | slot=a ref(c) slot=c deref(a) | deref(c) ", takeLogStr().c_str());
330
331     {
332         PoisonedRefCheckingRefLogger::Ref ref(a);
333         EXPECT_EQ(&a, ref.ptr());
334         log() << "| ";
335         a.slotToCheck = &ref;
336         ref = adoptRef(b);
337         a.slotToCheck = nullptr;
338         EXPECT_EQ(&b, ref.ptr());
339         log() << "| ";
340     }
341     EXPECT_STREQ("ref(a) | slot=b deref(a) | deref(b) ", takeLogStr().c_str());
342
343     {
344         PoisonedRefCheckingRefLogger::Ref ref(a);
345         EXPECT_EQ(&a, ref.ptr());
346         log() << "| ";
347         a.slotToCheck = &ref;
348         ref = adoptRef(c);
349         a.slotToCheck = nullptr;
350         EXPECT_EQ(&c, ref.ptr());
351         log() << "| ";
352     }
353     EXPECT_STREQ("ref(a) | slot=c deref(a) | deref(c) ", takeLogStr().c_str());
354 }
355
356 } // namespace TestWebKitAPI