goccy / go-json

Fast JSON encoder/decoder compatible with encoding/json for Go
MIT License
3.12k stars 148 forks source link

Runtime context is not reset before released to the pool #499

Open lovromazgon opened 9 months ago

lovromazgon commented 9 months ago

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))
    }
}

Results in:

    context_test.go:34: expected "foo", got "bar"