Environment
- powersync version: 2.1.0
- sqlite3 / sqlite3_connection_pool version: 0.2.4
- Flutter version: 3.41.9
- Platform: iOS Simulator (ARM-64, macOS 26.3.1)
- Dart mode: Debug (hot restart)
What happened
The app crashes intermittently during hot restart on the iOS Simulator.
The crash does not reproduce on a full app restart — only on hot restart.
Exception
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at 0x0000000000000007
Faulting Thread: DartWorker
Root cause analysis
The crash is a use-after-free race condition between two concurrent events triggered by hot restart:
-
Thread A — Dart_ShutdownIsolate fires NativeFinalizer callbacks,
which call sqlite3_connection_pool_close → sqlite3Close, tearing down
native SQLite state.
-
Thread B (crashed) — A DartWorker is still processing a message
from a background isolate. The message handler dereferences a Dart object
whose underlying native resource (the SQLite connection) has already been
freed by Thread A.
The crash address 0x0000000000000007 is a strong indicator of a
use-after-free: the code reads a field at offset 7 from a pointer that now
points to deallocated memory.
Key frames from the crash report:
Thread that closes the connection (NativeFinalizer path):
sqlite3MemFree
exprListDeleteNN
sqlite3SchemaClear
sqlite3BtreeClose
sqlite3LeaveMutexAndCloseZombie
sqlite3Close
pkg_sqlite3_connection_pool_close ← native asset: sqlite3_connection_pool
dart::NativeFinalizer::RunCallback
dart::Isolate::RunAndCleanupFinalizersOnShutdown
dart::Isolate::Shutdown
Dart_ShutdownIsolate
dart::ThreadPool::WorkerLoop
Crashed thread (still executing Dart code):
[Dart JIT frames — message handler executing against a torn-down connection]
dart::DartLibraryCalls::HandleMessage
dart::IsolateMessageHandler::HandleMessage
dart::MessageHandler::TaskCallback
dart::ThreadPool::WorkerLoop
Additional symptom — Thread 23 is blocked waiting on
dart::SafepointRwLock::EnterRead inside Library::LookupLibrary while
trying to deserialize a message, suggesting the VM library table is in a
partially-shutdown state during the race.
Expected behavior
PowerSync should drain or cancel all pending background isolate messages and
explicitly close SQLite connections before the Dart isolate reaches the
RunAndCleanupFinalizersOnShutdown phase during hot restart. This would
ensure no DartWorker is left processing messages that reference resources
whose NativeFinalizer has already fired.
Actual behavior
The connection pool's NativeFinalizer fires concurrently with in-flight
Dart message handlers, causing a use-after-free segfault.
Crash report
crash.txt.zip
Workaround
None found. The crash is non-deterministic and depends on thread scheduling
timing. It occurs more frequently under load or when more background workers
are active.
Environment
What happened
The app crashes intermittently during hot restart on the iOS Simulator.
The crash does not reproduce on a full app restart — only on hot restart.
Exception
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at 0x0000000000000007
Faulting Thread: DartWorker
Root cause analysis
The crash is a use-after-free race condition between two concurrent events triggered by hot restart:
Thread A —
Dart_ShutdownIsolatefiresNativeFinalizercallbacks,which call
sqlite3_connection_pool_close→sqlite3Close, tearing downnative SQLite state.
Thread B (crashed) — A
DartWorkeris still processing a messagefrom a background isolate. The message handler dereferences a Dart object
whose underlying native resource (the SQLite connection) has already been
freed by Thread A.
The crash address
0x0000000000000007is a strong indicator of ause-after-free: the code reads a field at offset 7 from a pointer that now
points to deallocated memory.
Key frames from the crash report:
Thread that closes the connection (NativeFinalizer path):
sqlite3MemFree
exprListDeleteNN
sqlite3SchemaClear
sqlite3BtreeClose
sqlite3LeaveMutexAndCloseZombie
sqlite3Close
pkg_sqlite3_connection_pool_close ← native asset: sqlite3_connection_pool
dart::NativeFinalizer::RunCallback
dart::Isolate::RunAndCleanupFinalizersOnShutdown
dart::Isolate::Shutdown
Dart_ShutdownIsolate
dart::ThreadPool::WorkerLoop
Crashed thread (still executing Dart code):
[Dart JIT frames — message handler executing against a torn-down connection]
dart::DartLibraryCalls::HandleMessage
dart::IsolateMessageHandler::HandleMessage
dart::MessageHandler::TaskCallback
dart::ThreadPool::WorkerLoop
Additional symptom — Thread 23 is blocked waiting on
dart::SafepointRwLock::EnterReadinsideLibrary::LookupLibrarywhiletrying to deserialize a message, suggesting the VM library table is in a
partially-shutdown state during the race.
Expected behavior
PowerSync should drain or cancel all pending background isolate messages and
explicitly close SQLite connections before the Dart isolate reaches the
RunAndCleanupFinalizersOnShutdownphase during hot restart. This wouldensure no
DartWorkeris left processing messages that reference resourceswhose
NativeFinalizerhas already fired.Actual behavior
The connection pool's
NativeFinalizerfires concurrently with in-flightDart message handlers, causing a use-after-free segfault.
Crash report
crash.txt.zip
Workaround
None found. The crash is non-deterministic and depends on thread scheduling
timing. It occurs more frequently under load or when more background workers
are active.