From 0c35feb195bc0b867f62fac36588cafc82a0195c Mon Sep 17 00:00:00 2001 From: Gabriele Ciech Date: Fri, 13 Nov 2026 17:12:02 +0100 Subject: [PATCH] Fix crash on NULL bcb_bdb after failed expand_buffers() (backport of CORE-6509) expand_buffers() sets bcb_count before the new buffer descriptors are allocated, so after a BadAlloc the tail of bcb_rpt has no BufferDesc. Initialise the new tail to NULL (as CORE-6509 did in 4.0) and stop at the first NULL in every loop over bcb_count that dereferences bcb_bdb: flushAll(), CCH_down_grade_dbb(), CCH_flush_ast(), CCH_shutdown() and get_prec_walk_mark(). Refs #9289 --- src/jrd/cch.cpp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/jrd/cch.cpp b/src/jrd/cch.cpp index 33147e6f89f..76d75dc8836 100644 --- a/src/jrd/cch.cpp +++ b/src/jrd/cch.cpp @@ -355,6 +355,8 @@ int CCH_down_grade_dbb(void* ast_object) for (const bcb_repeat* const end = tail + bcb->bcb_count; tail < end; ++tail) { BufferDesc* bdb = tail->bcb_bdb; + if (!bdb) // first non-initialized BDB, abandon following checks + break; // Acquire EX latch to avoid races with LCK_release (called by CCH_release) // or LCK_lock (by lock_buffer) in main thread. Take extra care to avoid @@ -1225,6 +1227,9 @@ void CCH_flush_ast(thread_db* tdbb) for (ULONG i = 0; (bcb = dbb->dbb_bcb) && i < bcb->bcb_count; i++) { BufferDesc* bdb = bcb->bcb_rpt[i].bcb_bdb; + if (!bdb) // first non-initialized BDB, abandon following checks + break; + if (bdb->bdb_flags & (BDB_dirty | BDB_db_dirty)) down_grade(tdbb, bdb, 1); } @@ -2161,6 +2166,8 @@ void CCH_shutdown(thread_db* tdbb) for (; tail < end; tail++) { BufferDesc* const bdb = tail->bcb_bdb; + if (!bdb) // first non-initialized BDB, abandon following checks + break; if (dbb->dbb_flags & DBB_bugcheck) { @@ -2672,6 +2679,8 @@ static void flushAll(thread_db* tdbb, USHORT flush_flag) for (ULONG i = 0; i < bcb->bcb_count; i++) { BufferDesc* bdb = bcb->bcb_rpt[i].bcb_bdb; + if (!bdb) // first non-initialized BDB, abandon following checks + break; if (bdb->bdb_flags & (BDB_db_dirty | BDB_dirty)) { @@ -3567,7 +3576,10 @@ static bool expand_buffers(thread_db* tdbb, ULONG number) // Initialize tail of new buffer control block bcb_repeat* new_tail; for (new_tail = bcb->bcb_rpt; new_tail < new_end; new_tail++) + { QUE_INIT(new_tail->bcb_page_mod); + new_tail->bcb_bdb = NULL; + } // Move any active buffers from old block to new @@ -4057,7 +4069,13 @@ static ULONG get_prec_walk_mark(BufferControl* bcb) if (++bcb->bcb_prec_walk_mark == 0) { for (ULONG i = 0; i < bcb->bcb_count; i++) - bcb->bcb_rpt[i].bcb_bdb->bdb_prec_walk_mark = 0; + { + BufferDesc* bdb = bcb->bcb_rpt[i].bcb_bdb; + if (!bdb) // first non-initialized BDB, abandon following checks + break; + + bdb->bdb_prec_walk_mark = 0; + } bcb->bcb_prec_walk_mark = 1; }