@@ -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*);
@@ -748,10 +750,7 @@ pag* CCH_fetch(thread_db* tdbb, WIN* window, int lock_type, SCHAR page_type, int
748750
749751 adjust_scan_count (window, lockState == lsLocked);
750752
751- // Validate the fetched page matches the expected type
752-
753- if (bdb->bdb_buffer ->pag_type != page_type && page_type != pag_undefined)
754- page_validation_error (tdbb, window, page_type);
753+ page_validate (tdbb, window, lockState, page_type);
755754
756755 return window->win_buffer ;
757756}
@@ -1413,10 +1412,7 @@ pag* CCH_handoff(thread_db* tdbb, WIN* window, ULONG page, int lock, SCHAR page_
14131412
14141413 adjust_scan_count (window, must_read == lsLocked);
14151414
1416- // Validate the fetched page matches the expected type
1417-
1418- if (bdb->bdb_buffer ->pag_type != page_type && page_type != pag_undefined)
1419- page_validation_error (tdbb, window, page_type);
1415+ page_validate (tdbb, window, must_read, page_type);
14201416
14211417 return window->win_buffer ;
14221418}
@@ -4364,7 +4360,7 @@ static ULONG memory_init(thread_db* tdbb, BufferControl* bcb, SLONG number)
43644360}
43654361
43664362
4367- static void page_validation_error (thread_db* tdbb, WIN* window, SSHORT type)
4363+ static void page_validation_error (thread_db* tdbb, WIN* window, SSHORT type, Arg::StatusVector& err )
43684364{
43694365/* *************************************
43704366 *
@@ -4383,22 +4379,140 @@ static void page_validation_error(thread_db* tdbb, WIN* window, SSHORT type)
43834379 **************************************/
43844380 SET_TDBB (tdbb);
43854381 BufferDesc* bdb = window->win_bdb ;
4386- const pag* page = bdb->bdb_buffer ;
4387-
43884382 PageSpace* pages =
43894383 tdbb->getDatabase ()->dbb_page_manager .findPageSpace (bdb->bdb_page .getPageSpaceID ());
43904384
43914385 ERR_build_status (tdbb->tdbb_status_vector ,
4392- Arg::Gds (isc_db_corrupt) << Arg::Str (pages->file ->fil_string ) <<
4393- Arg::Gds (isc_page_type_err) <<
4394- Arg::Gds (isc_badpagtyp) << Arg::Num (bdb->bdb_page .getPageNum ()) <<
4395- pagtype (type) <<
4396- pagtype (page->pag_type ));
4386+ Arg::Gds (isc_db_corrupt) << Arg::Str (pages->file ->fil_string ) << err);
4387+
43974388 // We should invalidate this bad buffer.
43984389 CCH_unwind (tdbb, true );
43994390}
44004391
44014392
4393+ inline void page_validate (thread_db* tdbb, WIN* window, const LockState ls, SSHORT type)
4394+ {
4395+ // Validate only when required page type is known and page was read from disk
4396+ if (type != pag_undefined && ls == lsLocked)
4397+ validate_read_page (tdbb, window, type);
4398+ }
4399+
4400+
4401+ static void validate_read_page (thread_db* tdbb, WIN* window, SSHORT type)
4402+ {
4403+ // Validate the fetched page matches the expected type
4404+ if (window->win_buffer ->pag_type != type)
4405+ {
4406+ BufferDesc* bdb = window->win_bdb ;
4407+ const pag* page = bdb->bdb_buffer ;
4408+
4409+ page_validation_error (tdbb, window, type,
4410+ Arg::Gds (isc_page_type_err) <<
4411+ Arg::Gds (isc_badpagtyp) << Arg::Num (bdb->bdb_page .getPageNum ()) << pagtype (type) << pagtype (page->pag_type ));
4412+ }
4413+
4414+ switch (type)
4415+ {
4416+ case pag_root:
4417+ {
4418+ index_root_page* pg = (index_root_page*) window->win_buffer ;
4419+
4420+ // check RPT size correctness
4421+ FB_UINT64 rptSize = sizeof (index_root_page) - sizeof (index_root_page::irt_repeat);
4422+ rptSize += FB_UINT64 (pg->irt_count ) * sizeof (index_root_page::irt_repeat);
4423+ if (rptSize > tdbb->getDatabase ()->dbb_page_size )
4424+ {
4425+ page_validation_error (tdbb, window, type,
4426+ Arg::Gds (isc_random) << " Bad index root page: too many indices" );
4427+ }
4428+
4429+ // check keys location on page
4430+ for (USHORT i = 0 ; i < pg->irt_count ; ++i)
4431+ {
4432+ index_root_page::irt_repeat* rpt = &pg->irt_rpt [i];
4433+ if (!rpt->getRoot ())
4434+ continue ;
4435+
4436+ FB_UINT64 descEnd = rpt->irt_desc ;
4437+ descEnd += FB_UINT64 (rpt->irt_keys ) * sizeof (irtd);
4438+ if (descEnd > tdbb->getDatabase ()->dbb_page_size )
4439+ {
4440+ page_validation_error (tdbb, window, type,
4441+ Arg::Gds (isc_random) << " Bad index root page: keys run out of page" );
4442+ }
4443+ }
4444+
4445+ break ;
4446+ }
4447+
4448+ case pag_blob:
4449+ {
4450+ blob_page* pg = (blob_page*) window->win_buffer ;
4451+
4452+ // check used space size correctness
4453+ FB_UINT64 usedSpace = sizeof (blob_page) - sizeof (blob_page::blp_page);
4454+ usedSpace += FB_UINT64 (pg->blp_length );
4455+ if (usedSpace > tdbb->getDatabase ()->dbb_page_size )
4456+ {
4457+ page_validation_error (tdbb, window, type,
4458+ Arg::Gds (isc_random) << " Bad blob page: data does not fit on page" );
4459+ }
4460+
4461+ break ;
4462+ }
4463+
4464+ case pag_data:
4465+ {
4466+ data_page* pg = (data_page*) window->win_buffer ;
4467+
4468+ // check RPT size correctness
4469+ FB_UINT64 rptSize = sizeof (data_page) - sizeof (data_page::dpg_repeat);
4470+ rptSize += FB_UINT64 (pg->dpg_count ) * sizeof (data_page::dpg_repeat);
4471+ if (rptSize > tdbb->getDatabase ()->dbb_page_size )
4472+ {
4473+ page_validation_error (tdbb, window, type,
4474+ Arg::Gds (isc_random) << " Bad data page: too many record fragments" );
4475+ }
4476+
4477+ // check fragments location on page
4478+ for (USHORT i = 0 ; i < pg->dpg_count ; ++i)
4479+ {
4480+ data_page::dpg_repeat* rpt = &pg->dpg_rpt [i];
4481+ if (!(rpt->dpg_offset && rpt->dpg_length ))
4482+ continue ;
4483+
4484+ FB_UINT64 fragEnd = rpt->dpg_offset ;
4485+ fragEnd += rpt->dpg_length ;
4486+ if (fragEnd > tdbb->getDatabase ()->dbb_page_size )
4487+ {
4488+ page_validation_error (tdbb, window, type,
4489+ Arg::Gds (isc_random) << " Bad data page: record fragment runs out of page" );
4490+ }
4491+ }
4492+
4493+ break ;
4494+ }
4495+
4496+ case pag_pointer:
4497+ {
4498+ pointer_page* pg = (pointer_page*) window->win_buffer ;
4499+
4500+ // check used space size correctness
4501+ FB_UINT64 usedSpace = sizeof (pointer_page) - sizeof (pointer_page::ppg_page);
4502+ usedSpace += FB_UINT64 (pg->ppg_count ) * sizeof (pointer_page::ppg_page);
4503+ if (usedSpace > tdbb->getDatabase ()->dbb_page_size )
4504+ {
4505+ page_validation_error (tdbb, window, type,
4506+ Arg::Gds (isc_random) << " Bad pointer page: data page vector does not fit on page" );
4507+ }
4508+
4509+ break ;
4510+ }
4511+
4512+ }
4513+ }
4514+
4515+
44024516#ifdef CACHE_READER
44034517static void prefetch_epilogue (Prefetch* prefetch, FbStatusVector* status_vector)
44044518{
0 commit comments