Modern IDB: UniqueIDBDatabase's m_databaseInfo is unsafely used from multiple threads.
authorbeidson@apple.com <beidson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 5 Feb 2016 22:30:04 +0000 (22:30 +0000)
committerbeidson@apple.com <beidson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 5 Feb 2016 22:30:04 +0000 (22:30 +0000)
https://bugs.webkit.org/show_bug.cgi?id=153912

Reviewed by Alex Christensen.

No new tests (Anything testable about this patch is already covered by existing tests).

* Modules/indexeddb/server/IDBBackingStore.h:

* Modules/indexeddb/server/MemoryIDBBackingStore.cpp:
(WebCore::IDBServer::MemoryIDBBackingStore::infoForObjectStore):
* Modules/indexeddb/server/MemoryIDBBackingStore.h:

Teach the SQLiteIDBBackingStore to actually keep its m_databaseInfo up to date as it changes,
and to revert it when version change transactions abort:
* Modules/indexeddb/server/SQLiteIDBBackingStore.cpp:
(WebCore::IDBServer::SQLiteIDBBackingStore::beginTransaction):
(WebCore::IDBServer::SQLiteIDBBackingStore::abortTransaction):
(WebCore::IDBServer::SQLiteIDBBackingStore::commitTransaction):
(WebCore::IDBServer::SQLiteIDBBackingStore::createObjectStore):
(WebCore::IDBServer::SQLiteIDBBackingStore::deleteObjectStore):
(WebCore::IDBServer::SQLiteIDBBackingStore::createIndex):
(WebCore::IDBServer::SQLiteIDBBackingStore::deleteIndex):
(WebCore::IDBServer::SQLiteIDBBackingStore::infoForObjectStore):
* Modules/indexeddb/server/SQLiteIDBBackingStore.h:

* Modules/indexeddb/server/UniqueIDBDatabase.cpp:
(WebCore::IDBServer::UniqueIDBDatabase::performPutOrAdd): Use the IDBBackingStore's copy of the
  IDBObjectStoreInfo, meant only for the database thread, instead of the UniqueIDBDatabase's copy,
  which is meant only for the main thread.

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

Source/WebCore/ChangeLog
Source/WebCore/Modules/indexeddb/server/IDBBackingStore.h
Source/WebCore/Modules/indexeddb/server/MemoryIDBBackingStore.cpp
Source/WebCore/Modules/indexeddb/server/MemoryIDBBackingStore.h
Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.cpp
Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.h
Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.cpp

index d7fb223..491ac95 100644 (file)
@@ -1,3 +1,36 @@
+2016-02-05  Brady Eidson  <beidson@apple.com>
+
+        Modern IDB: UniqueIDBDatabase's m_databaseInfo is unsafely used from multiple threads.
+        https://bugs.webkit.org/show_bug.cgi?id=153912
+
+        Reviewed by Alex Christensen.
+
+        No new tests (Anything testable about this patch is already covered by existing tests).
+
+        * Modules/indexeddb/server/IDBBackingStore.h:
+
+        * Modules/indexeddb/server/MemoryIDBBackingStore.cpp:
+        (WebCore::IDBServer::MemoryIDBBackingStore::infoForObjectStore):
+        * Modules/indexeddb/server/MemoryIDBBackingStore.h:
+
+        Teach the SQLiteIDBBackingStore to actually keep its m_databaseInfo up to date as it changes,
+        and to revert it when version change transactions abort:
+        * Modules/indexeddb/server/SQLiteIDBBackingStore.cpp:
+        (WebCore::IDBServer::SQLiteIDBBackingStore::beginTransaction):
+        (WebCore::IDBServer::SQLiteIDBBackingStore::abortTransaction):
+        (WebCore::IDBServer::SQLiteIDBBackingStore::commitTransaction):
+        (WebCore::IDBServer::SQLiteIDBBackingStore::createObjectStore):
+        (WebCore::IDBServer::SQLiteIDBBackingStore::deleteObjectStore):
+        (WebCore::IDBServer::SQLiteIDBBackingStore::createIndex):
+        (WebCore::IDBServer::SQLiteIDBBackingStore::deleteIndex):
+        (WebCore::IDBServer::SQLiteIDBBackingStore::infoForObjectStore):
+        * Modules/indexeddb/server/SQLiteIDBBackingStore.h:
+
+        * Modules/indexeddb/server/UniqueIDBDatabase.cpp:
+        (WebCore::IDBServer::UniqueIDBDatabase::performPutOrAdd): Use the IDBBackingStore's copy of the 
+          IDBObjectStoreInfo, meant only for the database thread, instead of the UniqueIDBDatabase's copy, 
+          which is meant only for the main thread.
+
 2016-02-05  Alex Christensen  <achristensen@webkit.org>
 
         Clean up Blob code
