fix(wallets): don't rebuild the wallet list inside its own row loop

Open on a wallet row whose file was moved or deleted after the list was
built rebuilt the list from inside the dialog's row loop. The loop still
held a reference to that row and walked a sort order sized for the old
list, so the click read freed memory and could index past the end. Open
now flags a rescan for the next frame; the vanished row drops out one
frame later, with no crash.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-09 21:09:48 -05:00
co-authored by Claude Opus 5.5
parent bb84243114
commit 1658950386
+4 -2
View File
@@ -654,8 +654,10 @@ private:
// The row could be stale (file moved/deleted between the scan and this click). Don't link a ghost:
// on Linux/macOS create_symlink to a missing target would happily succeed (a dangling link), we'd
// switch to it, and the daemon guard would silently fall back to wallet.dat — "opened X, got the
// default". Refresh the list instead so the vanished row drops out.
if (!fs::exists(src, ec)) { scan(); return; }
// default". Refresh the list instead so the vanished row drops out — but not here: we are inside
// render()'s row loop, which holds `const WalletRow& r` and iterates s_order sized for the current
// rows, so a rebuild would leave both dangling (out-of-bounds). Flag it; the next frame rescans.
if (!fs::exists(src, ec)) { s_needScan = true; return; }
// canonPath (symlinks resolved) is the wallet's stable identity: hash it so the same file reached
// via any path maps to ONE link name, and point the link straight at the resolved real file.
const std::string target = r.canonPath.empty() ? canonicalOf(src) : r.canonPath;