Add WTF::PoisonedUniquePtr to replace std::unique_ptr when poisoning is desired.
authormark.lam@apple.com <mark.lam@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 21 Dec 2017 23:05:11 +0000 (23:05 +0000)
committermark.lam@apple.com <mark.lam@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 21 Dec 2017 23:05:11 +0000 (23:05 +0000)
https://bugs.webkit.org/show_bug.cgi?id=181062
<rdar://problem/36167040>

Reviewed by Chris Dumez.

Source/JavaScriptCore:

* runtime/JSCPoisonedPtr.cpp:
- Added a needed #include.

Source/WTF:

* WTF.xcodeproj/project.pbxproj:
* wtf/CMakeLists.txt:
* wtf/PointerAsserts.cpp: Copied from Source/WTF/wtf/RefPtr.cpp.
- renamed file because we asserts all kinds of pointers in here, not just RefPtr.

* wtf/Poisoned.h:
- added a missing #include.
- make constexpr poison values more scrambled.
(WTF::makePoison):

* wtf/PoisonedUniquePtr.h: Added.
(WTF::PoisonedUniquePtr::PoisonedUniquePtr):
(WTF::PoisonedUniquePtr::~PoisonedUniquePtr):
(WTF::PoisonedUniquePtr::create):
(WTF::PoisonedUniquePtr::operator=):
(WTF::PoisonedUniquePtr::get const):
(WTF::PoisonedUniquePtr::operator[] const):
(WTF::PoisonedUniquePtr::clear):
(WTF::PoisonedUniquePtr::destroy):
(WTF::PoisonedUniquePtr::clearWithoutDestroy):
(WTF::makePoisonedUnique):
* wtf/RefPtr.cpp: Removed.

Tools:

* TestWebKitAPI/CMakeLists.txt:
* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:

* TestWebKitAPI/Tests/WTF/ConstExprPoisoned.cpp:
- Removed an unneeded #include.

* TestWebKitAPI/Tests/WTF/PoisonedUniquePtr.cpp: Added.
(TestWebKitAPI::TEST):
(TestWebKitAPI::poisonedPtrFoo):
* TestWebKitAPI/Tests/WTF/PoisonedUniquePtrForNonTriviallyDestructibleArrays.cpp: Added.
(TestWebKitAPI::TEST):
* TestWebKitAPI/Tests/WTF/PoisonedUniquePtrForTriviallyDestructibleArrays.cpp: Added.
(TestWebKitAPI::TEST):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@226247 268f45cc-cd09-0410-ab3c-d52691b4dbfc

15 files changed:
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/runtime/JSCPoisonedPtr.cpp
Source/WTF/ChangeLog
Source/WTF/WTF.xcodeproj/project.pbxproj
Source/WTF/wtf/CMakeLists.txt
Source/WTF/wtf/PointerAsserts.cpp [moved from Source/WTF/wtf/RefPtr.cpp with 82% similarity]
Source/WTF/wtf/Poisoned.h
Source/WTF/wtf/PoisonedUniquePtr.h [new file with mode: 0644]
Tools/ChangeLog
Tools/TestWebKitAPI/CMakeLists.txt
Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
Tools/TestWebKitAPI/Tests/WTF/ConstExprPoisoned.cpp
Tools/TestWebKitAPI/Tests/WTF/PoisonedUniquePtr.cpp [new file with mode: 0644]
Tools/TestWebKitAPI/Tests/WTF/PoisonedUniquePtrForNonTriviallyDestructibleArrays.cpp [new file with mode: 0644]
Tools/TestWebKitAPI/Tests/WTF/PoisonedUniquePtrForTriviallyDestructibleArrays.cpp [new file with mode: 0644]

index bc08b9a..a35c709 100644 (file)
@@ -1,3 +1,14 @@
+2017-12-21  Mark Lam  <mark.lam@apple.com>
+
+        Add WTF::PoisonedUniquePtr to replace std::unique_ptr when poisoning is desired.
+        https://bugs.webkit.org/show_bug.cgi?id=181062
+        <rdar://problem/36167040>
+
+        Reviewed by Chris Dumez.
+
+        * runtime/JSCPoisonedPtr.cpp:
+        - Added a needed #include.
+
 2017-12-21  Jeremy Jones  <jeremyj@apple.com>
 
         Update FULLSCREEN_API feature defines.
index 2ed575b..1f895e7 100644 (file)
@@ -26,6 +26,8 @@
 #include "config.h"
 #include "JSCPoisonedPtr.h"
 
+#include <mutex>
+
 namespace JSC {
 
 uintptr_t g_globalDataPoison;
index c465202..0a3e39f 100644 (file)
@@ -1,3 +1,34 @@
+2017-12-21  Mark Lam  <mark.lam@apple.com>
+
+        Add WTF::PoisonedUniquePtr to replace std::unique_ptr when poisoning is desired.
+        https://bugs.webkit.org/show_bug.cgi?id=181062
+        <rdar://problem/36167040>
+
+        Reviewed by Chris Dumez.
+
+        * WTF.xcodeproj/project.pbxproj:
+        * wtf/CMakeLists.txt:
+        * wtf/PointerAsserts.cpp: Copied from Source/WTF/wtf/RefPtr.cpp.
+        - renamed file because we asserts all kinds of pointers in here, not just RefPtr.
+        
+        * wtf/Poisoned.h:
+        - added a missing #include.
+        - make constexpr poison values more scrambled.
+        (WTF::makePoison):
+
+        * wtf/PoisonedUniquePtr.h: Added.
+        (WTF::PoisonedUniquePtr::PoisonedUniquePtr):
+        (WTF::PoisonedUniquePtr::~PoisonedUniquePtr):
+        (WTF::PoisonedUniquePtr::create):
+        (WTF::PoisonedUniquePtr::operator=):
+        (WTF::PoisonedUniquePtr::get const):
+        (WTF::PoisonedUniquePtr::operator[] const):
+        (WTF::PoisonedUniquePtr::clear):
+        (WTF::PoisonedUniquePtr::destroy):
+        (WTF::PoisonedUniquePtr::clearWithoutDestroy):
+        (WTF::makePoisonedUnique):
+        * wtf/RefPtr.cpp: Removed.
+
 2017-12-21  Jeremy Jones  <jeremyj@apple.com>
 
         Element fullscreen interface should display the location
index 8976693..eea58da 100644 (file)
                E3A32BC41FC830E2007D7E76 /* JSValueMalloc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E3A32BC21FC830E2007D7E76 /* JSValueMalloc.cpp */; };
                E4A0AD391A96245500536DF6 /* WorkQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4A0AD371A96245500536DF6 /* WorkQueue.cpp */; };
                E4A0AD3D1A96253C00536DF6 /* WorkQueueCocoa.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4A0AD3C1A96253C00536DF6 /* WorkQueueCocoa.cpp */; };
-               FE05FAFF1FE5007500093230 /* RefPtr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE05FAFE1FE5007500093230 /* RefPtr.cpp */; };
+               FE05FAFF1FE5007500093230 /* PointerAsserts.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE05FAFE1FE5007500093230 /* PointerAsserts.cpp */; };
                FE85416E1FBE285D008DA5DA /* Poisoned.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE85416C1FBE285B008DA5DA /* Poisoned.cpp */; };
                FEDACD3D1630F83F00C69634 /* StackStats.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FEDACD3B1630F83F00C69634 /* StackStats.cpp */; };
 /* End PBXBuildFile section */
                EF7D6CD59D8642A8A0DA86AD /* StackTrace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StackTrace.h; sourceTree = "<group>"; };
                F72BBDB107FA424886178B9E /* SymbolImpl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SymbolImpl.cpp; sourceTree = "<group>"; };
                FE05FAE61FDB214300093230 /* DumbPtrTraits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DumbPtrTraits.h; sourceTree = "<group>"; };
-               FE05FAFE1FE5007500093230 /* RefPtr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RefPtr.cpp; sourceTree = "<group>"; };
+               FE05FAFE1FE5007500093230 /* PointerAsserts.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PointerAsserts.cpp; sourceTree = "<group>"; };
+               FE05FB041FE8453200093230 /* PoisonedUniquePtr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PoisonedUniquePtr.h; sourceTree = "<group>"; };
                FE8225301B2A1E5B00BA68FD /* NakedPtr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NakedPtr.h; sourceTree = "<group>"; };
                FE85416C1FBE285B008DA5DA /* Poisoned.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Poisoned.cpp; sourceTree = "<group>"; };
                FE85416D1FBE285C008DA5DA /* Poisoned.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Poisoned.h; sourceTree = "<group>"; };
                                0F824A651B7443A0002E345D /* ParkingLot.h */,
                                A876DBD7151816E500DADB95 /* Platform.h */,
                                E3200AB41E9A536D003B59D2 /* PlatformRegisters.h */,
+                               FE05FAFE1FE5007500093230 /* PointerAsserts.cpp */,
                                0FF860941BCCBD740045127F /* PointerComparison.h */,
                                FE85416C1FBE285B008DA5DA /* Poisoned.cpp */,
                                FE85416D1FBE285C008DA5DA /* Poisoned.h */,
+                               FE05FB041FE8453200093230 /* PoisonedUniquePtr.h */,
                                0F9D335D165DBA73005AD387 /* PrintStream.cpp */,
                                0F9D335E165DBA73005AD387 /* PrintStream.h */,
                                53EC253C1E95AD30000831B9 /* PriorityQueue.h */,
                                A8A47301151A825B004123FF /* RefCountedLeakCounter.cpp */,
                                A8A47302151A825B004123FF /* RefCountedLeakCounter.h */,
                                86F46F5F1A2840EE00CCBF22 /* RefCounter.h */,
-                               FE05FAFE1FE5007500093230 /* RefPtr.cpp */,
                                A8A47303151A825B004123FF /* RefPtr.h */,
                                A8A47305151A825B004123FF /* RetainPtr.h */,
                                2CDED0F118115C85004DBA70 /* RunLoop.cpp */,
                                0F66B28A1DC97BAB004A1D3F /* ClockType.cpp in Sources */,
                                A8A47460151A825B004123FF /* CollatorDefault.cpp in Sources */,
                                A8A47463151A825B004123FF /* CollatorICU.cpp in Sources */,
