Modern IDB: Crash seen in IDBConnectionProxy::putOrAdd on GuardMalloc bot
authorbeidson@apple.com <beidson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 6 Jun 2016 18:38:34 +0000 (18:38 +0000)
committerbeidson@apple.com <beidson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 6 Jun 2016 18:38:34 +0000 (18:38 +0000)
https://bugs.webkit.org/show_bug.cgi?id=158124

Reviewed by Darin Adler.
Source/WebCore:

No new tests (Covered by existing test configurations).

* Modules/indexeddb/IDBTransaction.cpp:
(WebCore::IDBTransaction::putOrAddOnServer):

* Modules/indexeddb/client/IDBConnectionProxy.cpp:
(WebCore::IDBClient::IDBConnectionProxy::putOrAdd):

* Modules/indexeddb/client/IDBConnectionProxy.h:
(WebCore::IDBClient::IDBConnectionProxy::callConnectionOnMainThread):

* bindings/js/SerializedScriptValue.cpp:
(WebCore::SerializedScriptValue::writeBlobsToDiskForIndexedDB):
* bindings/js/SerializedScriptValue.h:

* platform/network/BlobRegistry.h:
* platform/network/BlobRegistryImpl.cpp:
(WebCore::BlobRegistryImpl::writeBlobsToTemporaryFiles):
* platform/network/BlobRegistryImpl.h:

Source/WebKit2:

* NetworkProcess/FileAPI/NetworkBlobRegistry.cpp:
(WebKit::NetworkBlobRegistry::writeBlobsToTemporaryFiles):
* NetworkProcess/FileAPI/NetworkBlobRegistry.h:

* WebProcess/FileAPI/BlobRegistryProxy.cpp:
(WebKit::BlobRegistryProxy::writeBlobsToTemporaryFiles):
* WebProcess/FileAPI/BlobRegistryProxy.h:

* WebProcess/Network/NetworkProcessConnection.cpp:
(WebKit::NetworkProcessConnection::didClose):
(WebKit::NetworkProcessConnection::writeBlobsToTemporaryFiles):
* WebProcess/Network/NetworkProcessConnection.h:

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

17 files changed:
Source/WebCore/ChangeLog
Source/WebCore/Modules/indexeddb/IDBTransaction.cpp
Source/WebCore/Modules/indexeddb/client/IDBConnectionProxy.cpp
Source/WebCore/Modules/indexeddb/client/IDBConnectionProxy.h
Source/WebCore/bindings/js/SerializedScriptValue.cpp
Source/WebCore/bindings/js/SerializedScriptValue.h
Source/WebCore/platform/network/BlobRegistry.h
Source/WebCore/platform/network/BlobRegistryImpl.cpp
Source/WebCore/platform/network/BlobRegistryImpl.h
Source/WebKit2/ChangeLog
Source/WebKit2/NetworkProcess/FileAPI/NetworkBlobRegistry.cpp
Source/WebKit2/NetworkProcess/FileAPI/NetworkBlobRegistry.h
Source/WebKit2/NetworkProcess/NetworkConnectionToWebProcess.cpp
Source/WebKit2/WebProcess/FileAPI/BlobRegistryProxy.cpp
Source/WebKit2/WebProcess/FileAPI/BlobRegistryProxy.h
Source/WebKit2/WebProcess/Network/NetworkProcessConnection.cpp
Source/WebKit2/WebProcess/Network/NetworkProcessConnection.h

index 7c1a812..ab5dc85 100644 (file)
@@ -1,3 +1,30 @@
+2016-06-06  Brady Eidson  <beidson@apple.com>
+
+        Modern IDB: Crash seen in IDBConnectionProxy::putOrAdd on GuardMalloc bot
+        https://bugs.webkit.org/show_bug.cgi?id=158124
+
+        Reviewed by Darin Adler.
+
+        No new tests (Covered by existing test configurations).
+
+        * Modules/indexeddb/IDBTransaction.cpp:
+        (WebCore::IDBTransaction::putOrAddOnServer):
+        
+        * Modules/indexeddb/client/IDBConnectionProxy.cpp:
+        (WebCore::IDBClient::IDBConnectionProxy::putOrAdd):
+        
+        * Modules/indexeddb/client/IDBConnectionProxy.h:
+        (WebCore::IDBClient::IDBConnectionProxy::callConnectionOnMainThread):
+        
+        * bindings/js/SerializedScriptValue.cpp:
+        (WebCore::SerializedScriptValue::writeBlobsToDiskForIndexedDB):
+        * bindings/js/SerializedScriptValue.h:
+        
+        * platform/network/BlobRegistry.h:
+        * platform/network/BlobRegistryImpl.cpp:
+        (WebCore::BlobRegistryImpl::writeBlobsToTemporaryFiles):
+        * platform/network/BlobRegistryImpl.h:
+
 2016-06-06  Commit Queue  <commit-queue@webkit.org>
 
         Unreviewed, rolling out r201706.
