Skip to content

Commit aa810b6

Browse files
authored
proto: fix handling of required fields after multiple violations (#679)
The previous logic only treated a required not set violation as non-fatal for the first instance. Afterwards, the logic incorrectly switched back to being fatal.
1 parent 20b6e0b commit aa810b6

File tree

3 files changed

+31
-5
lines changed

3 files changed

+31
-5
lines changed

proto/all_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2324,6 +2324,28 @@ func TestInvalidUTF8(t *testing.T) {
23242324
}
23252325
}
23262326

2327+
func TestRequired(t *testing.T) {
2328+
// The F_BoolRequired field appears after all of the required fields.
2329+
// It should still be handled even after multiple required field violations.
2330+
m := &GoTest{F_BoolRequired: Bool(true)}
2331+
got, err := Marshal(m)
2332+
if _, ok := err.(*RequiredNotSetError); !ok {
2333+
t.Errorf("Marshal() = %v, want RequiredNotSetError error", err)
2334+
}
2335+
if want := []byte{0x50, 0x01}; !bytes.Equal(got, want) {
2336+
t.Errorf("Marshal() = %x, want %x", got, want)
2337+
}
2338+
2339+
m = new(GoTest)
2340+
err = Unmarshal(got, m)
2341+
if _, ok := err.(*RequiredNotSetError); !ok {
2342+
t.Errorf("Marshal() = %v, want RequiredNotSetError error", err)
2343+
}
2344+
if !m.GetF_BoolRequired() {
2345+
t.Error("m.F_BoolRequired = false, want true")
2346+
}
2347+
}
2348+
23272349
// Benchmarks
23282350

23292351
func testMsg() *GoTest {

proto/table_marshal.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -252,11 +252,13 @@ func (u *marshalInfo) marshal(b []byte, ptr pointer, deterministic bool) ([]byte
252252
}
253253
}
254254
for _, f := range u.fields {
255-
if f.required && errLater == nil {
255+
if f.required {
256256
if ptr.offset(f.field).getPointer().isNil() {
257257
// Required field is not set.
258258
// We record the error but keep going, to give a complete marshaling.
259-
errLater = &RequiredNotSetError{f.name}
259+
if errLater == nil {
260+
errLater = &RequiredNotSetError{f.name}
261+
}
260262
continue
261263
}
262264
}
@@ -2592,7 +2594,7 @@ func (u *marshalInfo) appendMessageSet(b []byte, ext *XXX_InternalExtensions, de
25922594
p := toAddrPointer(&v, ei.isptr)
25932595
b, err = ei.marshaler(b, p, 3<<3|WireBytes, deterministic)
25942596
b = append(b, 1<<3|WireEndGroup)
2595-
if nerr.Merge(err) {
2597+
if !nerr.Merge(err) {
25962598
return b, err
25972599
}
25982600
}

proto/table_unmarshal.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,10 +175,12 @@ func (u *unmarshalInfo) unmarshal(m pointer, b []byte) error {
175175
reqMask |= f.reqMask
176176
continue
177177
}
178-
if r, ok := err.(*RequiredNotSetError); ok && errLater == nil {
178+
if r, ok := err.(*RequiredNotSetError); ok {
179179
// Remember this error, but keep parsing. We need to produce
180180
// a full parse even if a required field is missing.
181-
errLater = r
181+
if errLater == nil {
182+
errLater = r
183+
}
182184
reqMask |= f.reqMask
183185
continue
184186
}

0 commit comments

Comments
 (0)