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 <dneil@google.com>
This commit is contained in:
Joe Tsai 2020-04-02 10:31:06 -07:00
parent a75c9146b7
commit 7dfcffe5a7
3 changed files with 18 additions and 16 deletions

View File

@ -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),

View File

@ -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))
}
}
}
}
}

View File

@ -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()