From d2d1d1bc611454ca9cdffd1512face26d89f426f Mon Sep 17 00:00:00 2001 From: Jussi Saurio Date: Mon, 15 Sep 2025 21:41:18 +0300 Subject: [PATCH] fix re-entrancy issue in Pager::free_page current logic can lead to a situation where: - we call read_page(trunk_page_id) - we assign trunk_page in the FreePageState state machine - the page read fails and cache marks it as !locked && !loaded - next call to Pager::free_page() asserts that the page is loaded and panics --- core/storage/pager.rs | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/core/storage/pager.rs b/core/storage/pager.rs index 5fff92f93..1ce9e689b 100644 --- a/core/storage/pager.rs +++ b/core/storage/pager.rs @@ -552,13 +552,8 @@ enum AllocatePage1State { #[derive(Debug, Clone)] enum FreePageState { Start, - AddToTrunk { - page: Arc, - trunk_page: Option>, - }, - NewTrunk { - page: Arc, - }, + AddToTrunk { page: Arc }, + NewTrunk { page: Arc }, } impl Pager { @@ -1741,25 +1736,19 @@ impl Pager { let trunk_page_id = header.freelist_trunk_page.get(); if trunk_page_id != 0 { - *state = FreePageState::AddToTrunk { - page, - trunk_page: None, - }; + *state = FreePageState::AddToTrunk { page }; } else { *state = FreePageState::NewTrunk { page }; } } - FreePageState::AddToTrunk { page, trunk_page } => { + FreePageState::AddToTrunk { page } => { let trunk_page_id = header.freelist_trunk_page.get(); - if trunk_page.is_none() { - // Add as leaf to current trunk - let (page, c) = self.read_page(trunk_page_id as usize)?; - trunk_page.replace(page); - if let Some(c) = c { + let (trunk_page, c) = self.read_page(trunk_page_id as usize)?; + if let Some(c) = c { + if !c.is_completed() { io_yield_one!(c); } } - let trunk_page = trunk_page.as_ref().unwrap(); turso_assert!(trunk_page.is_loaded(), "trunk_page should be loaded"); let trunk_page_contents = trunk_page.get_contents(); @@ -1775,7 +1764,7 @@ impl Pager { trunk_page.get().id == trunk_page_id as usize, "trunk page has unexpected id" ); - self.add_dirty(trunk_page); + self.add_dirty(&trunk_page); trunk_page_contents.write_u32_no_offset( TRUNK_PAGE_LEAF_COUNT_OFFSET,