fix Go 1.7 pointer reference bug

This commit fixes a bug where page end-of-header pointers were being
converted to byte slices even when the pointer did not point to
allocated memory. This occurs with pages that have a `page.count`
of zero.

Note: This was not an issue in Go 1.6 but the new Go 1.7 SSA backend
handles `nil` checks differently.

See https://github.com/golang/go/issues/16772
master
Ben Johnson 2016-08-18 08:44:57 -06:00
parent 94c8db5968
commit 92410e0673
No known key found for this signature in database
GPG Key ID: 81741CD251883081
3 changed files with 23 additions and 6 deletions

View File

@ -166,12 +166,16 @@ func (f *freelist) read(p *page) {
} }
// Copy the list of page ids from the freelist. // Copy the list of page ids from the freelist.
ids := ((*[maxAllocSize]pgid)(unsafe.Pointer(&p.ptr)))[idx:count] if count == 0 {
f.ids = make([]pgid, len(ids)) f.ids = nil
copy(f.ids, ids) } else {
ids := ((*[maxAllocSize]pgid)(unsafe.Pointer(&p.ptr)))[idx:count]
f.ids = make([]pgid, len(ids))
copy(f.ids, ids)
// Make sure they're sorted. // Make sure they're sorted.
sort.Sort(pgids(f.ids)) sort.Sort(pgids(f.ids))
}
// Rebuild the page cache. // Rebuild the page cache.
f.reindex() f.reindex()
@ -189,7 +193,9 @@ func (f *freelist) write(p *page) error {
// The page.count can only hold up to 64k elements so if we overflow that // The page.count can only hold up to 64k elements so if we overflow that
// number then we handle it by putting the size in the first element. // number then we handle it by putting the size in the first element.
if len(ids) < 0xFFFF { if len(ids) == 0 {
p.count = uint16(len(ids))
} else if len(ids) < 0xFFFF {
p.count = uint16(len(ids)) p.count = uint16(len(ids))
copy(((*[maxAllocSize]pgid)(unsafe.Pointer(&p.ptr)))[:], ids) copy(((*[maxAllocSize]pgid)(unsafe.Pointer(&p.ptr)))[:], ids)
} else { } else {

View File

@ -201,6 +201,11 @@ func (n *node) write(p *page) {
} }
p.count = uint16(len(n.inodes)) p.count = uint16(len(n.inodes))
// Stop here if there are no items to write.
if p.count == 0 {
return
}
// Loop over each item and write it to the page. // Loop over each item and write it to the page.
b := (*[maxAllocSize]byte)(unsafe.Pointer(&p.ptr))[n.pageElementSize()*len(n.inodes):] b := (*[maxAllocSize]byte)(unsafe.Pointer(&p.ptr))[n.pageElementSize()*len(n.inodes):]
for i, item := range n.inodes { for i, item := range n.inodes {

View File

@ -62,6 +62,9 @@ func (p *page) leafPageElement(index uint16) *leafPageElement {
// leafPageElements retrieves a list of leaf nodes. // leafPageElements retrieves a list of leaf nodes.
func (p *page) leafPageElements() []leafPageElement { func (p *page) leafPageElements() []leafPageElement {
if p.count == 0 {
return nil
}
return ((*[0x7FFFFFF]leafPageElement)(unsafe.Pointer(&p.ptr)))[:] return ((*[0x7FFFFFF]leafPageElement)(unsafe.Pointer(&p.ptr)))[:]
} }
@ -72,6 +75,9 @@ func (p *page) branchPageElement(index uint16) *branchPageElement {
// branchPageElements retrieves a list of branch nodes. // branchPageElements retrieves a list of branch nodes.
func (p *page) branchPageElements() []branchPageElement { func (p *page) branchPageElements() []branchPageElement {
if p.count == 0 {
return nil
}
return ((*[0x7FFFFFF]branchPageElement)(unsafe.Pointer(&p.ptr)))[:] return ((*[0x7FFFFFF]branchPageElement)(unsafe.Pointer(&p.ptr)))[:]
} }