Bus Error when reading nil values
missinglink opened this issue · comments
Peter Johnson commented
I have encountered a signal SIGBUS: bus error
using txn.RawRead = true
when reading keys where the value was set to nil
.
A fix for the issue is the following:
// val.go
func getBytes(val *C.MDB_val) []byte {
+ if val.mv_size == 0 {
+ return nil
+ }
return (*[valMaxSize]byte)(val.mv_data)[:val.mv_size:val.mv_size]
}
The following minimal diff can be used to trigger the error:
diff --git a/lmdb/env_test.go b/lmdb/env_test.go
index afdde18..ddcfc79 100644
--- a/lmdb/env_test.go
+++ b/lmdb/env_test.go
@@ -560,6 +560,12 @@ func setupFlags(t T, flags uint) *Env {
if err != nil {
t.Fatalf("setmaxdbs: %v", err)
}
+
+ err = env.SetMapSize(3298534883328)
+ if err != nil {
+ t.Fatalf("Failed to set map size: %v", err)
+ }
+
err = env.Open(path, flags, 0664)
if err != nil {
t.Fatalf("open: %s", err)
diff --git a/lmdb/txn_test.go b/lmdb/txn_test.go
index eaadaf7..b796558 100644
--- a/lmdb/txn_test.go
+++ b/lmdb/txn_test.go
@@ -1519,3 +1519,50 @@ func openDBI(env *Env, key string, flags uint) (DBI, error) {
}
return db, nil
}
+
+func TestTxn_NilValue(t *testing.T) {
+ env := setup(t)
+ defer clean(env, t)
+
+ err := env.Update(func(txn *Txn) (err error) {
+ db, err := txn.OpenDBI("example", Create)
+ if err != nil {
+ return err
+ }
+ for i := 0; i < 100000; i++ {
+ // --------------- note: value is set to nil ---------------
+ if err = txn.Put(db, []byte(fmt.Sprintf("key%d", i)), nil, 0); err != nil {
+ return err
+ }
+ }
+ return nil
+ })
+ if err != nil {
+ t.Errorf("update: %v", err)
+ return
+ }
+
+ err = env.View(func(txn *Txn) (err error) {
+ txn.RawRead = true // <---- disabling RawRead doesn't trigger the error
+
+ db, err := txn.OpenDBI("example", 0)
+ cur, err := txn.OpenCursor(db)
+ if err != nil {
+ return err
+ }
+
+ for k, _, err := cur.Get(nil, nil, First); k != nil; k, _, err = cur.Get(
nil, nil, Next) {
+ if err != nil {
+ return err
+ }
+ if !bytes.HasPrefix(k, []byte("key")) {
+ return fmt.Errorf("key: %q", k)
+ }
+ }
+
+ return nil
+ })
+ if err != nil {
+ t.Errorf("view: %v", err)
+ return
+ }
+}
@AskAlexSharov I'm happy to draft a PR, do you have any insights into whether this is the ideal solution?
Alex Sharov commented
It's because - this bindings was copied from LMDB bindings. and LMDB didn't support nil value (and we never used it in mdbx). Feel free to create PR
Peter Johnson commented
This is the lmdb-go
repo, sorry for the confusion as I am also using the mdbx
repo.