-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Description
What version of protobuf and what language are you using?
v1.36.0
What did you do?
Here's a reproducer test case.
protocolbuffers/protobuf-go@master...jhump:protobuf-go:jh/panic-repro
The panic happens in the call to msg.WhichOneof (line 20).
What did you expect to see?
In prior versions, at least as recently as 1.34.0, this worked as expected. It would return nil if the underlying proto3 optional field was present and otherwise it would return its field descriptor.
What did you see instead?
panic: invalid oneof descriptor goproto.proto.test3.TestAllTypes._optional_int32 for message goproto.proto.test3.TestAllTypes [recovered]
panic: invalid oneof descriptor goproto.proto.test3.TestAllTypes._optional_int32 for message goproto.proto.test3.TestAllTypes
goroutine 21 [running]:
testing.tRunner.func1.2({0x10096da60, 0x1400008f2a0})
/Users/jhumphries/go/pkg/mod/golang.org/toolchain@v0.0.1-go1.23.4.darwin-arm64/src/testing/testing.go:1632 +0x1bc
testing.tRunner.func1()
/Users/jhumphries/go/pkg/mod/golang.org/toolchain@v0.0.1-go1.23.4.darwin-arm64/src/testing/testing.go:1635 +0x334
panic({0x10096da60?, 0x1400008f2a0?})
/Users/jhumphries/go/pkg/mod/golang.org/toolchain@v0.0.1-go1.23.4.darwin-arm64/src/runtime/panic.go:785 +0x124
google.golang.org/protobuf/internal/impl.(*messageState).WhichOneof(0x140000fc908, {0x1009cb318, 0x1400014a098})
/Users/jhumphries/src/protobuf-go/internal/impl/message_reflect_gen.go:126 +0x194
google.golang.org/protobuf/reflect/protoreflect_test.TestSyntheticOneof(0x140000ac9c0)
/Users/jhumphries/src/protobuf-go/reflect/protoreflect/oneof_test.go:20 +0x108
testing.tRunner(0x140000ac9c0, 0x1009c5868)
/Users/jhumphries/go/pkg/mod/golang.org/toolchain@v0.0.1-go1.23.4.darwin-arm64/src/testing/testing.go:1690 +0xe4
created by testing.(*T).Run in goroutine 1
/Users/jhumphries/go/pkg/mod/golang.org/toolchain@v0.0.1-go1.23.4.darwin-arm64/src/testing/testing.go:1743 +0x314
Anything else we should know about your project / environment?
Occurs on both OS X and Linux.
The following patch fixes the issue:
diff --git a/internal/impl/message_reflect_gen.go b/internal/impl/message_reflect_gen.go
index 99dc23c6..f12524be 100644
--- a/internal/impl/message_reflect_gen.go
+++ b/internal/impl/message_reflect_gen.go
@@ -123,6 +123,17 @@ func (m *messageState) WhichOneof(od protoreflect.OneofDescriptor) protoreflect.
if oi := mi.oneofs[od.Name()]; oi != nil && oi.oneofDesc == od {
return od.Fields().ByNumber(oi.which(m.pointer()))
}
+ if od.Parent() == m.Descriptor() && od.IsSynthetic() {
+ // Synthetic oneofs are absent from mi.oneofs, so fallback to slow way.
+ fields := od.Fields()
+ for i, length := 0, fields.Len(); i < length; i++ {
+ fd := fields.Get(i)
+ if m.Has(fd) {
+ return fd
+ }
+ }
+ return nil
+ }
panic("invalid oneof descriptor " + string(od.FullName()) + " for message " + string(m.Descriptor().FullName()))
}
func (m *messageState) GetUnknown() protoreflect.RawFields {However, the file in question (internal/impl/message_reflect_gen.go) is generated. So a real fix will have to be made in the code generator or perhaps to reverse whatever change caused synthetic oneofs to no longer appear in mi.oneofs.