cespare/xxhash

Apple M1 sum64 throw panic: runtime error: slice bounds out of range error

Closed this issue · 4 comments

panic: runtime error: slice bounds out of range [::41] with capacity 9

goroutine 1 [running]:
github.com/cespare/xxhash/v2.Sum64({0x14014c9ecc0, 0x29, 0x9})
.../vendor/github.com/cespare/xxhash/v2/xxhash_other.go:22 +0x6c4

Can you please show runnable code that demonstrates the problem? Thanks.

Can you please show runnable code that demonstrates the problem? Thanks.

package main

import (
	"context"
	"fmt"
	"time"
	"unsafe"

	"github.com/buraksezer/olric"
	"github.com/buraksezer/olric/config"
	"github.com/cespare/xxhash/v2"
)

type xxhasher struct {
}

func (xh xxhasher) Sum64(key []byte) uint64 {
	fmt.Println(fmt.Sprintf("key %s, length: %d", string(key), len(key)))
	return xxhash.Sum64(key) // replace to xxhash.Sum64([]byte(string(key))) can fixed this problem
}

var _dm olric.DMap

func main() {
	// in this case key length >= 32 always test pass
	tmp := "test-cluster-dmap" + "lock.xxx-xxxxx-xxxx-xxx"
	fmt.Println(fmt.Sprintf("key length: %d", len(tmp)))
	fmt.Println(xxhash.Sum64(*(*[]byte)(unsafe.Pointer(&tmp))))

	// but this case some time test failure
	initOlric()
	testDLock("xxx-xxxxx")          // key length < 32, test pass
	testDLock("xxx-xxxxx-xxxx-xxx") // key length >= 32, test failure
}

func initOlric() {
	ctx, cancel := context.WithCancel(context.Background())
	var db *olric.Olric
	c := config.New("local")
	c.Hasher = xxhasher{}
	c.Started = func() {
		defer cancel()
		fmt.Println("olric cluster is ready to accept connections")
	}

	db, err := olric.New(c)
	if err != nil {
		fmt.Println(fmt.Sprintf("Failed to create olric cluster instance: %v", err))
	}
	go func() {
		err = db.Start()
		if err != nil {
			fmt.Println(fmt.Sprintf("olric cluster Start returned an error: %v", err))
		}
	}()

	<-ctx.Done()

	if db != nil {
		embeddedClient := db.NewEmbeddedClient()
		if dm, err := embeddedClient.NewDMap(fmt.Sprintf("%s-cluster-dmap", "test")); err == nil {
			_dm = dm
		}
	}
}

func testDLock(key string) {
	if _dm != nil {
		ctx := context.Background()
		if lock, err := _dm.Lock(ctx, fmt.Sprintf("lock.%s", key), time.Second*5); err == nil {
			_ = lock.Unlock(ctx) // <--- failure
		}
	}
}
2024/03/19 10:26:10 [INFO] Routing table has been pushed by 127.0.0.1:3320 => operations.go:86
2024/03/19 10:26:10 [INFO] The cluster coordinator has been bootstrapped => discovery.go:42
2024/03/19 10:26:10 [INFO] Memberlist bindAddr: 127.0.0.1, bindPort: 3322 => routingtable.go:413
2024/03/19 10:26:10 [INFO] Cluster coordinator: 127.0.0.1:3320 => routingtable.go:414
2024/03/19 10:26:10 [INFO] Node name in the cluster: 127.0.0.1:3320 => olric.go:380
2024/03/19 10:26:10 [INFO] Olric bindAddr: 127.0.0.1, bindPort: 3320 => olric.go:386
2024/03/19 10:26:10 [INFO] Replication count is 1 => olric.go:388
olric cluster is ready to accept connections
key test-cluster-dmaplock.xxx-xxxxx, length: 31
key test-cluster-dmaplock.xxx-xxxxx, length: 31
key test-cluster-dmaplock.xxx-xxxxx, length: 31
key test-cluster-dmaplock.xxx-xxxxx, length: 31
key test-cluster-dmaplock.xxx-xxxxx, length: 31
key test-cluster-dmaplock.xxx-xxxxx-xxxx-xxx, length: 40
panic: runtime error: slice bounds out of range [::40] with capacity 0

goroutine 1 [running]:
github.com/cespare/xxhash/v2.Sum64({0x140000ce2d0, 0x28, 0x0})
        .../vendor/github.com/cespare/xxhash/v2/xxhash_other.go:22 +0x6c4
main.xxhasher.Sum64({}, {0x140000ce2d0, 0x28, 0x0})
        .../main.go:19 +0x1b8
github.com/buraksezer/olric/internal/cluster/partitions.HKey({0x140004ea000, 0x11}, {0x140004ea030, 0x17})
        .../vendor/github.com/buraksezer/olric/internal/cluster/partitions/hkey.go:37 +0x8c
github.com/buraksezer/olric/internal/dmap.(*DMap).put(0x140004ec000, 0x140004f0100)
        .../vendor/github.com/buraksezer/olric/internal/dmap/put.go:363 +0x68
github.com/buraksezer/olric/internal/dmap.(*DMap).tryLock(0x140004ec000, 0x140004f0100, 0x12a05f200)
        .../vendor/github.com/buraksezer/olric/internal/dmap/lock.go:94 +0x3c
github.com/buraksezer/olric/internal/dmap.(*DMap).Lock(0x140004ec000, {0x104ff5b10, 0x10544ce20}, {0x140004ea030, 0x17}, 0x0, 0x12a05f200)
        .../vendor/github.com/buraksezer/olric/internal/dmap/lock.go:157 +0x264
github.com/buraksezer/olric.(*EmbeddedDMap).Lock(0x14000126000, {0x104ff5b10, 0x10544ce20}, {0x140004ea030, 0x17}, 0x12a05f200)
        .../vendor/github.com/buraksezer/olric/embedded_client.go:167 +0x78
main.testDLock({0x104e27713, 0x12})
        .../main.go:70 +0x11c
main.main()
        .../main.go:33 +0x210
Exiting.

Debugger finished with the exit code 0

Can you make a simpler reproducer without the other packages? I suspect there is a bug in your code. At a glance, my best guess is that you have a data race on the slice you're passing to Sum64 (you can run with -race to check). But I'd want a simpler repro case before I do more debugging.

Can you make a simpler reproducer without the other packages? I suspect there is a bug in your code. At a glance, my best guess is that you have a data race on the slice you're passing to Sum64 (you can run with -race to check). But I'd want a simpler repro case before I do more debugging.

You are right!Thanks!

// xxhash.go:211 maybe binary.LittleEndian.Uint64(b) have a data race ?
func u64(b []byte) uint64 { return binary.LittleEndian.Uint64(b) }