Skip to content
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

Merged
merged 1 commit into from
Mar 19, 2020

Conversation

jrick
Copy link
Contributor

@jrick jrick commented Feb 7, 2020

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:

  1. All unsafe pointer conversions to type *T2 must have proper alignment for type T2

  2. 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:

% go test -run none -bench 'Benchmark*'
seed: 84000
quick settings: count=5, items=1000, ksize=1024, vsize=1024
goos: darwin
goarch: amd64
pkg: go.etcd.io/bbolt
Benchmark_FreelistRelease10K-24       	    3757	    302905 ns/op
Benchmark_FreelistRelease100K-24      	     294	   4076518 ns/op
Benchmark_FreelistRelease1000K-24     	      16	  66904544 ns/op
Benchmark_FreelistRelease10000K-24    	       1	1183743396 ns/op
BenchmarkDBBatchAutomatic-24          	      63	  16815505 ns/op
BenchmarkDBBatchSingle-24             	       1	14088192506 ns/op
BenchmarkDBBatchManual10x100-24       	       8	 141973506 ns/op
PASS
ok  	go.etcd.io/bbolt	25.682s
% git checkout master                  
Switched to branch 'master'
Your branch is up to date with 'origin/master'.
% go test -run none -bench 'Benchmark*' -args -quick.seed=84000
seed: 84000
quick settings: count=5, items=1000, ksize=1024, vsize=1024
goos: darwin
goarch: amd64
pkg: go.etcd.io/bbolt
Benchmark_FreelistRelease10K-24       	    3794	    303829 ns/op
Benchmark_FreelistRelease100K-24      	     294	   4084449 ns/op
Benchmark_FreelistRelease1000K-24     	      15	  66988066 ns/op
Benchmark_FreelistRelease10000K-24    	       1	1156598746 ns/op
BenchmarkDBBatchAutomatic-24          	      62	  17064184 ns/op
BenchmarkDBBatchSingle-24             	       1	13940793747 ns/op
BenchmarkDBBatchManual10x100-24       	       8	 141596004 ns/op
PASS
ok  	go.etcd.io/bbolt	24.129s

Fixes #187.

const unalignedMask = unsafe.Alignof(struct {
bucket
page
}{}) - 1
Copy link
Contributor Author

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).

@qbit
Copy link

qbit commented Feb 8, 2020 via email

@jrick
Copy link
Contributor Author

jrick commented Feb 8, 2020

That looks like #183.

@arjunsingri
Copy link

arjunsingri commented Mar 2, 2020

Is there a timeline for when this will be merged?

@jeffallen
Copy link
Contributor

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?

@vorburger
Copy link
Member

Sorry I'm not currently active in this project.

@gyuho
Copy link
Contributor

gyuho commented Mar 19, 2020

@jrick Can we squash commits?

@jrick
Copy link
Contributor Author

jrick commented Mar 19, 2020

@gyuho done.

@@ -1,3 +1,5 @@
module go.etcd.io/bbolt

go 1.12
Copy link
Contributor

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?

Copy link
Contributor Author

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...

@gyuho gyuho merged commit 2fc6815 into etcd-io:master Mar 19, 2020
@gyuho
Copy link
Contributor

gyuho commented Mar 19, 2020

@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))
Copy link
Contributor

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"

Copy link
Contributor Author

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),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here must be idx?

Copy link
Contributor Author

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.

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 ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no

artyom added a commit to Doist/bitmapist-server that referenced this pull request Mar 25, 2020
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.
jujubot added a commit to juju/juju that referenced this pull request May 18, 2020
#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
leoluk pushed a commit to monogon-dev/monogon that referenced this pull request Mar 30, 2021
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
rhafer added a commit to rhafer/idm that referenced this pull request Dec 7, 2021
To fix some issues caught by chkptr. See: etcd-io/bbolt#201
rhafer added a commit to libregraph/idm that referenced this pull request Dec 7, 2021
To fix some issues caught by chkptr. See: etcd-io/bbolt#201
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

panic: runtime error: unsafe pointer conversion (Go 1.14)
8 participants