-
Notifications
You must be signed in to change notification settings - Fork 17.7k
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
reflect: promoted pointer-methods created by StructOf corrupt memory #24782
Comments
See also #18617. |
"Afterwards, the field is magically allocated." I think OP misread the output. It hasn't allocated an X and put 42 in it, it wrote 42 to the *main.X field, which is total nonsense. Maybe the compiler forwarded the implementation for (main.X).Set instead of (*main.X).Set? |
Probably the compiler passed the address of the outer struct as the receiver to |
Yeah, I was about to edit my comment. If you add some logging it's clear that's exactly what's happening. I bet this has to do with direct ifaces somehow... |
@heschik You are right, I misread that. That makes it even worse, though, as it allows doing unsafe operations without importing unsafe (somewhat crude PoC, it's probably possible to do it more elegantly). |
@heschik and I looked into this briefly. I'm pretty sure this is because StructOf directly promotes the methods of embedded pointer types, but in general those require wrappers, which it's not creating. |
For
the promoted (*T).Set method needs to be:
I.e., two pointer indirections. But because it's directly reusing the underlying
method, the result is effectively instead:
|
Specifically, I think the problem is here: Lines 2476 to 2481 in 95e6a9f
It's taking the interface method from *X and using it in the generated type. But *X is a direct interface type, and skips one level of indirection. The runtime-generated type is not direct and needs the second level. When we do this operation for an embedded interface, we check whether the embedded type was indirect and generate a wrapper with an extra indirection if so: Lines 2419 to 2436 in 95e6a9f
We probably need something like that. |
Change https://golang.org/cl/121316 mentions this issue: |
What version of Go are you using (
go version
)?go version go1.10.1 linux/amd64
Does this issue reproduce with the latest release?
Yes
What operating system and processor architecture are you using (
go env
)?GOARCH="amd64"
GOBIN=""
GOCACHE="/home/mero/.cache/go-build"
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/mero"
GORACE=""
GOROOT="/home/mero/go"
GOTMPDIR=""
GOTOOLDIR="/home/mero/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-build038207887=/tmp/go-build -gno-record-gcc-switches"
What did you do?
This is from reddit. I reduced it to this example:
https://play.golang.org/p/vkdabA1W6mI
What did you expect to see?
What did you see instead?
The second two lines show the magic allocation: The field (containing an
*X
) is first nil, thenv.Set
is called, referring to the embedded field, which should panic, as it uses the receiver (which should be nil), but doesn't. Afterwards, the field is magically allocated.It seems, this is related to there only being a single field - if we add a second field, even of zero size, the program behaves as expected: https://play.golang.org/p/Kd4igw-vOp7. I assume this is in part related to the work on #15924 and similar issues.
The text was updated successfully, but these errors were encountered: