types/known/anypb: gracefully handle nil sources

Add checks so that MarshalFrom and UnmarshalTo consistently matches
the behavior of the proto package with regard to nil messages.
In particular, using a nil message as the destination results in
a panic (which is already the current behavior), while using a
nil message as the source does not panic (it is usually treated as
an untyped empty message). Since an untyped message has no
sensible meaning in the context of Any, return an error.

Change-Id: I99e86c2cdfbd8be57cc039efd550458dc56aadbc
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/237920
Reviewed-by: Damien Neil <dneil@google.com>
This commit is contained in:
Joe Tsai 2020-06-15 11:02:18 -07:00
parent beaa55256c
commit bfc31022a5
2 changed files with 12 additions and 0 deletions

View File

@ -25,6 +25,9 @@ func genMessageKnownFunctions(g *protogen.GeneratedFile, f *fileInfo, m *message
g.P("// If no options are specified, call dst.MarshalFrom instead.")
g.P("func MarshalFrom(dst *Any, src ", protoPackage.Ident("Message"), ", opts ", protoPackage.Ident("MarshalOptions"), ") error {")
g.P(" const urlPrefix = \"type.googleapis.com/\"")
g.P(" if src == nil {")
g.P(" return ", protoimplPackage.Ident("X"), ".NewError(\"invalid nil source message\")")
g.P(" }")
g.P(" b, err := opts.Marshal(src)")
g.P(" if err != nil {")
g.P(" return err")
@ -41,6 +44,9 @@ func genMessageKnownFunctions(g *protogen.GeneratedFile, f *fileInfo, m *message
g.P("//")
g.P("// If no options are specified, call src.UnmarshalTo instead.")
g.P("func UnmarshalTo(src *Any, dst ", protoPackage.Ident("Message"), ", opts ", protoPackage.Ident("UnmarshalOptions"), ") error {")
g.P(" if src.GetTypeUrl() == \"\" {")
g.P(" return ", protoimplPackage.Ident("X"), ".NewError(\"invalid empty type URL\")")
g.P(" }")
g.P(" if !src.MessageIs(dst) {")
g.P(" got := dst.ProtoReflect().Descriptor().FullName()")
g.P(" want := src.MessageName()")

View File

@ -167,6 +167,9 @@ type Any struct {
// If no options are specified, call dst.MarshalFrom instead.
func MarshalFrom(dst *Any, src proto.Message, opts proto.MarshalOptions) error {
const urlPrefix = "type.googleapis.com/"
if src == nil {
return protoimpl.X.NewError("invalid nil source message")
}
b, err := opts.Marshal(src)
if err != nil {
return err
@ -182,6 +185,9 @@ func MarshalFrom(dst *Any, src proto.Message, opts proto.MarshalOptions) error {
//
// If no options are specified, call src.UnmarshalTo instead.
func UnmarshalTo(src *Any, dst proto.Message, opts proto.UnmarshalOptions) error {
if src.GetTypeUrl() == "" {
return protoimpl.X.NewError("invalid empty type URL")
}
if !src.MessageIs(dst) {
got := dst.ProtoReflect().Descriptor().FullName()
want := src.MessageName()