Merge pull request from ptabor/20221218-defensive-pageread

Validate page being fetched at possition 'p' self identifies as page 'p'
pull/365/head
Piotr Tabor 2022-12-23 11:07:33 +01:00 committed by GitHub
commit d4831e6217
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 20 additions and 3 deletions

View File

@ -188,12 +188,16 @@ func (n *node) read(p *page) {
} }
// write writes the items onto one or more pages. // write writes the items onto one or more pages.
// The page should have p.id (might be 0 for meta or bucket-inline page) and p.overflow set
// and the rest should be zeroed.
func (n *node) write(p *page) { func (n *node) write(p *page) {
_assert(p.count == 0 && p.flags == 0, "node cannot be written into a not empty page")
// Initialize page. // Initialize page.
if n.isLeaf { if n.isLeaf {
p.flags |= leafPageFlag p.flags = leafPageFlag
} else { } else {
p.flags |= branchPageFlag p.flags = branchPageFlag
} }
if len(n.inodes) >= 0xFFFF { if len(n.inodes) >= 0xFFFF {

10
page.go
View File

@ -53,6 +53,16 @@ func (p *page) meta() *meta {
return (*meta)(unsafeAdd(unsafe.Pointer(p), unsafe.Sizeof(*p))) return (*meta)(unsafeAdd(unsafe.Pointer(p), unsafe.Sizeof(*p)))
} }
func (p *page) fastCheck(id pgid) {
_assert(p.id == id, "Page expected to be: %v, but self identifies as %v", id, p.id)
// Only one flag of page-type can be set.
_assert(p.flags == branchPageFlag ||
p.flags == leafPageFlag ||
p.flags == metaPageFlag ||
p.flags == freelistPageFlag,
"page %v: has unexpected type/flags: %x", p.id, p.flags)
}
// leafPageElement retrieves the leaf node by index // leafPageElement retrieves the leaf node by index
func (p *page) leafPageElement(index uint16) *leafPageElement { func (p *page) leafPageElement(index uint16) *leafPageElement {
return (*leafPageElement)(unsafeIndex(unsafe.Pointer(p), unsafe.Sizeof(*p), return (*leafPageElement)(unsafeIndex(unsafe.Pointer(p), unsafe.Sizeof(*p),

5
tx.go
View File

@ -609,12 +609,15 @@ func (tx *Tx) page(id pgid) *page {
// Check the dirty pages first. // Check the dirty pages first.
if tx.pages != nil { if tx.pages != nil {
if p, ok := tx.pages[id]; ok { if p, ok := tx.pages[id]; ok {
p.fastCheck(id)
return p return p
} }
} }
// Otherwise return directly from the mmap. // Otherwise return directly from the mmap.
return tx.db.page(id) p := tx.db.page(id)
p.fastCheck(id)
return p
} }
// forEachPage iterates over every page within a given page and executes a function. // forEachPage iterates over every page within a given page and executes a function.