aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLorenzo Stoakes <lstoakes@gmail.com>2016-07-28 14:25:49 +0100
committerLorenzo Stoakes <lstoakes@gmail.com>2016-07-28 14:25:49 +0100
commit97aba5586d36f9670a77dc6e60ec1b9ef31ce9ae (patch)
tree73a11e42e09b69b082f2de84f59f64b927cf619a
parentMerge pull request #573 from evnix/patch-1 (diff)
downloaddedo-97aba5586d36f9670a77dc6e60ec1b9ef31ce9ae.tar.gz
dedo-97aba5586d36f9670a77dc6e60ec1b9ef31ce9ae.tar.xz
bucket: correct broken unaligned load/store in armv5
armv5 devices and older (i.e. <= arm9 generation) require addresses that are stored to and loaded from to to be 4-byte aligned. If this is not the case the lower 2 bits of the address are cleared and the load is performed in an unexpected order, including up to 3 bytes of data located prior to the address. Inlined buckets are stored after their key in a page and since there is no guarantee that the key will be of a length that is a multiple of 4, it is possible for unaligned load/stores to occur when they are cast back to bucket and page pointer types. The fix adds a new field to track whether the current architecture exhibits this issue, sets it on module load for ARM architectures, and then on bucket open, if this field is set and the address is unaligned, a byte-by-byte copy of the inlined bucket is performed. Ref: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka15414.html
-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 {