Skip to content

Commit 361f94a

Browse files
committed
Error on conversion to unstructured for invalid json.Marshalers.
If a type's implementation of json.Marshaler returns bytes representing a valid JSON object or array followed by anything other than trailing whitespace, return an error rather than ignoring the trailing data. The documentation for the Marshaler interface indicates that implementations shouldn't do this, but it is safer to check (as json.Marshal does) than to rely on it.
1 parent 92c1d38 commit 361f94a

File tree

2 files changed

+28
-3
lines changed

2 files changed

+28
-3
lines changed

Diff for: value/reflectcache.go

+12
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ package value
1919
import (
2020
"bytes"
2121
"encoding/json"
22+
"errors"
2223
"fmt"
24+
"io"
2325
"reflect"
2426
"sort"
2527
"sync"
@@ -389,6 +391,11 @@ func unmarshal(data []byte, v interface{}) error {
389391
if err := decoder.Decode(v); err != nil {
390392
return err
391393
}
394+
next := decoder.InputOffset()
395+
if _, err := decoder.Token(); !errors.Is(err, io.EOF) {
396+
tail := bytes.TrimLeft(data[next:], " \t\r\n")
397+
return fmt.Errorf("unexpected trailing data at offset %d", len(data)-len(tail))
398+
}
392399
// If the decode succeeds, post-process the map to convert json.Number objects to int64 or float64
393400
return convertMapNumbers(*v, 0)
394401

@@ -401,6 +408,11 @@ func unmarshal(data []byte, v interface{}) error {
401408
if err := decoder.Decode(v); err != nil {
402409
return err
403410
}
411+
next := decoder.InputOffset()
412+
if _, err := decoder.Token(); !errors.Is(err, io.EOF) {
413+
tail := bytes.TrimLeft(data[next:], " \t\r\n")
414+
return fmt.Errorf("unexpected trailing data at offset %d", len(data)-len(tail))
415+
}
404416
// If the decode succeeds, post-process the map to convert json.Number objects to int64 or float64
405417
return convertSliceNumbers(*v, 0)
406418

Diff for: value/reflectcache_test.go

+16-3
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,9 @@ func (t Time) ToUnstructured() interface{} {
5757

5858
func TestToUnstructured(t *testing.T) {
5959
testcases := []struct {
60-
Data string
61-
Expected interface{}
60+
Data string
61+
Expected interface{}
62+
ExpectedErrorMessage string
6263
}{
6364
{Data: `null`, Expected: nil},
6465
{Data: `true`, Expected: true},
@@ -69,6 +70,12 @@ func TestToUnstructured(t *testing.T) {
6970
{Data: `{"a":1}`, Expected: map[string]interface{}{"a": int64(1)}},
7071
{Data: `0`, Expected: int64(0)},
7172
{Data: `0.0`, Expected: float64(0)},
73+
{Data: "{} \t\r\n", Expected: map[string]interface{}{}},
74+
{Data: "{} \t\r\n}", ExpectedErrorMessage: "error decoding object from json: unexpected trailing data at offset 6"},
75+
{Data: "{} \t\r\n{}", ExpectedErrorMessage: "error decoding object from json: unexpected trailing data at offset 6"},
76+
{Data: "[] \t\r\n", Expected: []interface{}{}},
77+
{Data: "[] \t\r\n]", ExpectedErrorMessage: "error decoding array from json: unexpected trailing data at offset 6"},
78+
{Data: "[] \t\r\n[]", ExpectedErrorMessage: "error decoding array from json: unexpected trailing data at offset 6"},
7279
}
7380

7481
for _, tc := range testcases {
@@ -84,7 +91,13 @@ func TestToUnstructured(t *testing.T) {
8491
rv := reflect.ValueOf(custom)
8592
result, err := TypeReflectEntryOf(rv.Type()).ToUnstructured(rv)
8693
if err != nil {
87-
t.Fatal(err)
94+
if tc.ExpectedErrorMessage == "" {
95+
t.Fatal(err)
96+
} else if got := err.Error(); got != tc.ExpectedErrorMessage {
97+
t.Fatalf("expected error message %q but got %q", tc.ExpectedErrorMessage, got)
98+
}
99+
} else if tc.ExpectedErrorMessage != "" {
100+
t.Fatalf("expected error message %q but got nil error", tc.ExpectedErrorMessage)
88101
}
89102
if !reflect.DeepEqual(result, tc.Expected) {
90103
t.Errorf("expected %#v but got %#v", tc.Expected, result)

0 commit comments

Comments
 (0)