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

interface{} & unsafe.Pointer: the value of original variable changed after assigning to interface{}.data #42776

Closed
MMMMMMoSky opened this issue Nov 23, 2020 · 5 comments

Comments

@MMMMMMoSky
Copy link

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

$ go version
go version go1.15.4 darwin/amd64

Does this issue reproduce with the latest release?

Yes, the output of the codes below on my machine is the same as golang playground (1.15.5)

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

go env Output
$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOINSECURE=""
GOOS="darwin"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/darwin_amd64"
GCCGO="gccgo"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD=""
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 -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/lp/dkglnlh92pn1x64wv1mr06_40000gp/T/go-build123819166=/tmp/go-build -gno-record-gcc-switches -fno-common"

What did you do?

First I had var i int, and assigned it to an empty interface var e interface{} = i.

Then I tried to modify the value which e.data point to. Unexpectedly, i was changed too. i is a variable, but not pointer, so I think it's value should NOT be changed.

Just run the code below, see the output.

package main

import (
	"fmt"
	"unsafe"
)

func main() {
	issue(101, 233) // both < 256
	issue(253, 886) // oldVal < 256
	issue(987, 254) // newVal < 256
	issue(998, 258) // both >= 256

	// Try this four calls, the output will be more strange.
	// issue(100, 255) // both < 256
	// issue(255, 999) // oldVal < 256
	// issue(999, 255) // newVal < 256
	// issue(999, 256) // both >= 256
}

// type eface struct {
// 	  _type *_type
// 	  data  unsafe.Pointer
// }
// data is *int (unsafe.Pointer(&i))
func issue(oldVal, newVal int) {
	fmt.Printf("\n==== running issue(%d, %d) ====\n", oldVal, newVal)

	var (
		i             = oldVal // int
		e interface{} = i
	)
	pdata := unsafe.Pointer(uintptr(unsafe.Pointer(&e)) + unsafe.Sizeof(&i))
	data := unsafe.Pointer(*(**int)(pdata))

	fmt.Printf("      i,   &i = %d, %p\n", i, &i)
	fmt.Printf("  *data, data = %d, %p\n", *((*int)(data)), data)

	// when 0 <= oldVal < 256, i will be changed, WHY???
	*((*int)(data)) = newVal
	fmt.Printf("\n  exec *((*int)(data)) = %d\n\n", newVal)

	fmt.Printf("      i,   &i = %d, %p\n", i, &i)
	fmt.Printf("  *data, data = %d, %p\n", *((*int)(data)), data)
}

Maybe it's a feature/bug about small integer cache...?

@randall77
Copy link
Contributor

You are not allowed to write to the location pointed to by the data field of an interface. Interfaces are assumed to be immutable.
(Just like you can't write to the backing store of a string, or the type pointer of an interface, or lots of other things.)

@MMMMMMoSky
Copy link
Author

Interfaces are assumed to be immutable.
Got it, thanks~

@ShiinaOrez
Copy link

You are not allowed to write to the location pointed to by the data field of an interface. Interfaces are assumed to be immutable.
(Just like you can't write to the backing store of a string, or the type pointer of an interface, or lots of other things.)

Here is the reason of WHY NUMBER LESS THAN 256 CAUSE CHANGE? https://golang.org/doc/go1.15#runtime

@MMMMMMoSky
Copy link
Author

MMMMMMoSky commented Nov 23, 2020

Then I studied the source code about interface, seen staticuint64s.

Because fmt.Printf receives ...interface{}, so the value it print is in staticuint64s.

println or manually convert i to string will print the true value of i —— it never changed.

@MMMMMMoSky
Copy link
Author

So it's all my mistake. sorry 😅

Be ⚠️CAREFUL⚠️ playing with unsafe, stop C behavior.

@golang golang locked and limited conversation to collaborators Nov 23, 2021
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