index d7e4ef6..012d524 100644 (file)
@@ -966,20 +966,18 @@ void IDBTransaction::putOrAddOnServer(IDBClient::TransactionOperation& operation
         return;
     }
 
-    RefPtr<IDBTransaction> protectedThis(this);
-    RefPtr<IDBClient::TransactionOperation> protectedOperation(&operation);
-    value->writeBlobsToDiskForIndexedDB([protectedThis = WTFMove(protectedThis), this, protectedOperation = WTFMove(protectedOperation), key = WTFMove(key), overwriteMode](const IDBValue& idbValue) mutable {
+    value->writeBlobsToDiskForIndexedDB([protectedThis = Ref<IDBTransaction>(*this), this, protectedOperation = Ref<IDBClient::TransactionOperation>(operation), keyData = IDBKeyData(key.get()).isolatedCopy(), overwriteMode](const IDBValue& idbValue) mutable {
         ASSERT(currentThread() == originThreadID());
         ASSERT(isMainThread());
         if (idbValue.data().data()) {
-            m_database->connectionProxy().putOrAdd(*protectedOperation, key.get(), idbValue, overwriteMode);
+            m_database->connectionProxy().putOrAdd(protectedOperation.get(), WTFMove(keyData), idbValue, overwriteMode);
             return;
         }
 
         // If the IDBValue doesn't have any data, then something went wrong writing the blobs to disk.
         // In that case, we cannot successfully store this record, so we callback with an error.
         auto result = IDBResultData::error(protectedOperation->identifier(), { IDBDatabaseException::UnknownError, ASCIILiteral("Error preparing Blob/File data to be stored in object store") });
-        callOnMainThread([protectedThis = WTFMove(protectedThis), protectedOperation = WTFMove(protectedOperation), result = WTFMove(result)]() {
+        callOnMainThread([protectedThis = WTFMove(protectedThis), protectedOperation = WTFMove(protectedOperation), result = WTFMove(result)]() mutable {
             protectedOperation->completed(result);
         });
     });
index 64ee930..bb560b1 100644 (file)
@@ -156,12 +156,12 @@ void IDBConnectionProxy::deleteIndex(TransactionOperation& operation, uint64_t o
     callConnectionOnMainThread(&IDBConnectionToServer::deleteIndex, requestData, WTFMove(objectStoreIdentifier), indexName);
 }
 
-void IDBConnectionProxy::putOrAdd(TransactionOperation& operation, IDBKey* key, const IDBValue& value, const IndexedDB::ObjectStoreOverwriteMode mode)
+void IDBConnectionProxy::putOrAdd(TransactionOperation& operation, IDBKeyData&& keyData, const IDBValue& value, const IndexedDB::ObjectStoreOverwriteMode mode)
 {
     const IDBRequestData requestData(operation);
     saveOperation(operation);
 
-    callConnectionOnMainThread(&IDBConnectionToServer::putOrAdd, requestData, IDBKeyData(key), value, mode);
+    callConnectionOnMainThread(&IDBConnectionToServer::putOrAdd, requestData, keyData, value, mode);
 }
 
 void IDBConnectionProxy::getRecord(TransactionOperation& operation, const IDBKeyRangeData& keyRange)
index 4d370c9..9d58a81 100644 (file)
@@ -70,7 +70,7 @@ public:
     void clearObjectStore(TransactionOperation&, uint64_t objectStoreIdentifier);
     void createIndex(TransactionOperation&, const IDBIndexInfo&);
     void deleteIndex(TransactionOperation&, uint64_t objectStoreIdentifier, const String& indexName);
-    void putOrAdd(TransactionOperation&, IDBKey*, const IDBValue&, const IndexedDB::ObjectStoreOverwriteMode);
+    void putOrAdd(TransactionOperation&, IDBKeyData&&, const IDBValue&, const IndexedDB::ObjectStoreOverwriteMode);
     void getRecord(TransactionOperation&, const IDBKeyRangeData&);
     void getCount(TransactionOperation&, const IDBKeyRangeData&);
     void deleteRecord(TransactionOperation&, const IDBKeyRangeData&);
@@ -124,7 +124,7 @@ private:
     void callConnectionOnMainThread(void (IDBConnectionToServer::*method)(Parameters...), Arguments&&... arguments)
     {
         if (isMainThread())
-            (m_connectionToServer.*method)(arguments...);
+            (m_connectionToServer.*method)(std::forward<Arguments>(arguments)...);
         else
             postMainThreadTask(m_connectionToServer, method, arguments...);
     }
index 4b9ac9a..b202891 100644 (file)
@@ -2796,7 +2796,7 @@ Vector<String> SerializedScriptValue::blobURLsIsolatedCopy() const
     return result;
 }
 
-void SerializedScriptValue::writeBlobsToDiskForIndexedDB(std::function<void (const IDBValue&)> completionHandler)
+void SerializedScriptValue::writeBlobsToDiskForIndexedDB(NoncopyableFunction<void (const IDBValue&)>&& completionHandler)
 {
     ASSERT(isMainThread());
     ASSERT(hasBlobURLs());
index 7c75682..4c670e6 100644 (file)
@@ -31,6 +31,7 @@
 #include <runtime/ArrayBuffer.h>
 #include <runtime/JSCJSValue.h>
 #include <wtf/Forward.h>
+#include <wtf/NoncopyableFunction.h>
 #include <wtf/RefCounted.h>
 #include <wtf/text/WTFString.h>
 
@@ -86,7 +87,7 @@ public:
 
 #if ENABLE(INDEXED_DATABASE)
     Vector<String> blobURLsIsolatedCopy() const;
-    void writeBlobsToDiskForIndexedDB(std::function<void (const IDBValue&)> completionHandler);
+    void writeBlobsToDiskForIndexedDB(NoncopyableFunction<void (const IDBValue&)>&& completionHandler);
     IDBValue writeBlobsToDiskForIndexedDBSynchronously();
 #endif // ENABLE(INDEXED_DATABASE)
 
index e23cfc0..12c6e92 100644 (file)
@@ -33,6 +33,7 @@
 
 #include <functional>
 #include <wtf/Forward.h>
+#include <wtf/NoncopyableFunction.h>
 #include <wtf/Vector.h>
 
 namespace WebCore {
@@ -67,7 +68,7 @@ public:
 
     virtual unsigned long long blobSize(const URL&) = 0;
 
-    virtual void writeBlobsToTemporaryFiles(const Vector<String>& blobURLs, std::function<void (const Vector<String>& filePaths)> completionHandler) = 0;
+    virtual void writeBlobsToTemporaryFiles(const Vector<String>& blobURLs, NoncopyableFunction<void (const Vector<String>& filePaths)>&& completionHandler) = 0;
 
     virtual bool isBlobRegistryImpl() const { return false; }
 
index ba28f32..5d4aac8 100644 (file)
@@ -256,7 +256,7 @@ struct BlobForFileWriting {
     Vector<std::pair<String, ThreadSafeDataBuffer>> filePathsOrDataBuffers;
 };
 
-void BlobRegistryImpl::writeBlobsToTemporaryFiles(const Vector<String>& blobURLs, std::function<void (const Vector<String>& filePaths)> completionHandler)
+void BlobRegistryImpl::writeBlobsToTemporaryFiles(const Vector<String>& blobURLs, NoncopyableFunction<void (const Vector<String>& filePaths)>&& completionHandler)
 {
     Vector<BlobForFileWriting> blobsForWriting;
     for (auto& url : blobURLs) {
@@ -287,47 +287,45 @@ void BlobRegistryImpl::writeBlobsToTemporaryFiles(const Vector<String>& blobURLs
     blobUtilityQueue().dispatch([blobsForWriting = WTFMove(blobsForWriting), completionHandler = WTFMove(completionHandler)]() mutable {
         Vector<String> filePaths;
 
-        ScopeGuard completionCaller([completionHandler]() mutable {
-            callOnMainThread([completionHandler = WTFMove(completionHandler)]() {
-                Vector<String> filePaths;
-                completionHandler(filePaths);
-            });
-        });
-
-        for (auto& blob : blobsForWriting) {
-            PlatformFileHandle file;
-            String tempFilePath = openTemporaryFile(ASCIILiteral("Blob"), file);
-
-            ScopeGuard fileCloser([file]() {
-                PlatformFileHandle handle = file;
-                closeFile(handle);
-            });
-            
-            if (tempFilePath.isEmpty() || !isHandleValid(file)) {
-                LOG_ERROR("Failed to open temporary file for writing a Blob to IndexedDB");
-                return;
-            }
+        auto performWriting = [blobsForWriting = WTFMove(blobsForWriting), &filePaths]() {
+            for (auto& blob : blobsForWriting) {
+                PlatformFileHandle file;
+                String tempFilePath = openTemporaryFile(ASCIILiteral("Blob"), file);
+
+                ScopeGuard fileCloser([file]() mutable {
+                    closeFile(file);
+                });
+                
+                if (tempFilePath.isEmpty() || !isHandleValid(file)) {
+                    LOG_ERROR("Failed to open temporary file for writing a Blob to IndexedDB");
+                    return false;
+                }
 
-            for (auto& part : blob.filePathsOrDataBuffers) {
-                if (part.second.data()) {
-                    int length = part.second.data()->size();
-                    if (writeToFile(file, reinterpret_cast<const char*>(part.second.data()->data()), length) != length) {
-                        LOG_ERROR("Failed writing a Blob to temporary file for storage in IndexedDB");
-                        return;
-                    }
-                } else {
-                    ASSERT(!part.first.isEmpty());
-                    if (!appendFileContentsToFileHandle(part.first, file)) {
-                        LOG_ERROR("Failed copying File contents to a Blob temporary file for storage in IndexedDB (%s to %s)", part.first.utf8().data(), tempFilePath.utf8().data());
-                        return;
+                for (auto& part : blob.filePathsOrDataBuffers) {
+                    if (part.second.data()) {
+                        int length = part.second.data()->size();
+                        if (writeToFile(file, reinterpret_cast<const char*>(part.second.data()->data()), length) != length) {
+                            LOG_ERROR("Failed writing a Blob to temporary file for storage in IndexedDB");
+                            return false;
+                        }
+                    } else {
+                        ASSERT(!part.first.isEmpty());
+                        if (!appendFileContentsToFileHandle(part.first, file)) {
+                            LOG_ERROR("Failed copying File contents to a Blob temporary file for storage in IndexedDB (%s to %s)", part.first.utf8().data(), tempFilePath.utf8().data());
+                            return false;
+                        }
                     }
                 }
+
+                filePaths.append(tempFilePath.isolatedCopy());
             }
 
-            filePaths.append(tempFilePath.isolatedCopy());
-        }
+            return true;
+        };
+
+        if (!performWriting())
+            filePaths.clear();
 
-        completionCaller.disable();
         callOnMainThread([completionHandler = WTFMove(completionHandler), filePaths = WTFMove(filePaths)]() {
             completionHandler(filePaths);
         });
index 4e3997a..3cfda98 100644 (file)
@@ -68,7 +68,7 @@ private:
 
     unsigned long long blobSize(const URL&) override;
 
-    void writeBlobsToTemporaryFiles(const Vector<String>& blobURLs, std::function<void (const Vector<String>& filePaths)> completionHandler) override;
+    void writeBlobsToTemporaryFiles(const Vector<String>& blobURLs, NoncopyableFunction<void (const Vector<String>& filePaths)>&& completionHandler) override;
 
     HashMap<String, RefPtr<BlobData>> m_blobs;
 };
index 3d82589..67f8ec8 100644 (file)
@@ -1,3 +1,23 @@
+2016-06-06  Brady Eidson  <beidson@apple.com>
+
+        Modern IDB: Crash seen in IDBConnectionProxy::putOrAdd on GuardMalloc bot
+        https://bugs.webkit.org/show_bug.cgi?id=158124
+
+        Reviewed by Darin Adler.
+        
+        * NetworkProcess/FileAPI/NetworkBlobRegistry.cpp:
+        (WebKit::NetworkBlobRegistry::writeBlobsToTemporaryFiles):
+        * NetworkProcess/FileAPI/NetworkBlobRegistry.h:
+        
+        * WebProcess/FileAPI/BlobRegistryProxy.cpp:
+        (WebKit::BlobRegistryProxy::writeBlobsToTemporaryFiles):
+        * WebProcess/FileAPI/BlobRegistryProxy.h:
+        
+        * WebProcess/Network/NetworkProcessConnection.cpp:
+        (WebKit::NetworkProcessConnection::didClose):
+        (WebKit::NetworkProcessConnection::writeBlobsToTemporaryFiles):
+        * WebProcess/Network/NetworkProcessConnection.h:
+
 2016-06-06  Commit Queue  <commit-queue@webkit.org>
 
         Unreviewed, rolling out r201706.
index 50d3136..d34d842 100644 (file)
@@ -132,9 +132,9 @@ uint64_t NetworkBlobRegistry::blobSize(NetworkConnectionToWebProcess* connection
     return blobRegistry().blobSize(url);
 }
 
-void NetworkBlobRegistry::writeBlobsToTemporaryFiles(const Vector<String>& blobURLs, std::function<void(const Vector<String>&)> completionHandler)
+void NetworkBlobRegistry::writeBlobsToTemporaryFiles(const Vector<String>& blobURLs, NoncopyableFunction<void(const Vector<String>&)>&& completionHandler)
 {
-    blobRegistry().writeBlobsToTemporaryFiles(blobURLs, completionHandler);
+    blobRegistry().writeBlobsToTemporaryFiles(blobURLs, WTFMove(completionHandler));
 }
 
 void NetworkBlobRegistry::connectionToWebProcessDidClose(NetworkConnectionToWebProcess* connection)
index 9bfb2e6..a20169a 100644 (file)
@@ -30,6 +30,7 @@
 #include <functional>
 #include <wtf/HashMap.h>
 #include <wtf/HashSet.h>
+#include <wtf/NoncopyableFunction.h>
 
 namespace WebCore {
 class BlobDataFileReference;
@@ -54,7 +55,7 @@ public:
     void registerBlobURLForSlice(NetworkConnectionToWebProcess*, const WebCore::URL&, const WebCore::URL& srcURL, int64_t start, int64_t end);
     void unregisterBlobURL(NetworkConnectionToWebProcess*, const WebCore::URL&);
     uint64_t blobSize(NetworkConnectionToWebProcess*, const WebCore::URL&);
-    void writeBlobsToTemporaryFiles(const Vector<String>& blobURLs, std::function<void(const Vector<String>&)> completionHandler);
+    void writeBlobsToTemporaryFiles(const Vector<String>& blobURLs, NoncopyableFunction<void(const Vector<String>&)>&& completionHandler);
 
     void connectionToWebProcessDidClose(NetworkConnectionToWebProcess*);
 
index e0d19ad..6d91876 100644 (file)
@@ -308,20 +308,18 @@ void NetworkConnectionToWebProcess::blobSize(const URL& url, uint64_t& resultSiz
 
 void NetworkConnectionToWebProcess::writeBlobsToTemporaryFiles(const Vector<String>& blobURLs, uint64_t requestIdentifier)
 {
-    RefPtr<NetworkConnectionToWebProcess> protector(this);
-
-    Vector<RefPtr<WebCore::BlobDataFileReference>> fileReferences;
+    Vector<RefPtr<BlobDataFileReference>> fileReferences;
     for (auto& url : blobURLs)
         fileReferences.appendVector(NetworkBlobRegistry::singleton().filesInBlob(*this, { ParsedURLString, url }));
 
     for (auto& file : fileReferences)
         file->prepareForFileAccess();
 
-    NetworkBlobRegistry::singleton().writeBlobsToTemporaryFiles(blobURLs, [this, protector, requestIdentifier, fileReferences](auto& fileNames) {
+    NetworkBlobRegistry::singleton().writeBlobsToTemporaryFiles(blobURLs, [this, protectedThis = Ref<NetworkConnectionToWebProcess>(*this), requestIdentifier, fileReferences = WTFMove(fileReferences)](auto& fileNames) mutable {
         for (auto& file : fileReferences)
             file->revokeFileAccess();
 
-        NetworkProcess::singleton().grantSandboxExtensionsToDatabaseProcessForBlobs(fileNames, [this, protector, requestIdentifier, fileNames]() {
+        NetworkProcess::singleton().grantSandboxExtensionsToDatabaseProcessForBlobs(fileNames, [this, protectedThis = WTFMove(protectedThis), requestIdentifier, fileNames = WTFMove(fileNames)]() {
             if (!m_connection || !m_connection->isValid())
                 return;
 
index dcca8c3..ecdcad6 100644 (file)
@@ -81,9 +81,9 @@ unsigned long long BlobRegistryProxy::blobSize(const URL& url)
     return resultSize;
 }
 
-void BlobRegistryProxy::writeBlobsToTemporaryFiles(const Vector<String>& blobURLs, std::function<void (const Vector<String>& filePaths)> completionHandler)
+void BlobRegistryProxy::writeBlobsToTemporaryFiles(const Vector<String>& blobURLs, NoncopyableFunction<void (const Vector<String>& filePaths)>&& completionHandler)
 {
-    WebProcess::singleton().networkConnection()->writeBlobsToTemporaryFiles(blobURLs, completionHandler);
+    WebProcess::singleton().networkConnection()->writeBlobsToTemporaryFiles(blobURLs, WTFMove(completionHandler));
 }
 
 }
index 1720e29..4ddd5cd 100644 (file)
@@ -39,7 +39,7 @@ public:
     void unregisterBlobURL(const WebCore::URL&) override;
     void registerBlobURLForSlice(const WebCore::URL&, const WebCore::URL& srcURL, long long start, long long end) override;
     unsigned long long blobSize(const WebCore::URL&) override;
-    void writeBlobsToTemporaryFiles(const Vector<String>& blobURLs, std::function<void (const Vector<String>& filePaths)> completionHandler) override;
+    void writeBlobsToTemporaryFiles(const Vector<String>& blobURLs, NoncopyableFunction<void (const Vector<String>& filePaths)>&& completionHandler) override;
 };
 
 }
index ac7600d..3c83a47 100644 (file)
@@ -75,7 +75,7 @@ void NetworkProcessConnection::didClose(IPC::Connection&)
     WebProcess::singleton().networkProcessConnectionClosed(this);
 
     Vector<String> dummyFilenames;
-    for (auto handler : m_writeBlobToFileCompletionHandlers.values())
+    for (auto& handler : m_writeBlobToFileCompletionHandlers.values())
         handler(dummyFilenames);
 
     m_writeBlobToFileCompletionHandlers.clear();
@@ -85,12 +85,12 @@ void NetworkProcessConnection::didReceiveInvalidMessage(IPC::Connection&, IPC::S
 {
 }
 
-void NetworkProcessConnection::writeBlobsToTemporaryFiles(const Vector<String>& blobURLs, std::function<void (const Vector<String>& filePaths)> completionHandler)
+void NetworkProcessConnection::writeBlobsToTemporaryFiles(const Vector<String>& blobURLs, NoncopyableFunction<void (const Vector<String>& filePaths)>&& completionHandler)
 {
     static uint64_t writeBlobToFileIdentifier;
     uint64_t requestIdentifier = ++writeBlobToFileIdentifier;
 
-    m_writeBlobToFileCompletionHandlers.set(requestIdentifier, completionHandler);
+    m_writeBlobToFileCompletionHandlers.set(requestIdentifier, WTFMove(completionHandler));
 
     WebProcess::singleton().networkConnection()->connection()->send(Messages::NetworkConnectionToWebProcess::WriteBlobsToTemporaryFiles(blobURLs, requestIdentifier), 0);
 }
index 7bece98..77b54da 100644 (file)
@@ -58,7 +58,7 @@ public:
 
     void didReceiveNetworkProcessConnectionMessage(IPC::Connection&, IPC::MessageDecoder&);
 
-    void writeBlobsToTemporaryFiles(const Vector<String>& blobURLs, std::function<void (const Vector<String>& filePaths)> completionHandler);
+    void writeBlobsToTemporaryFiles(const Vector<String>& blobURLs, NoncopyableFunction<void (const Vector<String>& filePaths)>&& completionHandler);
 
 private:
     NetworkProcessConnection(IPC::Connection::Identifier);
@@ -81,7 +81,7 @@ private:
     // The connection from the web process to the network process.
     RefPtr<IPC::Connection> m_connection;
 
-    HashMap<uint64_t, std::function<void (const Vector<String>&)>> m_writeBlobToFileCompletionHandlers;
+    HashMap<uint64_t, NoncopyableFunction<void (const Vector<String>&)>> m_writeBlobToFileCompletionHandlers;
 };
 
 } // namespace WebKit