index b0f97d3..c3325aa 100644 (file)
@@ -77,6 +77,7 @@ public:
     virtual IDBError openCursor(const IDBResourceIdentifier& transactionIdentifier, const IDBCursorInfo&, IDBGetResult& outResult) = 0;
     virtual IDBError iterateCursor(const IDBResourceIdentifier& transactionIdentifier, const IDBResourceIdentifier& cursorIdentifier, const IDBKeyData&, uint32_t count, IDBGetResult& outResult) = 0;
 
+    virtual IDBObjectStoreInfo* infoForObjectStore(uint64_t objectStoreIdentifier) = 0;
     virtual void deleteBackingStore() = 0;
     virtual bool supportsSimultaneousTransactions() = 0;
 };
index 74dd6f4..54c1fa8 100644 (file)
@@ -481,6 +481,12 @@ RefPtr<MemoryObjectStore> MemoryIDBBackingStore::takeObjectStoreByIdentifier(uin
     return objectStoreByIdentifier;
 }
 
+IDBObjectStoreInfo* MemoryIDBBackingStore::infoForObjectStore(uint64_t objectStoreIdentifier)
+{
+    ASSERT(m_databaseInfo);
+    return m_databaseInfo->infoForExistingObjectStore(objectStoreIdentifier);
+}
+
 void MemoryIDBBackingStore::deleteBackingStore()
 {
     // The in-memory IDB backing store doesn't need to do any cleanup when it is deleted.
index 63a9ea5..49202f6 100644 (file)
@@ -69,6 +69,7 @@ public:
     virtual IDBError openCursor(const IDBResourceIdentifier& transactionIdentifier, const IDBCursorInfo&, IDBGetResult& outResult) override final;
     virtual IDBError iterateCursor(const IDBResourceIdentifier& transactionIdentifier, const IDBResourceIdentifier& cursorIdentifier, const IDBKeyData&, uint32_t count, IDBGetResult& outResult) override final;
 
+    virtual IDBObjectStoreInfo* infoForObjectStore(uint64_t objectStoreIdentifier) override final;
     virtual void deleteBackingStore() override final;
     virtual bool supportsSimultaneousTransactions() override final { return true; }
 
index 90bcd1c..b5d5256 100644 (file)
@@ -612,6 +612,7 @@ IDBError SQLiteIDBBackingStore::beginTransaction(const IDBTransactionInfo& info)
 
     ASSERT(m_sqliteDB);
     ASSERT(m_sqliteDB->isOpen());
+    ASSERT(m_databaseInfo);
 
     auto addResult = m_transactions.add(info.identifier(), nullptr);
     if (!addResult.isNewEntry) {
@@ -620,7 +621,12 @@ IDBError SQLiteIDBBackingStore::beginTransaction(const IDBTransactionInfo& info)
     }
 
     addResult.iterator->value = std::make_unique<SQLiteIDBTransaction>(*this, info);
-    return addResult.iterator->value->begin(*m_sqliteDB);
+
+    auto error = addResult.iterator->value->begin(*m_sqliteDB);
+    if (error.isNull() && info.mode() == IndexedDB::TransactionMode::VersionChange)
+        m_originalDatabaseInfoBeforeVersionChange = std::make_unique<IDBDatabaseInfo>(*m_databaseInfo);
+
+    return error;
 }
 
 IDBError SQLiteIDBBackingStore::abortTransaction(const IDBResourceIdentifier& identifier)
@@ -636,6 +642,12 @@ IDBError SQLiteIDBBackingStore::abortTransaction(const IDBResourceIdentifier& id
         return { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to abort a transaction that hasn't been established") };
     }
 
+
+    if (transaction->mode() == IndexedDB::TransactionMode::VersionChange) {
+        ASSERT(m_originalDatabaseInfoBeforeVersionChange);
+        m_databaseInfo = WTFMove(m_originalDatabaseInfoBeforeVersionChange);
+    }
+
     return transaction->abort();
 }
 
@@ -652,7 +664,16 @@ IDBError SQLiteIDBBackingStore::commitTransaction(const IDBResourceIdentifier& i
         return { IDBDatabaseException::UnknownError, ASCIILiteral("Attempt to commit a transaction that hasn't been established") };
     }
 