-                               FE05FAFF1FE5007500093230 /* RefPtr.cpp in Sources */,
+                               FE05FAFF1FE5007500093230 /* PointerAsserts.cpp in Sources */,
                                0F8F2B92172E0103007DBDA5 /* CompilationThread.cpp in Sources */,
                                0F30CB5A1FCDF134004B5323 /* ConcurrentPtrHashSet.cpp in Sources */,
                                0F8E85DB1FD485B000691889 /* CountingLock.cpp in Sources */,
index 09b0476..1048954 100644 (file)
@@ -111,6 +111,7 @@ set(WTF_HEADERS
     Platform.h
     PlatformRegisters.h
     Poisoned.h
+    PoisonedUniquePtr.h
     PrintStream.h
     ProcessID.h
     RAMSize.h
@@ -262,6 +263,7 @@ set(WTF_SOURCES
     ParallelHelperPool.cpp
     ParallelJobsGeneric.cpp
     ParkingLot.cpp
+    PointerAsserts.cpp
     Poisoned.cpp
     PrintStream.cpp
     RAMSize.cpp
@@ -269,7 +271,6 @@ set(WTF_SOURCES
     RandomNumber.cpp
     ReadWriteLock.cpp
     RefCountedLeakCounter.cpp
-    RefPtr.cpp
     RunLoop.cpp
     SHA1.cpp
     Seconds.cpp
similarity index 82%
rename from Source/WTF/wtf/RefPtr.cpp
rename to Source/WTF/wtf/PointerAsserts.cpp
index ea373ca..a97526f 100644 (file)
  */
 
 #include "config.h"
-#include "RefPtr.h"
 
-#include "Poisoned.h"
+#include <wtf/Poisoned.h>
+#include <wtf/PoisonedUniquePtr.h>
+#include <wtf/RefPtr.h>
 
 namespace WTF {
 
+namespace {
 struct DummyClass { };
+}
 
 static_assert(sizeof(Ref<DummyClass>) == sizeof(DummyClass*), "");
 static_assert(sizeof(PoisonedRef<0xffff, DummyClass>) == sizeof(DummyClass*), "");
@@ -38,5 +41,9 @@ static_assert(sizeof(PoisonedRef<0xffff, DummyClass>) == sizeof(DummyClass*), ""
 static_assert(sizeof(RefPtr<DummyClass>) == sizeof(DummyClass*), "");
 static_assert(sizeof(PoisonedRefPtr<0xffff, DummyClass>) == sizeof(DummyClass*), "");
 
+static_assert(sizeof(PoisonedUniquePtr<0xffff, DummyClass>) == sizeof(DummyClass*), "");
+static_assert(sizeof(PoisonedUniquePtr<0xffff, int[]>) == sizeof(int*), "");
+static_assert(sizeof(PoisonedUniquePtr<0xffff, DummyClass[]>) == sizeof(DummyClass*), "");
+
 } // namespace WTF
 
index 46b6417..ebb1949 100644 (file)
@@ -25,6 +25,7 @@
 
 #pragma once
 
+#include <utility>
 #include <wtf/Assertions.h>
 
 #define ENABLE_POISON 1
@@ -216,7 +217,9 @@ WTF_EXPORT_PRIVATE uintptr_t makePoison();
 inline constexpr uintptr_t makePoison(uint32_t key)
 {
 #if ENABLE(POISON)
-    return static_cast<uintptr_t>(0x80000000 | key) << 32;
+    uintptr_t poison1 = static_cast<uintptr_t>(key) * 6906969069 + 1234567;
+    uintptr_t poison2 = static_cast<uintptr_t>(key) * 8253729 + 2396403;
+    return ((poison1 << 3) ^ (poison2 << 32)) | (static_cast<uintptr_t>(1) << 63);
 #else
     return (void)key, 0;
 #endif
diff --git a/Source/WTF/wtf/PoisonedUniquePtr.h b/Source/WTF/wtf/PoisonedUniquePtr.h
new file mode 100644 (file)
index 0000000..be6ba0a
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <wtf/FastMalloc.h>
+#include <wtf/Poisoned.h>
+
+namespace WTF {
+
+template<uint32_t key, typename T, typename Enable = void>
+class PoisonedUniquePtr : public ConstExprPoisoned<key, T*> {
+    WTF_MAKE_FAST_ALLOCATED;
+    using Base = ConstExprPoisoned<key, T*>;
+public:
+    PoisonedUniquePtr() = default;
+    PoisonedUniquePtr(T* ptr) : Base(ptr) { }
+    PoisonedUniquePtr(PoisonedUniquePtr&& ptr) : Base(WTFMove(ptr)) { ptr.clearWithoutDestroy(); }
+
+    template<uint32_t key2, typename U, typename = std::enable_if_t<std::is_base_of<T, U>::value>>
+    PoisonedUniquePtr(PoisonedUniquePtr<key2, U>&& ptr)
+        : Base(ptr.unpoisoned())
+    {
+        ptr.clearWithoutDestroy();
+    }
+
+    PoisonedUniquePtr(const PoisonedUniquePtr&) = delete;
+
+    ~PoisonedUniquePtr() { destroy(); }
+
+    template<typename... Arguments>
+    static PoisonedUniquePtr create(Arguments&&... arguments)
+    {
+        return new T(std::forward<Arguments>(arguments)...);
+    }
+
+    PoisonedUniquePtr& operator=(T* ptr)
+    {
+        if (LIKELY(this->unpoisoned() != ptr)) {
+            this->clear();
+            this->Base::operator=(ptr);
+        }
+        return *this;
+    }
+
+    template<uint32_t key2, typename U, typename = std::enable_if_t<std::is_base_of<T, U>::value>>
+    PoisonedUniquePtr& operator=(PoisonedUniquePtr<key2, U>&& ptr)
+    {
+        ASSERT(this == static_cast<void*>(&ptr) || this->unpoisoned() != ptr.unpoisoned());
+        if (LIKELY(this != static_cast<void*>(&ptr))) {
+            this->clear();
+            this->Base::operator=(WTFMove(ptr));
+            ptr.clearWithoutDestroy();
+        }
+        return *this;
+    }
+
+    PoisonedUniquePtr& operator=(const PoisonedUniquePtr&) = delete;
+
+    T* get() const { return this->unpoisoned(); }
+    T& operator[](size_t index) const { return this->unpoisoned()[index]; }
+
+    void clear()
+    {
+        destroy();
+        clearWithoutDestroy();
+    }
+
+private:
+    void destroy()
+    {
+        if (!this->bits())
+            return;
+        delete this->unpoisoned();
+    }
+
+    void clearWithoutDestroy() { Base::clear(); }
+
+    template<uint32_t, typename, typename> friend class PoisonedUniquePtr;
+};
+
+template<uint32_t key, typename T, typename... Arguments, typename Enable = void>
+PoisonedUniquePtr<key, T> makePoisonedUnique(Arguments&&... arguments)
+{
+    return PoisonedUniquePtr<key, T>::create(std::forward<Arguments>(arguments)...);
+}
+
+template<uint32_t key, typename T>
+class PoisonedUniquePtr<key, T[]> : public ConstExprPoisoned<key, T*> {
+    WTF_MAKE_FAST_ALLOCATED;
+    using Base = ConstExprPoisoned<key, T*>;
+public:
+    PoisonedUniquePtr() = default;
+    PoisonedUniquePtr(T* ptr) : Base(ptr) { }
+    PoisonedUniquePtr(PoisonedUniquePtr&& ptr) : Base(WTFMove(ptr)) { ptr.clearWithoutDestroy(); }
+
+    template<uint32_t key2>
+    PoisonedUniquePtr(PoisonedUniquePtr<key2, T[]>&& ptr)
+        : Base(ptr.unpoisoned())
+    {
+        ptr.clearWithoutDestroy();
+    }
+
+    PoisonedUniquePtr(const PoisonedUniquePtr&) = delete;
+
+    ~PoisonedUniquePtr() { destroy(); }
+
+    template<typename... Arguments>
+    static PoisonedUniquePtr create(size_t count, Arguments&&... arguments)
+    {
+        T* result = new T[count];
+        while (count--)
+            new (result + count) T(std::forward<Arguments>(arguments)...);
+        return result;
+    }
+
+    PoisonedUniquePtr& operator=(T* ptr)
+    {
+        if (LIKELY(this->unpoisoned() != ptr)) {
+            this->clear();
+            this->Base::operator=(ptr);
+        }
+        return *this;
+    }
+
+    template<uint32_t key2>
+    PoisonedUniquePtr& operator=(PoisonedUniquePtr<key2, T[]>&& ptr)
+    {
+        ASSERT(this == static_cast<void*>(&ptr) || this->unpoisoned() != ptr.unpoisoned());
+        if (LIKELY(this != static_cast<void*>(&ptr))) {
+            this->clear();
+            this->Base::operator=(WTFMove(ptr));
+            ptr.clearWithoutDestroy();
+        }
+        return *this;
+    }
+
+    PoisonedUniquePtr& operator=(const PoisonedUniquePtr&) = delete;
+
+    T* get() const { return this->unpoisoned(); }
+    T& operator[](size_t index) const { return this->unpoisoned()[index]; }
+
+    void clear()
+    {
+        destroy();
+        clearWithoutDestroy();
+    }
+
+private:
+    void destroy()
+    {
+        if (!this->bits())
+            return;
+        delete[] this->unpoisoned();
+    }
+
+    void clearWithoutDestroy() { Base::clear(); }
+
+    template<uint32_t, typename, typename> friend class PoisonedUniquePtr;
+};
+
+template<uint32_t key, typename T, typename... Arguments>
+PoisonedUniquePtr<key, T[]> makePoisonedUnique(size_t count, Arguments&&... arguments)
+{
+    return PoisonedUniquePtr<key, T[]>::create(count, std::forward<Arguments>(arguments)...);
+}
+
+} // namespace WTF
+
+using WTF::PoisonedUniquePtr;
+using WTF::makePoisonedUnique;
+
index bcbcd93..e3b4cc1 100644 (file)
@@ -1,3 +1,25 @@
+2017-12-21  Mark Lam  <mark.lam@apple.com>
+
+        Add WTF::PoisonedUniquePtr to replace std::unique_ptr when poisoning is desired.
+        https://bugs.webkit.org/show_bug.cgi?id=181062
+        <rdar://problem/36167040>
+
+        Reviewed by Chris Dumez.
+
+        * TestWebKitAPI/CMakeLists.txt:
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+
+        * TestWebKitAPI/Tests/WTF/ConstExprPoisoned.cpp:
+        - Removed an unneeded #include.
+
+        * TestWebKitAPI/Tests/WTF/PoisonedUniquePtr.cpp: Added.
+        (TestWebKitAPI::TEST):
+        (TestWebKitAPI::poisonedPtrFoo):
+        * TestWebKitAPI/Tests/WTF/PoisonedUniquePtrForNonTriviallyDestructibleArrays.cpp: Added.
+        (TestWebKitAPI::TEST):
+        * TestWebKitAPI/Tests/WTF/PoisonedUniquePtrForTriviallyDestructibleArrays.cpp: Added.
+        (TestWebKitAPI::TEST):
+
 2017-12-21  Jeremy Jones  <jeremyj@apple.com>
 
         Update FULLSCREEN_API feature defines.
index 40a2d37..06ba1d1 100644 (file)
@@ -126,6 +126,9 @@ set(TestWTF_SOURCES
     ${TESTWEBKITAPI_DIR}/Tests/WTF/Poisoned.cpp
     ${TESTWEBKITAPI_DIR}/Tests/WTF/PoisonedRef.cpp
     ${TESTWEBKITAPI_DIR}/Tests/WTF/PoisonedRefPtr.cpp
+    ${TESTWEBKITAPI_DIR}/Tests/WTF/PoisonedUniquePtr.cpp
+    ${TESTWEBKITAPI_DIR}/Tests/WTF/PoisonedUniquePtrForNonTriviallyDestructibleArrays.cpp
+    ${TESTWEBKITAPI_DIR}/Tests/WTF/PoisonedUniquePtrForTriviallyDestructibleArrays.cpp
     ${TESTWEBKITAPI_DIR}/Tests/WTF/PriorityQueue.cpp
     ${TESTWEBKITAPI_DIR}/Tests/WTF/RedBlackTree.cpp
     ${TESTWEBKITAPI_DIR}/Tests/WTF/Ref.cpp
index 165eadc..bd0c002 100644 (file)
                FE05FAED1FDB510E00093230 /* PoisonedRefPtr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE05FAEA1FDB510100093230 /* PoisonedRefPtr.cpp */; };
                FE05FAEF1FE0645B00093230 /* Poisoned.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE05FAEE1FE0643D00093230 /* Poisoned.cpp */; };
                FE05FAF11FE08CD400093230 /* ConstExprPoisoned.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE05FAF01FE08CCD00093230 /* ConstExprPoisoned.cpp */; };
+               FE05FB061FE84FB700093230 /* PoisonedUniquePtr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE05FB051FE84FAE00093230 /* PoisonedUniquePtr.cpp */; };
+               FEC8F4E71FE9C9050056FD8A /* PoisonedUniquePtrForTriviallyDestructibleArrays.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FEC8F4E61FE9C8DE0056FD8A /* PoisonedUniquePtrForTriviallyDestructibleArrays.cpp */; };
+               FEC8F4EB1FE9F5AF0056FD8A /* PoisonedUniquePtrForNonTriviallyDestructibleArrays.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FEC8F4EA1FE9F5A70056FD8A /* PoisonedUniquePtrForNonTriviallyDestructibleArrays.cpp */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXContainerItemProxy section */
                FE05FAEB1FDB510200093230 /* PoisonedRef.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PoisonedRef.cpp; sourceTree = "<group>"; };
                FE05FAEE1FE0643D00093230 /* Poisoned.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Poisoned.cpp; sourceTree = "<group>"; };
                FE05FAF01FE08CCD00093230 /* ConstExprPoisoned.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ConstExprPoisoned.cpp; sourceTree = "<group>"; };
+               FE05FB051FE84FAE00093230 /* PoisonedUniquePtr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PoisonedUniquePtr.cpp; sourceTree = "<group>"; };
                FEB6F74E1B2BA44E009E4922 /* NakedPtr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NakedPtr.cpp; sourceTree = "<group>"; };
+               FEC8F4E61FE9C8DE0056FD8A /* PoisonedUniquePtrForTriviallyDestructibleArrays.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PoisonedUniquePtrForTriviallyDestructibleArrays.cpp; sourceTree = "<group>"; };
+               FEC8F4EA1FE9F5A70056FD8A /* PoisonedUniquePtrForNonTriviallyDestructibleArrays.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PoisonedUniquePtrForNonTriviallyDestructibleArrays.cpp; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
                                FE05FAEE1FE0643D00093230 /* Poisoned.cpp */,
                                FE05FAEB1FDB510200093230 /* PoisonedRef.cpp */,
                                FE05FAEA1FDB510100093230 /* PoisonedRefPtr.cpp */,
+                               FE05FB051FE84FAE00093230 /* PoisonedUniquePtr.cpp */,
+                               FEC8F4EA1FE9F5A70056FD8A /* PoisonedUniquePtrForNonTriviallyDestructibleArrays.cpp */,
+                               FEC8F4E61FE9C8DE0056FD8A /* PoisonedUniquePtrForTriviallyDestructibleArrays.cpp */,
                                53EC253F1E96BC80000831B9 /* PriorityQueue.cpp */,
                                0FC6C4CB141027E0005B7F0C /* RedBlackTree.cpp */,
                                93A427AA180DA26400CD24D7 /* Ref.cpp */,
                                7C83DED41D0A590C00FEBCF3 /* HashSet.cpp in Sources */,
                                7C83DEE01D0A590C00FEBCF3 /* IntegerToStringConversion.cpp in Sources */,
                                7A0509411FB9F06400B33FB8 /* JSONValue.cpp in Sources */,
+                               FE05FB061FE84FB700093230 /* PoisonedUniquePtr.cpp in Sources */,
                                531C1D8E1DF8EF72006E979F /* LEBDecoder.cpp in Sources */,
                                A57D54F91F3397B400A97AA7 /* LifecycleLogger.cpp in Sources */,
                                93E2C5551FD3204100E1DF6A /* LineEnding.cpp in Sources */,
                                7C83DF321D0A590C00FEBCF3 /* StringBuilder.cpp in Sources */,
                                7CD4C26E1E2C0E6E00929470 /* StringConcatenate.cpp in Sources */,
                                7C83DF361D0A590C00FEBCF3 /* StringHasher.cpp in Sources */,
+                               FEC8F4E71FE9C9050056FD8A /* PoisonedUniquePtrForTriviallyDestructibleArrays.cpp in Sources */,
                                7C83DF371D0A590C00FEBCF3 /* StringImpl.cpp in Sources */,
                                7C83DF381D0A590C00FEBCF3 /* StringOperators.cpp in Sources */,
                                7C83DF3A1D0A590C00FEBCF3 /* StringView.cpp in Sources */,
                                9329AA291DE3F81E003ABD07 /* TextBreakIterator.cpp in Sources */,
                                E3DEA8111F0A589000CBC2E8 /* ThreadGroup.cpp in Sources */,
                                E38A0D351FD50CC300E98C8B /* Threading.cpp in Sources */,
+                               FEC8F4EB1FE9F5AF0056FD8A /* PoisonedUniquePtrForNonTriviallyDestructibleArrays.cpp in Sources */,
                                5311BD5E1EA9490E00525281 /* ThreadMessages.cpp in Sources */,
                                0F2C20B81DCD545000542D9E /* Time.cpp in Sources */,
                                7C83E03B1D0A602700FEBCF3 /* UtilitiesCocoa.mm in Sources */,
index 1675aa3..3110eb5 100644 (file)
@@ -26,7 +26,6 @@
 #include "config.h"
 
 #include "RefLogger.h"
-#include <mutex>
 #include <wtf/Poisoned.h>
 
 namespace TestWebKitAPI {
diff --git a/Tools/TestWebKitAPI/Tests/WTF/PoisonedUniquePtr.cpp b/Tools/TestWebKitAPI/Tests/WTF/PoisonedUniquePtr.cpp
new file mode 100644 (file)
index 0000000..4af4a3e
--- /dev/null
@@ -0,0 +1,538 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <wtf/PoisonedUniquePtr.h>
+
+namespace TestWebKitAPI {
+
+namespace {
+
+const uint32_t PoisonA = 0xaaaa;
+const uint32_t PoisonB = 0xbbbb;
+
+struct Logger {
+    Logger(const char* name, int& destructCount)
+        : name(*name)
+        , destructCount(destructCount)
+    { }
+
+    ~Logger() { ++destructCount; }
+
+    const char& name;
+    int& destructCount;
+};
+    
+struct DerivedLogger : Logger {
+    DerivedLogger(const char* name, int& destructCount)
+        : Logger(name, destructCount)
+    { }
+};
+
+struct Other {
+    Other(const char*, int&)
+    { }
+};
+
+} // anonymous namespace
+
+TEST(WTF_PoisonedUniquePtr, Basic)
+{
+    {
+        PoisonedUniquePtr<PoisonA, Logger> empty;
+        ASSERT_EQ(nullptr, empty.unpoisoned());
+        ASSERT_EQ(0u, empty.bits());
+    }
+
+    {
+        int aDestructCount = 0;
+        Logger* a = new Logger("a", aDestructCount);
+        {
+            PoisonedUniquePtr<PoisonA, Logger> ptr(a);
+            ASSERT_EQ(0, aDestructCount);
+            ASSERT_EQ(a, ptr.unpoisoned());
+            ASSERT_EQ(a, &*ptr);
+            ASSERT_EQ(&a->name, &ptr->name);
+
+#if ENABLE(POISON)
+            uintptr_t ptrBits;
+            std::memcpy(&ptrBits, &ptr, sizeof(ptrBits));
+            ASSERT_TRUE(ptrBits != bitwise_cast<uintptr_t>(a));
+#if ENABLE(POISON_ASSERTS)
+            ASSERT_TRUE((PoisonedUniquePtr<PoisonA, Logger>::isPoisoned(ptrBits)));
+#endif
+#endif // ENABLE(POISON)
+        }
+        ASSERT_EQ(1, aDestructCount);
+
+        int bDestructCount = 0;
+        DerivedLogger* b = new DerivedLogger("b", bDestructCount);
+        {
+            PoisonedUniquePtr<PoisonA, Logger> ptr(b);
+            ASSERT_EQ(0, bDestructCount);
+            ASSERT_EQ(b, ptr.unpoisoned());
+            ASSERT_EQ(b, &*ptr);
+            ASSERT_EQ(&b->name, &ptr->name);
+        }
+        ASSERT_EQ(1, bDestructCount);
+    }
+
+    {
+        int aDestructCount = 0;
+        Logger* a = new Logger("a", aDestructCount);
+        {
+            PoisonedUniquePtr<PoisonA, Logger> ptr = a;
+            ASSERT_EQ(0, aDestructCount);
+            ASSERT_EQ(a, ptr.unpoisoned());
+        }
+        ASSERT_EQ(1, aDestructCount);
+
+        int bDestructCount = 0;
+        DerivedLogger* b = new DerivedLogger("b", bDestructCount);
+        {
+            PoisonedUniquePtr<PoisonA, Logger> ptr = b;
+            ASSERT_EQ(0, bDestructCount);
+            ASSERT_EQ(b, ptr.unpoisoned());
+        }
+        ASSERT_EQ(1, bDestructCount);
+    }
+
+    {
+        int aDestructCount = 0;
+        const char* aName = "a";
+        {
+            PoisonedUniquePtr<PoisonA, Logger> ptr = PoisonedUniquePtr<PoisonA, Logger>::create(aName, aDestructCount);
+            ASSERT_EQ(0, aDestructCount);
+            ASSERT_TRUE(nullptr != ptr.unpoisoned());
+            ASSERT_EQ(aName, &ptr->name);
+        }
+        ASSERT_EQ(1, aDestructCount);
+
+        int bDestructCount = 0;
+        const char* bName = "b";
+        {
+            PoisonedUniquePtr<PoisonA, Logger> ptr = PoisonedUniquePtr<PoisonA, DerivedLogger>::create(bName, bDestructCount);
+            ASSERT_EQ(0, bDestructCount);
+            ASSERT_TRUE(nullptr != ptr.unpoisoned());
+            ASSERT_EQ(bName, &ptr->name);
+        }
+        ASSERT_EQ(1, bDestructCount);
+    }
+
+    {
+        int aDestructCount = 0;
+        const char* aName = "a";
+        {
+            PoisonedUniquePtr<PoisonA, Logger> ptr = makePoisonedUnique<PoisonA, Logger>(aName, aDestructCount);
+            ASSERT_EQ(0, aDestructCount);
+            ASSERT_TRUE(nullptr != ptr.unpoisoned());
+            ASSERT_EQ(aName, &ptr->name);
+        }
+        ASSERT_EQ(1, aDestructCount);
+
+        int bDestructCount = 0;
+        const char* bName = "b";
+        {
+            PoisonedUniquePtr<PoisonA, Logger> ptr = makePoisonedUnique<PoisonA, DerivedLogger>(bName, bDestructCount);
+            ASSERT_EQ(0, bDestructCount);
+            ASSERT_TRUE(nullptr != ptr.unpoisoned());
+            ASSERT_EQ(bName, &ptr->name);
+        }
+        ASSERT_EQ(1, bDestructCount);
+    }
+
+    {
+        int aDestructCount = 0;
+        int bDestructCount = 0;
+        Logger* a = new Logger("a", aDestructCount);
+        Logger* b = new Logger("b", bDestructCount);
+        {
+            PoisonedUniquePtr<PoisonA, Logger> p1 = a;
+            PoisonedUniquePtr<PoisonA, Logger> p2 = WTFMove(p1);
+            ASSERT_EQ(aDestructCount, 0);
+            ASSERT_EQ(nullptr, p1.unpoisoned());
+            ASSERT_EQ(0u, p1.bits());
+            ASSERT_EQ(a, p2.unpoisoned());
+
+            PoisonedUniquePtr<PoisonA, Logger> p3 = b;
+            PoisonedUniquePtr<PoisonB, Logger> p4 = WTFMove(p3);
+            ASSERT_EQ(0, bDestructCount);
+            ASSERT_EQ(nullptr, p3.unpoisoned());
+            ASSERT_EQ(0u, p3.bits());
+            ASSERT_EQ(b, p4.unpoisoned());
+        }
+        ASSERT_EQ(1, aDestructCount);
+        ASSERT_EQ(1, bDestructCount);
+    }
+
+    {
+        int aDestructCount = 0;
+        int bDestructCount = 0;
+        Logger* a = new Logger("a", aDestructCount);
+        Logger* b = new Logger("b", bDestructCount);
+        {
+            PoisonedUniquePtr<PoisonA, Logger> p1 = a;
+            PoisonedUniquePtr<PoisonA, Logger> p2(WTFMove(p1));
+            ASSERT_EQ(0, aDestructCount);
+            ASSERT_EQ(nullptr, p1.unpoisoned());
+            ASSERT_EQ(0u, p1.bits());
+            ASSERT_EQ(a, p2.unpoisoned());
+
+            PoisonedUniquePtr<PoisonA, Logger> p3 = b;
+            PoisonedUniquePtr<PoisonB, Logger> p4(WTFMove(p3));
+            ASSERT_EQ(0, bDestructCount);
+            ASSERT_EQ(nullptr, p3.unpoisoned());
+            ASSERT_EQ(0u, p3.bits());
+            ASSERT_EQ(b, p4.unpoisoned());
+        }
+        ASSERT_EQ(1, aDestructCount);
+        ASSERT_EQ(1, bDestructCount);
+    }
+
+    {
+        int aDestructCount = 0;
+        int bDestructCount = 0;
+        DerivedLogger* a = new DerivedLogger("a", aDestructCount);
+        DerivedLogger* b = new DerivedLogger("b", bDestructCount);
+        {
+            PoisonedUniquePtr<PoisonA, Logger> p1 = a;
+            PoisonedUniquePtr<PoisonA, Logger> p2 = WTFMove(p1);
+            ASSERT_EQ(aDestructCount, 0);
+            ASSERT_TRUE(!p1.unpoisoned());
+            ASSERT_TRUE(!p1.bits());
+            ASSERT_EQ(a, p2.unpoisoned());
+
+            PoisonedUniquePtr<PoisonA, Logger> p3 = b;
+            PoisonedUniquePtr<PoisonB, Logger> p4 = WTFMove(p3);
+            ASSERT_EQ(bDestructCount, 0);
+            ASSERT_TRUE(!p3.unpoisoned());
+            ASSERT_TRUE(!p3.bits());
+            ASSERT_EQ(b, p4.unpoisoned());
+        }
+        ASSERT_EQ(1, aDestructCount);
+        ASSERT_EQ(1, bDestructCount);
+    }
+
+    {
+        int aDestructCount = 0;
+        int bDestructCount = 0;
+        DerivedLogger* a = new DerivedLogger("a", aDestructCount);
+        DerivedLogger* b = new DerivedLogger("b", bDestructCount);
+        {
+            PoisonedUniquePtr<PoisonA, Logger> p1 = a;
+            PoisonedUniquePtr<PoisonA, Logger> p2(WTFMove(p1));
+            ASSERT_EQ(aDestructCount, 0);
+            ASSERT_TRUE(!p1.unpoisoned());
+            ASSERT_TRUE(!p1.bits());
+            ASSERT_EQ(a, p2.unpoisoned());
+
+            PoisonedUniquePtr<PoisonA, Logger> p3 = b;
+            PoisonedUniquePtr<PoisonB, Logger> p4(WTFMove(p3));
+            ASSERT_EQ(bDestructCount, 0);
+            ASSERT_TRUE(!p3.unpoisoned());
+            ASSERT_TRUE(!p3.bits());
+            ASSERT_EQ(b, p4.unpoisoned());
+        }
+        ASSERT_EQ(1, aDestructCount);
+        ASSERT_EQ(1, bDestructCount);
+    }
+
+    {
+        int aDestructCount = 0;
+        Logger* a = new Logger("a", aDestructCount);
+        {
+            PoisonedUniquePtr<PoisonA, Logger> ptr(a);
+            ASSERT_EQ(a, ptr.unpoisoned());
+            ptr.clear();
+            ASSERT_TRUE(!ptr.unpoisoned());
+            ASSERT_TRUE(!ptr.bits());
+            ASSERT_EQ(1, aDestructCount);
+        }
+        ASSERT_EQ(1, aDestructCount);
+    }
+}
+
+TEST(WTF_PoisonedUniquePtr, Assignment)
+{
+    {
+        int aDestructCount = 0;
+        int bDestructCount = 0;
+        Logger* a = new Logger("a", aDestructCount);
+        Logger* b = new Logger("b", bDestructCount);
+        {
+            PoisonedUniquePtr<PoisonA, Logger> ptr(a);
+            ASSERT_EQ(0, aDestructCount);
+            ASSERT_EQ(0, bDestructCount);
+            ASSERT_EQ(a, ptr.unpoisoned());
+            ptr = b;
+            ASSERT_EQ(1, aDestructCount);
+            ASSERT_EQ(0, bDestructCount);
+            ASSERT_EQ(b, ptr.unpoisoned());
+        }
+        ASSERT_EQ(1, aDestructCount);
+        ASSERT_EQ(1, bDestructCount);
+    }
+
+    {
+        int aDestructCount = 0;
+        Logger* a = new Logger("a", aDestructCount);
+        {
+            PoisonedUniquePtr<PoisonA, Logger> ptr(a);
+            ASSERT_EQ(0, aDestructCount);
+            ASSERT_EQ(a, ptr.unpoisoned());
+            ptr = nullptr;
+            ASSERT_EQ(1, aDestructCount);
+            ASSERT_EQ(nullptr, ptr.unpoisoned());
+        }
+        ASSERT_EQ(1, aDestructCount);
+    }
+
+    {
+        int aDestructCount = 0;
+        int bDestructCount = 0;
+        int cDestructCount = 0;
+        int dDestructCount = 0;
+        Logger* a = new Logger("a", aDestructCount);
+        Logger* b = new Logger("b", bDestructCount);
+        Logger* c = new Logger("c", cDestructCount);
+        Logger* d = new Logger("d", dDestructCount);
+        {
+            PoisonedUniquePtr<PoisonA, Logger> p1(a);
+            PoisonedUniquePtr<PoisonA, Logger> p2(b);
+            ASSERT_EQ(0, aDestructCount);
+            ASSERT_EQ(0, bDestructCount);
+            ASSERT_EQ(a, p1.unpoisoned());
+            ASSERT_EQ(b, p2.unpoisoned());
+            p1 = WTFMove(p2);
+            ASSERT_EQ(1, aDestructCount);
+            ASSERT_EQ(0, bDestructCount);
+            ASSERT_EQ(b, p1.unpoisoned());
+            ASSERT_EQ(nullptr, p2.unpoisoned());
+
+            PoisonedUniquePtr<PoisonA, Logger> p3(c);
+            PoisonedUniquePtr<PoisonB, Logger> p4(d);
+            ASSERT_EQ(0, cDestructCount);
+            ASSERT_EQ(0, dDestructCount);
+            ASSERT_EQ(c, p3.unpoisoned());
+            ASSERT_EQ(d, p4.unpoisoned());
+            p3 = WTFMove(p4);
+            ASSERT_EQ(1, cDestructCount);
+            ASSERT_EQ(0, dDestructCount);
+            ASSERT_EQ(d, p3.unpoisoned());
+            ASSERT_EQ(nullptr, p4.unpoisoned());
+        }
+        ASSERT_EQ(1, aDestructCount);
+        ASSERT_EQ(1, bDestructCount);
+        ASSERT_EQ(1, cDestructCount);
+        ASSERT_EQ(1, dDestructCount);
+    }
+
+    {
+        int aDestructCount = 0;
+        int bDestructCount = 0;
+        DerivedLogger* a = new DerivedLogger("a", aDestructCount);
+        DerivedLogger* b = new DerivedLogger("b", bDestructCount);
+        {
+            PoisonedUniquePtr<PoisonA, Logger> ptr(a);
+            ASSERT_EQ(0, aDestructCount);
+            ASSERT_EQ(0, bDestructCount);
+            ASSERT_EQ(a, ptr.unpoisoned());
+            ptr = b;
+            ASSERT_EQ(1, aDestructCount);
+            ASSERT_EQ(0, bDestructCount);
+            ASSERT_EQ(b, ptr.unpoisoned());
+        }
+        ASSERT_EQ(1, aDestructCount);
+        ASSERT_EQ(1, bDestructCount);
+    }
+
+    {
+        int aDestructCount = 0;
+        int bDestructCount = 0;
+        int cDestructCount = 0;
+        int dDestructCount = 0;
+        DerivedLogger* a = new DerivedLogger("a", aDestructCount);
+        DerivedLogger* b = new DerivedLogger("b", bDestructCount);
+        DerivedLogger* c = new DerivedLogger("c", cDestructCount);
+        DerivedLogger* d = new DerivedLogger("d", dDestructCount);
+        {
+            PoisonedUniquePtr<PoisonA, Logger> p1(a);
+            PoisonedUniquePtr<PoisonA, DerivedLogger> p2(b);
+            ASSERT_EQ(0, aDestructCount);
+            ASSERT_EQ(0, bDestructCount);
+            ASSERT_EQ(a, p1.unpoisoned());
+            ASSERT_EQ(b, p2.unpoisoned());
+            p1 = WTFMove(p2);
+            ASSERT_EQ(1, aDestructCount);
+            ASSERT_EQ(0, bDestructCount);
+            ASSERT_EQ(b, p1.unpoisoned());
+            ASSERT_EQ(nullptr, p2.unpoisoned());
+
+            PoisonedUniquePtr<PoisonA, Logger> p3(c);
+            PoisonedUniquePtr<PoisonB, DerivedLogger> p4(d);
+            ASSERT_EQ(0, cDestructCount);
+            ASSERT_EQ(0, dDestructCount);
+            ASSERT_EQ(c, p3.unpoisoned());
+            ASSERT_EQ(d, p4.unpoisoned());
+            p3 = WTFMove(p4);
+            ASSERT_EQ(1, cDestructCount);
+            ASSERT_EQ(0, dDestructCount);
+            ASSERT_EQ(d, p3.unpoisoned());
+            ASSERT_EQ(nullptr, p4.unpoisoned());
+        }
+        ASSERT_EQ(1, aDestructCount);
+        ASSERT_EQ(1, bDestructCount);
+        ASSERT_EQ(1, cDestructCount);
+        ASSERT_EQ(1, dDestructCount);
+    }
+
+    {
+        int aDestructCount = 0;
+        Logger* a = new Logger("a", aDestructCount);
+        {
+            PoisonedUniquePtr<PoisonA, Logger> ptr(a);
+            ASSERT_EQ(0, aDestructCount);
+            ASSERT_EQ(a, ptr.unpoisoned());
+            ptr = a;
+            ASSERT_EQ(0, aDestructCount);
+            ASSERT_EQ(a, ptr.unpoisoned());
+        }
+        ASSERT_EQ(1, aDestructCount);
+    }
+
+    {
+        int aDestructCount = 0;
+        Logger* a = new Logger("a", aDestructCount);
+        {
+            PoisonedUniquePtr<PoisonA, Logger> ptr(a);
+            ASSERT_EQ(0, aDestructCount);
+            ASSERT_EQ(a, ptr.unpoisoned());
+#if COMPILER(CLANG)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunknown-pragmas"
+#pragma clang diagnostic ignored "-Wself-move"
+#endif
+            ptr = WTFMove(ptr);
+#if COMPILER(CLANG)
+#pragma clang diagnostic pop
+#endif
+            ASSERT_EQ(0, aDestructCount);
+            ASSERT_EQ(a, ptr.unpoisoned());
+        }
+        ASSERT_EQ(1, aDestructCount);
+    }
+}
+
+TEST(WTF_PoisonedUniquePtr, Swap)
+{
+    {
+        int aDestructCount = 0;
+        int bDestructCount = 0;
+        Logger* a = new Logger("a", aDestructCount);
+        Logger* b = new Logger("b", bDestructCount);
+        {
+            PoisonedUniquePtr<PoisonA, Logger> p1 = a;
+            PoisonedUniquePtr<PoisonA, Logger> p2;
+            ASSERT_EQ(a, p1.unpoisoned());
+            ASSERT_TRUE(!p2.bits());
+            ASSERT_TRUE(!p2.unpoisoned());
+            p2.swap(p1);
+            ASSERT_EQ(aDestructCount, 0);
+            ASSERT_TRUE(!p1.bits());
+            ASSERT_TRUE(!p1.unpoisoned());
+            ASSERT_EQ(a, p2.unpoisoned());
+
+            PoisonedUniquePtr<PoisonA, Logger> p3 = b;
+            PoisonedUniquePtr<PoisonB, Logger> p4;
+            ASSERT_EQ(b, p3.unpoisoned());
+            ASSERT_TRUE(!p4.bits());
+            ASSERT_TRUE(!p4.unpoisoned());
+            p4.swap(p3);
+            ASSERT_EQ(0, bDestructCount);
+            ASSERT_TRUE(!p3.bits());
+            ASSERT_TRUE(!p3.unpoisoned());
+            ASSERT_EQ(b, p4.unpoisoned());
+        }
+        ASSERT_EQ(1, aDestructCount);
+        ASSERT_EQ(1, bDestructCount);
+    }
+
+    {
+        int aDestructCount = 0;
+        int bDestructCount = 0;
+        Logger* a = new Logger("a", aDestructCount);
+        Logger* b = new Logger("b", bDestructCount);
+        {
+            PoisonedUniquePtr<PoisonA, Logger> p1 = a;
+            PoisonedUniquePtr<PoisonA, Logger> p2;
+            ASSERT_EQ(a, p1.unpoisoned());
+            ASSERT_TRUE(!p2.bits());
+            ASSERT_TRUE(!p2.unpoisoned());
+            swap(p1, p2);
+            ASSERT_EQ(0, aDestructCount);
+            ASSERT_TRUE(!p1.bits());
+            ASSERT_TRUE(!p1.unpoisoned());
+            ASSERT_EQ(a, p2.unpoisoned());
+
+            PoisonedUniquePtr<PoisonA, Logger> p3 = b;
+            PoisonedUniquePtr<PoisonB, Logger> p4;
+            ASSERT_EQ(b, p3.unpoisoned());
+            ASSERT_TRUE(!p4.bits());
+            ASSERT_TRUE(!p4.unpoisoned());
+            swap(p3, p4);
+            ASSERT_EQ(0, bDestructCount);
+            ASSERT_TRUE(!p3.bits());
+            ASSERT_TRUE(!p3.unpoisoned());
+            ASSERT_EQ(b, p4.unpoisoned());
+        }
+        ASSERT_EQ(1, aDestructCount);
+        ASSERT_EQ(1, bDestructCount);
+    }
+}
+
+static PoisonedUniquePtr<PoisonA, Logger> poisonedPtrFoo(Logger* logger)
+{
+    return PoisonedUniquePtr<PoisonA, Logger>(logger);
+}
+
+TEST(WTF_PoisonedUniquePtr, ReturnValue)
+{
+    {
+        int aDestructCount = 0;
+        Logger* a = new Logger("a", aDestructCount);
+        {
+            auto ptr = poisonedPtrFoo(a);
+            ASSERT_EQ(0, aDestructCount);
+            ASSERT_EQ(a, ptr.unpoisoned());
+            ASSERT_EQ(a, &*ptr);
+            ASSERT_EQ(&a->name, &ptr->name);
+        }
+        ASSERT_EQ(1, aDestructCount);
+    }
+}
+
+} // namespace TestWebKitAPI
+
diff --git a/Tools/TestWebKitAPI/Tests/WTF/PoisonedUniquePtrForNonTriviallyDestructibleArrays.cpp b/Tools/TestWebKitAPI/Tests/WTF/PoisonedUniquePtrForNonTriviallyDestructibleArrays.cpp
new file mode 100644 (file)
index 0000000..a96ebaf
--- /dev/null
@@ -0,0 +1,459 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <wtf/PoisonedUniquePtr.h>
+
+namespace TestWebKitAPI {
+
+namespace {
+
+const uint32_t PoisonA = 0xaaaa;
+const uint32_t PoisonB = 0xbbbb;
+
+struct Logger {
+    Logger() { }
+    Logger(const char* name, int& destructCount)
+        : name(name)
+        , destructCount(&destructCount)
+    { }
+
+    ~Logger() { ++(*destructCount); }
+
+    const char* name;
+    int* destructCount;
+};
+    
+template<typename T, typename... Arguments>
+T* makeArray(size_t count, Arguments&&... arguments)
+{
+    T* result = new T[count];
+    while (count--)
+        new (result + count) T(std::forward<Arguments>(arguments)...);
+    return result;
+}
+
+const int arraySize = 5;
+
+} // anonymous namespace
+
+TEST(WTF_PoisonedUniquePtrForNonTriviallyDestructibleArrays, Basic)
+{
+    {
+        PoisonedUniquePtr<PoisonA, Logger[]> empty;
+        ASSERT_EQ(nullptr, empty.unpoisoned());
+        ASSERT_EQ(0u, empty.bits());
+    }
+
+    {
+        int aDestructCount = 0;
+        Logger* a = makeArray<Logger>(arraySize, "a", aDestructCount);
+        {
+            PoisonedUniquePtr<PoisonA, Logger[]> ptr(a);
+            ASSERT_EQ(0, aDestructCount);
+            ASSERT_EQ(a, ptr.unpoisoned());
+            ASSERT_EQ(a, &*ptr);
+            for (auto i = 0; i < arraySize; ++i)
+                ASSERT_EQ(a[i].name, ptr[i].name);
+
+#if ENABLE(POISON)
+            uintptr_t ptrBits;
+            std::memcpy(&ptrBits, &ptr, sizeof(ptrBits));
+            ASSERT_TRUE(ptrBits != bitwise_cast<uintptr_t>(a));
+#if ENABLE(POISON_ASSERTS)
+            ASSERT_TRUE((PoisonedUniquePtr<PoisonA, Logger[]>::isPoisoned(ptrBits)));
+#endif
+#endif // ENABLE(POISON)
+        }
+        ASSERT_EQ(arraySize, aDestructCount);
+    }
+
+    {
+        int aDestructCount = 0;
+        Logger* a = makeArray<Logger>(arraySize, "a", aDestructCount);
+        {
+            PoisonedUniquePtr<PoisonA, Logger[]> ptr = a;
+            ASSERT_EQ(0, aDestructCount);
+            ASSERT_EQ(a, ptr.unpoisoned());
+            for (auto i = 0; i < arraySize; ++i)
+                ASSERT_EQ(a[i].name, ptr[i].name);
+        }
+        ASSERT_EQ(arraySize, aDestructCount);
+    }
+
+    {
+        int aDestructCount = 0;
+        const char* aName = "a";
+        {
+            PoisonedUniquePtr<PoisonA, Logger[]> ptr = PoisonedUniquePtr<PoisonA, Logger[]>::create(arraySize, aName, aDestructCount);
+            ASSERT_EQ(0, aDestructCount);
+            ASSERT_TRUE(nullptr != ptr.unpoisoned());
+            for (auto i = 0; i < arraySize; ++i)
+                ASSERT_EQ(aName, ptr[i].name);
+        }
+        ASSERT_EQ(arraySize, aDestructCount);
+    }
+
+    {
+        int aDestructCount = 0;
+        const char* aName = "a";
+        {
+            PoisonedUniquePtr<PoisonA, Logger[]> ptr = makePoisonedUnique<PoisonA, Logger[]>(arraySize, aName, aDestructCount);
+            ASSERT_EQ(0, aDestructCount);
+            ASSERT_TRUE(nullptr != ptr.unpoisoned());
+            for (auto i = 0; i < arraySize; ++i)
+                ASSERT_EQ(aName, ptr[i].name);
+        }
+        ASSERT_EQ(arraySize, aDestructCount);
+    }
+
+    {
+        int aDestructCount = 0;
+        const char* aName = "a";
+        {
+            PoisonedUniquePtr<PoisonA, Logger[]> ptr = makePoisonedUnique<PoisonA, Logger[]>(arraySize, aName, aDestructCount);
+            ASSERT_EQ(0, aDestructCount);
+            ASSERT_TRUE(nullptr != ptr.unpoisoned());
+            for (auto i = 0; i < arraySize; ++i)
+                ASSERT_EQ(aName, ptr[i].name);
+        }
+        ASSERT_EQ(arraySize, aDestructCount);
+    }
+
+    {
+        int aDestructCount = 0;
+        int bDestructCount = 0;
+        Logger* a = makeArray<Logger>(arraySize, "a", aDestructCount);
+        Logger* b = makeArray<Logger>(arraySize, "b", bDestructCount);
+        {
+            PoisonedUniquePtr<PoisonA, Logger[]> p1 = a;
+            PoisonedUniquePtr<PoisonA, Logger[]> p2 = WTFMove(p1);
+            ASSERT_EQ(aDestructCount, 0);
+            ASSERT_EQ(nullptr, p1.unpoisoned());
+            ASSERT_EQ(0u, p1.bits());
+            ASSERT_EQ(a, p2.unpoisoned());
+
+            PoisonedUniquePtr<PoisonA, Logger[]> p3 = b;
+            PoisonedUniquePtr<PoisonB, Logger[]> p4 = WTFMove(p3);
+            ASSERT_EQ(0, bDestructCount);
+            ASSERT_EQ(nullptr, p3.unpoisoned());
+            ASSERT_EQ(0u, p3.bits());
+            ASSERT_EQ(b, p4.unpoisoned());
+        }
+        ASSERT_EQ(arraySize, aDestructCount);
+        ASSERT_EQ(arraySize, bDestructCount);
+    }
+
+    {
+        int aDestructCount = 0;
+        int bDestructCount = 0;
+        Logger* a = makeArray<Logger>(arraySize, "a", aDestructCount);
+        Logger* b = makeArray<Logger>(arraySize, "b", bDestructCount);
+        {
+            PoisonedUniquePtr<PoisonA, Logger[]> p1 = a;
+            PoisonedUniquePtr<PoisonA, Logger[]> p2(WTFMove(p1));
+            ASSERT_EQ(0, aDestructCount);
+            ASSERT_EQ(nullptr, p1.unpoisoned());
+            ASSERT_EQ(0u, p1.bits());
+            ASSERT_EQ(a, p2.unpoisoned());
+
+            PoisonedUniquePtr<PoisonA, Logger[]> p3 = b;
+            PoisonedUniquePtr<PoisonB, Logger[]> p4(WTFMove(p3));
+            ASSERT_EQ(0, bDestructCount);
+            ASSERT_EQ(nullptr, p3.unpoisoned());
+            ASSERT_EQ(0u, p3.bits());
+            ASSERT_EQ(b, p4.unpoisoned());
+        }
+        ASSERT_EQ(arraySize, aDestructCount);
+        ASSERT_EQ(arraySize, bDestructCount);
+    }
+
+    {
+        int aDestructCount = 0;
+        int bDestructCount = 0;
+        Logger* a = makeArray<Logger>(arraySize, "a", aDestructCount);
+        Logger* b = makeArray<Logger>(arraySize, "b", bDestructCount);
+        {
+            PoisonedUniquePtr<PoisonA, Logger[]> p1 = a;
+            PoisonedUniquePtr<PoisonA, Logger[]> p2 = WTFMove(p1);
+            ASSERT_EQ(aDestructCount, 0);
+            ASSERT_TRUE(!p1.unpoisoned());
+            ASSERT_TRUE(!p1.bits());
+            ASSERT_EQ(a, p2.unpoisoned());
+
+            PoisonedUniquePtr<PoisonA, Logger[]> p3 = b;
+            PoisonedUniquePtr<PoisonB, Logger[]> p4 = WTFMove(p3);
+            ASSERT_EQ(bDestructCount, 0);
+            ASSERT_TRUE(!p3.unpoisoned());
+            ASSERT_TRUE(!p3.bits());
+            ASSERT_EQ(b, p4.unpoisoned());
+        }
+        ASSERT_EQ(arraySize, aDestructCount);
+        ASSERT_EQ(arraySize, bDestructCount);
+    }
+
+    {
+        int aDestructCount = 0;
+        int bDestructCount = 0;
+        Logger* a = makeArray<Logger>(arraySize, "a", aDestructCount);
+        Logger* b = makeArray<Logger>(arraySize, "b", bDestructCount);
+        {
+            PoisonedUniquePtr<PoisonA, Logger[]> p1 = a;
+            PoisonedUniquePtr<PoisonA, Logger[]> p2(WTFMove(p1));
+            ASSERT_EQ(aDestructCount, 0);
+            ASSERT_TRUE(!p1.unpoisoned());
+            ASSERT_TRUE(!p1.bits());
+            ASSERT_EQ(a, p2.unpoisoned());
+
+            PoisonedUniquePtr<PoisonA, Logger[]> p3 = b;
+            PoisonedUniquePtr<PoisonB, Logger[]> p4(WTFMove(p3));
+            ASSERT_EQ(bDestructCount, 0);
+            ASSERT_TRUE(!p3.unpoisoned());
+            ASSERT_TRUE(!p3.bits());
+            ASSERT_EQ(b, p4.unpoisoned());
+        }
+        ASSERT_EQ(arraySize, aDestructCount);
+        ASSERT_EQ(arraySize, bDestructCount);
+    }
+
+    {
+        int aDestructCount = 0;
+        Logger* a = makeArray<Logger>(arraySize, "a", aDestructCount);
+        {
+            PoisonedUniquePtr<PoisonA, Logger[]> ptr(a);
+            ASSERT_EQ(a, ptr.unpoisoned());
+            ptr.clear();
+            ASSERT_TRUE(!ptr.unpoisoned());
+            ASSERT_TRUE(!ptr.bits());
+            ASSERT_EQ(arraySize, aDestructCount);
+        }
+        ASSERT_EQ(arraySize, aDestructCount);
+    }
+}
+
+TEST(WTF_PoisonedUniquePtrForNonTriviallyDestructibleArrays, Assignment)
+{
+    {
+        int aDestructCount = 0;
+        int bDestructCount = 0;
+        Logger* a = makeArray<Logger>(arraySize, "a", aDestructCount);
+        Logger* b = makeArray<Logger>(arraySize, "b", bDestructCount);
+        {
+            PoisonedUniquePtr<PoisonA, Logger[]> ptr(a);
+            ASSERT_EQ(0, aDestructCount);
+            ASSERT_EQ(0, bDestructCount);
+            ASSERT_EQ(a, ptr.unpoisoned());
+            ptr = b;
+            ASSERT_EQ(arraySize, aDestructCount);
+            ASSERT_EQ(0, bDestructCount);
+            ASSERT_EQ(b, ptr.unpoisoned());
+        }
+        ASSERT_EQ(arraySize, aDestructCount);
+        ASSERT_EQ(arraySize, bDestructCount);
+    }
+
+    {
+        int aDestructCount = 0;
+        Logger* a = makeArray<Logger>(arraySize, "a", aDestructCount);
+        {
+            PoisonedUniquePtr<PoisonA, Logger[]> ptr(a);
+            ASSERT_EQ(0, aDestructCount);
+            ASSERT_EQ(a, ptr.unpoisoned());
+            ptr = nullptr;
+            ASSERT_EQ(arraySize, aDestructCount);
+            ASSERT_EQ(nullptr, ptr.unpoisoned());
+        }
+        ASSERT_EQ(arraySize, aDestructCount);
+    }
+
+    {
+        int aDestructCount = 0;
+        int bDestructCount = 0;
+        int cDestructCount = 0;
+        int dDestructCount = 0;
+        Logger* a = makeArray<Logger>(arraySize, "a", aDestructCount);
+        Logger* b = makeArray<Logger>(arraySize, "b", bDestructCount);
+        Logger* c = makeArray<Logger>(arraySize, "c", cDestructCount);
+        Logger* d = makeArray<Logger>(arraySize, "d", dDestructCount);
+        {
+            PoisonedUniquePtr<PoisonA, Logger[]> p1(a);
+            PoisonedUniquePtr<PoisonA, Logger[]> p2(b);
+            ASSERT_EQ(0, aDestructCount);
+            ASSERT_EQ(0, bDestructCount);
+            ASSERT_EQ(a, p1.unpoisoned());
+            ASSERT_EQ(b, p2.unpoisoned());
+            p1 = WTFMove(p2);
+            ASSERT_EQ(arraySize, aDestructCount);
+            ASSERT_EQ(0, bDestructCount);
+            ASSERT_EQ(b, p1.unpoisoned());
+            ASSERT_EQ(nullptr, p2.unpoisoned());
+
+            PoisonedUniquePtr<PoisonA, Logger[]> p3(c);
+            PoisonedUniquePtr<PoisonB, Logger[]> p4(d);
+            ASSERT_EQ(0, cDestructCount);
+            ASSERT_EQ(0, dDestructCount);
+            ASSERT_EQ(c, p3.unpoisoned());
+            ASSERT_EQ(d, p4.unpoisoned());
+            p3 = WTFMove(p4);
+            ASSERT_EQ(arraySize, cDestructCount);
+            ASSERT_EQ(0, dDestructCount);
+            ASSERT_EQ(d, p3.unpoisoned());
+            ASSERT_EQ(nullptr, p4.unpoisoned());
+        }
+        ASSERT_EQ(arraySize, aDestructCount);
+        ASSERT_EQ(arraySize, bDestructCount);
+        ASSERT_EQ(arraySize, cDestructCount);
+        ASSERT_EQ(arraySize, dDestructCount);
+    }
+
+    {
+        int aDestructCount = 0;
+        Logger* a = makeArray<Logger>(arraySize, "a", aDestructCount);
+        {
+            PoisonedUniquePtr<PoisonA, Logger[]> ptr(a);
+            ASSERT_EQ(0, aDestructCount);
+            ASSERT_EQ(a, ptr.unpoisoned());
+            ptr = a;
+            ASSERT_EQ(0, aDestructCount);
+            ASSERT_EQ(a, ptr.unpoisoned());
+        }
+        ASSERT_EQ(arraySize, aDestructCount);
+    }
+
+    {
+        int aDestructCount = 0;
+        Logger* a = makeArray<Logger>(arraySize, "a", aDestructCount);
+        {
+            PoisonedUniquePtr<PoisonA, Logger[]> ptr(a);
+            ASSERT_EQ(0, aDestructCount);
+            ASSERT_EQ(a, ptr.unpoisoned());
+#if COMPILER(CLANG)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunknown-pragmas"
+#pragma clang diagnostic ignored "-Wself-move"
+#endif
+            ptr = WTFMove(ptr);
+#if COMPILER(CLANG)
+#pragma clang diagnostic pop
+#endif
+            ASSERT_EQ(0, aDestructCount);
+            ASSERT_EQ(a, ptr.unpoisoned());
+        }
+        ASSERT_EQ(arraySize, aDestructCount);
+    }
+}
+
+TEST(WTF_PoisonedUniquePtrForNonTriviallyDestructibleArrays, Swap)
+{
+    {
+        int aDestructCount = 0;
+        int bDestructCount = 0;
+        Logger* a = makeArray<Logger>(arraySize, "a", aDestructCount);
+        Logger* b = makeArray<Logger>(arraySize, "b", bDestructCount);
+        {
+            PoisonedUniquePtr<PoisonA, Logger[]> p1 = a;
+            PoisonedUniquePtr<PoisonA, Logger[]> p2;
+            ASSERT_EQ(a, p1.unpoisoned());
+            ASSERT_TRUE(!p2.bits());
+            ASSERT_TRUE(!p2.unpoisoned());
+            p2.swap(p1);
+            ASSERT_EQ(aDestructCount, 0);
+            ASSERT_TRUE(!p1.bits());
+            ASSERT_TRUE(!p1.unpoisoned());
+            ASSERT_EQ(a, p2.unpoisoned());
+
+            PoisonedUniquePtr<PoisonA, Logger[]> p3 = b;
+            PoisonedUniquePtr<PoisonB, Logger[]> p4;
+            ASSERT_EQ(b, p3.unpoisoned());
+            ASSERT_TRUE(!p4.bits());
+            ASSERT_TRUE(!p4.unpoisoned());
+            p4.swap(p3);
+            ASSERT_EQ(0, bDestructCount);
+            ASSERT_TRUE(!p3.bits());
+            ASSERT_TRUE(!p3.unpoisoned());
+            ASSERT_EQ(b, p4.unpoisoned());
+        }
+        ASSERT_EQ(arraySize, aDestructCount);
+        ASSERT_EQ(arraySize, bDestructCount);
+    }
+
+    {
+        int aDestructCount = 0;
+        int bDestructCount = 0;
+        Logger* a = makeArray<Logger>(arraySize, "a", aDestructCount);
+        Logger* b = makeArray<Logger>(arraySize, "b", bDestructCount);
+        {
+            PoisonedUniquePtr<PoisonA, Logger[]> p1 = a;
+            PoisonedUniquePtr<PoisonA, Logger[]> p2;
+            ASSERT_EQ(a, p1.unpoisoned());
+            ASSERT_TRUE(!p2.bits());
+            ASSERT_TRUE(!p2.unpoisoned());
+            swap(p1, p2);
+            ASSERT_EQ(0, aDestructCount);
+            ASSERT_TRUE(!p1.bits());
+            ASSERT_TRUE(!p1.unpoisoned());
+            ASSERT_EQ(a, p2.unpoisoned());
+
+            PoisonedUniquePtr<PoisonA, Logger[]> p3 = b;
+            PoisonedUniquePtr<PoisonB, Logger[]> p4;
+            ASSERT_EQ(b, p3.unpoisoned());
+            ASSERT_TRUE(!p4.bits());
+            ASSERT_TRUE(!p4.unpoisoned());
+            swap(p3, p4);
+            ASSERT_EQ(0, bDestructCount);
+            ASSERT_TRUE(!p3.bits());
+            ASSERT_TRUE(!p3.unpoisoned());
+            ASSERT_EQ(b, p4.unpoisoned());
+        }
+        ASSERT_EQ(arraySize, aDestructCount);
+        ASSERT_EQ(arraySize, bDestructCount);
+    }
+}
+
+static PoisonedUniquePtr<PoisonA, Logger[]> poisonedPtrFoo(Logger* array)
+{
+    return PoisonedUniquePtr<PoisonA, Logger[]>(array);
+}
+
+TEST(WTF_PoisonedUniquePtrForNonTriviallyDestructibleArrays, ReturnValue)
+{
+    {
+        int aDestructCount = 0;
+        Logger* a = makeArray<Logger>(arraySize, "a", aDestructCount);
+        {
+            auto ptr = poisonedPtrFoo(a);
+            ASSERT_EQ(0, aDestructCount);
+            ASSERT_EQ(a, ptr.unpoisoned());
+            ASSERT_EQ(a, &*ptr);
+            for (auto i = 0; i < arraySize; ++i)
+                ASSERT_EQ(a[i].name, ptr[i].name);
+        }
+        ASSERT_EQ(arraySize, aDestructCount);
+    }
+}
+
+} // namespace TestWebKitAPI
+
diff --git a/Tools/TestWebKitAPI/Tests/WTF/PoisonedUniquePtrForTriviallyDestructibleArrays.cpp b/Tools/TestWebKitAPI/Tests/WTF/PoisonedUniquePtrForTriviallyDestructibleArrays.cpp
new file mode 100644 (file)
index 0000000..678a8d7
--- /dev/null
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <wtf/FastMalloc.h>
+#include <wtf/PoisonedUniquePtr.h>
+
+namespace TestWebKitAPI {
+
+namespace {
+
+const uint32_t PoisonA = 0xaaaa;
+const uint32_t PoisonB = 0xbbbb;
+
+template<typename T>
+static void fillArray(T& array, int size)
+{
+    for (int i = 0; i < size; ++i)
+        array[i] = i + 100;
+}
+
+static const int arraySize = 5;
+
+} // anonymous namespace
+
+TEST(WTF_PoisonedUniquePtrForTriviallyDestructibleArrays, Basic)
+{
+    {
+        PoisonedUniquePtr<PoisonA, int[]> empty;
+        ASSERT_EQ(nullptr, empty.unpoisoned());
+        ASSERT_EQ(0u, empty.bits());
+    }
+
+    {
+        auto* a = new int[arraySize];
+        fillArray(a, arraySize);
+        {
+            PoisonedUniquePtr<PoisonA, int[]> ptr(a);
+            ASSERT_EQ(a, ptr.unpoisoned());
+            ASSERT_EQ(a, &*ptr);
+            for (auto i = 0; i < arraySize; ++i)
+                ASSERT_EQ(a[i], ptr[i]);
+
+#if ENABLE(POISON)
+            uintptr_t ptrBits;
+            std::memcpy(&ptrBits, &ptr, sizeof(ptrBits));
+            ASSERT_TRUE(ptrBits != bitwise_cast<uintptr_t>(a));
+#if ENABLE(POISON_ASSERTS)
+            ASSERT_TRUE((PoisonedUniquePtr<PoisonA, int[]>::isPoisoned(ptrBits)));
+#endif
+#endif // ENABLE(POISON)
+        }
+    }
+
+    {
+        auto* a = new int[arraySize];
+        fillArray(a, arraySize);
+
+        PoisonedUniquePtr<PoisonA, int[]> ptr = a;
+        ASSERT_EQ(a, ptr.unpoisoned());
+        ASSERT_EQ(a, &*ptr);
+        for (auto i = 0; i < arraySize; ++i)
+            ASSERT_EQ(a[i], ptr[i]);
+    }
+
+    {
+        PoisonedUniquePtr<PoisonA, int[]> ptr = PoisonedUniquePtr<PoisonA, int[]>::create(arraySize);
+        ASSERT_TRUE(nullptr != ptr.unpoisoned());
+        fillArray(ptr, arraySize);
+        for (auto i = 0; i < arraySize; ++i)
+            ASSERT_EQ((100 + i), ptr[i]);
+    }
+
+    {
+        auto* a = new int[arraySize];
+        fillArray(a, arraySize);
+        auto* b = new int[arraySize];
+        fillArray(b, arraySize);
+
+        PoisonedUniquePtr<PoisonA, int[]> p1 = a;
+        PoisonedUniquePtr<PoisonA, int[]> p2 = WTFMove(p1);
+        ASSERT_EQ(nullptr, p1.unpoisoned());
+        ASSERT_EQ(0u, p1.bits());
+        ASSERT_EQ(a, p2.unpoisoned());
+        for (auto i = 0; i < arraySize; ++i)
+            ASSERT_EQ(a[i], p2[i]);
+
+        PoisonedUniquePtr<PoisonA, int[]> p3 = b;
+        PoisonedUniquePtr<PoisonB, int[]> p4 = WTFMove(p3);
+        ASSERT_EQ(nullptr, p3.unpoisoned());
+        ASSERT_EQ(0u, p3.bits());
+        ASSERT_EQ(b, p4.unpoisoned());
+        for (auto i = 0; i < arraySize; ++i)
+            ASSERT_EQ(b[i], p4[i]);
+    }
+
+    {
+        auto* a = new int[arraySize];
+        fillArray(a, arraySize);
+        auto* b = new int[arraySize];
+        fillArray(b, arraySize);
+
+        PoisonedUniquePtr<PoisonA, int[]> p1 = a;
+        PoisonedUniquePtr<PoisonA, int[]> p2(WTFMove(p1));
+        ASSERT_EQ(nullptr, p1.unpoisoned());
+        ASSERT_EQ(0u, p1.bits());
+        ASSERT_EQ(a, p2.unpoisoned());
+        for (auto i = 0; i < arraySize; ++i)
+            ASSERT_EQ(a[i], p2[i]);
+
+        PoisonedUniquePtr<PoisonA, int[]> p3 = b;
+        PoisonedUniquePtr<PoisonB, int[]> p4(WTFMove(p3));
+        ASSERT_EQ(nullptr, p3.unpoisoned());
+        ASSERT_EQ(0u, p3.bits());
+        ASSERT_EQ(b, p4.unpoisoned());
+        for (auto i = 0; i < arraySize; ++i)
+            ASSERT_EQ(b[i], p4[i]);
+    }
+
+    {
+        auto* a = new int[arraySize];
+        fillArray(a, arraySize);
+
+        PoisonedUniquePtr<PoisonA, int[]> ptr(a);
+        ASSERT_EQ(a, ptr.unpoisoned());
+        ptr.clear();
+        ASSERT_TRUE(!ptr.unpoisoned());
+        ASSERT_TRUE(!ptr.bits());
+    }
+}
+
+TEST(WTF_PoisonedUniquePtrForTriviallyDestructibleArrays, Assignment)
+{
+    {
+        auto* a = new int[arraySize];
+        auto* b = new int[arraySize];
+        fillArray(a, arraySize);
+        fillArray(b, arraySize);
+
+        PoisonedUniquePtr<PoisonA, int[]> ptr(a);
+        ASSERT_EQ(a, ptr.unpoisoned());
+        ptr = b;
+        ASSERT_EQ(b, ptr.unpoisoned());
+    }
+
+    {
+        auto* a = new int[arraySize];
+        fillArray(a, arraySize);
+
+        PoisonedUniquePtr<PoisonA, int[]> ptr(a);
+        ASSERT_EQ(a, ptr.unpoisoned());
+        ptr = nullptr;
+        ASSERT_EQ(nullptr, ptr.unpoisoned());
+    }
+
+    {
+        auto* a = new int[arraySize];
+        auto* b = new int[arraySize];
+        auto* c = new int[arraySize];
+        auto* d = new int[arraySize];
+        fillArray(a, arraySize);
+        fillArray(b, arraySize);
+        fillArray(c, arraySize);
+        fillArray(d, arraySize);
+
+        PoisonedUniquePtr<PoisonA, int[]> p1(a);
+        PoisonedUniquePtr<PoisonA, int[]> p2(b);
+        ASSERT_EQ(a, p1.unpoisoned());
+        ASSERT_EQ(b, p2.unpoisoned());
+        p1 = WTFMove(p2);
+        ASSERT_EQ(b, p1.unpoisoned());
+        ASSERT_EQ(nullptr, p2.unpoisoned());
+
+        PoisonedUniquePtr<PoisonA, int[]> p3(c);
+        PoisonedUniquePtr<PoisonB, int[]> p4(d);
+        ASSERT_EQ(c, p3.unpoisoned());
+        ASSERT_EQ(d, p4.unpoisoned());
+        p3 = WTFMove(p4);
+        ASSERT_EQ(d, p3.unpoisoned());
+        ASSERT_EQ(nullptr, p4.unpoisoned());
+    }
+
+    {
+        auto* a = new int[arraySize];
+        fillArray(a, arraySize);
+
+        PoisonedUniquePtr<PoisonA, int[]> ptr(a);
+        ASSERT_EQ(a, ptr.unpoisoned());
+        ptr = a;
+        ASSERT_EQ(a, ptr.unpoisoned());
+    }
+
+    {
+        auto* a = new int[arraySize];
+        fillArray(a, arraySize);
+
+        PoisonedUniquePtr<PoisonA, int[]> ptr(a);
+        ASSERT_EQ(a, ptr.unpoisoned());
+#if COMPILER(CLANG)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunknown-pragmas"
+#pragma clang diagnostic ignored "-Wself-move"
+#endif
+        ptr = WTFMove(ptr);
+#if COMPILER(CLANG)
+#pragma clang diagnostic pop
+#endif
+        ASSERT_EQ(a, ptr.unpoisoned());
+    }
+}
+
+TEST(WTF_PoisonedUniquePtrForTriviallyDestructibleArrays, Swap)
+{
+    {
+        auto* a = new int[arraySize];
+        auto* b = new int[arraySize];
+        fillArray(a, arraySize);
+        fillArray(b, arraySize);
+
+        PoisonedUniquePtr<PoisonA, int[]> p1 = a;
+        PoisonedUniquePtr<PoisonA, int[]> p2;
+        ASSERT_EQ(p1.unpoisoned(), a);
+        ASSERT_TRUE(!p2.bits());
+        ASSERT_TRUE(!p2.unpoisoned());
+        p2.swap(p1);
+        ASSERT_TRUE(!p1.bits());
+        ASSERT_TRUE(!p1.unpoisoned());
+        ASSERT_EQ(p2.unpoisoned(), a);
+
+        PoisonedUniquePtr<PoisonA, int[]> p3 = b;
+        PoisonedUniquePtr<PoisonB, int[]> p4;
+        ASSERT_EQ(p3.unpoisoned(), b);
+        ASSERT_TRUE(!p4.bits());
+        ASSERT_TRUE(!p4.unpoisoned());
+        p4.swap(p3);
+        ASSERT_TRUE(!p3.bits());
+        ASSERT_TRUE(!p3.unpoisoned());
+        ASSERT_EQ(p4.unpoisoned(), b);
+    }
+
+    {
+        auto* a = new int[arraySize];
+        auto* b = new int[arraySize];
+        fillArray(a, arraySize);
+        fillArray(b, arraySize);
+
+        PoisonedUniquePtr<PoisonA, int[]> p1 = a;
+        PoisonedUniquePtr<PoisonA, int[]> p2;
+        ASSERT_EQ(p1.unpoisoned(), a);
+        ASSERT_TRUE(!p2.bits());
+        ASSERT_TRUE(!p2.unpoisoned());
+        swap(p1, p2);
+        ASSERT_TRUE(!p1.bits());
+        ASSERT_TRUE(!p1.unpoisoned());
+        ASSERT_EQ(p2.unpoisoned(), a);
+
+        PoisonedUniquePtr<PoisonA, int[]> p3 = b;
+        PoisonedUniquePtr<PoisonB, int[]> p4;
+        ASSERT_EQ(p3.unpoisoned(), b);
+        ASSERT_TRUE(!p4.bits());
+        ASSERT_TRUE(!p4.unpoisoned());
+        swap(p3, p4);
+        ASSERT_TRUE(!p3.bits());
+        ASSERT_TRUE(!p3.unpoisoned());
+        ASSERT_EQ(p4.unpoisoned(), b);
+    }
+}
+
+static PoisonedUniquePtr<PoisonA, int[]> poisonedPtrFoo(int* ptr)
+{
+    return PoisonedUniquePtr<PoisonA, int[]>(ptr);
+}
+
+TEST(WTF_PoisonedUniquePtrForTriviallyDestructibleArrays, ReturnValue)
+{
+    {
+        auto* a = new int[arraySize];
+        fillArray(a, arraySize);
+
+        auto ptr = poisonedPtrFoo(a);
+        ASSERT_EQ(a, ptr.unpoisoned());
+        ASSERT_EQ(a, &*ptr);
+        for (auto i = 0; i < arraySize; ++i)
+            ASSERT_EQ(a[i], ptr[i]);
+    }
+}
+
+} // namespace TestWebKitAPI
+