Skip to content

Commit 33d3d2b

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 33d3d2b

File tree

2 files changed

+20
-3
lines changed

2 files changed

+20
-3
lines changed

Diff for: value/reflectcache.go

+8
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,9 @@ func unmarshal(data []byte, v interface{}) error {
389391
if err := decoder.Decode(v); err != nil {
390392
return err
391393
}
394+
if _, err := decoder.Token(); !errors.Is(err, io.EOF) {
395+
return errors.New("unexpected trailing data after object end")
396+
}
392397
// If the decode succeeds, post-process the map to convert json.Number objects to int64 or float64
393398
return convertMapNumbers(*v, 0)
394399

@@ -401,6 +406,9 @@ func unmarshal(data []byte, v interface{}) error {
401406
if err := decoder.Decode(v); err != nil {
402407
return err
403408
}
409+
if _, err := decoder.Token(); !errors.Is(err, io.EOF) {
410+
return errors.New("unexpected trailing data after array end")
411+
}
404412
// If the decode succeeds, post-process the map to convert json.Number objects to int64 or float64
405413
return convertSliceNumbers(*v, 0)
406414

Diff for: value/reflectcache_test.go

+12-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,8 @@ 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: `{}}`, ExpectedErrorMessage: "error decoding object from json: unexpected trailing data after object end"},
74+
{Data: `[]]`, ExpectedErrorMessage: "error decoding array from json: unexpected trailing data after array end"},
7275
}
7376

7477
for _, tc := range testcases {
@@ -84,7 +87,13 @@ func TestToUnstructured(t *testing.T) {
8487
rv := reflect.ValueOf(custom)
8588
result, err := TypeReflectEntryOf(rv.Type()).ToUnstructured(rv)
8689
if err != nil {
87-
t.Fatal(err)
90+
if tc.ExpectedErrorMessage == "" {
91+
t.Fatal(err)
92+
} else if got := err.Error(); got != tc.ExpectedErrorMessage {
93+
t.Fatalf("expected error message %q but got %q", tc.ExpectedErrorMessage, got)
94+
}
95+
} else if tc.ExpectedErrorMessage != "" {
96+
t.Fatalf("expected error message %q but got nil error", tc.ExpectedErrorMessage)
8897
}
8998
if !reflect.DeepEqual(result, tc.Expected) {
9099
t.Errorf("expected %#v but got %#v", tc.Expected, result)

0 commit comments

Comments
 (0)