IndexedDB: leak IDBDatabase and IDBTransacstion in layout tests
authorsihui_liu@apple.com <sihui_liu@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 18 Feb 2019 17:30:18 +0000 (17:30 +0000)
committersihui_liu@apple.com <sihui_liu@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 18 Feb 2019 17:30:18 +0000 (17:30 +0000)
https://bugs.webkit.org/show_bug.cgi?id=194709

Reviewed by Geoffrey Garen.

Source/WebCore:

When connection to IDB server is closed, IDBTransaction would abort without notifying IDBDatabase, so
IDBDatabase didn't clear its reference to IDBTransaction which created a reference cycle.

Also IDBTransaction didn't clear its reference to IDBRequest in this case and it led to another reference cycle
between IDBOpenDBRequest and IDBTransaction.

Test: storage/indexeddb/IDBObject-leak.html

* Modules/indexeddb/IDBDatabase.cpp:
(WebCore::IDBDatabase::connectionToServerLost):
* Modules/indexeddb/IDBTransaction.cpp:
(WebCore::IDBTransaction::IDBTransaction):
(WebCore::IDBTransaction::~IDBTransaction):
(WebCore::IDBTransaction::finishedDispatchEventForRequest):
(WebCore::IDBTransaction::connectionClosedFromServer):
* Modules/indexeddb/IDBTransaction.h:
* testing/Internals.cpp:
(WebCore::Internals::numberOfIDBTransactions const):
* testing/Internals.h:
* testing/Internals.idl:

LayoutTests:

* storage/indexeddb/IDBObject-leak.html: Added.

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

LayoutTests/ChangeLog
LayoutTests/storage/indexeddb/IDBObject-leak.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/Modules/indexeddb/IDBDatabase.cpp
Source/WebCore/Modules/indexeddb/IDBTransaction.cpp
Source/WebCore/Modules/indexeddb/IDBTransaction.h
Source/WebCore/testing/Internals.cpp
Source/WebCore/testing/Internals.h
Source/WebCore/testing/Internals.idl

index cbd0e8c..2c4da96 100644 (file)
@@ -1,3 +1,12 @@
+2019-02-18  Sihui Liu  <sihui_liu@apple.com>
+
+        IndexedDB: leak IDBDatabase and IDBTransacstion in layout tests
+        https://bugs.webkit.org/show_bug.cgi?id=194709
+
+        Reviewed by Geoffrey Garen.
+
+        * storage/indexeddb/IDBObject-leak.html: Added.
+
 2019-02-18  Megan Gardner  <megan_gardner@apple.com>
 
         Turn On Smart Delete
diff --git a/LayoutTests/storage/indexeddb/IDBObject-leak.html b/LayoutTests/storage/indexeddb/IDBObject-leak.html
new file mode 100644 (file)
index 0000000..5507b82
--- /dev/null
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<script src="../../resources/js-test.js"></script>
+<script src="resources/shared.js"></script>
+<script>
+description('This test verifies that IDBTransaction objects are freed.');
+
+function test() {
+    if (!window.internals || !internals.numberOfIDBTransactions) {
+        testFailed('This test requires access to the Internals object');
+        finishJSTest();
+        return;
+    }
+
+    if (sessionStorage.doneFirstLoad) {
+        gc();
+        shouldBeEqualToNumber("internals.numberOfIDBTransactions()", 0);
+        finishJSTest();
+        return;
+    }
+
+    var dbname = setDBNameFromPath() + Date();
+    var request =  window.indexedDB.open(dbname);
+    request.onupgradeneeded = function(evt) {
+        sessionStorage.doneFirstLoad = true;
+        if (window.testRunner) {
+            testRunner.waitUntilDone();
+            testRunner.terminateNetworkProcess();
+        } else {
+            testFailed('This test requires access to the TestRunner object');
+        }
+        setTimeout((()=> {
+            location.reload();
+        }), 0);
+    }
+}
+
+test();
+</script>
index bec0fd4..686a28f 100644 (file)
@@ -1,3 +1,31 @@
+2019-02-18  Sihui Liu  <sihui_liu@apple.com>
+
+        IndexedDB: leak IDBDatabase and IDBTransacstion in layout tests
+        https://bugs.webkit.org/show_bug.cgi?id=194709
+
+        Reviewed by Geoffrey Garen.
+
+        When connection to IDB server is closed, IDBTransaction would abort without notifying IDBDatabase, so 
+        IDBDatabase didn't clear its reference to IDBTransaction which created a reference cycle. 
+
+        Also IDBTransaction didn't clear its reference to IDBRequest in this case and it led to another reference cycle
+        between IDBOpenDBRequest and IDBTransaction.
+
+        Test: storage/indexeddb/IDBObject-leak.html
+
+        * Modules/indexeddb/IDBDatabase.cpp:
+        (WebCore::IDBDatabase::connectionToServerLost):
+        * Modules/indexeddb/IDBTransaction.cpp:
+        (WebCore::IDBTransaction::IDBTransaction):
+        (WebCore::IDBTransaction::~IDBTransaction):
+        (WebCore::IDBTransaction::finishedDispatchEventForRequest):
+        (WebCore::IDBTransaction::connectionClosedFromServer):
+        * Modules/indexeddb/IDBTransaction.h:
+        * testing/Internals.cpp:
+        (WebCore::Internals::numberOfIDBTransactions const):
+        * testing/Internals.h:
+        * testing/Internals.idl:
+
 2019-02-18  Chris Fleizach  <cfleizach@apple.com>
 
         AX: PSON: Going back from apple.com to search results, cannot interact with HTML content. Disabling Swap Processes on Cross-Site Navigation resolves the issue.
