From 9819f6af2492691ad428e660ac2d06d78f9b37bf Mon Sep 17 00:00:00 2001 From: Alex Sharov Date: Sat, 22 Oct 2022 10:55:19 +0700 Subject: [PATCH] eliasfano: To fix checkptr fatal error (#697) ``` go test -race -run=TestEliasFano ./recsplit/eliasfano32 fatal error: checkptr: converted pointer straddles multiple allocations goroutine 35 [running]: runtime.throw({0x13bb5bf?, 0x13446ca?}) runtime/panic.go:1047 +0x5d fp=0xc000137790 sp=0xc000137760 pc=0x108a13d runtime.checkptrAlignment(0xa9?, 0x0?, 0x0?) runtime/checkptr.go:26 +0x6c fp=0xc0001377b0 sp=0xc000137790 pc=0x1059f8c github.com/ledgerwatch/erigon-lib/recsplit/eliasfano32.Min({0xc00012c280, 0x40, 0x40}) github.com/ledgerwatch/erigon-lib/recsplit/eliasfano32/elias_fano.go:324 +0x36f fp=0xc000137868 sp=0xc0001377b0 pc=0x133e66f github.com/ledgerwatch/erigon-lib/recsplit/eliasfano32.TestEliasFano(0x0?) github.com/ledgerwatch/erigon-lib/recsplit/eliasfano32/elias_fano_test.go:58 ``` --- commitment/hex_patricia_hashed.go | 2 +- recsplit/eliasfano32/elias_fano.go | 26 +++++++++++-------------- recsplit/eliasfano32/elias_fano_test.go | 10 ++++++++-- state/aggregator.go | 2 +- 4 files changed, 21 insertions(+), 19 deletions(-) diff --git a/commitment/hex_patricia_hashed.go b/commitment/hex_patricia_hashed.go index 1c9bc01ea..8a498b594 100644 --- a/commitment/hex_patricia_hashed.go +++ b/commitment/hex_patricia_hashed.go @@ -1409,7 +1409,7 @@ func (s *state) Encode(buf []byte) ([]byte, error) { if err := binary.Write(ee, binary.BigEndian, uint16(len(s.Root))); err != nil { return nil, fmt.Errorf("encode root len: %w", err) } - if n, err := ee.Write(s.Root[:]); err != nil || n != len(s.Root) { + if n, err := ee.Write(s.Root); err != nil || n != len(s.Root) { return nil, fmt.Errorf("encode root: %w", err) } d := make([]byte, len(s.Depths)) diff --git a/recsplit/eliasfano32/elias_fano.go b/recsplit/eliasfano32/elias_fano.go index 8639b2081..67e9d73ec 100644 --- a/recsplit/eliasfano32/elias_fano.go +++ b/recsplit/eliasfano32/elias_fano.go @@ -280,9 +280,8 @@ func (ef *EliasFano) Write(w io.Writer) error { if _, e := w.Write(numBuf[:]); e != nil { return e } - p := (*[maxDataSize]byte)(unsafe.Pointer(&ef.data[0])) - b := (*p)[:] - if _, e := w.Write(b[:len(ef.data)*8]); e != nil { + b := unsafe.Slice((*byte)(unsafe.Pointer(&ef.data[0])), len(ef.data)*uint64Size) + if _, e := w.Write(b); e != nil { return e } return nil @@ -295,17 +294,14 @@ func (ef *EliasFano) AppendBytes(buf []byte) []byte { buf = append(buf, numBuf[:]...) binary.BigEndian.PutUint64(numBuf[:], ef.u) buf = append(buf, numBuf[:]...) - p := (*[maxDataSize]byte)(unsafe.Pointer(&ef.data[0])) - b := (*p)[:] - buf = append(buf, b[:len(ef.data)*8]...) + b := unsafe.Slice((*byte)(unsafe.Pointer(&ef.data[0])), len(ef.data)*uint64Size) + buf = append(buf, b...) return buf } -const maxDataSize = 0xFFFFFFFFFFFF //2^48 - // Read inputs the state of golomb rice encoding from a reader s func ReadEliasFano(r []byte) (*EliasFano, int) { - p := (*[maxDataSize / 8]uint64)(unsafe.Pointer(&r[16])) + p := unsafe.Slice((*uint64)(unsafe.Pointer(&r[16])), (len(r)-16)/uint64Size) ef := &EliasFano{ count: binary.BigEndian.Uint64(r[:8]), u: binary.BigEndian.Uint64(r[8:16]), @@ -318,10 +314,12 @@ func ReadEliasFano(r []byte) (*EliasFano, int) { func Max(r []byte) uint64 { return binary.BigEndian.Uint64(r[8:16]) - 1 } +const uint64Size = 8 + func Min(r []byte) uint64 { count := binary.BigEndian.Uint64(r[:8]) u := binary.BigEndian.Uint64(r[8:16]) - p := (*[maxDataSize / 8]uint64)(unsafe.Pointer(&r[16])) + p := unsafe.Slice((*uint64)(unsafe.Pointer(&r[16])), (len(r)-16)/uint64Size) var l uint64 if u/(count+1) == 0 { l = 0 @@ -650,9 +648,8 @@ func (ef *DoubleEliasFano) Write(w io.Writer) error { if _, e := w.Write(numBuf[:]); e != nil { return e } - p := (*[maxDataSize]byte)(unsafe.Pointer(&ef.data[0])) - b := (*p)[:] - if _, e := w.Write(b[:len(ef.data)*8]); e != nil { + b := unsafe.Slice((*byte)(unsafe.Pointer(&ef.data[0])), len(ef.data)*uint64Size) + if _, e := w.Write(b); e != nil { return e } return nil @@ -665,8 +662,7 @@ func (ef *DoubleEliasFano) Read(r []byte) int { ef.uPosition = binary.BigEndian.Uint64(r[16:24]) ef.cumKeysMinDelta = binary.BigEndian.Uint64(r[24:32]) ef.posMinDelta = binary.BigEndian.Uint64(r[32:40]) - p := (*[maxDataSize / 8]uint64)(unsafe.Pointer(&r[40])) - ef.data = p[:] + ef.data = unsafe.Slice((*uint64)(unsafe.Pointer(&r[40])), (len(r)-40)/uint64Size) ef.deriveFields() return 40 + 8*len(ef.data) } diff --git a/recsplit/eliasfano32/elias_fano_test.go b/recsplit/eliasfano32/elias_fano_test.go index 408f56938..1d29715c6 100644 --- a/recsplit/eliasfano32/elias_fano_test.go +++ b/recsplit/eliasfano32/elias_fano_test.go @@ -52,10 +52,16 @@ func TestEliasFano(t *testing.T) { v, ok = ef.Search(11) assert.True(t, ok, "search4") assert.Equal(t, uint64(14), v, "search4") + buf := bytes.NewBuffer(nil) ef.Write(buf) - assert.Equal(t, ef.Max(), Max(buf.Bytes())) - assert.Equal(t, ef.Min(), Min(buf.Bytes())) + assert.Equal(t, ef.AppendBytes(nil), buf.Bytes()) + + ef2, _ := ReadEliasFano(buf.Bytes()) + assert.Equal(t, ef.Min(), ef2.Min()) + assert.Equal(t, ef.Max(), ef2.Max()) + assert.Equal(t, ef2.Max(), Max(buf.Bytes())) + assert.Equal(t, ef2.Min(), Min(buf.Bytes())) } func TestIterator(t *testing.T) { diff --git a/state/aggregator.go b/state/aggregator.go index 63d22fb47..753ba2e2f 100644 --- a/state/aggregator.go +++ b/state/aggregator.go @@ -1375,7 +1375,7 @@ func DecodeAccountBytes(enc []byte) (nonce uint64, balance *uint256.Int, hash [] pos++ if codeHashBytes > 0 { codeHash := make([]byte, length.Hash) - copy(codeHash[:], enc[pos:pos+codeHashBytes]) + copy(codeHash, enc[pos:pos+codeHashBytes]) } } return