Skip to content
This repository was archived by the owner on Mar 9, 2019. It is now read-only.

Commit 97aba55

Browse files
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
1 parent 5cc10bb commit 97aba55

7 files changed

+45
-1
lines changed

bolt_386.go

+3
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,6 @@ const maxMapSize = 0x7FFFFFFF // 2GB
55

66
// maxAllocSize is the size used when creating array pointers.
77
const maxAllocSize = 0xFFFFFFF
8+
9+
// Are unaligned load/stores broken on this arch?
10+
var brokenUnaligned = false

bolt_amd64.go

+3
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,6 @@ const maxMapSize = 0xFFFFFFFFFFFF // 256TB
55

66
// maxAllocSize is the size used when creating array pointers.
77
const maxAllocSize = 0x7FFFFFFF
8+
9+
// Are unaligned load/stores broken on this arch?
10+
var brokenUnaligned = false

bolt_arm.go

+21
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,28 @@
11
package bolt
22

3+
import "unsafe"
4+
35
// maxMapSize represents the largest mmap size supported by Bolt.
46
const maxMapSize = 0x7FFFFFFF // 2GB
57

68
// maxAllocSize is the size used when creating array pointers.
79
const maxAllocSize = 0xFFFFFFF
10+
11+
// Are unaligned load/stores broken on this arch?
12+
var brokenUnaligned bool
13+
14+
func init() {
15+
// Simple check to see whether this arch handles unaligned load/stores
16+
// correctly.
17+
18+
// ARM9 and older devices require load/stores to be from/to aligned
19+
// addresses. If not, the lower 2 bits are cleared and that address is
20+
// read in a jumbled up order.
21+
22+
// See http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka15414.html
23+
24+
raw := [6]byte{0xfe, 0xef, 0x11, 0x22, 0x22, 0x11}
25+
val := *(*uint32)(unsafe.Pointer(uintptr(unsafe.Pointer(&raw)) + 2))
26+
27+
brokenUnaligned = val != 0x11222211
28+
}

bolt_arm64.go

+3
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,6 @@ const maxMapSize = 0xFFFFFFFFFFFF // 256TB
77

88
// maxAllocSize is the size used when creating array pointers.
99
const maxAllocSize = 0x7FFFFFFF
10+
11+
// Are unaligned load/stores broken on this arch?
12+
var brokenUnaligned = false

bolt_ppc64le.go

+3
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,6 @@ const maxMapSize = 0xFFFFFFFFFFFF // 256TB
77

88
// maxAllocSize is the size used when creating array pointers.
99
const maxAllocSize = 0x7FFFFFFF
10+
11+
// Are unaligned load/stores broken on this arch?
12+
var brokenUnaligned = false

bolt_s390x.go

+3
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,6 @@ const maxMapSize = 0xFFFFFFFFFFFF // 256TB
77

88
// maxAllocSize is the size used when creating array pointers.
99
const maxAllocSize = 0x7FFFFFFF
10+
11+
// Are unaligned load/stores broken on this arch?
12+
var brokenUnaligned = false

bucket.go

+9-1
Original file line numberDiff line numberDiff line change
@@ -130,9 +130,17 @@ func (b *Bucket) Bucket(name []byte) *Bucket {
130130
func (b *Bucket) openBucket(value []byte) *Bucket {
131131
var child = newBucket(b.tx)
132132

133+
// If unaligned load/stores are broken on this arch and value is
134+
// unaligned simply clone to an aligned byte array.
135+
unaligned := brokenUnaligned && uintptr(unsafe.Pointer(&value[0]))&3 != 0
136+
137+
if unaligned {
138+
value = cloneBytes(value)
139+
}
140+
133141
// If this is a writable transaction then we need to copy the bucket entry.
134142
// Read-only transactions can point directly at the mmap entry.
135-
if b.tx.writable {
143+
if b.tx.writable && !unaligned {
136144
child.bucket = &bucket{}
137145
*child.bucket = *(*bucket)(unsafe.Pointer(&value[0]))
138146
} else {

0 commit comments

Comments
 (0)