From 9034717d690b8fe1bb56de1802f621b83fadf676 Mon Sep 17 00:00:00 2001 From: Josh Rickmar Date: Thu, 21 May 2020 18:50:41 +0000 Subject: [PATCH] Try to use reflect.SliceHeader correctly this time --- freelist.go | 21 +++++++++++++++------ page.go | 14 ++++++++------ unsafe.go | 16 +++++++++++++++- 3 files changed, 38 insertions(+), 13 deletions(-) diff --git a/freelist.go b/freelist.go index 0e7369c85..697a46968 100644 --- a/freelist.go +++ b/freelist.go @@ -267,18 +267,23 @@ func (f *freelist) read(p *page) { } // If the page.count is at the max uint16 value (64k) then it's considered // an overflow and the size of the freelist is stored as the first element. - var idx, count uintptr = 0, uintptr(p.count) + var idx, count = 0, int(p.count) if count == 0xFFFF { idx = 1 - count = uintptr(*(*pgid)(unsafeAdd(unsafe.Pointer(p), unsafe.Sizeof(*p)))) + c := *(*pgid)(unsafeAdd(unsafe.Pointer(p), unsafe.Sizeof(*p))) + count = int(c) + if count < 0 { + panic(fmt.Sprintf("leading element count %d overflows int", c)) + } } // Copy the list of page ids from the freelist. if count == 0 { f.ids = nil } else { - ids := (*[maxAllocSize]pgid)(unsafeAdd( - unsafe.Pointer(p), unsafe.Sizeof(*p)))[idx : idx+count : idx+count] + var ids []pgid + data := unsafeIndex(unsafe.Pointer(p), unsafe.Sizeof(*p), unsafe.Sizeof(ids[0]), idx) + unsafeSlice(unsafe.Pointer(&ids), data, count) // copy the ids, so we don't modify on the freelist page directly idsCopy := make([]pgid, count) @@ -316,11 +321,15 @@ func (f *freelist) write(p *page) error { p.count = uint16(l) } else if l < 0xFFFF { p.count = uint16(l) - ids := (*[maxAllocSize]pgid)(unsafeAdd(unsafe.Pointer(p), unsafe.Sizeof(*p)))[:l:l] + var ids []pgid + data := unsafeAdd(unsafe.Pointer(p), unsafe.Sizeof(*p)) + unsafeSlice(unsafe.Pointer(&ids), data, l) f.copyall(ids) } else { p.count = 0xFFFF - ids := (*[maxAllocSize]pgid)(unsafeAdd(unsafe.Pointer(p), unsafe.Sizeof(*p)))[: l+1 : l+1] + var ids []pgid + data := unsafeAdd(unsafe.Pointer(p), unsafe.Sizeof(*p)) + unsafeSlice(unsafe.Pointer(&ids), data, l+1) ids[0] = pgid(l) f.copyall(ids[1:]) } diff --git a/page.go b/page.go index 334f0ab8c..c9a158fb0 100644 --- a/page.go +++ b/page.go @@ -64,9 +64,10 @@ func (p *page) leafPageElements() []leafPageElement { if p.count == 0 { return nil } - const maxArraySize = maxAllocSize / unsafe.Sizeof(leafPageElement{}) - return (*[maxArraySize]leafPageElement)(unsafeIndex(unsafe.Pointer(p), unsafe.Sizeof(*p), - unsafe.Sizeof(leafPageElement{}), 0))[:p.count:p.count] + var elems []leafPageElement + data := unsafeAdd(unsafe.Pointer(p), unsafe.Sizeof(*p)) + unsafeSlice(unsafe.Pointer(&elems), data, int(p.count)) + return elems } // branchPageElement retrieves the branch node by index @@ -80,9 +81,10 @@ func (p *page) branchPageElements() []branchPageElement { if p.count == 0 { return nil } - const maxArraySize = maxAllocSize / unsafe.Sizeof(branchPageElement{}) - return (*[maxArraySize]branchPageElement)(unsafeIndex(unsafe.Pointer(p), unsafe.Sizeof(*p), - unsafe.Sizeof(branchPageElement{}), 0))[:p.count:p.count] + var elems []branchPageElement + data := unsafeAdd(unsafe.Pointer(p), unsafe.Sizeof(*p)) + unsafeSlice(unsafe.Pointer(&elems), data, int(p.count)) + return elems } // dump writes n bytes of the page to STDERR as hex output. diff --git a/unsafe.go b/unsafe.go index a5e2a1a04..c0e503750 100644 --- a/unsafe.go +++ b/unsafe.go @@ -1,6 +1,9 @@ package bbolt -import "unsafe" +import ( + "reflect" + "unsafe" +) func unsafeAdd(base unsafe.Pointer, offset uintptr) unsafe.Pointer { return unsafe.Pointer(uintptr(base) + offset) @@ -23,3 +26,14 @@ func unsafeByteSlice(base unsafe.Pointer, offset uintptr, i, j int) []byte { // all), so this is believed to be correct. return (*[maxAllocSize]byte)(unsafeAdd(base, offset))[i:j:j] } + +// unsafeSlice modifies the data, len, and cap of a slice variable pointed to by +// the slice parameter. This helper should be used over other direct +// manipulation of reflect.SliceHeader to prevent misuse, namely, converting +// from reflect.SliceHeader to a Go slice type. +func unsafeSlice(slice, data unsafe.Pointer, len int) { + s := (*reflect.SliceHeader)(slice) + s.Data = uintptr(data) + s.Cap = len + s.Len = len +}