index 1847439..0a09572 100644 (file)
@@ -264,7 +264,8 @@ void IDBDatabase::connectionToServerLost(const IDBError& error)
     m_closePending = true;
     m_closedInServer = true;
 
-    for (auto& transaction : m_activeTransactions.values())
+    auto transactions = copyToVector(m_activeTransactions.values());
+    for (auto& transaction : transactions)
         transaction->connectionClosedFromServer(error);
 
     auto errorEvent = Event::create(m_eventNames.errorEvent, Event::CanBubble::Yes, Event::IsCancelable::No);
index 2e965e9..e38204c 100644 (file)
@@ -79,6 +79,9 @@ IDBTransaction::IDBTransaction(IDBDatabase& database, const IDBTransactionInfo&
     , m_currentlyCompletingRequest(request)
 
 {
+    auto addResult = allIDBTransactions().add(this);
+    ASSERT_UNUSED(addResult, addResult.isNewEntry);
+
     LOG(IndexedDB, "IDBTransaction::IDBTransaction - %s", m_info.loggingString().utf8().data());
     ASSERT(&m_database->originThread() == &Thread::current());
 
@@ -106,6 +109,14 @@ IDBTransaction::IDBTransaction(IDBDatabase& database, const IDBTransactionInfo&
 IDBTransaction::~IDBTransaction()
 {
     ASSERT(&m_database->originThread() == &Thread::current());
+    ASSERT(allIDBTransactions().contains(this));
+    allIDBTransactions().remove(this);
+}
+
+HashSet<IDBTransaction*>& IDBTransaction::allIDBTransactions()
+{
+    static NeverDestroyed<HashSet<IDBTransaction*>> transactions;
+    return transactions;
 }
 
 IDBClient::IDBConnectionProxy& IDBTransaction::connectionProxy()
@@ -1434,7 +1445,8 @@ void IDBTransaction::connectionClosedFromServer(const IDBError& error)
 {
     LOG(IndexedDB, "IDBTransaction::connectionClosedFromServer - %s", error.message().utf8().data());
 
-    m_state = IndexedDB::TransactionState::Aborting;
+    m_database->willAbortTransaction(*this);
+    transitionedToFinishing(IndexedDB::TransactionState::Aborting);
 
     abortInProgressOperations(error);
 
@@ -1445,6 +1457,7 @@ void IDBTransaction::connectionClosedFromServer(const IDBError& error)
         ASSERT(m_transactionOperationsInProgressQueue.first() == operation.get());
         operation->doComplete(IDBResultData::error(operation->identifier(), error));
     }
+    m_currentlyCompletingRequest = nullptr;
 
     connectionProxy().forgetActiveOperations(operations);
 
@@ -1454,6 +1467,7 @@ void IDBTransaction::connectionClosedFromServer(const IDBError& error)
 
     m_idbError = error;
     m_domError = error.toDOMException();
+    m_database->didAbortTransaction(*this);
     fireOnAbort();
 }
 
index 722f12c..edd15e6 100644 (file)
@@ -152,6 +152,8 @@ public:
 
     void visitReferencedObjectStores(JSC::SlotVisitor&) const;
 
+    WEBCORE_EXPORT static HashSet<IDBTransaction*>& allIDBTransactions();
+
 private:
     IDBTransaction(IDBDatabase&, const IDBTransactionInfo&, IDBOpenDBRequest*);
 
index 21a0597..8d57b7d 100644 (file)
@@ -93,6 +93,8 @@
 #include "HistoryController.h"
 #include "HistoryItem.h"
 #include "HitTestResult.h"
+#include "IDBRequest.h"
+#include "IDBTransaction.h"
 #include "InspectorClient.h"
 #include "InspectorController.h"
 #include "InspectorFrontendClientLocal.h"
@@ -2383,6 +2385,11 @@ ExceptionOr<unsigned> Internals::countFindMatches(const String& text, const Vect
     return document->page()->countFindMatches(text, parsedOptions.releaseReturnValue(), 1000);
 }
 
+unsigned Internals::numberOfIDBTransactions() const
+{
+    return IDBTransaction::allIDBTransactions().size();
+}
+
 unsigned Internals::numberOfLiveNodes() const
 {
     unsigned nodeCount = 0;
index c19382f..4e4d9d7 100644 (file)
@@ -378,6 +378,8 @@ public:
     ExceptionOr<void> insertAuthorCSS(const String&) const;
     ExceptionOr<void> insertUserCSS(const String&) const;
 
+    unsigned numberOfIDBTransactions() const;
+
     unsigned numberOfLiveNodes() const;
     unsigned numberOfLiveDocuments() const;
     unsigned referencingNodeCount(const Document&) const;
index e638512..01399ec 100644 (file)
@@ -405,6 +405,8 @@ enum CompositingPolicy {
     void beginSimulatedMemoryPressure();
     void endSimulatedMemoryPressure();
 
+    unsigned long numberOfIDBTransactions();
+
     unsigned long numberOfLiveNodes();
     unsigned long numberOfLiveDocuments();
     unsigned long referencingNodeCount(Document document);