-
Notifications
You must be signed in to change notification settings - Fork 18k
cmd/compile: nilcheck is tightened in a branch allowing the other one to execute when it should have panicked #72860
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
Comments
Interesting. I see a segfault with gccgo and with Go versions up through 1.20. From 1.21 onward there is no segfault. CC @golang/compiler |
@khr Appears to be caused by https://go.dev/cl/537775 for #63657. |
If no one has done so by tomorrow I'll fix this by making |
I think a better fix is just to prevent the nil check from moving blocks during the tighten pass. CL incoming. |
@gopherbot please open backport issues. |
Backport issue(s) opened: #72862 (for 1.23), #72863 (for 1.24). Remember to create the cherry-pick CL(s) as soon as the patch is submitted to master, according to https://go.dev/wiki/MinorReleases. |
Change https://go.dev/cl/657715 mentions this issue: |
We've decided not to backport this change.
Where This code is incorrect, in that it dereferences the Because there is probably code out there dependent on this bug, we're going to just fix this issue going forward (starting in 1.25). We don't want a point release to break anyone's (even incorrect) code without a very compelling reason. |
1.25 changelog:
😄 |
Change https://go.dev/cl/658955 mentions this issue: |
This could bite people during the 1.25 release, so make sure it has good documentation in the release notes. Update #72860 Change-Id: Ie9aaa219025a631e81ebc48461555c5fb898f43f Reviewed-on: https://go-review.googlesource.com/c/go/+/658955 Reviewed-by: Jorropo <jorropo.pgm@gmail.com> Reviewed-by: Ian Lance Taylor <iant@google.com> Reviewed-by: Keith Randall <khr@google.com> Auto-Submit: Keith Randall <khr@golang.org> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Does it work now, actually? I've tried to build from latest master, ran these snippet: package main
import (
"errors"
"fmt"
)
type A struct{
B int
}
func ptr[V any](source V, condition bool) (*V, error) {
if condition {
return nil, errors.New("test error")
}
return &source, nil
}
func main(){
object, err := ptr(A{B: 42}, true)
fmt.Println(object.B)
if err != nil {
fmt.Println("error case")
}
} And it compiles and falls into nil pointer panic on run, despite 3309658 says it should not. Go version:
|
It's the opposite: it says this program should always panic. Before the change, it (or some variant of it) may unexpectedly succeed instead of panicking. |
Oh, thank you for clarity. Seems like I misinterpret the document and the issue. |
This is radically different than this issue, this issue tl;dr is:
And then fixing the go compiler to implement the go spec properly. What you are talking about is changing the go spec.
Because a program which always panic is still a valid go program, so the compiler must compile it properly.
This is contrary to what the go spec requires, so we can't do that. If you want to change the go spec I would be having a hard time believing this wouldn't have been proposed before but 2 minutes of searching failed to bring it up. https://github.com/uber-go/nilaway also exists and does pretty much exactly what you say altho warning opinion part incoming: *which don't actually fix bugs, just turn panics in errors |
Go version
go version go1.24.1 darwin/arm64
Output of
go env
in your module/workspace:What did you do?
Working with a map to a pointer (
map[string]*thing
) a coworker remarked during a PR review that they were surprised it work, indeed the code would be expected to segfault.I've reduced the code to a small reproduction sample which exhibits the behaviour: https://go.dev/play/p/6Jv5ePF2o4n.
The suspicious code in question (lines 19-22):
Computing the value of
valid
is expected to segfault, ast
is alwaysnil
in the example snippet.What did you see happen?
The code snippet executes successfully, printing out
got: <nil>
instead of segfaulting.I checked it against all versions of Go available in go.dev/play:
1.24
,1.23
, anddev branch
. All of them exhibit this behaviour.My guess is this might be a compiler optimization, because making changes to the code like calling
fmt.Printf
or printing out the value ofvalid
later both cause the code to segfault as expected.That is; I think it transforms:
into
Likely irrelevant, but: anecdotally
1.23
timed out while building this example several times.What did you expect to see?
This program is expected to segfault. Computing the
valid
variable unconditionally would result in a dereferencednil
pointer.This execution appears to violate the Go memory model and the order of evaluation, quoting:
Thanks to @nwchandler for pointing this apparent spec violation out to me.
The text was updated successfully, but these errors were encountered: