-
Notifications
You must be signed in to change notification settings - Fork 646
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix unsafe pointer conversions caught by Go 1.14 checkptr #201
Conversation
const unalignedMask = unsafe.Alignof(struct { | ||
bucket | ||
page | ||
}{}) - 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have any 32-bit hardware available (i386, armv7, etc) so if someone could test whether this still passes with -gcflags=all=-d=checkptr
on these architectures I'd love to know. My concern is that the allocation for the copied byte slice below will be pointer aligned (4 bytes), and not aligned for the 64-bit fields of these structs (8 bytes).
On Sat, 08 Feb 2020 at 00:17:10 -0800, Josh Rickmar wrote:
jrick commented on this pull request.
> @@ -123,8 +123,11 @@ func (b *Bucket) Bucket(name []byte) *Bucket {
func (b *Bucket) openBucket(value []byte) *Bucket {
var child = newBucket(b.tx)
- // Unaligned pointer access requires a copy to be made.
- const unalignedMask = unsafe.Alignof(uintptr(0)) - 1
+ // Unaligned access requires a copy to be made.
+ const unalignedMask = unsafe.Alignof(struct {
+ bucket
+ page
+ }{}) - 1
I don't have any 32-bit hardware available (i386, armv7, etc) so if someone could test whether this still passes with `-gcflags=all=-d=checkptr` on these architectures I'd love to know. My concern is that the allocation for the copied byte slice below will be pointer aligned (4 bytes), and not aligned for the 64-bit fields of these structs (8 bytes).
Tested on OpenBSD i386:
go test -gcflags=all=-d=checkptr
seed: 24103
quick settings: count=5, items=1000, ksize=1024, vsize=1024
00010000000000000000000000000000
unexpected fault address 0x6f010040
fatal error: fault
[signal SIGSEGV: segmentation violation code=0x1 addr=0x6f010040 pc=0x8169ebd]
goroutine 42 [running]:
runtime.throw(0x8202ba8, 0x5)
/home/qbit/go/src/runtime/panic.go:1112 +0x64 fp=0x4f086e44
sp=0x4f086e30 pc=0x8077674
runtime.sigpanic()
/home/qbit/go/src/runtime/signal_unix.go:694 +0x2fe fp=0x4f086e5c
sp=0x4f086e44 pc=0x808bb0e
go.etcd.io/bbolt.(*DB).meta(0x4f07c000, 0x3)
/home/qbit/bbolt/db.go:901 +0x1d fp=0x4f086e74 sp=0x4f086e5c
pc=0x8169ebd
go.etcd.io/bbolt.(*DB).hasSyncedFreelist(...)
/home/qbit/bbolt/db.go:323
go.etcd.io/bbolt.(*Tx).rollback(0x4f068480)
/home/qbit/bbolt/tx.go:280 +0x63 fp=0x4f086e90 sp=0x4f086e74
pc=0x8173343
go.etcd.io/bbolt.(*Tx).Commit(0x4f068480, 0x0, 0x0)
/home/qbit/bbolt/tx.go:162 +0x481 fp=0x4f086f30 sp=0x4f086e90
pc=0x8172e01
go.etcd.io/bbolt.(*DB).Update(0x4f07c000, 0x4f086f84, 0x0, 0x0)
/home/qbit/bbolt/db.go:701 +0xd1 fp=0x4f086f60 sp=0x4f086f30
pc=0x8169511
go.etcd.io/bbolt_test.TestDB_Put_VeryLarge(0x4f05c000)
/home/qbit/bbolt/bucket_test.go:221 +0xfb fp=0x4f086fa8 sp=0x4f086f60
pc=0x818001b
testing.tRunner(0x4f05c000, 0x820fa78)
/home/qbit/go/src/testing/testing.go:993 +0xae fp=0x4f086fe8
sp=0x4f086fa8 pc=0x812640e
runtime.goexit()
/home/qbit/go/src/runtime/asm_386.s:1337 +0x1 fp=0x4f086fec
sp=0x4f086fe8 pc=0x80a2d51
created by testing.(*T).Run
/home/qbit/go/src/testing/testing.go:1044 +0x2a7
goroutine 1 [chan receive]:
testing.(*T).Run(0x4f05c000, 0x82063f5, 0x14, 0x820fa78, 0x301)
/home/qbit/go/src/testing/testing.go:1045 +0x2c6
testing.runTests.func1(0x4f05c140)
/home/qbit/go/src/testing/testing.go:1286 +0x54
testing.tRunner(0x4f05c140, 0x4f02068c)
/home/qbit/go/src/testing/testing.go:993 +0xae
testing.runTests(0x4f00c060, 0x83683e0, 0xab, 0xab, 0x1)
/home/qbit/go/src/testing/testing.go:1284 +0x227
testing.(*M).Run(0x4f038100, 0x0)
/home/qbit/go/src/testing/testing.go:1201 +0x10e
go.etcd.io/bbolt_test.TestMain(0x4f038100)
/home/qbit/bbolt/quick_test.go:37 +0x3bc
main.main()
_testmain.go:418 +0xfa
exit status 2
FAIL go.etcd.io/bbolt 6.815s
…
--
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
#201 (review)
--
PGP: 0x1F81112D62A9ADCE / 3586 3350 BFEA C101 DB1A 4AF0 1F81 112D 62A9 ADCE
|
That looks like #183. |
Is there a timeline for when this will be merged? |
Ping @xiang90, @gyuho @vorburger ? This is a pretty important change, not having it checked in prevents all users of boltdb from upgrading to Go 1.14. Do you need more committers on the boltdb team? |
Sorry I'm not currently active in this project. |
@jrick Can we squash commits? |
@gyuho done. |
@@ -1,3 +1,5 @@ | |||
module go.etcd.io/bbolt | |||
|
|||
go 1.12 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we bump up to 1.14
as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't be necessary. The Go version in the go.mod is the minimum supported Go version, and this still works fine with Go 1.12. Changing it is also unrelated to this fix, but you could change it in a different commit later...
@jrick Thanks for the fix. |
// 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)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Build is now failing on arm:
bolt_arm.go:3:8: imported and not used: "unsafe"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry :( didn't try a cross compile, which would have caught that
ids := ((*[maxAllocSize]pgid)(unsafe.Pointer(&p.ptr)))[idx : idx+count] | ||
ids := *(*[]pgid)(unsafe.Pointer(&reflect.SliceHeader{ | ||
Data: uintptr(unsafe.Pointer(p)) + unsafe.Sizeof(*p) + idx*unsafe.Sizeof(pgid(0)), | ||
Len: int(count), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
here must be idx
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the code this replaced had len count as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i see code before was: [idx:idx+count]
Means len=idx and cap=idx+count ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no
This includes fix to boltdb unsafe pointer conversions discovered by extra checks added in Go 1.14 enabled in -race mode. Also changes CI to use Go 1.14. See etcd-io/bbolt#201 for background.
#11594 ## Description of change - Fix deferreturn panic on go1.14 on arm64 and ppc64 by disabling optimizations - Fix unaligned ptrs by moving to go.etcd.io/bbolt ## QA steps - Run unit tests - Build for ppc64 and arm64 (juju bins will be quite large) - Deploy a HA controller (+ anything else you can think to test raft) ## Documentation changes N/A ## Bug reference https://golang.org/issue/39049 etcd-io/bbolt#201
This unbreaks bbolt (as part of containerd) on 1.14+ (see etcd-io/bbolt#201 and etcd-io/bbolt#220), pulls in my patch to ignore image-defined volumes (containerd/cri#1504) and gets us some robustness fixes in containerd CNI/CRI integration (containerd/cri#1405). This also updates K8s at the same time since they share a lot of dependencies and only updating one is very annoying. On the K8s side we mostly get the standard stream of fixes plus some patches that are no longer necessary. One annoying on the K8s side (but with no impact to the functionality) are these messages in the logs of various components: ``` W0714 11:51:26.323590 1 warnings.go:67] policy/v1beta1 PodSecurityPolicy is deprecated in v1.22+, unavailable in v1.25+ ``` They are caused by KEP-1635, but there's not explanation why this gets logged so aggressively considering the operators cannot do anything about it. There's no newer version of PodSecurityPolicy and you are pretty much required to use it if you use RBAC. Test Plan: Covered by existing tests Bug: T753 X-Origin-Diff: phab/D597 GitOrigin-RevId: f6c447da1de037c27646f9ec9f45ebd5d6660ab0
To fix some issues caught by chkptr. See: etcd-io/bbolt#201
To fix some issues caught by chkptr. See: etcd-io/bbolt#201
Go 1.14 introduces a checkptr debug flag for the compiler, which is enabled by default with -race and can be enabled separately with
-gcflags=all=-d=checkptr
. checkptr enables two checks during type conversions of unsafe.Pointer:All unsafe pointer conversions to type *T2 must have proper alignment for type T2
All unsafe pointer conversions from *T1 to unsafe.Pointer to *T2 must not cause the new allocation to span more than two separate Go heap allocations.
bbolt was performing unsafe pointer conversions that were failing each of these checks.
This change modifies bbolt to avoid type conversions that are both caught by the new checks and were previously invalid according to the Go memory model. Rather than subslicing arrays of "max allocations" number of elements, slices are created with the precise sizes required. This change also removes all unaligned access even on architectures where the hardware permits it.
The performance hit, if any, for removing unaligned access appears negligible according to the project's benchmarks:
Fixes #187.