Skip to content

reflect: reflect.NewAt can't deal with address of interface{} #60804

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

Closed
kkqy opened this issue Jun 15, 2023 · 4 comments
Closed

reflect: reflect.NewAt can't deal with address of interface{} #60804

kkqy opened this issue Jun 15, 2023 · 4 comments
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. FrozenDueToAge

Comments

@kkqy
Copy link

kkqy commented Jun 15, 2023

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

$ go version go1.20.5 windows/amd64

Does this issue reproduce with the latest release?

Yes.

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

go env Output
$ go env
set GO111MODULE=
set GOARCH=amd64
set GOBIN=
set GOCACHE=C:\Users\User\AppData\Local\go-build
set GOENV=C:\Users\User\AppData\Roaming\go\env
set GOEXE=.exe
set GOEXPERIMENT=
set GOFLAGS=
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GOINSECURE=
set GOMODCACHE=C:\Users\User\go\pkg\mod
set GONOPROXY=
set GONOSUMDB=
set GOOS=windows
set GOPATH=C:\Users\User\go
set GOPRIVATE=
set GOPROXY=
set GOROOT=C:\Program Files\Go
set GOSUMDB=sum.golang.org
set GOTMPDIR=
set GOTOOLDIR=C:\Program Files\Go\pkg\tool\windows_amd64
set GOVCS=
set GOVERSION=go1.20.5
set GCCGO=gccgo
set GOAMD64=v1
set AR=ar
set CC=clang
set CXX=g++
set CGO_ENABLED=1
set GOMOD=D:\projects\strategies\go.mod
set GOWORK=
set CGO_CFLAGS=-O2 -g
set CGO_CPPFLAGS=
set CGO_CXXFLAGS=-O2 -g
set CGO_FFLAGS=-O2 -g
set CGO_LDFLAGS=-O2 -g
set PKG_CONFIG=pkg-config
set GOGCCFLAGS=-m64 -mthreads -fno-caret-diagnostics -Qunused-arguments -Wl,--no-gc-sections -fmessage-length=0 -fdebug-prefix-map=C:\Users\User\AppData\Local\Temp\go-build2533795677=/tmp/go-build -gno-record-gcc-switche

What did you do?

When PickData() returns Data type directly , reflect.NewAt works well.
https://go.dev/play/p/b2I5NRsVoTd

When PickData() returns interface{} that contains Data , the program crashes.
https://go.dev/play/p/7MsCSlPDT6s

What did you expect to see?

I want to get a pointer that points to the concrete value of interface{} and then print it.

What did you see instead?

The program crash.

@gopherbot gopherbot added the compiler/runtime Issues related to the Go compiler and/or runtime. label Jun 15, 2023
@kkqy
Copy link
Author

kkqy commented Jun 15, 2023

I find the reason, the number's address is not equal with t's address

func main() {
	var number int = 3
	var t interface{} = number
	fmt.Println(&number,&t) //Not equal.
}

So I read the document of reflect, but I don't find any function that can get the pointer of the value that the interface point to.
Is there no way to get number 's address by interface t ?

@randall77
Copy link
Contributor

No, there's no way to get the "address" of a int. That isn't a sensible thing to ask for. Particularly, t does not contain any information about where its value (3) came from. The value '3' is the only thing in the interface, just as if you did

var t interface{} = 3

You could do

var t interface{} = &number

That would provide something you could compare successfully with &number.

@kkqy
Copy link
Author

kkqy commented Jun 15, 2023

No, there's no way to get the "address" of a int. That isn't a sensible thing to ask for. Particularly, t does not contain any information about where its value (3) came from. The value '3' is the only thing in the interface, just as if you did

var t interface{} = 3

You could do

var t interface{} = &number

That would provide something you could compare successfully with &number.

@randall77
My example above is not suitable, please check the original example.

https://go.dev/play/p/7MsCSlPDT6s

package main

import (
	"fmt"
	"reflect"
)

type Data struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
}

func PickData() interface{} {
	return Data{
		Name: "Test",
		Age:  30,
	}
}

func main() {
	t := PickData()
	tValue := reflect.ValueOf(t)
	newData := reflect.NewAt(tValue.Type(), reflect.ValueOf(&t).UnsafePointer()).Interface()
        // Crashed
	fmt.Println(newData.(*Data))
}

It is a sensible thing when using json.Unmarshal.

https://go.dev/play/p/aLNyxR_tmwf

package main

import (
	"encoding/json"
	"fmt"
	"reflect"
)

type Data struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
}

func PickData() interface{} {
	return Data{
		Name: "Test",
		Age:  30,
	}
}

func main() {
	jsonData := []byte(`{"name":"NewName","age":18}`)
        // I can't determine the type of the return of PickData() ,but I can confirm that it must be a struct.
	t := PickData()
	// It changes the t to map[string]interface{}
	// json.Unmarshal(jsonData, &t)

	// So I want to get the pointer of the Data struct so that I can unmarshal to the struct instead of map[string]interface{}.
	pointer := reflect.NewAt(reflect.ValueOf(t).Type(), reflect.ValueOf(&t).UnsafePointer()).Interface()
	// But it crashes if I print the pointer.
	fmt.Println(pointer.(*Data))
	json.Unmarshal(jsonData, pointer)
	fmt.Println(pointer.(*Data))
}

Although I can make a new pointer by this:

func main() {
	jsonData := []byte(`{"name":"NewName","age":18}`)
	t := PickData()

	// I need make a new pointer.
	pointer := reflect.New(reflect.TypeOf(t)).Interface()
	fmt.Println(pointer)
	json.Unmarshal(jsonData, &pointer)
	fmt.Println(pointer)
}

I have to defined a new variable which cost more memory if the struct is so huge.
so I think unsafe or reflect should have ability to access the pointer of data in interface.

@randall77
Copy link
Contributor

This is just a bug in how you're using NewAt.

newData := reflect.NewAt(tValue.Type(), reflect.ValueOf(&t).UnsafePointer()).Interface()

&t has type *interface{}, it does not have type *Data. You're effectively casting it to a *Data forcibly anyway using unsafe, and that will lead to very bad things™.

It's pretty clear this is not a bug in Go, You might want to ask your question in one of the forums listed here, they will probably be of more help.

@golang golang locked and limited conversation to collaborators Jun 14, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. FrozenDueToAge
Projects
None yet
Development

No branches or pull requests

3 participants