@@ -138,6 +138,8 @@ static LatchState latch_buffer(thread_db*, Sync&, BufferDesc*, const PageNumber,
138138static LockState lock_buffer (thread_db*, BufferDesc*, const SSHORT, const SCHAR);
139139static ULONG memory_init (thread_db*, BufferControl*, SLONG);
140140static void page_validation_error (thread_db*, win*, SSHORT);
141+ inline void page_validate (thread_db*, win*, const LockState, SSHORT);
142+ static void validate_read_page (thread_db*, win*, SSHORT);
141143static void purgePrecedence (BufferControl*, BufferDesc*);
142144static SSHORT related (BufferDesc*, const BufferDesc*, SSHORT, const ULONG);
143145static bool writeable (BufferDesc*);
@@ -747,10 +749,7 @@ pag* CCH_fetch(thread_db* tdbb, WIN* window, int lock_type, SCHAR page_type, int
747749
748750 adjust_scan_count (window, lockState == lsLocked);
749751
750- // Validate the fetched page matches the expected type
751-
752- if (bdb->bdb_buffer ->pag_type != page_type && page_type != pag_undefined)
753- page_validation_error (tdbb, window, page_type);
752+ page_validate (tdbb, window, lockState, page_type);
754753
755754 return window->win_buffer ;
756755}
@@ -1412,10 +1411,7 @@ pag* CCH_handoff(thread_db* tdbb, WIN* window, ULONG page, int lock, SCHAR page_
14121411
14131412 adjust_scan_count (window, must_read == lsLocked);
14141413
1415- // Validate the fetched page matches the expected type
1416-
1417- if (bdb->bdb_buffer ->pag_type != page_type && page_type != pag_undefined)
1418- page_validation_error (tdbb, window, page_type);
1414+ page_validate (tdbb, window, must_read, page_type);
14191415
14201416 return window->win_buffer ;
14211417}
@@ -4357,7 +4353,7 @@ static ULONG memory_init(thread_db* tdbb, BufferControl* bcb, SLONG number)
43574353}
43584354
43594355
4360- static void page_validation_error (thread_db* tdbb, WIN* window, SSHORT type)
4356+ static void page_validation_error (thread_db* tdbb, WIN* window, SSHORT type, Arg::StatusVector& err )
43614357{
43624358/* *************************************
43634359 *
@@ -4376,22 +4372,140 @@ static void page_validation_error(thread_db* tdbb, WIN* window, SSHORT type)
43764372 **************************************/
43774373 SET_TDBB (tdbb);
43784374 BufferDesc* bdb = window->win_bdb ;
4379- const pag* page = bdb->bdb_buffer ;
4380-
43814375 PageSpace* pages =
43824376 tdbb->getDatabase ()->dbb_page_manager .findPageSpace (bdb->bdb_page .getPageSpaceID ());
43834377
43844378 ERR_build_status (tdbb->tdbb_status_vector ,
4385- Arg::Gds (isc_db_corrupt) << Arg::Str (pages->file ->fil_string ) <<
4386- Arg::Gds (isc_page_type_err) <<
4387- Arg::Gds (isc_badpagtyp) << Arg::Num (bdb->bdb_page .getPageNum ()) <<
4388- pagtype (type) <<
4389- pagtype (page->pag_type ));
4379+ Arg::Gds (isc_db_corrupt) << Arg::Str (pages->file ->fil_string ) << err);
4380+
43904381 // We should invalidate this bad buffer.
43914382 CCH_unwind (tdbb, true );
43924383}
43934384
43944385
4386+ inline void page_validate (thread_db* tdbb, WIN* window, const LockState ls, SSHORT type)
4387+ {
4388+ // Validate only when required page type is known and page was read from disk
4389+ // if (type != pag_undefined && ls == lsLocked)
4390+ // validate_read_page(tdbb, window, type);
4391+ }
4392+
4393+
4394+ static void validate_read_page (thread_db* tdbb, WIN* window, SSHORT type)
4395+ {
4396+ // Validate the fetched page matches the expected type
4397+ if (window->win_buffer ->pag_type != type)
4398+ {
4399+ BufferDesc* bdb = window->win_bdb ;
4400+ const pag* page = bdb->bdb_buffer ;
4401+
4402+ page_validation_error (tdbb, window, type,
4403+ Arg::Gds (isc_page_type_err) <<
4404+ Arg::Gds (isc_badpagtyp) << Arg::Num (bdb->bdb_page .getPageNum ()) << pagtype (type) << pagtype (page->pag_type ));
4405+ }
4406+
4407+ switch (type)
4408+ {
4409+ case pag_root:
4410+ {
4411+ index_root_page* pg = (index_root_page*) window->win_buffer ;
4412+
4413+ // check RPT size correctness
4414+ FB_UINT64 rptSize = sizeof (index_root_page) - sizeof (index_root_page::irt_repeat);
4415+ rptSize += FB_UINT64 (pg->irt_count ) * sizeof (index_root_page::irt_repeat);
4416+ if (rptSize > tdbb->getDatabase ()->dbb_page_size )
4417+ {
4418+ page_validation_error (tdbb, window, type,
4419+ Arg::Gds (isc_random) << " Bad index root page: too many indices" );
4420+ }
4421+
4422+ // check keys location on page
4423+ for (USHORT i = 0 ; i < pg->irt_count ; ++i)
4424+ {
4425+ index_root_page::irt_repeat* rpt = &pg->irt_rpt [i];
4426+ if (!rpt->getRoot ())
4427+ continue ;
4428+
4429+ FB_UINT64 descEnd = rpt->irt_desc ;
4430+ descEnd += FB_UINT64 (rpt->irt_keys ) * sizeof (irtd);
4431+ if (descEnd > tdbb->getDatabase ()->dbb_page_size )
4432+ {
4433+ page_validation_error (tdbb, window, type,
4434+ Arg::Gds (isc_random) << " Bad index root page: keys run out of page" );
4435+ }
4436+ }
4437+
4438+ break ;
4439+ }
4440+
4441+ case pag_blob:
4442+ {
4443+ blob_page* pg = (blob_page*) window->win_buffer ;
4444+
4445+ // check used space size correctness
4446+ FB_UINT64 usedSpace = sizeof (blob_page) - sizeof (blob_page::blp_page);
4447+ usedSpace += FB_UINT64 (pg->blp_length );
4448+ if (usedSpace > tdbb->getDatabase ()->dbb_page_size )
4449+ {
4450+ page_validation_error (tdbb, window, type,
4451+ Arg::Gds (isc_random) << " Bad blob page: data does not fit on page" );
4452+ }
4453+
4454+ break ;
4455+ }
4456+
4457+ case pag_data:
4458+ {
4459+ data_page* pg = (data_page*) window->win_buffer ;
4460+
4461+ // check RPT size correctness
4462+ FB_UINT64 rptSize = sizeof (data_page) - sizeof (data_page::dpg_repeat);
4463+ rptSize += FB_UINT64 (pg->dpg_count ) * sizeof (data_page::dpg_repeat);
4464+ if (rptSize > tdbb->getDatabase ()->dbb_page_size )
4465+ {
4466+ page_validation_error (tdbb, window, type,
4467+ Arg::Gds (isc_random) << " Bad data page: too many record fragments" );
4468+ }
4469+
4470+ // check fragments location on page
4471+ for (USHORT i = 0 ; i < pg->dpg_count ; ++i)
4472+ {
4473+ data_page::dpg_repeat* rpt = &pg->dpg_rpt [i];
4474+ if (!(rpt->dpg_offset && rpt->dpg_length ))
4475+ continue ;
4476+
4477+ FB_UINT64 fragEnd = rpt->dpg_offset ;
4478+ fragEnd += rpt->dpg_length ;
4479+ if (fragEnd > tdbb->getDatabase ()->dbb_page_size )
4480+ {
4481+ page_validation_error (tdbb, window, type,
4482+ Arg::Gds (isc_random) << " Bad data page: record fragment runs out of page" );
4483+ }
4484+ }
4485+
4486+ break ;
4487+ }
4488+
4489+ case pag_pointer:
4490+ {
4491+ pointer_page* pg = (pointer_page*) window->win_buffer ;
4492+
4493+ // check used space size correctness
4494+ FB_UINT64 usedSpace = sizeof (pointer_page) - sizeof (pointer_page::ppg_page);
4495+ usedSpace += FB_UINT64 (pg->ppg_count ) * sizeof (pointer_page::ppg_page);
4496+ if (usedSpace > tdbb->getDatabase ()->dbb_page_size )
4497+ {
4498+ page_validation_error (tdbb, window, type,
4499+ Arg::Gds (isc_random) << " Bad pointer page: data page vector does not fit on page" );
4500+ }
4501+
4502+ break ;
4503+ }
4504+
4505+ }
4506+ }
4507+
4508+
43954509#ifdef CACHE_READER
43964510static void prefetch_epilogue (Prefetch* prefetch, FbStatusVector* status_vector)
43974511{
0 commit comments