Skip to content

Commit a3d1fde

Browse files
tigratok8s-publishing-bot
authored andcommitted
fix: fixes a possible panic in NewYAMLToJSONDecoder
This PR fixes a possible panic caused by decoding a JSON document followed by a YAML document that is shorter than the first json document. This can cause a panic because the stream already consumed the JSON data. When we fallback to YAML reader, the YAML starts with a zero offset while the stream consumed data is non-zero. This could lead into consuming negative bytes because `d.yaml.InputOffset() - d.stream.Consumed()` is negative which will cause a panic. Signed-off-by: Tiago Silva <[email protected]> Kubernetes-commit: a257be82995ab689659c98dfb6336d63f677641d
1 parent 955939f commit a3d1fde

File tree

2 files changed

+24
-6
lines changed

2 files changed

+24
-6
lines changed

pkg/util/yaml/decoder.go

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -247,10 +247,12 @@ func splitYAMLDocument(data []byte, atEOF bool) (advance int, token []byte, err
247247
// finding a non-YAML-delimited series of objects), it will not switch to YAML.
248248
// Once it switches to YAML it will not switch back to JSON.
249249
type YAMLOrJSONDecoder struct {
250-
json *json.Decoder
251-
yaml *YAMLToJSONDecoder
252-
stream *StreamReader
253-
count int // how many objects have been decoded
250+
json *json.Decoder
251+
jsonConsumed int64 // of the stream total, how much was JSON?
252+
yaml *YAMLToJSONDecoder
253+
yamlConsumed int64 // of the stream total, how much was YAML?
254+
stream *StreamReader
255+
count int // how many objects have been decoded
254256
}
255257

256258
type JSONSyntaxError struct {
@@ -299,8 +301,10 @@ func (d *YAMLOrJSONDecoder) Decode(into interface{}) error {
299301
if d.json != nil {
300302
err := d.json.Decode(into)
301303
if err == nil {
302-
d.stream.Consume(int(d.json.InputOffset()) - d.stream.Consumed())
303304
d.count++
305+
consumed := d.json.InputOffset() - d.jsonConsumed
306+
d.stream.Consume(int(consumed))
307+
d.jsonConsumed += consumed
304308
return nil
305309
}
306310
if err == io.EOF { //nolint:errorlint
@@ -334,7 +338,9 @@ func (d *YAMLOrJSONDecoder) Decode(into interface{}) error {
334338
if d.yaml != nil {
335339
err := d.yaml.Decode(into)
336340
if err == nil {
337-
d.stream.Consume(d.yaml.InputOffset() - d.stream.Consumed())
341+
consumed := int64(d.yaml.InputOffset()) - d.yamlConsumed
342+
d.stream.Consume(int(consumed))
343+
d.yamlConsumed += consumed
338344
d.count++
339345
return nil
340346
}
@@ -375,6 +381,7 @@ func (d *YAMLOrJSONDecoder) consumeWhitespace() error {
375381
if err == io.EOF { //nolint:errorlint
376382
break
377383
}
384+
consumed += sz
378385
}
379386
return io.EOF
380387
}

pkg/util/yaml/decoder_test.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,17 @@ func TestYAMLOrJSONDecoder(t *testing.T) {
343343
{"foo": "bar"},
344344
{"baz": "biz"},
345345
}},
346+
// First document is JSON, second is YAML but with smaller size.
347+
{"{\"foo\": \"bar\"}\n---\na: b", 100, false, false, []generic{
348+
{"foo": "bar"},
349+
{"a": "b"},
350+
}},
351+
// First document is JSON, second is YAML,but with smaller size and
352+
// trailing whitespace.
353+
{"{\"foo\": \"bar\"} \n---\na: b", 100, false, false, []generic{
354+
{"foo": "bar"},
355+
{"a": "b"},
356+
}},
346357
// First document is JSON, second is YAML, longer than the buffer
347358
{"{\"foo\": \"bar\"}\n---\n{baz: biz0123456780123456780123456780123456780123456789}", 20, false, false, []generic{
348359
{"foo": "bar"},

0 commit comments

Comments
 (0)