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

cmd/compile: incorrect location of panic during 2-phase execution of assignment statement #71054

Closed
yaxum62 opened this issue Dec 29, 2024 · 9 comments
Labels
compiler/runtime Issues related to the Go compiler and/or runtime.

Comments

@yaxum62
Copy link

yaxum62 commented Dec 29, 2024

Go version

go version go1.23.2 linux/amd64

Output of go env in your module/workspace:

GO111MODULE=''
GOARCH='amd64'
GOBIN=''
GOCACHE='/home/yaxum62/.cache/go-build'
GOENV='/home/yaxum62/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMODCACHE='/home/yaxum62/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/home/yaxum62/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/usr/lib/go-1.23'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/usr/lib/go-1.23/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.23.2'
GODEBUG=''
GOTELEMETRY='local'
GOTELEMETRYDIR='/home/yaxum62/.config/go/telemetry'
GCCGO='gccgo'
GOAMD64='v1'
AR='ar'
CC='gcc'
CXX='g++'
CGO_ENABLED='1'
GOMOD='/home/yaxum62/src/test/go.mod'
GOWORK=''
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
PKG_CONFIG='pkg-config'
GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build812913915=/tmp/go-build -gno-record-gcc-switches'

What did you do?

Original post: https://groups.google.com/g/golang-nuts/c/anNFVPtCGyQ/
Example code: https://go.dev/play/p/6RulNQwIk4n

The example code contains an assignment statement:

phase_2, foo.bar.value = "??????", compute_value()

The assignment statement will trigger nil pointer panic and contains visible side effects in both phases as described in golang spec:

The assignment proceeds in two phases. First, the operands of index expressions and pointer indirections (including implicit pointer indirections in selectors) on the left and the expressions on the right are all evaluated in the usual order. Second, the assignments are carried out in left-to-right order.

What did you see happen?

The nil pointer panic happened after compute_value() expression is evaluated in phase 1 but before phase_2 variable is updated in phase 2.

What did you expect to see?

The nil pointer panic happened before compute_value() expression is evaluated in phase 1, as mentioned in original post.

@gopherbot gopherbot added the compiler/runtime Issues related to the Go compiler and/or runtime. label Dec 29, 2024
@randall77
Copy link
Contributor

This looks like it is working correctly to me.

In phase 1, we need to evaluate 3 things:

foo.bar
"??????"
compute_value()

The order of evaluation between those 3 things is not specified. The first one nil-pointer panics, but that may happen before or after the call to compute_value.

Because phase 1 panics, phase 2 does not happen.

@yaxum62
Copy link
Author

yaxum62 commented Dec 29, 2024

The spec mentioned the phase 1 is evaluated in "usual order", which is very strict:

when evaluating the operands of an expression, assignment, or return statement, all function calls, method calls, receive operations, and binary logical operations are evaluated in lexical left-to-right order.

With that, I interpret it as the evaluation order must be:

foo.bar
"??????"
compute_value()

@randall77
Copy link
Contributor

It is, but that statement relates only the ordering between those events listed (function call, method call, receive operator, or binary logic operator). There is only one such event here, a function call.
It goes on to say:

However, the order of those events compared to the evaluation and indexing of x and the evaluation of y and z is not specified, except as required lexically.

More generally, the ordering of those events with respect to all other operations (of import here, a pointer dereference) is not guaranteed.

@yaxum62
Copy link
Author

yaxum62 commented Dec 29, 2024

I see, thanks for the explanation! That makes more sense. I'll close this bug.

@yaxum62 yaxum62 closed this as not planned Won't fix, can't repro, duplicate, stale Dec 29, 2024
@robaho
Copy link

robaho commented Dec 29, 2024

Isn’t this a problem though with it not being specified as the function could make the nil pointer dereference not or happen. (Ie what if foo is passed to the function call)

Why not specify this? This is the same sort of undefined behavior that makes C++ such a pain.

@randall77
Copy link
Contributor

@robaho
I think there is an argument to be made that Go is too lax in how it defines evaluation order. But we have the semantics we have; it would require a proposal to change the meaning of the language. And that proposal would require evidence that this is a real problem people run into. All I've seen in this area are toy programs that have confusing evaluation order that I personally would never give a +2 to in code review.

@robaho
Copy link

robaho commented Dec 29, 2024

@robaho I think there is an argument to be made that Go is too lax in how it defines evaluation order. But we have the semantics we have; it would require a proposal to change the meaning of the language. And that proposal would require evidence that this is a real problem people run into. All I've seen in this area are toy programs that have confusing evaluation order that I personally would never give a +2 to in code review.

Fair enough. Probably just triggered by being bitten by similar stuff in C++.

@zigo101
Copy link

zigo101 commented Dec 30, 2024

see #27804

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler/runtime Issues related to the Go compiler and/or runtime.
Projects
None yet
Development

No branches or pull requests

6 participants