Skip to content

reflect: Value.SetIterXXX allows setting values that are unexported #54628

@dsnet

Description

@dsnet

Consider the following snippet:

v := reflect.ValueOf(struct {
	m map[string]string // m is exported, we should never be able to get an interfaceable value of it or any sub-elements of it
}{m: map[string]string{"hello": "goodbye"}})
vm := v.FieldByName("m")
fmt.Println(vm.CanInterface()) // correctly prints false

ve := vm.MapIndex(reflect.ValueOf("hello"))
fmt.Println(ve.CanInterface()) // correctly prints false

ve = reflect.New(reflect.TypeOf("")).Elem()
for iter := vm.MapRange(); iter.Next(); {
	ve.SetIterValue(iter)          // incorrectly succeeds; expect panic due to read-only bit being false

	vv := iter.Value()             // older API for obtain a map value; it propagates the read-only bit check
	fmt.Println(vv.CanInterface()) // correctly prints false
	ve.Set(vv)                     // correctly panics
}

The newer Value.SetIterXXX APIs added in Go 1.18 provide a way to circumvent the unexported field checks, thus allowing users to obtain an interfaceable value of an unexported field without the use of unsafe.

Metadata

Metadata

Assignees

Labels

FrozenDueToAgeNeedsFixThe path to resolution is known, but the work has not been done.compiler/runtimeIssues related to the Go compiler and/or runtime.

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions