]> Cypherpunks repositories - gostls13.git/commitdiff
reflect: fix StructOf panics from too many methods in embedded fields
authorRaghavendra Nagaraj <jamdagni86@gmail.com>
Tue, 6 Nov 2018 09:02:03 +0000 (09:02 +0000)
committerIan Lance Taylor <iant@golang.org>
Tue, 6 Nov 2018 13:52:29 +0000 (13:52 +0000)
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 <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
src/reflect/all_test.go
src/reflect/type.go

index c463b61c57b896348d8f32f041ba7d9b32d3aca1..4b215f120c963b04c265d95e645f8298e6f23cc0 100644 (file)
@@ -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
index a04234ca692825836f416d9cebf05b0cf549866f..5bbab79fc0775d0ce2fad62a877c2473e118a884 100644 (file)
@@ -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.