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/internal/impl/legacy_message.go b/internal/impl/legacy_message.go
index 1bded31..cb1a111 100644
--- a/internal/impl/legacy_message.go
+++ b/internal/impl/legacy_message.go
@@ -108,6 +108,23 @@
 		return aberrantLoadMessageDesc(t, name)
 	}
 
+	// If the Go type has no fields, then this might be a proto3 empty message
+	// from before the size cache was added. If there are any fields, check to
+	// see that at least one of them looks like something we generated.
+	if nfield := t.Elem().NumField(); nfield > 0 {
+		hasProtoField := false
+		for i := 0; i < nfield; i++ {
+			f := t.Elem().Field(i)
+			if tag := f.Tag.Get("protobuf"); tag != "" || strings.HasPrefix(f.Name, "XXX_") {
+				hasProtoField = true
+				break
+			}
+		}
+		if !hasProtoField {
+			return aberrantLoadMessageDesc(t, name)
+		}
+	}
+
 	md := legacyLoadFileDesc(b).Messages().Get(idxs[0])
 	for _, i := range idxs[1:] {
 		md = md.Messages().Get(i)