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

spec: Empty struct address comparison returns false even if addresses are equal #23440

Closed
quasilyte opened this issue Jan 13, 2018 · 5 comments
Closed

Comments

@quasilyte
Copy link
Contributor

quasilyte commented Jan 13, 2018

What version of Go are you using (go version)?

Reproducible in Go 1.8.1, Go devel, and on playground.

Does this issue reproduce with the latest release?

Yes.

What operating system and processor architecture are you using (go env)?

(some paths are manually edited to avoid personal data leakage.)

GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GORACE=""
GOTMPDIR=""
GOTOOLDIR="?/go/go/pkg/tool/linux_amd64"
GCCGO="?/gccgo"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build150273130=/tmp/go-build -gno-record-gcc-switches"

What did you do?

Run this code: https://play.golang.org/p/9C0puRUstrP.

What did you expect to see?

Both functions print same address and
address comparison yields true.

What did you see instead?

Both functions print same address, but
only f2 prints true for address comparison.

Works as expected in GCCGO:

go run -compiler gccgo empty.go
0x7ff2fc9834c0
0x7ff2fc9834c0
true
0x7ff2fc9834c0
0x7ff2fc9834c0
true

Attaching 6g output here for comparison:

go run empty.go
0xc420045f50
0xc420045f50
false
0x54ca38
0x54ca38
true

The actual addresses does not matter. Only true/false results do.

The spec only mentions that their addresses may be identical,
which seems to be the case, but for some reason comparison disagrees.

Two distinct zero-size variables may have the same address in memory.

The false case can be reduced:

func f1() bool {
	var a, b struct{}
	return &a == &b
}

The assembly output on x86 for it is:

"".f1 STEXT nosplit size=6 args=0x8 locals=0x0
	0x0000 00000 (empty.go:7)	TEXT	"".f1(SB), NOSPLIT, $0-8
	0x0000 00000 (empty.go:7)	FUNCDATA	$0, gclocals·2a5305abe05176240e61b8620e19a815(SB)
	0x0000 00000 (empty.go:7)	FUNCDATA	$1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
	0x0000 00000 (empty.go:9)	MOVB	$0, "".~r0+8(SP)
	0x0005 00005 (empty.go:9)	RET

...which basically means return false.
If I understand this right, unless we seen that addresses are equal by printing it or assigning it numerical representation, comparison can always return false.

Using numerical value returns true:

return uintptr(unsafe.Pointer(&a)) == uintptr(unsafe.Pointer(&b))
@quasilyte
Copy link
Contributor Author

Who is more spec-compliant in this case: gccgo or 6g?
Or is this some kind of UB/implementation defined behavior?

@quasilyte quasilyte changed the title Empty struct address mismatch Empty struct address mismatch, even though seem to be numerically equal Jan 13, 2018
@quasilyte quasilyte changed the title Empty struct address mismatch, even though seem to be numerically equal Empty struct address comparison returns false even if addresses are equal Jan 13, 2018
@randall77
Copy link
Contributor

randall77 commented Jan 13, 2018

This is implementation defined behavior. From the spec:

Pointers to distinct zero-size variables may or may not be equal.

Closing as it is working as intended.

@quasilyte
Copy link
Contributor Author

quasilyte commented Jan 13, 2018

It says they may not be equal, but their values in this particular case seems to be equal.
Maybe spec could be more precise on that.

But anyway, thank you for clarification.

@quasilyte
Copy link
Contributor Author

quasilyte commented Jan 13, 2018

@randall77, is there any reason the address comparison does not always return either true or false for empty structs?
Run-time values are not respected during comparison anyway.

@ianlancetaylor
Copy link
Contributor

The spec says "may or may not be equal." Either option is permitted. This is an intentional language choice to give implementations flexibility in how they handle pointers to zero-sized objects. If every pointer to a zero-sized object were required to be different, then each allocation of a zero-sized object would have to allocate at least one byte. If every pointer to a zero-sized object were required to be the same, it would be different to handle taking the address of a zero-sized field within a larger struct.

Further discussion of this should take place on a forum, not the issue tracker. See https://golang.org/wiki/Questions . Thanks.

@mikioh mikioh changed the title Empty struct address comparison returns false even if addresses are equal spec: Empty struct address comparison returns false even if addresses are equal Jan 13, 2018
@golang golang locked and limited conversation to collaborators Jan 13, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants