reflect/protoreflect: remove nullability from repeated extension fields
Remove repeated extension fields from the set of nullable fields,
so that Has reports false and Range does not visit a a zero-length
repeated extension field.
This corrects a fuzzer-detected case where unmarshaling and remarshaling
a wire-format message could result in a semantic change. For a repeated
extension field in non-packed encoding, unmarshaling a packed
representation of the field would result in a message which Has the
extension. Remarshaling it would discard the the field.
Fixes golang.org/protobuf#975
Change-Id: Ie836559c93d218db5b5201742a3b8ebbaacf54ed
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/204897
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
Reviewed-by: Joe Tsai <joetsai@google.com>
diff --git a/internal/impl/message_reflect.go b/internal/impl/message_reflect.go
index bc50303..f5f7f2b 100644
--- a/internal/impl/message_reflect.go
+++ b/internal/impl/message_reflect.go
@@ -145,18 +145,33 @@
func (m *extensionMap) Range(f func(pref.FieldDescriptor, pref.Value) bool) {
if m != nil {
for _, x := range *m {
- xt := x.Type()
- if !f(xt.TypeDescriptor(), x.Value()) {
+ xd := x.Type().TypeDescriptor()
+ v := x.Value()
+ if xd.IsList() && v.List().Len() == 0 {
+ continue
+ }
+ if !f(xd, v) {
return
}
}
}
}
func (m *extensionMap) Has(xt pref.ExtensionType) (ok bool) {
- if m != nil {
- _, ok = (*m)[int32(xt.TypeDescriptor().Number())]
+ if m == nil {
+ return false
}
- return ok
+ xd := xt.TypeDescriptor()
+ x, ok := (*m)[int32(xd.Number())]
+ if !ok {
+ return false
+ }
+ switch {
+ case xd.IsList():
+ return x.Value().List().Len() > 0
+ case xd.IsMap():
+ return x.Value().Map().Len() > 0
+ }
+ return true
}
func (m *extensionMap) Clear(xt pref.ExtensionType) {
delete(*m, int32(xt.TypeDescriptor().Number()))