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
No known key found for this signature in database
GPG Key ID: A6551E73A5974C30
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)
}
}