From 72683da2b01286030fd61228168712c84aea79d4 Mon Sep 17 00:00:00 2001 From: Bitflash Date: Wed, 29 Jul 2026 17:41:10 -0300 Subject: db: catch BDB exceptions so unreadable files fail cleanly (#34) (#38) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Berkeley DB throws when it cannot open a file written by another platform's build (e.g. BDB 5.3 wallet read by 6.2). Nothing on the call path caught these, so the exception unwound into std::terminate -- surfacing on Windows as STATUS_STACK_BUFFER_OVERRUN (0xC0000409) with no useful message. Three layers of defense: 1. main_gui.cpp: try/catch around LoadBlockIndex() and LoadWallet(), printing the reason and exiting cleanly. 2. db.cpp LoadWallet: try/catch around the record-reading loop (Satoshi's 2009 TODO), tracking the last record type so the error message says what it choked on. 3. db.cpp cleanup paths: every dbenv.close(), pdb->close(), txn_checkpoint() and log_archive() wrapped in try/catch so the environment teardown after a failed open does not throw a second exception into std::terminate. Tested: cross-platform wallet (Linux BDB 5.3 → Windows 6.2) now prints a clear message and exits with code 1, wallet left untouched. Closes #34 Co-authored-by: Claude Opus 4.6 --- src/main_gui.cpp | 41 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) (limited to 'src/main_gui.cpp') diff --git a/src/main_gui.cpp b/src/main_gui.cpp index 99e63d4..a94d01d 100644 --- a/src/main_gui.cpp +++ b/src/main_gui.cpp @@ -170,11 +170,46 @@ int main(int argc, char* argv[]) ParseStartupArguments(argc, argv); - printf("Loading block index...\n"); + // Berkeley DB reports failure by throwing, and CDB's constructor lets it + // through. Nothing on this path caught anything, so an unreadable + // blkindex.dat or wallet.dat -- one written by another platform's Berkeley + // DB, a truncated file, a version mismatch -- unwound out of main() into + // std::terminate and abort(). On Windows that surfaces as + // STATUS_STACK_BUFFER_OVERRUN (0xC0000409) inside ucrtbase.dll: no message, + // no log line past "Loading wallet...", and a faulting module with nothing + // to do with the real problem. Confirmed by stack trace: + // + // libdb_cxx-6.2.dll -> CDB::CDB(...) -> LoadBlockIndex(...) -> main() + // + // The program knew what had gone wrong and threw the reason away. string strErrors; - if (!LoadBlockIndex()) { fprintf(stderr,"LoadBlockIndex failed\n"); return 1; } + printf("Loading block index...\n"); + try + { + if (!LoadBlockIndex()) { fprintf(stderr, "LoadBlockIndex failed\n"); return 1; } + } + catch (const std::exception& e) + { + fprintf(stderr, "Cannot read the block index: %s\n", e.what()); + fprintf(stderr, "blkindex.dat and blk0001.dat may be from another machine or " + "incomplete. Deleting both is safe -- they are re-downloaded -- " + "but never delete wallet.dat, which holds your keys.\n"); + return 1; + } + printf("Loading wallet...\n"); - if (!LoadWallet()) { fprintf(stderr,"LoadWallet failed\n"); return 1; } + try + { + if (!LoadWallet()) { fprintf(stderr, "LoadWallet failed\n"); return 1; } + } + catch (const std::exception& e) + { + fprintf(stderr, "Cannot read wallet.dat: %s\n", e.what()); + fprintf(stderr, "The file was left untouched. A wallet.dat written by a " + "different platform's Berkeley DB is the usual cause; back it " + "up before trying anything else.\n"); + return 1; + } printf("Height=%d\n", nBestHeight); ReacceptWalletTransactions(); -- cgit v1.2.3