-
Notifications
You must be signed in to change notification settings - Fork 17.8k
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
cmd/compile: -d=checkptr should not reject unaligned pointers to non-pointer data #37298
Comments
@bcmills thanks for the title update. Besides answering the "should it be allowed" question, it would be nice if the error message could say what the problem is (e.g., it would be good to include the word "unaligned"). |
@mdempsky, @randall77, @aclements, @ianlancetaylor, @griesemer: I think this issue needs a decision before Go 1.14.1. The spec and As a result, users may perceive If unaligned integer reads on these architectures should not be treated as an error, then I think it is important for Go 1.14.1 to no longer flag them in On the other hand, if unaligned reads really should be disallowed, then we need to know that sooner rather than later so that we can fix violations (such as #37644) appropriately. |
Change https://golang.org/cl/222855 mentions this issue: |
It is unclear whether unaligned reads should be allowed, or if they are even actually a good idea here. However, while we figure that out, we should un-break 'go test -race' for users of this package. Updates golang/go#37644 Updates golang/go#37298 Updates golang/go#37715 Updates golang/go#34972 Updates golang/go#35128 Change-Id: I088f5703023e4f05ee274a6753e925973f12ac1b Reviewed-on: https://go-review.googlesource.com/c/crypto/+/222855 Run-TryBot: Bryan C. Mills <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Matthew Dempsky <[email protected]>
I think that the |
@twmb, my concern is that if we allow |
I don't see why this should be architecture specific. The point of So I think the question is: should I don't have a good sense of the philosophy of |
Marking as release-blocker per #37298 (comment). (FYI @toothrot @cagedmantis) We might need to just get some compiler & runtime folks on a videoconference to figure this out... |
@ianlancetaylor, the question is, are unaligned integer reads “bad code” when you know (by build constraint) that the architecture supports them, or are they always bad regardless for some reason (such as a current or potential-future detail of the garbage collector)? If they're always bad, then |
I think in a sense this comes down to a question of whether My rationale behind The rationale of code like sha3's xor_unaligned though seems to be that One option would be: on x86, the compilers could define |
It sounds like three of our options are:
(3) seems to be our de facto state in Go 1.14, but I don't think it's workable. [Edit: deleted some incorrect stuff here.] In my case, the flagged conversion occurs in reflect code called via fmt (demo code) or go-cmp (real code). There's no place I can stick a |
No, checkptr only checks unsafe.Pointer conversions. It doesn't instrument every possible read/write using a pointer. |
I don't think we should change the I would still like to more clearly understand the philosophy of |
Thanks -- I updated my comment. I think the general idea still stands, though. The code that triggers the check may not be under the control of the person who created the unaligned pointer. |
I'd argue the code that created the unaligned pointer is here:
This is nominally just a The issue here is that the compiler doesn't emit checks for this code pattern, because (in general) it doesn't know the type of slice pointed to by It's certainly unfortunate though that this false negative manifests as triggering a failure in very distant code though. |
I think deciding this is the essence of the issue here. My rationale in implementing checkptr is based on wanting code to strictly conform to the specifications guaranteed to users (e.g., the Go language spec and unsafe.Pointer safety rules). We don't make any guarantees that pointers to unaligned integers are safe on any platforms, so I think it's appropriate to warn (by default) when that happens, even on platforms where it happens to be safe to do so. In that sense, I disagree with @bcmills's characterization of these as false positives. Analogously, the race detector warns about all memory accesses that aren't synchronized according to the Go memory model. It doesn't rule out non-synchronized accesses that are impossible on certain CPUs/OSes. For example, this program is race free, but the race detector still reports about it:
But that said, I don't think other positions are inconsistent, and I'm not opposed to if we overall prefer a more lenient philosophy. |
I think that interpretation is significantly stronger than what the documentation for
And the spec itself says:
Note that both of those are expressed in terms of compiler-allocated variables, not backing stores of pointers. The documentation for |
I agree: this state seems untenable to me, because in the limit it requires that nearly every function that uses Consider the function: func Identity(b *uint64) *uint64 {
p := unsafe.Pointer(b)
return (*uint64)(p)
} If a |
Maybe? But these days we have a formal memory model for data races. In contrast, reads through unaligned pointers are not clearly defined one way or the other, and my impression is that the Go project prefers to bias toward providing “intuitive” semantics for not-explicitly-defined programs rather than defining them to be erroneous (as in, say, C). Empirically, even parts of the Go project intuitively expect unaligned integers to work, for better or for worse. I wouldn't object to a spec change to clearly define unaligned integer pointers as an error, but I would expect such a clarification to have its own release note and perhaps proposal, and to arrive in a major release (like 1.15) rather than a minor one (like 1.14.1 or 1.14.2). |
Ack, it could certainly be clearer. I'm arguing my position here, but I'm not dogmatic about it. I'm open to whatever the group consensus is. (And so I'm definitely hoping more folks will weigh in with their thoughts/interpretations.)
Note that the Go spec uses "variable" to refer to any memory location used for storing a value. It's not used exclusively in reference to declared variables such as introduced by the "var" keyword. E.g., Moreover, by definition, a pointer of type *T is either nil or points to a variable of type T. There's nothing else it can point to.
Note that the Go spec defines alignment as a property of variables, whereas |
I think we should declare unaligned pointers to be ok on at least x86. Maybe everywhere. There are going to be too many people using unaligned pointers. I think we could break those people's programs if we needed to, but I just don't see a commensurate benefit in doing so. The main benefit of the check is to catch people making alignment assumptions on x86, where their program would then fail on another architecture. That just doesn't seem that much of a pain point to me. Even if it fails on another architecture, at least it does so loudly, without silently corrupting data (I hope: it would do so on early Alpha chips, but I don't know any other arch that just ignores low bits of addresses when accessing memory). I guess another benefit is just to catch people doing bad pointer arithmetic. That is a nice feature (and could potentially detect otherwise silent memory corruption bugs), but I don't think that's the intended purpose of this check. |
We discussed this at the runtime meeting today and decided that we'd disable the alignment check if the base type of the pointer is pointer-free. So we'd still catch unaligned pointer accesses, but would allow other unaligned accesses to happen (on all architectures, even if that means they might fault). |
Change https://golang.org/cl/223781 mentions this issue: |
Was the decision to guarantee support for non-aligned integer accesses on x86, or simply not to proactively warn against it? E.g., if we implement points-to optimizations in the compiler in the future, do we have to worry about partially overlapping variables? |
@gopherbot please open a backport issue to 1.14.1 |
Backport issue(s) opened: #37905 (for 1.14). Remember to create the cherry-pick CL(s) as soon as the patch is submitted to master, according to https://golang.org/wiki/MinorReleases. |
We only discussed not warning about unaligned pointers to integer values. We didn't discuss whether they should be supported in any real sense. There is a more general discussion to have about the interaction of unsafe pointers and points-to analysis, such as whether we should consider the possibility that a |
I wanted to add that the key observation for me, at least, was that unaligned access will either work or crash on all architectures we support (at least, we're pretty sure; Cherry is confirming). That puts it in a different category from other things checkptr checks for. |
ARMv5 does a rotated load depending on the lower two bits of the address. See https://heyrick.eu/armwiki/Unaligned_data_access. |
FWIW, I would be fine with keeping the integer-alignment check on architectures where unaligned loads are not known to be safe, such as (And I'd be fine with requiring proper alignment everywhere, including |
Thanks for pointing that out, @zeebo. After a bit of discussion about whether we should keep the check just for ARM, we decided that we don't really want to do an ARCH-specific checkptr check, especially since it only affects a small minority of deployments even on that architecture. |
Change https://golang.org/cl/249378 mentions this issue: |
As of Go 1.14.1, -d=checkptr no longer errors on unaligned reads of non-pointer data. This reverts the code change (but not the test) from CL 222855. Fixes golang/go#37644 Updates golang/go#37298 Change-Id: I935c773a3541ed8dca7eb005d39a082eb5f10eb8 Reviewed-on: https://go-review.googlesource.com/c/crypto/+/249378 Run-TryBot: Bryan C. Mills <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Matthew Dempsky <[email protected]>
I'm testing some code with Go 1.14 and found that some tests are failing which passed in Go 1.13 while running under
-race
.This is due to the new checkptr checks that are enabled by
-race
. Here's a minimized repro:This error isn't particularly helpful (why is it unsafe?) and when I looked at the source, it still wasn't clear to me what the problem is.
Even if there's some problem with unaligned pointers into the Go heap, in my application the backing data doesn't come from
make([]byte)
but rather fromunix.Mmap
. And my CPU (amd64) should have no problem with reading unaligned data, right?It's also strange that the crash didn't happen in my code, but inside the reflect-y fmt code that looked at my data. (Not that it matters, but in my real code the crash isn't triggered by fmt but rather by go-cmp, also via use of
reflect.Value.Int
.)/cc @mdempsky
The text was updated successfully, but these errors were encountered: