Skip to content

reflect: fix StructOf panics from too many methods in embedded fields #26865

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
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/reflect/all_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5019,6 +5019,17 @@ func TestStructOfWithInterface(t *testing.T) {
})
}

func TestStructOfTooManyFields(t *testing.T) {
// Bug Fix: #25402 - this should not panic
tt := StructOf([]StructField{
{Name: "Time", Type: TypeOf(time.Time{}), Anonymous: true},
})

if _, present := tt.MethodByName("After"); !present {
t.Errorf("Expected method `After` to be found")
}
}

func TestChanOf(t *testing.T) {
// check construction and use of type not in binary
type T string
Expand Down
79 changes: 19 additions & 60 deletions src/reflect/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -1889,6 +1889,8 @@ func MapOf(key, elem Type) Type {
return ti.(Type)
}

// TODO(crawshaw): as these funcTypeFixedN structs have no methods,
// they could be defined at runtime using the StructOf function.
type funcTypeFixed4 struct {
funcType
args [4]*rtype
Expand Down Expand Up @@ -2278,42 +2280,6 @@ type structTypeUncommon struct {
u uncommonType
}

// A *rtype representing a struct is followed directly in memory by an
// array of method objects representing the methods attached to the
// struct. To get the same layout for a run time generated type, we
// need an array directly following the uncommonType memory. The types
// structTypeFixed4, ...structTypeFixedN are used to do this.
//
// A similar strategy is used for funcTypeFixed4, ...funcTypeFixedN.

// TODO(crawshaw): as these structTypeFixedN and funcTypeFixedN structs
// have no methods, they could be defined at runtime using the StructOf
// function.

type structTypeFixed4 struct {
structType
u uncommonType
m [4]method
}

type structTypeFixed8 struct {
structType
u uncommonType
m [8]method
}

type structTypeFixed16 struct {
structType
u uncommonType
m [16]method
}

type structTypeFixed32 struct {
structType
u uncommonType
m [32]method
}

// isLetter reports whether a given 'rune' is classified as a Letter.
func isLetter(ch rune) bool {
return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= utf8.RuneSelf && unicode.IsLetter(ch)
Expand Down Expand Up @@ -2571,33 +2537,26 @@ func StructOf(fields []StructField) Type {
var typ *structType
var ut *uncommonType

switch {
case len(methods) == 0:
if len(methods) == 0 {
t := new(structTypeUncommon)
typ = &t.structType
ut = &t.u
case len(methods) <= 4:
t := new(structTypeFixed4)
typ = &t.structType
ut = &t.u
copy(t.m[:], methods)
case len(methods) <= 8:
t := new(structTypeFixed8)
typ = &t.structType
ut = &t.u
copy(t.m[:], methods)
case len(methods) <= 16:
t := new(structTypeFixed16)
typ = &t.structType
ut = &t.u
copy(t.m[:], methods)
case len(methods) <= 32:
t := new(structTypeFixed32)
typ = &t.structType
ut = &t.u
copy(t.m[:], methods)
default:
panic("reflect.StructOf: too many methods")
} else {
// A *rtype representing a struct is followed directly in memory by an
// array of method objects representing the methods attached to the
// struct. To get the same layout for a run time generated type, we
// need an array directly following the uncommonType memory.
// A similar strategy is used for funcTypeFixed4, ...funcTypeFixedN.
tt := New(StructOf([]StructField{
{Name: "S", Type: TypeOf(structType{})},
{Name: "U", Type: TypeOf(uncommonType{})},
{Name: "M", Type: ArrayOf(len(methods), TypeOf(methods[0]))},
}))

typ = (*structType)(unsafe.Pointer(tt.Elem().Field(0).UnsafeAddr()))
ut = (*uncommonType)(unsafe.Pointer(tt.Elem().Field(1).UnsafeAddr()))

copy(tt.Elem().Field(2).Slice(0, len(methods)).Interface().([]method), methods)
}
// TODO(sbinet): Once we allow embedding multiple types,
// methods will need to be sorted like the compiler does.
Expand Down