diff options
| author | Michael Anthony Knyszek <mknyszek@google.com> | 2024-12-09 19:07:40 +0000 |
|---|---|---|
| committer | Gopher Robot <gobot@golang.org> | 2025-05-20 10:37:12 -0700 |
| commit | 3df078fc74a550168440d5afd5f9a9204b77f0f9 (patch) | |
| tree | b59b10a2cbc4e09c5f12ad6b10d4703eaca24960 /src/runtime/testdata | |
| parent | 2a65100e68cd82172b214a4d12cd2586c0b9ef99 (diff) | |
| download | go-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.go | 50 |
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) +} |
