WebPlatformForEmbedded / WPEWebKit

WPE WebKit port (downstream)
210 stars 135 forks source link

[LocalStorage] Fix NetworkProcess crash on sqlite database corruption #1359

Open asurdej-comcast opened 1 week ago

asurdej-comcast commented 1 week ago

1) Corrupted database is handled inside handleDatabaseCorruptionIfNeeded(), that closes database connection and clears all cached statements (m_cachedStatements). The second destroys all SQLiteStatement(s) objects. But a pointer to such object may be still kept inside SQLiteStatementAutoResetScope created inside SQLiteStorageArea.cpp:

auto statement = cachedStatement(StatementType::SetItem);

This will call m_statement->reset() at scope exit (from ~SQLiteStatementAutoResetScope) on already deleted object that results with crash.

The solution is to use WeakPtr to make sure object is still alive before calling statement->reset()

2) Special case happens when corruption is detected on setting new item (setItem). If there are no cached entries, handleDatabaseCorruptionIfNeeded() will not create new database (m_database == nullptr) that will lead to another crash when re-trying to create cachedStatement again.

Solution here is to replace direct statement execution with full setItem() call that will prepareDatabase() again if needed.

I simulated database corruption with

echo "dummy data" | tee http_example.com_0.localstorage*

directly on localstorage database file.

The issue was originally found during device reboot tests

asurdej-comcast commented 1 week ago

backtrace:

0
sqlite3_reset
‎/usr/src/debug/sqlite3/3_3.31.1-r0/build/../sqlite-autoconf-3310100/sqlite3.c:82667
1
WebCore::SQLiteStatement::reset
‎/usr/src/debug/wpe-webkit/2.38.5+gitAUTOINC+44cb95d724-r8/build/../git/Source/WebCore/platform/sql/SQLiteStatement.cpp:85
2
WebCore::SQLiteStatementAutoResetScope::~SQLiteStatementAutoResetScope
‎/usr/src/debug/wpe-webkit/2.38.5+gitAUTOINC+44cb95d724-r8/build/../git/Source/WebCore/platform/sql/SQLiteStatementAutoResetScope.cpp:54
3
WebKit::SQLiteStorageArea::setItem
‎/usr/src/debug/wpe-webkit/2.38.5+gitAUTOINC+44cb95d724-r8/build/../git/Source/WebKit/NetworkProcess/storage/SQLiteStorageArea.cpp:359
4
WebKit::SQLiteStorageArea::setItem
‎/usr/src/debug/wpe-webkit/2.38.5+gitAUTOINC+44cb95d724-r8/build/../git/Source/WebKit/NetworkProcess/storage/SQLiteStorageArea.cpp:331
5
WebKit::NetworkStorageManager::setItem
‎/usr/src/debug/wpe-webkit/2.38.5+gitAUTOINC+44cb95d724-r8/build/../git/Source/WebKit/NetworkProcess/storage/NetworkStorageManager.cpp:957
6
void IPC::handleMessageAsyncWantsConnection
‎/usr/src/debug/wpe-webkit/2.38.5+gitAUTOINC+44cb95d724-r8/build/../git/Source/WebKit/Platform/IPC/HandleMessage.h:159
7
WebKit::NetworkStorageManager::didReceiveMessage
‎/usr/src/debug/wpe-webkit/2.38.5+gitAUTOINC+44cb95d724-r8/build/DerivedSources/WebKit/NetworkStorageManagerMessageReceiver.cpp:432
8
WTF::RunLoop::performWork
‎/usr/src/debug/wpe-webkit/2.38.5+gitAUTOINC+44cb95d724-r8/build/../git/Source/WTF/wtf/Function.h:82
9
_FUN
‎/usr/src/debug/wpe-webkit/2.38.5+gitAUTOINC+44cb95d724-r8/build/../git/Source/WTF/wtf/glib/RunLoopGLib.cpp:80
10
_FUN
‎/usr/src/debug/wpe-webkit/2.38.5+gitAUTOINC+44cb95d724-r8/build/../git/Source/WTF/wtf/glib/RunLoopGLib.cpp:53
11
g_main_context_dispatch
‎/usr/src/debug/glib-2.0/1_2.72.3-r0/build/../glib-2.72.3/glib/gmain.c:3417
12
g_main_context_iterate
‎/usr/src/debug/glib-2.0/1_2.72.3-r0/build/../glib-2.72.3/glib/gmain.c:4211
13
g_main_loop_run
‎/usr/src/debug/glib-2.0/1_2.72.3-r0/build/../glib-2.72.3/glib/gmain.c:4411
14
WTF::RunLoop::run
‎/usr/src/debug/wpe-webkit/2.38.5+gitAUTOINC+44cb95d724-r8/build/../git/Source/WTF/wtf/glib/RunLoopGLib.cpp:108
15
WTF::Thread::entryPoint
‎/usr/src/debug/wpe-webkit/2.38.5+gitAUTOINC+44cb95d724-r8/build/../git/Source/WTF/wtf/Function.h:82
16
wtfThreadEntryPoint
‎/usr/src/debug/wpe-webkit/2.38.5+gitAUTOINC+44cb95d724-r8/build/../git/Source/WTF/wtf/posix/ThreadingPOSIX.cpp:242
17
start_thread
‎/usr/src/debug/glibc/2.35-r0/git/nptl/pthread_create.c:442
18
clone
‎: