aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bolt_386.go3
-rw-r--r--bolt_amd64.go3
-rw-r--r--bolt_arm.go21
-rw-r--r--bolt_arm64.go3
-rw-r--r--bolt_ppc64le.go3
-rw-r--r--bolt_s390x.go3
-rw-r--r--bucket.go10
7 files changed, 45 insertions, 1 deletions
diff --git a/bolt_386.go b/bolt_386.go
index e659bfb..820d533 100644
--- a/bolt_386.go
+++ b/bolt_386.go
@@ -5,3 +5,6 @@ const maxMapSize = 0x7FFFFFFF // 2GB
// maxAllocSize is the size used when creating array pointers.
const maxAllocSize = 0xFFFFFFF
+
+// Are unaligned load/stores broken on this arch?
+var brokenUnaligned = false
diff --git a/bolt_amd64.go b/bolt_amd64.go
index cca6b7e..98fafdb 100644
--- a/bolt_amd64.go
+++ b/bolt_amd64.go
@@ -5,3 +5,6 @@ const maxMapSize = 0xFFFFFFFFFFFF // 256TB
// maxAllocSize is the size used when creating array pointers.
const maxAllocSize = 0x7FFFFFFF
+
+// Are unaligned load/stores broken on this arch?
+var brokenUnaligned = false
diff --git a/bolt_arm.go b/bolt_arm.go
index e659bfb..7e5cb4b 100644
--- a/bolt_arm.go
+++ b/bolt_arm.go
@@ -1,7 +1,28 @@
package bolt
+import "unsafe"
+
// maxMapSize represents the largest mmap size supported by Bolt.
const maxMapSize = 0x7FFFFFFF // 2GB
// maxAllocSize is the size used when creating array pointers.
const maxAllocSize = 0xFFFFFFF
+
+// Are unaligned load/stores broken on this arch?
+var brokenUnaligned bool
+
+func init() {
+ // Simple check to see whether this arch handles unaligned load/stores
+ // correctly.
+
+ // ARM9 and older devices require load/stores to be from/to aligned
+ // addresses. If not, the lower 2 bits are cleared and that address is
+ // read in a jumbled up order.
+
+ // See http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka15414.html
+
+ raw := [6]byte{0xfe, 0xef, 0x11, 0x22, 0x22, 0x11}
+ val := *(*uint32)(unsafe.Pointer(uintptr(unsafe.Pointer(&raw)) + 2))
+
+ brokenUnaligned = val != 0x11222211
+}
diff --git a/bolt_arm64.go b/bolt_arm64.go
index 6d23093..b26d84f 100644
--- a/bolt_arm64.go
+++ b/bolt_arm64.go
@@ -7,3 +7,6 @@ const maxMapSize = 0xFFFFFFFFFFFF // 256TB
// maxAllocSize is the size used when creating array pointers.
const maxAllocSize = 0x7FFFFFFF
+
+// Are unaligned load/stores broken on this arch?
+var brokenUnaligned = false
diff --git a/bolt_ppc64le.go b/bolt_ppc64le.go
index 8351e12..8c143bc 100644
--- a/bolt_ppc64le.go
+++ b/bolt_ppc64le.go
@@ -7,3 +7,6 @@ const maxMapSize = 0xFFFFFFFFFFFF // 256TB
// maxAllocSize is the size used when creating array pointers.
const maxAllocSize = 0x7FFFFFFF
+
+// Are unaligned load/stores broken on this arch?
+var brokenUnaligned = false
diff --git a/bolt_s390x.go b/bolt_s390x.go
index f4dd26b..d7c39af 100644
--- a/bolt_s390x.go
+++ b/bolt_s390x.go
@@ -7,3 +7,6 @@ const maxMapSize = 0xFFFFFFFFFFFF // 256TB
// maxAllocSize is the size used when creating array pointers.
const maxAllocSize = 0x7FFFFFFF
+
+// Are unaligned load/stores broken on this arch?
+var brokenUnaligned = false
diff --git a/bucket.go b/bucket.go
index d2f8c52..6cae1bb 100644
--- a/bucket.go
+++ b/bucket.go
@@ -130,9 +130,17 @@ func (b *Bucket) Bucket(name []byte) *Bucket {
func (b *Bucket) openBucket(value []byte) *Bucket {
var child = newBucket(b.tx)
+ // If unaligned load/stores are broken on this arch and value is
+ // unaligned simply clone to an aligned byte array.
+ unaligned := brokenUnaligned && uintptr(unsafe.Pointer(&value[0]))&3 != 0
+
+ if unaligned {
+ value = cloneBytes(value)
+ }
+
// If this is a writable transaction then we need to copy the bucket entry.
// Read-only transactions can point directly at the mmap entry.
- if b.tx.writable {
+ if b.tx.writable && !unaligned {
child.bucket = &bucket{}
*child.bucket = *(*bucket)(unsafe.Pointer(&value[0]))
} else {