summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorDean Deng <deandeng@google.com>2020-08-10 10:31:27 -0700
committergVisor bot <gvisor-bot@google.com>2020-08-10 10:33:22 -0700
commit79e7d0b06ac019e3c302e2ab9c5861311304d7d1 (patch)
treef446279a6f69206b7c473b7b51a6efa1befcc14c
parentb404b5c255214a37d7f787f9fe24bb8e22509eb4 (diff)
Run GC before sandbox exit when leak checking is enabled.
Running garbage collection enqueues all finalizers, which are used by the refs/refs_vfs2 packages to detect reference leaks. Note that even with GC, there is no guarantee that all finalizers will be run before the program exits. This is a best effort attempt to activate leak checks as much as possible. Updates #3545. PiperOrigin-RevId: 325834438
-rw-r--r--pkg/refs/refcounter.go10
-rw-r--r--runsc/boot/loader.go3
2 files changed, 13 insertions, 0 deletions
diff --git a/pkg/refs/refcounter.go b/pkg/refs/refcounter.go
index 3f39edb66..d9d5e6bcb 100644
--- a/pkg/refs/refcounter.go
+++ b/pkg/refs/refcounter.go
@@ -475,3 +475,13 @@ func (r *AtomicRefCount) DecRefWithDestructor(ctx context.Context, destroy func(
func (r *AtomicRefCount) DecRef(ctx context.Context) {
r.DecRefWithDestructor(ctx, nil)
}
+
+// OnExit is called on sandbox exit. It runs GC to enqueue refcount finalizers,
+// which check for reference leaks. There is no way to guarantee that every
+// finalizer will run before exiting, but this at least ensures that they will
+// be discovered/enqueued by GC.
+func OnExit() {
+ if LeakMode(atomic.LoadUint32(&leakMode)) != NoLeakChecking {
+ runtime.GC()
+ }
+}
diff --git a/runsc/boot/loader.go b/runsc/boot/loader.go
index 533b9c5e7..40c6f99fd 100644
--- a/runsc/boot/loader.go
+++ b/runsc/boot/loader.go
@@ -32,6 +32,7 @@ import (
"gvisor.dev/gvisor/pkg/log"
"gvisor.dev/gvisor/pkg/memutil"
"gvisor.dev/gvisor/pkg/rand"
+ "gvisor.dev/gvisor/pkg/refs"
"gvisor.dev/gvisor/pkg/sentry/arch"
"gvisor.dev/gvisor/pkg/sentry/control"
"gvisor.dev/gvisor/pkg/sentry/fdimport"
@@ -1011,6 +1012,8 @@ func (l *Loader) WaitExit() kernel.ExitStatus {
// Cleanup
l.ctrl.stop()
+ refs.OnExit()
+
return l.k.GlobalInit().ExitStatus()
}