internal/impl: more checks for aberrant messages

When loading a *MessageInfo for a legacy message type, check to see if
the Go type contains at least one field which looks like a message
field. Specifically, look for at least one field with a `protobuf:` tag,
or an XXX_unrecognized field.

If a message has no recognizable fields, assume that it's something we
don't know how to interpret and treat it as an aberrant message.

Change-Id: If5c09087f1a0187271c98539d761395a2ee70a9e
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/210617
Reviewed-by: Joe Tsai <joetsai@google.com>
diff --git a/proto/methods_test.go b/proto/methods_test.go
index 385fcbf..91019fa 100644
--- a/proto/methods_test.go
+++ b/proto/methods_test.go
@@ -15,6 +15,8 @@
 
 	"google.golang.org/protobuf/internal/impl"
 	"google.golang.org/protobuf/proto"
+
+	legacypb "google.golang.org/protobuf/internal/testprotos/legacy"
 )
 
 type selfMarshaler struct {
@@ -84,19 +86,46 @@
 
 const descPanicSelfMarshalerBytes = "bytes"
 
-func (m descPanicSelfMarshaler) Reset()                      {}
-func (m descPanicSelfMarshaler) ProtoMessage()               {}
-func (m descPanicSelfMarshaler) Descriptor() ([]byte, []int) { panic("Descriptor method panics") }
-func (m descPanicSelfMarshaler) String() string              { return "descPanicSelfMarshaler{}" }
-func (m descPanicSelfMarshaler) Marshal() ([]byte, error) {
+func (m *descPanicSelfMarshaler) Reset()                      {}
+func (m *descPanicSelfMarshaler) ProtoMessage()               {}
+func (m *descPanicSelfMarshaler) Descriptor() ([]byte, []int) { panic("Descriptor method panics") }
+func (m *descPanicSelfMarshaler) String() string              { return "descPanicSelfMarshaler{}" }
+func (m *descPanicSelfMarshaler) Marshal() ([]byte, error) {
 	return []byte(descPanicSelfMarshalerBytes), nil
 }
 
 func TestSelfMarshalerDescriptorPanics(t *testing.T) {
-	m := descPanicSelfMarshaler{}
+	m := &descPanicSelfMarshaler{}
 	got, err := proto.Marshal(impl.Export{}.MessageOf(m).Interface())
 	want := []byte(descPanicSelfMarshalerBytes)
 	if err != nil || !bytes.Equal(got, want) {
 		t.Fatalf("proto.Marshal(%v) = %v, %v; want %v, nil", m, got, err, want)
 	}
 }
+
+type descSelfMarshaler struct {
+	someField int // some non-generated field
+}
+
+const descSelfMarshalerBytes = "bytes"
+
+func (m *descSelfMarshaler) Reset()        {}
+func (m *descSelfMarshaler) ProtoMessage() {}
+func (m *descSelfMarshaler) Descriptor() ([]byte, []int) {
+	return ((*legacypb.Legacy)(nil)).GetF1().Descriptor()
+}
+func (m *descSelfMarshaler) String() string {
+	return "descSelfMarshaler{}"
+}
+func (m *descSelfMarshaler) Marshal() ([]byte, error) {
+	return []byte(descSelfMarshalerBytes), nil
+}
+
+func TestSelfMarshalerWithDescriptor(t *testing.T) {
+	m := &descSelfMarshaler{}
+	got, err := proto.Marshal(impl.Export{}.MessageOf(m).Interface())
+	want := []byte(descSelfMarshalerBytes)
+	if err != nil || !bytes.Equal(got, want) {
+		t.Fatalf("proto.Marshal(%v) = %v, %v; want %v, nil", m, got, err, want)
+	}
+}