From b9c280684065d28b52d8e4992eba8a3666899dbc Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Thu, 13 Nov 2014 17:39:13 +0100 Subject: Fix race-condition crash on leaving pages using Indexed DB ScriptExecutionContext does not allow the list of active DOM objects to change while it is iterating over it. Since the IDB transaction backend implementations holds several active DOM objects it should not delete itself while aborting. Change-Id: Icd2f5b5a3f1957461b9a253d1005896bb2461466 Reviewed-by: Jocelyn Turcotte --- .../Modules/indexeddb/IDBTransactionBackendImpl.cpp | 15 ++++++++++++++- .../WebCore/Modules/indexeddb/IDBTransactionBackendImpl.h | 2 ++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/Source/WebCore/Modules/indexeddb/IDBTransactionBackendImpl.cpp b/Source/WebCore/Modules/indexeddb/IDBTransactionBackendImpl.cpp index 656255770..1e3e32b2d 100644 --- a/Source/WebCore/Modules/indexeddb/IDBTransactionBackendImpl.cpp +++ b/Source/WebCore/Modules/indexeddb/IDBTransactionBackendImpl.cpp @@ -57,6 +57,7 @@ IDBTransactionBackendImpl::IDBTransactionBackendImpl(int64_t id, PassRefPtrbackingStore().get()) , m_taskTimer(this, &IDBTransactionBackendImpl::taskTimerFired) + , m_asyncDerefTimer(this, &IDBTransactionBackendImpl::asyncDerefTimerFired) , m_pendingPreemptiveEvents(0) { // We pass a reference of this object before it can be adopted. @@ -106,7 +107,7 @@ void IDBTransactionBackendImpl::abort(PassRefPtr error) // The last reference to this object may be released while performing the // abort steps below. We therefore take a self reference to keep ourselves // alive while executing this method. - RefPtr protect(this); + this->ref(); m_state = Finished; m_taskTimer.stop(); @@ -138,6 +139,18 @@ void IDBTransactionBackendImpl::abort(PassRefPtr error) m_database->transactionFinishedAndAbortFired(this); m_database = 0; + + if (this->refCount() == 1) { + // We may already be iterating over active DOM Objects which would make it illegal + // to cause ourselves to be deleted here. + m_asyncDerefTimer.startOneShot(0); + } else + this->deref(); +} + +void IDBTransactionBackendImpl::asyncDerefTimerFired(Timer*) +{ + this->deref(); } bool IDBTransactionBackendImpl::isTaskQueueEmpty() const diff --git a/Source/WebCore/Modules/indexeddb/IDBTransactionBackendImpl.h b/Source/WebCore/Modules/indexeddb/IDBTransactionBackendImpl.h index 3718e61c6..1a5a962e3 100644 --- a/Source/WebCore/Modules/indexeddb/IDBTransactionBackendImpl.h +++ b/Source/WebCore/Modules/indexeddb/IDBTransactionBackendImpl.h @@ -87,6 +87,7 @@ private: bool hasPendingTasks() const; void taskTimerFired(Timer*); + void asyncDerefTimerFired(Timer*); void closeOpenCursors(); const int64_t m_id; @@ -107,6 +108,7 @@ private: // FIXME: delete the timer once we have threads instead. Timer m_taskTimer; + Timer m_asyncDerefTimer; int m_pendingPreemptiveEvents; HashSet m_openCursors; -- cgit v1.2.3