From 176f1a338a59802e4673b609850c444807ebd58d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20D=E2=80=99Aquino?= Date: Mon, 4 Aug 2025 11:41:05 -0700 Subject: [PATCH] Fix app swap crash MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- nostrdb/NdbTxn.swift | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/nostrdb/NdbTxn.swift b/nostrdb/NdbTxn.swift index f690e479..af94f921 100644 --- a/nostrdb/NdbTxn.swift +++ b/nostrdb/NdbTxn.swift @@ -30,7 +30,10 @@ class NdbTxn: 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 { 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