-
Notifications
You must be signed in to change notification settings - Fork 17.6k
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: Value.Addr().Elem() loses flagEmbedRO in origin value #32772
Comments
I don't really see how to fix this safely: ensuring that the |
@ianlancetaylor I thought after your response, I think it is safe for reasons:
I have update commits with more test cases in trial fix branch to (kezhuw/go@306e9c9 kezhuw/go@a16093d), I plan to send a pull request later after job (at least 10 hours late) if above sounds good to you. See Value.Field(). |
Currently, `Value.Addr()` collapses `flagRO`, which is a combination of `flagEmbedRO` and `flagStickyRO`, to `flagStickyRO`. This causes exported fields of unexported anonymous field from `Value.Addr().Elem()` read only. This commit fix this by inheriting all bits of `flagRO` from origin value in `Value.Addr()`. This should be safe due to following reasons: * Result of `Value.Addr()` is not `CanSet()` because of it is not `CanAddr()`, but not `flagRO`. * `Addr().Elem()` get same `flagRO` as origin, so it should behave same as origin in `CanSet()`. Fix golang#32772.
Currently, Value.Addr() collapses flagRO, which is a combination of flagEmbedRO and flagStickyRO, to flagStickyRO. This causes exported fields of unexported anonymous field from Value.Addr().Elem() read only. This commit fix this by inheriting all bits of flagRO from origin value in Value.Addr(). This should be safe due to following reasons: * Result of Value.Addr() is not CanSet() because of it is not CanAddr() but not flagRO. * Addr().Elem() get same flagRO as origin, so it should behave same as origin in CanSet(). Fixes golang#32772.
Change https://golang.org/cl/183937 mentions this issue: |
I'm sympathetic to the rationale that if In general, package reflect exposes the same API as you could use through a package's exported interface. An issue arises when fields are promoted from a non-exported embedded field. For example:
An external package can access This is problematic for package reflect because reflect doesn't provide a way to directly access promoted fields. They have to be accessed field-by-field, and the behavior differed between cmd/compile (née gc) and gccgo. It was decided in #12367 (included in Go 1.6) to reconcile this by special casing accesses like This is where the intuition about @kezhuw You mentioned finding this when upgrading from Go 1.5 to Go 1.11. Do you mean this broke some code you had written? Can you share the code? |
@mdempsky You can see the last two commits in https://github.com/kezhuw/toml/commits/9d1a8af4e1bcb6c1efa7523c915d9570b4a40e48. I have push another branch https://github.com/kezhuw/toml/commits/go-issues-32772 to revert the fix and preserve only one test case, you can |
@mdempsky Here is build matrix https://travis-ci.org/github/kezhuw/toml/builds/676804186 after reverting the fix. |
@kezhuw Thanks. Knowing this broke real world code rather than just a theoretical concern is useful information. @ianlancetaylor What do you think? Package reflect today special cases I can't think of any negative consequences to this aside from theoretical purity. |
Thanks for the analysis. I'm OK with the change if it doesn't introduce any holes in the type system, which it sounds like it doesn't. |
Currently, Value.Addr collapses flagRO, which is a combination of flagEmbedRO and flagStickyRO, to flagStickyRO. This causes exported fields of unexported anonymous field from Value.Addr.Elem read only. This commit fix this by keeping all bits of flagRO from origin value in Value.Addr. This should be safe due to following reasons: * Result of Value.Addr is not CanSet because of it is not CanAddr but not flagRO. * Addr.Elem get same flagRO as origin, so it should behave same as origin in CanSet. Fixes golang#32772. Change-Id: I79e086628c0fb6569a50ce63f3b95916f997eda1 GitHub-Last-Rev: 78e280e GitHub-Pull-Request: golang#32787 Reviewed-on: https://go-review.googlesource.com/c/go/+/183937 Reviewed-by: Matthew Dempsky <mdempsky@google.com> Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org>
This makes exported fields in unexported anonymous field not settable
What version of Go are you using (
go version
)?Does this issue reproduce with the latest release?
Yes
What operating system and processor architecture are you using (
go env
)?go env
OutputWhat did you do?
https://play.golang.org/p/mKRa1-3j2He
What did you expect to see?
The second should prints
true
forCanSet
.What did you see instead?
The second prints
false
forCanSet
.See also
TestCanSetField
in go.The text was updated successfully, but these errors were encountered: