diff --git a/src/sync/oncefunc.go b/src/sync/oncefunc.go index c2eeb7a83e3..52daeeb767a 100644 --- a/src/sync/oncefunc.go +++ b/src/sync/oncefunc.go @@ -48,8 +48,8 @@ func OnceValue[T any](f func() T) func() T { result T ) g := func() { - f = nil // Do not keep f alive after invoking it. defer func() { + f = nil // Do not keep f alive after invoking it. p = recover() if !valid { panic(p) @@ -80,8 +80,8 @@ func OnceValues[T1, T2 any](f func() (T1, T2)) func() (T1, T2) { r2 T2 ) g := func() { - f = nil // Do not keep f alive after invoking it. defer func() { + f = nil // Do not keep f alive after invoking it. p = recover() if !valid { panic(p) diff --git a/src/sync/oncefunc_test.go b/src/sync/oncefunc_test.go index 5f0d5640631..da1094f3330 100644 --- a/src/sync/oncefunc_test.go +++ b/src/sync/oncefunc_test.go @@ -198,6 +198,18 @@ func TestOnceXGC(t *testing.T) { f := sync.OnceValues(func() (any, any) { buf[0] = 1; return nil, nil }) return func() { f() } }, + + "OnceFunc panic": func(buf []byte) func() { + return sync.OnceFunc(func() { buf[0] = 1; panic("test panic") }) + }, + "OnceValue panic": func(buf []byte) func() { + f := sync.OnceValue(func() any { buf[0] = 1; panic("test panic") }) + return func() { f() } + }, + "OnceValues panic": func(buf []byte) func() { + f := sync.OnceValues(func() (any, any) { buf[0] = 1; panic("test panic") }) + return func() { f() } + }, } for n, fn := range fns { t.Run(n, func(t *testing.T) { @@ -211,14 +223,20 @@ func TestOnceXGC(t *testing.T) { if gc.Load() != false { t.Fatal("wrapped function garbage collected too early") } - f() + func() { + defer func() { recover() }() + f() + }() gcwaitfin() if gc.Load() != true { // Even if f is still alive, the function passed to Once(Func|Value|Values) // is not kept alive after the first call to f. t.Fatal("wrapped function should be garbage collected, but still live") } - f() + func() { + defer func() { recover() }() + f() + }() }) } }