From 0e4a0b93d25f56eda3b6026a98bdee4cf6fc7b8f Mon Sep 17 00:00:00 2001 From: Raghavendra Nagaraj Date: Tue, 6 Nov 2018 09:02:03 +0000 Subject: [PATCH] reflect: fix StructOf panics from too many methods in embedded fields Previously we panicked if the number of methods present for an embedded field was >= 32. This change removes that limit and now StructOf dynamically calls itself to create space for the number of methods. Fixes #25402 Change-Id: I3b1deb119796d25f7e6eee1cdb126327b49a0b5e GitHub-Last-Rev: 16da71ad6b23563f3ed26f1914adf41e3d42de69 GitHub-Pull-Request: golang/go#26865 Reviewed-on: https://go-review.googlesource.com/c/128479 Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor --- src/reflect/all_test.go | 11 ++++++ src/reflect/type.go | 79 ++++++++++------------------------------- 2 files changed, 30 insertions(+), 60 deletions(-) diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go index c463b61c57..4b215f120c 100644 --- a/src/reflect/all_test.go +++ b/src/reflect/all_test.go @@ -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 diff --git a/src/reflect/type.go b/src/reflect/type.go index a04234ca69..5bbab79fc0 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -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 @@ -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) @@ -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. -- 2.50.0