Skip to content

cmd/compile: encoding/binary.PutUint16 sometimes doesn't write #59367

@sveeig

Description

@sveeig

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

$ go version go1.20.2 linux/amd64

Does this issue reproduce with the latest release?

yes, also reproduced with go 1.18 and 1.19

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

go env Output
$ go env
GO111MODULE="on"
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/me/.cache/go-build"
GOENV="/home/me/.config/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/home/me/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/home/me/go"
GOPRIVATE=""
GOPROXY="direct"
GOROOT="/usr/lib/go"
GOSUMDB="off"
GOTMPDIR=""
GOTOOLDIR="/usr/lib/go/pkg/tool/linux_amd64"
GOVCS=""
GOVERSION="go1.20.2"
GCCGO="gccgo"
GOAMD64="v1"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/home/me/my/project/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 -fdebug-prefix-map=/tmp/go-build460000454=/tmp/go-build -gno-record-gcc-switches"

What did you do?

In certain situations binary.BigEndian.PutUint16 does not modify the targeted byte slice correctly.
See https://go.dev/play/p/OjvbLQZvYcn.

Details

	e := &struct{ flag bool }{flag: true}
	bufferOne := make([]byte, 2)
	bufferTwo := make([]byte, 2)
	var x uint16

	// This if statement is somehow important, must access heap, does not work with local bool
	if e.flag {
		x = 1
	}

	binary.BigEndian.PutUint16(bufferOne, x)

	// do operation that touches heap? print statement instead of Sleep also works, make slice and assign to a var also works
	time.Sleep(1 * time.Microsecond)

	binary.BigEndian.PutUint16(bufferTwo, x)

	fmt.Println("buffers should have same value:", x)
	fmt.Printf("bufferOne: %+v\n", bufferOne)
	fmt.Printf("bufferTwo: %+v", bufferTwo)

Note that the code runs correctly when a dlv debugger is attached to the program. The behaviour is the same if PutUint32 is used instead of PutUint16. Or if the shifted bytes are assigned directly like this:

	bufferOne[0] = byte(x >> 8)
	bufferOne[1] = byte(x)

	time.Sleep(1 * time.Microsecond)

	bufferTwo[0] = byte(x >> 8)
	bufferTwo[1] = byte(x)

What did you expect to see?

PutUint16 updates two buffers with the same value under given circumstances.

What did you see instead?

bufferTwo did not get updated or updated with wrong value.

Metadata

Metadata

Assignees

Labels

FrozenDueToAgeNeedsFixThe path to resolution is known, but the work has not been done.compiler/runtimeIssues related to the Go compiler and/or runtime.

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions