diff --git a/userdata.go b/userdata.go index 38cca86..20366b6 100644 --- a/userdata.go +++ b/userdata.go @@ -77,6 +77,8 @@ func (d *userData) Reset() { if vc, ok := v.(io.Closer); ok { vc.Close() } + (*d)[i].value = nil + (*d)[i].key = nil } *d = (*d)[:0] } @@ -92,6 +94,7 @@ func (d *userData) Remove(key any) { if kv.key == key { n-- args[i], args[n] = args[n], args[i] + args[n].key = nil args[n].value = nil args = args[:n] *d = args diff --git a/userdata_test.go b/userdata_test.go index fd6a924..1e19044 100644 --- a/userdata_test.go +++ b/userdata_test.go @@ -3,7 +3,9 @@ package fasthttp import ( "fmt" "reflect" + "runtime" "testing" + "time" ) func TestUserData(t *testing.T) { @@ -118,3 +120,32 @@ func TestUserDataSetAndRemove(t *testing.T) { testUserDataGet(t, &u, []byte(shortKey), "") testUserDataGet(t, &u, []byte(longKey), "") } + +func TestUserData_GC(t *testing.T) { + t.Parallel() + + var u userData + key := "foo" + final := make(chan struct{}) + + func() { + val := &RequestHeader{} + runtime.SetFinalizer(val, func(v *RequestHeader) { + close(final) + }) + + u.Set(key, val) + }() + + u.Reset() + runtime.GC() + + select { + case <-final: + case <-time.After(time.Second): + t.Fatalf("value is garbage collected") + } + + // Keep u alive, otherwise val will always get garbage collected. + u.Set("bar", 1) +}