Copy input to UnmarshalJSON on the apiextensions JSON types.

According to the contract of json.Unmarshaler: "UnmarshalJSON must copy the JSON data if it wishes
to retain the data after returning." If the input is not copied, the underlying array of Raw could
be reused by the caller of UnmarshalJSON, and any modifications would be visible in Raw (and vice
versa).
This commit is contained in:
Ben Luddy
2024-06-20 13:35:47 -04:00
parent 3ee4d98364
commit dda4b0d838
4 changed files with 44 additions and 2 deletions

View File

@@ -130,7 +130,7 @@ func (s JSON) MarshalJSON() ([]byte, error) {
func (s *JSON) UnmarshalJSON(data []byte) error {
if len(data) > 0 && !bytes.Equal(data, nullLiteral) {
s.Raw = data
s.Raw = append(s.Raw[0:0], data...)
}
return nil
}

View File

@@ -148,3 +148,24 @@ func TestJSONSchemaPropsOrArrayMarshalJSON(t *testing.T) {
}
}
}
func TestJSONUnderlyingArrayReuse(t *testing.T) {
const want = `{"foo":"bar"}`
b := []byte(want)
var s JSON
if err := s.UnmarshalJSON(b); err != nil {
t.Fatalf("unexpected error: %v", err)
}
// Underlying array is modified.
copy(b[2:5], "bar")
copy(b[8:11], "foo")
// If UnmarshalJSON copied the bytes of its argument, then it should not have been affected
// by the mutation.
if got := string(s.Raw); got != want {
t.Errorf("unexpected mutation, got %s want %s", got, want)
}
}

View File

@@ -130,7 +130,7 @@ func (s JSON) MarshalJSON() ([]byte, error) {
func (s *JSON) UnmarshalJSON(data []byte) error {
if len(data) > 0 && !bytes.Equal(data, nullLiteral) {
s.Raw = data
s.Raw = append(s.Raw[0:0], data...)
}
return nil
}

View File

@@ -148,3 +148,24 @@ func TestJSONSchemaPropsOrArrayMarshalJSON(t *testing.T) {
}
}
}
func TestJSONUnderlyingArrayReuse(t *testing.T) {
const want = `{"foo":"bar"}`
b := []byte(want)
var s JSON
if err := s.UnmarshalJSON(b); err != nil {
t.Fatalf("unexpected error: %v", err)
}
// Underlying array is modified.
copy(b[2:5], "bar")
copy(b[8:11], "foo")
// If UnmarshalJSON copied the bytes of its argument, then it should not have been affected
// by the mutation.
if got := string(s.Raw); got != want {
t.Errorf("unexpected mutation, got %s want %s", got, want)
}
}