-    return transaction->commit();
+    auto error = transaction->commit();
+    if (!error.isNull()) {
+        if (transaction->mode() == IndexedDB::TransactionMode::VersionChange) {
+            ASSERT(m_originalDatabaseInfoBeforeVersionChange);
+            m_databaseInfo = WTFMove(m_originalDatabaseInfoBeforeVersionChange);
+        }
+    } else
+        m_originalDatabaseInfoBeforeVersionChange = nullptr;
+
+    return error;
 }
 
 IDBError SQLiteIDBBackingStore::createObjectStore(const IDBResourceIdentifier& transactionIdentifier, const IDBObjectStoreInfo& info)
@@ -702,6 +723,8 @@ IDBError SQLiteIDBBackingStore::createObjectStore(const IDBResourceIdentifier& t
         }
     }
 
+    m_databaseInfo->addExistingObjectStore(info);
+
     return { };
 }
 
@@ -777,6 +800,8 @@ IDBError SQLiteIDBBackingStore::deleteObjectStore(const IDBResourceIdentifier& t
         }
     }
 
+    m_databaseInfo->deleteObjectStore(objectStoreIdentifier);
+
     return true;
 }
 
@@ -890,6 +915,10 @@ IDBError SQLiteIDBBackingStore::createIndex(const IDBResourceIdentifier& transac
         }
     }
 
+    auto* objectStore = m_databaseInfo->infoForExistingObjectStore(info.objectStoreIdentifier());
+    ASSERT(objectStore);
+    objectStore->addExistingIndex(info);
+
     return { };
 }
 
@@ -1032,6 +1061,10 @@ IDBError SQLiteIDBBackingStore::deleteIndex(const IDBResourceIdentifier& transac
         }
     }
 
+    auto* objectStore = m_databaseInfo->infoForExistingObjectStore(objectStoreIdentifier);
+    ASSERT(objectStore);
+    objectStore->deleteIndex(indexIdentifier);
+
     return { };
 }
 
@@ -1622,6 +1655,12 @@ IDBError SQLiteIDBBackingStore::iterateCursor(const IDBResourceIdentifier& trans
     return { };
 }
 
+IDBObjectStoreInfo* SQLiteIDBBackingStore::infoForObjectStore(uint64_t objectStoreIdentifier)
+{
+    ASSERT(m_databaseInfo);
+    return m_databaseInfo->infoForExistingObjectStore(objectStoreIdentifier);
+}
+
 void SQLiteIDBBackingStore::deleteBackingStore()
 {
     String dbFilename = fullDatabasePath();
index 88df4d6..131c39e 100644 (file)
@@ -73,6 +73,7 @@ public:
     virtual IDBError openCursor(const IDBResourceIdentifier& transactionIdentifier, const IDBCursorInfo&, IDBGetResult& outResult) override final;
     virtual IDBError iterateCursor(const IDBResourceIdentifier& transactionIdentifier, const IDBResourceIdentifier& cursorIdentifier, const IDBKeyData&, uint32_t count, IDBGetResult& outResult) override final;
 
+    virtual IDBObjectStoreInfo* infoForObjectStore(uint64_t objectStoreIdentifier) override final;
     virtual void deleteBackingStore() override final;
     virtual bool supportsSimultaneousTransactions() override final { return false; }
 
@@ -104,6 +105,7 @@ private:
 
     IDBDatabaseIdentifier m_identifier;
     std::unique_ptr<IDBDatabaseInfo> m_databaseInfo;
+    std::unique_ptr<IDBDatabaseInfo> m_originalDatabaseInfoBeforeVersionChange;
 
     std::unique_ptr<SQLiteDatabase> m_sqliteDB;
 
index 73832a5..d907c8e 100644 (file)
@@ -690,7 +690,7 @@ void UniqueIDBDatabase::performPutOrAdd(uint64_t callbackIdentifier, const IDBRe
     IDBKeyData usedKey;
     IDBError error;
 
-    auto objectStoreInfo = m_databaseInfo->infoForExistingObjectStore(objectStoreIdentifier);
+    auto* objectStoreInfo = m_backingStore->infoForObjectStore(objectStoreIdentifier);
     if (!objectStoreInfo) {
         error = IDBError(IDBDatabaseException::InvalidStateError, ASCIILiteral("Object store cannot be found in the backing store"));
         m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, error, usedKey));