aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/testdata
diff options
context:
space:
mode:
authorMichael Anthony Knyszek <mknyszek@google.com>2024-12-09 19:07:40 +0000
committerGopher Robot <gobot@golang.org>2025-05-20 10:37:12 -0700
commit3df078fc74a550168440d5afd5f9a9204b77f0f9 (patch)
treeb59b10a2cbc4e09c5f12ad6b10d4703eaca24960 /src/runtime/testdata
parent2a65100e68cd82172b214a4d12cd2586c0b9ef99 (diff)
downloadgo-3df078fc74a550168440d5afd5f9a9204b77f0f9.tar.xz
runtime: add new GODEBUG checkfinalizer
This new debug mode detects cleanup/finalizer leaks using checkmark mode. It runs a partial GC using only specials as roots. If the GC can find a path from one of these roots back to the object the special is attached to, then the object might never be reclaimed. (The cycle could be broken in the future, but it's almost certainly a bug.) This debug mode is very barebones. It contains no type information and no stack location for where the finalizer or cleanup was created. For #72949. Change-Id: Ibffd64c1380b51f281950e4cfe61f677385d42a5 Reviewed-on: https://go-review.googlesource.com/c/go/+/634599 Reviewed-by: Carlos Amedee <carlos@golang.org> Reviewed-by: Michael Pratt <mpratt@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Auto-Submit: Michael Knyszek <mknyszek@google.com>
Diffstat (limited to 'src/runtime/testdata')
-rw-r--r--src/runtime/testdata/testprog/checkfinalizers.go50
1 files changed, 50 insertions, 0 deletions
diff --git a/src/runtime/testdata/testprog/checkfinalizers.go b/src/runtime/testdata/testprog/checkfinalizers.go
new file mode 100644
index 0000000000..ef0108a7e0
--- /dev/null
+++ b/src/runtime/testdata/testprog/checkfinalizers.go
@@ -0,0 +1,50 @@
+// Copyright 2024 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "runtime"
+)
+
+func init() {
+ register("DetectFinalizerAndCleanupLeaks", DetectFinalizerAndCleanupLeaks)
+}
+
+// Intended to be run only with `GODEBUG=checkfinalizers=1`.
+func DetectFinalizerAndCleanupLeaks() {
+ type T *int
+
+ // Leak a cleanup.
+ cLeak := new(T)
+ runtime.AddCleanup(cLeak, func(x int) {
+ **cLeak = x
+ }, int(0))
+
+ // Have a regular cleanup to make sure it doesn't trip the detector.
+ cNoLeak := new(T)
+ runtime.AddCleanup(cNoLeak, func(_ int) {}, int(0))
+
+ // Leak a finalizer.
+ fLeak := new(T)
+ runtime.SetFinalizer(fLeak, func(_ *T) {
+ **fLeak = 12
+ })
+
+ // Have a regular finalizer to make sure it doesn't trip the detector.
+ fNoLeak := new(T)
+ runtime.SetFinalizer(fNoLeak, func(x *T) {
+ **x = 51
+ })
+
+ // runtime.GC here should crash.
+ runtime.GC()
+ println("OK")
+
+ // Keep everything alive.
+ runtime.KeepAlive(cLeak)
+ runtime.KeepAlive(cNoLeak)
+ runtime.KeepAlive(fLeak)
+ runtime.KeepAlive(fNoLeak)
+}