commit 176f1a338a59802e4673b609850c444807ebd58d
parent fc1eb326e84afb3b8c634dd346e799fa75ab2ac5
Author: Daniel D’Aquino <daniel@daquino.me>
Date: Mon, 4 Aug 2025 11:41:05 -0700
Fix app swap crash
This commit fixes a crash that occurred when swapping between Damus and
other apps.
When Damus enters background mode, NostrDB is closed and its resources
released. When Damus re-enters foreground mode, NostrDB is reopened.
However, an issue with the transaction inheritance logic
caused a race condition where a side menu profile lookup would get an
obsolete transaction containing pointers that have been freedwhen
NostrDB was closed, causing a "use-after-free" memory error.
The issue was fixed by improving the transaction inheritance logic to
double-check if the "generation" counter (which auto increments when
Damus closes and re-opens) matches the generation marked on the
thread-specific transaction. This effectively prevents lookups from
inheriting an obsolete transaction from a previous NostrDB generation.
Closes: https://github.com/damus-io/damus/issues/3167
Changelog-Fixed: Fixed an issue where the app would crash when swapping between apps
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Diffstat:
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/nostrdb/NdbTxn.swift b/nostrdb/NdbTxn.swift
@@ -30,7 +30,10 @@ class NdbTxn<T>: RawNdbTxnAccessible {
self.name = name ?? "txn"
self.ndb = ndb
self.generation = ndb.generation
- if let active_txn = Thread.current.threadDictionary["ndb_txn"] as? ndb_txn {
+ if let active_txn = Thread.current.threadDictionary["ndb_txn"] as? ndb_txn,
+ let txn_generation = Thread.current.threadDictionary["txn_generation"] as? Int,
+ txn_generation == ndb.generation
+ {
// some parent thread is active, use that instead
print("txn: inherited txn")
self.txn = active_txn
@@ -147,7 +150,10 @@ class SafeNdbTxn<T: ~Copyable> {
var generation = ndb.generation
var txn: ndb_txn
let inherited: Bool
- if let active_txn = Thread.current.threadDictionary["ndb_txn"] as? ndb_txn {
+ if let active_txn = Thread.current.threadDictionary["ndb_txn"] as? ndb_txn,
+ let txn_generation = Thread.current.threadDictionary["txn_generation"] as? Int,
+ txn_generation == ndb.generation
+ {
// some parent thread is active, use that instead
print("txn: inherited txn")
txn = active_txn