Branch: refs/heads/main
  Home:   https://github.com/WebKit/WebKit
  Commit: 03efc9761a39b4849f8c849c455b4f6806c250f9
      
https://github.com/WebKit/WebKit/commit/03efc9761a39b4849f8c849c455b4f6806c250f9
  Author: Sihui Liu <[email protected]>
  Date:   2026-08-26 (Wed, 26 Aug 2026)

  Changed paths:
    M Source/WebCore/Modules/indexeddb/server/IDBConnectionToClient.cpp
    M Source/WebCore/Modules/indexeddb/server/IDBConnectionToClient.h
    M Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.cpp
    M Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.h
    M Source/WebKit/NetworkProcess/storage/NetworkStorageManager.cpp
    M Tools/TestWebKitAPI/Tests/WebKit/WKWebView/IndexedDBSuspendImminently.mm

  Log Message:
  -----------
  REGRESSION(315609@main): Stack overflow in NetworkProcess aborting the queued 
transactions of a suspended process
https://bugs.webkit.org/show_bug.cgi?id=322386
rdar://184669941

Reviewed by Chris Dumez.

A page that queues many read-write transactions operating on the same object 
store and is then suspended crashed the
network process. The cause is that handleTransactions() ended every scheduling 
pass by calling
abortInProgressTransactionsBlockedOnSuspendedClients(), and that pass ended by 
calling handleTransactions() again. When
the scopes all overlap, takeNextRunnableTransaction() starts exactly one 
transaction before deferring the rest, so each
cycle handled a single queued transaction and cost one frame pair; the reported 
crash recursed over 3000 levels.
Batching the aborts in 318222@main did not help, because there is never more 
than one transaction to abort per pass.

This patch breaks the cycle at both ends. handleTransactions() no longer calls 
the abort pass, and
takeNextRunnableTransaction() no longer picks transactions of suspended 
clients: such a client cannot send requests, so
starting its transaction only holds the scope without making progress, and 
since the SQLite backing stores serialize
writes it blocks every other client's writes as well.

The abort pass now runs only from the three points where the blocked set can 
change, each followed by
handleTransactions() to start whatever became runnable:
- Suspending a client marks it suspended and aborts its in-progress 
transactions that block an active client.
- Resuming a client marks it active and aborts the in-progress transactions of 
still-suspended clients that now block
it.
- Queuing a transaction aborts the in-progress transactions of suspended 
clients that block it.

All three are IPC entry points, so the abort pass is unreachable from the 
scheduler and the recursion is structurally
impossible; a debug-only re-entrancy assertion replaces the recursion-depth 
counter from 318222@main. A suspended
client's queued transactions are now kept rather than started and rolled back, 
so their writes are no longer lost.

Also renamed setClientProcessSuspended() to setClientSuspended(), since a 
client connection in this layer is already
identified by a ProcessIdentifier.

Added 3 IndexedDB API tests to expand coverage:
- ManyQueuedTransactionsOfSuspendedProcessAreDeferredNotAborted covers the 
reported crash and checks that only the
in-progress transaction is aborted, that the 99 queued ones complete after 
resume, and that the network process
survived.
- TransactionOfSuspendedProcessIsNotAbortedByItsOwnQueuedTransaction checks 
that a suspended client's in-progress
transaction is left alone when the only thing waiting on it is that client's 
own queued transaction.
- TransactionOfSuspendedProcessIsAbortedWhenAnotherSuspendedProcessResumes 
checks that with two suspended clients,
resuming one aborts the other's in-progress transaction and starts the resumed 
client's.

* Source/WebCore/Modules/indexeddb/server/IDBConnectionToClient.cpp:
(WebCore::IDBServer::IDBConnectionToClient::setClientSuspended):
(WebCore::IDBServer::IDBConnectionToClient::setClientProcessSuspended): Deleted.
* Source/WebCore/Modules/indexeddb/server/IDBConnectionToClient.h:
(WebCore::IDBServer::IDBConnectionToClient::isClientSuspended const):
(WebCore::IDBServer::IDBConnectionToClient::isClientProcessSuspended const): 
Deleted.
* Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.cpp:
(WebCore::IDBServer::UniqueIDBDatabase::enqueueTransaction):
(WebCore::IDBServer::UniqueIDBDatabase::handleTransactions):
(WebCore::IDBServer::isTransactionOfSuspendedClient):
(WebCore::IDBServer::UniqueIDBDatabase::takeNextRunnableTransaction):
(WebCore::IDBServer::UniqueIDBDatabase::transactionBlocksPendingTransactions):
(WebCore::IDBServer::UniqueIDBDatabase::handleTransactionsAfterAbortingSuspendedClientTransactions):
(WebCore::IDBServer::UniqueIDBDatabase::abortInProgressTransactionsOfSuspendedClientsIfNeeded):
(WebCore::IDBServer::UniqueIDBDatabase::abortInProgressTransactionsBlockedOnSuspendedClients):
 Deleted.
* Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.h:
* Source/WebKit/NetworkProcess/storage/NetworkStorageManager.cpp:
(WebKit::NetworkStorageManager::setWebProcessSuspended):
* Tools/TestWebKitAPI/Tests/WebKit/WKWebView/IndexedDBSuspendImminently.mm:
(ManyQueuedTransactionsOfSuspendedProcessAreDeferredNotAborted)):
(TransactionOfSuspendedProcessIsNotAbortedByItsOwnQueuedTransaction)):
(TransactionOfSuspendedProcessIsAbortedWhenAnotherSuspendedProcessResumes)):

Canonical link: https://commits.webkit.org/319873@main



To unsubscribe from these emails, change your notification settings at 
https://github.com/WebKit/WebKit/settings/notifications

Reply via email to