When RuntimeContext is released back into the pool (here), it is not reset, which can cause the context passed to json.MarshalContext to be leaked into a different call to json.Marshal.
Failing test:
type Foo struct{}
func (Foo) MarshalJSON(ctx context.Context) ([]byte, error) {
if ctx != nil {
if val := ctx.Value("ctxKey"); val != nil {
return []byte(`"` + val.(string) + `"`), nil
}
}
return []byte(`"foo"`), nil
}
func TestContext(t *testing.T) {
foo := Foo{}
// first marshal with context
ctx := context.WithValue(context.Background(), "ctxKey", "bar")
out, _ := json.MarshalContext(ctx, foo)
if string(out) != `"bar"` {
t.Fatalf(`expected "bar", got %v`, string(out))
}
// second marshal without context (bug: it actually uses the previous context)
out, _ = json.Marshal(foo)
if string(out) != `"foo"` {
t.Fatalf(`expected "foo", got %v`, string(out))
}
}
When
RuntimeContext
is released back into the pool (here), it is not reset, which can cause the context passed tojson.MarshalContext
to be leaked into a different call tojson.Marshal
.Failing test:
Results in: