-
Notifications
You must be signed in to change notification settings - Fork 18k
cmd/link: removing deadcode check for reflect.Value.Call causes miscompilation #38515
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
Comments
This program failed even before CL 228792:
|
I think as a short-term workaround, we should revert CL 228792, and also add a check for reflect.Value.CallSlice, and add these as regress tests. Longer term, we should figure out how to make the reflection-use analysis more precise without compromising soundness. |
Observation: Changing
to
causes the test cases to pass, even with CL 228792. It looks like what's happening is the ReflectMethod check doesn't work within package reflect itself. While compiling a package, localpkg.Path will be "", not it's actual package path (e.g., "reflect"). Changing |
CC @cherrymui |
@mdempsky, thanks! Nice! That was the program I was trying to write that prompted my golang-dev post. In playground form: https://play.golang.org/p/8L3UVmShhQf (showing that a Call anywhere else makes it work fine in Go 1.14) |
@mdempsky How about using
|
Yeah, actually I was thinking about this the other day. It looks like the compiler only marks direct call to reflect.Type.Method, but not call by function pointers. And reflect.Value.Call doesn't really matter, as you could get a method and do other things with it without actually call it, and the method should be live in this case as well. I'm thinking there could be a different way of doing it. |
Change https://golang.org/cl/228879 mentions this issue: |
@cuonglm I wouldn't think that would fix the test cases. Does it? @cherrymui I don't think the linker should be involved in checking for interface wrapper methods. There can be many wrappers semantically equivalent to reflect.Type.Method (as a method expression) in different packages, and only the compiler can detect them all correctly. |
@mdempsky it does, I have a patch in my local, do you want to take a look? |
Ah, sorry, I haven’t tested with the CallSlice case. |
It does pass. |
@cuonglm Oh, right, LongString uses package name, not package path. No, I don't think that's a desirable change. It's not likely to cause problems in practice, but that can lead to false positives. We always want to identify standard library packages by path, not name. |
Yeah, I think you're probably right. There could be more method wrappers, like
It seems those wrapper functions actually do have REFLECTMETHOD set. Only reflect.Type.Method itself. Maybe we just didn't check the package name correctly, then. |
@cherrymui Yeah, that's what the change I mentioned in #38515 (comment) was meant to address. With that change, reflect.Type.Method gets marked REFLECTMETHOD. |
Yeah, thanks! (I somehow missed that, sorry.) Do you want to send a CL? Or I can do that. |
(With that, the linker change actually makes it work. But it is clearly not the best way to do it.) |
@cherrymui No problem, and either way works for me. I probably won't get to my desktop to create a CL until later today. Happy if you beat me to it. :) |
Okay, I can do that. Thanks! |
Just wanted to mention that, as @rsc pointed out in the email thread, Call or CallSlice is not important here. You could obtain a method and do things with it, without using Call or CallSlice. If the method is not retained by the linker, bad things will happen. E.g. https://play.golang.org/p/rSIx14FBMNs |
@cherrymui Thanks for pointing out that example. Yeah, I don't think the linker should need to check for Call or CallSlice. I only suggested restoring those checks as a short-term workaround. I think if we just fix the compiler's Edit: I do think the linker should / needs to continue checking for reflect.Value.Method. |
Yeah, I think so. Thanks. |
Change https://golang.org/cl/228880 mentions this issue: |
…self reflect.Type.Method (and MethodByName) can be used to obtain a reference of a method by reflection. The linker needs to know if reflect.Type.Method is called, and retain all exported methods accordingly. This is handled by the compiler, which marks the caller of reflect.Type.Method with REFLECTMETHOD attribute. The current code failed to handle the reflect package itself, so the method wrapper reflect.Type.Method is not marked. This CL fixes it. Fixes golang#38515. Change-Id: I12904d23eda664cf1794bc3676152f3218fb762b Reviewed-on: https://go-review.googlesource.com/c/go/+/228880 Run-TryBot: Cherry Zhang <cherryyz@google.com> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
This program now panics at master due to CL 228792:
It should print "ok".
/cc @cherrymui @bradfitz
The text was updated successfully, but these errors were encountered: