From 7dfcffe5a74a46c36b079a6e074cee6f821d85e6 Mon Sep 17 00:00:00 2001 From: Joe Tsai Date: Thu, 2 Apr 2020 10:31:06 -0700 Subject: [PATCH] internal/impl: handle extremely old messages At some point in time, protoc-gen-go actually emitted an XXX_OneofFuncs with a different signature. Adjust the logic for handling XXX_OneofFuncs to not assume that the return arguments are in a specific order. Change-Id: Idd9c09231c4129c655d4a635bb1ae094896a1ff4 Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/226980 Reviewed-by: Damien Neil --- internal/impl/legacy_aberrant_test.go | 2 +- internal/impl/legacy_message.go | 19 +++++++++---------- internal/impl/message.go | 13 ++++++++----- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/internal/impl/legacy_aberrant_test.go b/internal/impl/legacy_aberrant_test.go index c51b0c7e..905981a4 100644 --- a/internal/impl/legacy_aberrant_test.go +++ b/internal/impl/legacy_aberrant_test.go @@ -86,7 +86,7 @@ func (m *AberrantMessage) ExtensionRangeArray() []protoiface.ExtensionRangeV1 { return []protoiface.ExtensionRangeV1{{Start: 10, End: 100}} } -func (m *AberrantMessage) XXX_OneofWrappers() []interface{} { +func (m *AberrantMessage) XXX_OneofFuncs() []interface{} { return []interface{}{ (*OneofBool)(nil), (*OneofInt32)(nil), diff --git a/internal/impl/legacy_message.go b/internal/impl/legacy_message.go index a7235696..06c68e11 100644 --- a/internal/impl/legacy_message.go +++ b/internal/impl/legacy_message.go @@ -195,16 +195,15 @@ func aberrantLoadMessageDescReentrant(t reflect.Type, name pref.FullName) pref.M // Obtain a list of oneof wrapper types. var oneofWrappers []reflect.Type - if fn, ok := t.MethodByName("XXX_OneofFuncs"); ok { - vs := fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))})[3] - for _, v := range vs.Interface().([]interface{}) { - oneofWrappers = append(oneofWrappers, reflect.TypeOf(v)) - } - } - if fn, ok := t.MethodByName("XXX_OneofWrappers"); ok { - vs := fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))})[0] - for _, v := range vs.Interface().([]interface{}) { - oneofWrappers = append(oneofWrappers, reflect.TypeOf(v)) + for _, method := range []string{"XXX_OneofFuncs", "XXX_OneofWrappers"} { + if fn, ok := t.MethodByName(method); ok { + for _, v := range fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))}) { + if vs, ok := v.Interface().([]interface{}); ok { + for _, v := range vs { + oneofWrappers = append(oneofWrappers, reflect.TypeOf(v)) + } + } + } } } diff --git a/internal/impl/message.go b/internal/impl/message.go index 65de48a4..c1d89023 100644 --- a/internal/impl/message.go +++ b/internal/impl/message.go @@ -182,11 +182,14 @@ fieldLoop: // Derive a mapping of oneof wrappers to fields. oneofWrappers := mi.OneofWrappers - if fn, ok := reflect.PtrTo(t).MethodByName("XXX_OneofFuncs"); ok { - oneofWrappers = fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))})[3].Interface().([]interface{}) - } - if fn, ok := reflect.PtrTo(t).MethodByName("XXX_OneofWrappers"); ok { - oneofWrappers = fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))})[0].Interface().([]interface{}) + for _, method := range []string{"XXX_OneofFuncs", "XXX_OneofWrappers"} { + if fn, ok := reflect.PtrTo(t).MethodByName(method); ok { + for _, v := range fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))}) { + if vs, ok := v.Interface().([]interface{}); ok { + oneofWrappers = vs + } + } + } } for _, v := range oneofWrappers { tf := reflect.TypeOf(v).Elem()