diff options
Diffstat (limited to 'pkg/sentry/fsimpl/proc')
-rw-r--r-- | pkg/sentry/fsimpl/proc/fd_dir_inode_refs.go | 56 | ||||
-rw-r--r-- | pkg/sentry/fsimpl/proc/fd_info_dir_inode_refs.go | 56 | ||||
-rw-r--r-- | pkg/sentry/fsimpl/proc/subtasks_inode_refs.go | 56 | ||||
-rw-r--r-- | pkg/sentry/fsimpl/proc/task_inode_refs.go | 56 | ||||
-rw-r--r-- | pkg/sentry/fsimpl/proc/tasks_inode_refs.go | 56 |
5 files changed, 180 insertions, 100 deletions
diff --git a/pkg/sentry/fsimpl/proc/fd_dir_inode_refs.go b/pkg/sentry/fsimpl/proc/fd_dir_inode_refs.go index 2f0dd126e..895298eb9 100644 --- a/pkg/sentry/fsimpl/proc/fd_dir_inode_refs.go +++ b/pkg/sentry/fsimpl/proc/fd_dir_inode_refs.go @@ -7,9 +7,15 @@ import ( "gvisor.dev/gvisor/pkg/refsvfs2" ) -// ownerType is used to customize logging. Note that we use a pointer to T so -// that we do not copy the entire object when passed as a format parameter. -var fdDirInodeownerType *fdDirInode +// enableLogging indicates whether reference-related events should be logged (with +// stack traces). This is false by default and should only be set to true for +// debugging purposes, as it can generate an extremely large amount of output +// and drastically degrade performance. +const fdDirInodeenableLogging = false + +// obj is used to customize logging. Note that we use a pointer to T so that +// we do not copy the entire object when passed as a format parameter. +var fdDirInodeobj *fdDirInode // Refs implements refs.RefCounter. It keeps a reference count using atomic // operations and calls the destructor when the count reaches zero. @@ -29,16 +35,24 @@ type fdDirInodeRefs struct { refCount int64 } -// EnableLeakCheck enables reference leak checking on r. -func (r *fdDirInodeRefs) EnableLeakCheck() { - if refsvfs2.LeakCheckEnabled() { - refsvfs2.Register(r, fmt.Sprintf("%T", fdDirInodeownerType)) - } +// RefType implements refsvfs2.CheckedObject.RefType. +func (r *fdDirInodeRefs) RefType() string { + return fmt.Sprintf("%T", fdDirInodeobj)[1:] } // LeakMessage implements refsvfs2.CheckedObject.LeakMessage. func (r *fdDirInodeRefs) LeakMessage() string { - return fmt.Sprintf("%T %p: reference count of %d instead of 0", fdDirInodeownerType, r, r.ReadRefs()) + return fmt.Sprintf("[%s %p] reference count of %d instead of 0", r.RefType(), r, r.ReadRefs()) +} + +// LogRefs implements refsvfs2.CheckedObject.LogRefs. +func (r *fdDirInodeRefs) LogRefs() bool { + return fdDirInodeenableLogging +} + +// EnableLeakCheck enables reference leak checking on r. +func (r *fdDirInodeRefs) EnableLeakCheck() { + refsvfs2.Register(r) } // ReadRefs returns the current number of references. The returned count is @@ -52,8 +66,10 @@ func (r *fdDirInodeRefs) ReadRefs() int64 { // //go:nosplit func (r *fdDirInodeRefs) IncRef() { - if v := atomic.AddInt64(&r.refCount, 1); v <= 0 { - panic(fmt.Sprintf("Incrementing non-positive count %p on %T", r, fdDirInodeownerType)) + v := atomic.AddInt64(&r.refCount, 1) + refsvfs2.LogIncRef(r, v+1) + if v <= 0 { + panic(fmt.Sprintf("Incrementing non-positive count %p on %s", r, r.RefType())) } } @@ -66,14 +82,14 @@ func (r *fdDirInodeRefs) IncRef() { //go:nosplit func (r *fdDirInodeRefs) TryIncRef() bool { const speculativeRef = 1 << 32 - v := atomic.AddInt64(&r.refCount, speculativeRef) - if int32(v) < 0 { + if v := atomic.AddInt64(&r.refCount, speculativeRef); int32(v) < 0 { atomic.AddInt64(&r.refCount, -speculativeRef) return false } - atomic.AddInt64(&r.refCount, -speculativeRef+1) + v := atomic.AddInt64(&r.refCount, -speculativeRef+1) + refsvfs2.LogTryIncRef(r, v+1) return true } @@ -90,14 +106,14 @@ func (r *fdDirInodeRefs) TryIncRef() bool { // //go:nosplit func (r *fdDirInodeRefs) DecRef(destroy func()) { - switch v := atomic.AddInt64(&r.refCount, -1); { + v := atomic.AddInt64(&r.refCount, -1) + refsvfs2.LogDecRef(r, v+1) + switch { case v < -1: - panic(fmt.Sprintf("Decrementing non-positive ref count %p, owned by %T", r, fdDirInodeownerType)) + panic(fmt.Sprintf("Decrementing non-positive ref count %p, owned by %s", r, r.RefType())) case v == -1: - if refsvfs2.LeakCheckEnabled() { - refsvfs2.Unregister(r, fmt.Sprintf("%T", fdDirInodeownerType)) - } + refsvfs2.Unregister(r) if destroy != nil { destroy() @@ -106,7 +122,7 @@ func (r *fdDirInodeRefs) DecRef(destroy func()) { } func (r *fdDirInodeRefs) afterLoad() { - if refsvfs2.LeakCheckEnabled() && r.ReadRefs() > 0 { + if r.ReadRefs() > 0 { r.EnableLeakCheck() } } diff --git a/pkg/sentry/fsimpl/proc/fd_info_dir_inode_refs.go b/pkg/sentry/fsimpl/proc/fd_info_dir_inode_refs.go index 2065c97b4..8e3458485 100644 --- a/pkg/sentry/fsimpl/proc/fd_info_dir_inode_refs.go +++ b/pkg/sentry/fsimpl/proc/fd_info_dir_inode_refs.go @@ -7,9 +7,15 @@ import ( "gvisor.dev/gvisor/pkg/refsvfs2" ) -// ownerType is used to customize logging. Note that we use a pointer to T so -// that we do not copy the entire object when passed as a format parameter. -var fdInfoDirInodeownerType *fdInfoDirInode +// enableLogging indicates whether reference-related events should be logged (with +// stack traces). This is false by default and should only be set to true for +// debugging purposes, as it can generate an extremely large amount of output +// and drastically degrade performance. +const fdInfoDirInodeenableLogging = false + +// obj is used to customize logging. Note that we use a pointer to T so that +// we do not copy the entire object when passed as a format parameter. +var fdInfoDirInodeobj *fdInfoDirInode // Refs implements refs.RefCounter. It keeps a reference count using atomic // operations and calls the destructor when the count reaches zero. @@ -29,16 +35,24 @@ type fdInfoDirInodeRefs struct { refCount int64 } -// EnableLeakCheck enables reference leak checking on r. -func (r *fdInfoDirInodeRefs) EnableLeakCheck() { - if refsvfs2.LeakCheckEnabled() { - refsvfs2.Register(r, fmt.Sprintf("%T", fdInfoDirInodeownerType)) - } +// RefType implements refsvfs2.CheckedObject.RefType. +func (r *fdInfoDirInodeRefs) RefType() string { + return fmt.Sprintf("%T", fdInfoDirInodeobj)[1:] } // LeakMessage implements refsvfs2.CheckedObject.LeakMessage. func (r *fdInfoDirInodeRefs) LeakMessage() string { - return fmt.Sprintf("%T %p: reference count of %d instead of 0", fdInfoDirInodeownerType, r, r.ReadRefs()) + return fmt.Sprintf("[%s %p] reference count of %d instead of 0", r.RefType(), r, r.ReadRefs()) +} + +// LogRefs implements refsvfs2.CheckedObject.LogRefs. +func (r *fdInfoDirInodeRefs) LogRefs() bool { + return fdInfoDirInodeenableLogging +} + +// EnableLeakCheck enables reference leak checking on r. +func (r *fdInfoDirInodeRefs) EnableLeakCheck() { + refsvfs2.Register(r) } // ReadRefs returns the current number of references. The returned count is @@ -52,8 +66,10 @@ func (r *fdInfoDirInodeRefs) ReadRefs() int64 { // //go:nosplit func (r *fdInfoDirInodeRefs) IncRef() { - if v := atomic.AddInt64(&r.refCount, 1); v <= 0 { - panic(fmt.Sprintf("Incrementing non-positive count %p on %T", r, fdInfoDirInodeownerType)) + v := atomic.AddInt64(&r.refCount, 1) + refsvfs2.LogIncRef(r, v+1) + if v <= 0 { + panic(fmt.Sprintf("Incrementing non-positive count %p on %s", r, r.RefType())) } } @@ -66,14 +82,14 @@ func (r *fdInfoDirInodeRefs) IncRef() { //go:nosplit func (r *fdInfoDirInodeRefs) TryIncRef() bool { const speculativeRef = 1 << 32 - v := atomic.AddInt64(&r.refCount, speculativeRef) - if int32(v) < 0 { + if v := atomic.AddInt64(&r.refCount, speculativeRef); int32(v) < 0 { atomic.AddInt64(&r.refCount, -speculativeRef) return false } - atomic.AddInt64(&r.refCount, -speculativeRef+1) + v := atomic.AddInt64(&r.refCount, -speculativeRef+1) + refsvfs2.LogTryIncRef(r, v+1) return true } @@ -90,14 +106,14 @@ func (r *fdInfoDirInodeRefs) TryIncRef() bool { // //go:nosplit func (r *fdInfoDirInodeRefs) DecRef(destroy func()) { - switch v := atomic.AddInt64(&r.refCount, -1); { + v := atomic.AddInt64(&r.refCount, -1) + refsvfs2.LogDecRef(r, v+1) + switch { case v < -1: - panic(fmt.Sprintf("Decrementing non-positive ref count %p, owned by %T", r, fdInfoDirInodeownerType)) + panic(fmt.Sprintf("Decrementing non-positive ref count %p, owned by %s", r, r.RefType())) case v == -1: - if refsvfs2.LeakCheckEnabled() { - refsvfs2.Unregister(r, fmt.Sprintf("%T", fdInfoDirInodeownerType)) - } + refsvfs2.Unregister(r) if destroy != nil { destroy() @@ -106,7 +122,7 @@ func (r *fdInfoDirInodeRefs) DecRef(destroy func()) { } func (r *fdInfoDirInodeRefs) afterLoad() { - if refsvfs2.LeakCheckEnabled() && r.ReadRefs() > 0 { + if r.ReadRefs() > 0 { r.EnableLeakCheck() } } diff --git a/pkg/sentry/fsimpl/proc/subtasks_inode_refs.go b/pkg/sentry/fsimpl/proc/subtasks_inode_refs.go index c4c0baf31..c609e618a 100644 --- a/pkg/sentry/fsimpl/proc/subtasks_inode_refs.go +++ b/pkg/sentry/fsimpl/proc/subtasks_inode_refs.go @@ -7,9 +7,15 @@ import ( "gvisor.dev/gvisor/pkg/refsvfs2" ) -// ownerType is used to customize logging. Note that we use a pointer to T so -// that we do not copy the entire object when passed as a format parameter. -var subtasksInodeownerType *subtasksInode +// enableLogging indicates whether reference-related events should be logged (with +// stack traces). This is false by default and should only be set to true for +// debugging purposes, as it can generate an extremely large amount of output +// and drastically degrade performance. +const subtasksInodeenableLogging = false + +// obj is used to customize logging. Note that we use a pointer to T so that +// we do not copy the entire object when passed as a format parameter. +var subtasksInodeobj *subtasksInode // Refs implements refs.RefCounter. It keeps a reference count using atomic // operations and calls the destructor when the count reaches zero. @@ -29,16 +35,24 @@ type subtasksInodeRefs struct { refCount int64 } -// EnableLeakCheck enables reference leak checking on r. -func (r *subtasksInodeRefs) EnableLeakCheck() { - if refsvfs2.LeakCheckEnabled() { - refsvfs2.Register(r, fmt.Sprintf("%T", subtasksInodeownerType)) - } +// RefType implements refsvfs2.CheckedObject.RefType. +func (r *subtasksInodeRefs) RefType() string { + return fmt.Sprintf("%T", subtasksInodeobj)[1:] } // LeakMessage implements refsvfs2.CheckedObject.LeakMessage. func (r *subtasksInodeRefs) LeakMessage() string { - return fmt.Sprintf("%T %p: reference count of %d instead of 0", subtasksInodeownerType, r, r.ReadRefs()) + return fmt.Sprintf("[%s %p] reference count of %d instead of 0", r.RefType(), r, r.ReadRefs()) +} + +// LogRefs implements refsvfs2.CheckedObject.LogRefs. +func (r *subtasksInodeRefs) LogRefs() bool { + return subtasksInodeenableLogging +} + +// EnableLeakCheck enables reference leak checking on r. +func (r *subtasksInodeRefs) EnableLeakCheck() { + refsvfs2.Register(r) } // ReadRefs returns the current number of references. The returned count is @@ -52,8 +66,10 @@ func (r *subtasksInodeRefs) ReadRefs() int64 { // //go:nosplit func (r *subtasksInodeRefs) IncRef() { - if v := atomic.AddInt64(&r.refCount, 1); v <= 0 { - panic(fmt.Sprintf("Incrementing non-positive count %p on %T", r, subtasksInodeownerType)) + v := atomic.AddInt64(&r.refCount, 1) + refsvfs2.LogIncRef(r, v+1) + if v <= 0 { + panic(fmt.Sprintf("Incrementing non-positive count %p on %s", r, r.RefType())) } } @@ -66,14 +82,14 @@ func (r *subtasksInodeRefs) IncRef() { //go:nosplit func (r *subtasksInodeRefs) TryIncRef() bool { const speculativeRef = 1 << 32 - v := atomic.AddInt64(&r.refCount, speculativeRef) - if int32(v) < 0 { + if v := atomic.AddInt64(&r.refCount, speculativeRef); int32(v) < 0 { atomic.AddInt64(&r.refCount, -speculativeRef) return false } - atomic.AddInt64(&r.refCount, -speculativeRef+1) + v := atomic.AddInt64(&r.refCount, -speculativeRef+1) + refsvfs2.LogTryIncRef(r, v+1) return true } @@ -90,14 +106,14 @@ func (r *subtasksInodeRefs) TryIncRef() bool { // //go:nosplit func (r *subtasksInodeRefs) DecRef(destroy func()) { - switch v := atomic.AddInt64(&r.refCount, -1); { + v := atomic.AddInt64(&r.refCount, -1) + refsvfs2.LogDecRef(r, v+1) + switch { case v < -1: - panic(fmt.Sprintf("Decrementing non-positive ref count %p, owned by %T", r, subtasksInodeownerType)) + panic(fmt.Sprintf("Decrementing non-positive ref count %p, owned by %s", r, r.RefType())) case v == -1: - if refsvfs2.LeakCheckEnabled() { - refsvfs2.Unregister(r, fmt.Sprintf("%T", subtasksInodeownerType)) - } + refsvfs2.Unregister(r) if destroy != nil { destroy() @@ -106,7 +122,7 @@ func (r *subtasksInodeRefs) DecRef(destroy func()) { } func (r *subtasksInodeRefs) afterLoad() { - if refsvfs2.LeakCheckEnabled() && r.ReadRefs() > 0 { + if r.ReadRefs() > 0 { r.EnableLeakCheck() } } diff --git a/pkg/sentry/fsimpl/proc/task_inode_refs.go b/pkg/sentry/fsimpl/proc/task_inode_refs.go index 67638f6ae..2ee58bd62 100644 --- a/pkg/sentry/fsimpl/proc/task_inode_refs.go +++ b/pkg/sentry/fsimpl/proc/task_inode_refs.go @@ -7,9 +7,15 @@ import ( "gvisor.dev/gvisor/pkg/refsvfs2" ) -// ownerType is used to customize logging. Note that we use a pointer to T so -// that we do not copy the entire object when passed as a format parameter. -var taskInodeownerType *taskInode +// enableLogging indicates whether reference-related events should be logged (with +// stack traces). This is false by default and should only be set to true for +// debugging purposes, as it can generate an extremely large amount of output +// and drastically degrade performance. +const taskInodeenableLogging = false + +// obj is used to customize logging. Note that we use a pointer to T so that +// we do not copy the entire object when passed as a format parameter. +var taskInodeobj *taskInode // Refs implements refs.RefCounter. It keeps a reference count using atomic // operations and calls the destructor when the count reaches zero. @@ -29,16 +35,24 @@ type taskInodeRefs struct { refCount int64 } -// EnableLeakCheck enables reference leak checking on r. -func (r *taskInodeRefs) EnableLeakCheck() { - if refsvfs2.LeakCheckEnabled() { - refsvfs2.Register(r, fmt.Sprintf("%T", taskInodeownerType)) - } +// RefType implements refsvfs2.CheckedObject.RefType. +func (r *taskInodeRefs) RefType() string { + return fmt.Sprintf("%T", taskInodeobj)[1:] } // LeakMessage implements refsvfs2.CheckedObject.LeakMessage. func (r *taskInodeRefs) LeakMessage() string { - return fmt.Sprintf("%T %p: reference count of %d instead of 0", taskInodeownerType, r, r.ReadRefs()) + return fmt.Sprintf("[%s %p] reference count of %d instead of 0", r.RefType(), r, r.ReadRefs()) +} + +// LogRefs implements refsvfs2.CheckedObject.LogRefs. +func (r *taskInodeRefs) LogRefs() bool { + return taskInodeenableLogging +} + +// EnableLeakCheck enables reference leak checking on r. +func (r *taskInodeRefs) EnableLeakCheck() { + refsvfs2.Register(r) } // ReadRefs returns the current number of references. The returned count is @@ -52,8 +66,10 @@ func (r *taskInodeRefs) ReadRefs() int64 { // //go:nosplit func (r *taskInodeRefs) IncRef() { - if v := atomic.AddInt64(&r.refCount, 1); v <= 0 { - panic(fmt.Sprintf("Incrementing non-positive count %p on %T", r, taskInodeownerType)) + v := atomic.AddInt64(&r.refCount, 1) + refsvfs2.LogIncRef(r, v+1) + if v <= 0 { + panic(fmt.Sprintf("Incrementing non-positive count %p on %s", r, r.RefType())) } } @@ -66,14 +82,14 @@ func (r *taskInodeRefs) IncRef() { //go:nosplit func (r *taskInodeRefs) TryIncRef() bool { const speculativeRef = 1 << 32 - v := atomic.AddInt64(&r.refCount, speculativeRef) - if int32(v) < 0 { + if v := atomic.AddInt64(&r.refCount, speculativeRef); int32(v) < 0 { atomic.AddInt64(&r.refCount, -speculativeRef) return false } - atomic.AddInt64(&r.refCount, -speculativeRef+1) + v := atomic.AddInt64(&r.refCount, -speculativeRef+1) + refsvfs2.LogTryIncRef(r, v+1) return true } @@ -90,14 +106,14 @@ func (r *taskInodeRefs) TryIncRef() bool { // //go:nosplit func (r *taskInodeRefs) DecRef(destroy func()) { - switch v := atomic.AddInt64(&r.refCount, -1); { + v := atomic.AddInt64(&r.refCount, -1) + refsvfs2.LogDecRef(r, v+1) + switch { case v < -1: - panic(fmt.Sprintf("Decrementing non-positive ref count %p, owned by %T", r, taskInodeownerType)) + panic(fmt.Sprintf("Decrementing non-positive ref count %p, owned by %s", r, r.RefType())) case v == -1: - if refsvfs2.LeakCheckEnabled() { - refsvfs2.Unregister(r, fmt.Sprintf("%T", taskInodeownerType)) - } + refsvfs2.Unregister(r) if destroy != nil { destroy() @@ -106,7 +122,7 @@ func (r *taskInodeRefs) DecRef(destroy func()) { } func (r *taskInodeRefs) afterLoad() { - if refsvfs2.LeakCheckEnabled() && r.ReadRefs() > 0 { + if r.ReadRefs() > 0 { r.EnableLeakCheck() } } diff --git a/pkg/sentry/fsimpl/proc/tasks_inode_refs.go b/pkg/sentry/fsimpl/proc/tasks_inode_refs.go index b882335d7..71dcaed9e 100644 --- a/pkg/sentry/fsimpl/proc/tasks_inode_refs.go +++ b/pkg/sentry/fsimpl/proc/tasks_inode_refs.go @@ -7,9 +7,15 @@ import ( "gvisor.dev/gvisor/pkg/refsvfs2" ) -// ownerType is used to customize logging. Note that we use a pointer to T so -// that we do not copy the entire object when passed as a format parameter. -var tasksInodeownerType *tasksInode +// enableLogging indicates whether reference-related events should be logged (with +// stack traces). This is false by default and should only be set to true for +// debugging purposes, as it can generate an extremely large amount of output +// and drastically degrade performance. +const tasksInodeenableLogging = false + +// obj is used to customize logging. Note that we use a pointer to T so that +// we do not copy the entire object when passed as a format parameter. +var tasksInodeobj *tasksInode // Refs implements refs.RefCounter. It keeps a reference count using atomic // operations and calls the destructor when the count reaches zero. @@ -29,16 +35,24 @@ type tasksInodeRefs struct { refCount int64 } -// EnableLeakCheck enables reference leak checking on r. -func (r *tasksInodeRefs) EnableLeakCheck() { - if refsvfs2.LeakCheckEnabled() { - refsvfs2.Register(r, fmt.Sprintf("%T", tasksInodeownerType)) - } +// RefType implements refsvfs2.CheckedObject.RefType. +func (r *tasksInodeRefs) RefType() string { + return fmt.Sprintf("%T", tasksInodeobj)[1:] } // LeakMessage implements refsvfs2.CheckedObject.LeakMessage. func (r *tasksInodeRefs) LeakMessage() string { - return fmt.Sprintf("%T %p: reference count of %d instead of 0", tasksInodeownerType, r, r.ReadRefs()) + return fmt.Sprintf("[%s %p] reference count of %d instead of 0", r.RefType(), r, r.ReadRefs()) +} + +// LogRefs implements refsvfs2.CheckedObject.LogRefs. +func (r *tasksInodeRefs) LogRefs() bool { + return tasksInodeenableLogging +} + +// EnableLeakCheck enables reference leak checking on r. +func (r *tasksInodeRefs) EnableLeakCheck() { + refsvfs2.Register(r) } // ReadRefs returns the current number of references. The returned count is @@ -52,8 +66,10 @@ func (r *tasksInodeRefs) ReadRefs() int64 { // //go:nosplit func (r *tasksInodeRefs) IncRef() { - if v := atomic.AddInt64(&r.refCount, 1); v <= 0 { - panic(fmt.Sprintf("Incrementing non-positive count %p on %T", r, tasksInodeownerType)) + v := atomic.AddInt64(&r.refCount, 1) + refsvfs2.LogIncRef(r, v+1) + if v <= 0 { + panic(fmt.Sprintf("Incrementing non-positive count %p on %s", r, r.RefType())) } } @@ -66,14 +82,14 @@ func (r *tasksInodeRefs) IncRef() { //go:nosplit func (r *tasksInodeRefs) TryIncRef() bool { const speculativeRef = 1 << 32 - v := atomic.AddInt64(&r.refCount, speculativeRef) - if int32(v) < 0 { + if v := atomic.AddInt64(&r.refCount, speculativeRef); int32(v) < 0 { atomic.AddInt64(&r.refCount, -speculativeRef) return false } - atomic.AddInt64(&r.refCount, -speculativeRef+1) + v := atomic.AddInt64(&r.refCount, -speculativeRef+1) + refsvfs2.LogTryIncRef(r, v+1) return true } @@ -90,14 +106,14 @@ func (r *tasksInodeRefs) TryIncRef() bool { // //go:nosplit func (r *tasksInodeRefs) DecRef(destroy func()) { - switch v := atomic.AddInt64(&r.refCount, -1); { + v := atomic.AddInt64(&r.refCount, -1) + refsvfs2.LogDecRef(r, v+1) + switch { case v < -1: - panic(fmt.Sprintf("Decrementing non-positive ref count %p, owned by %T", r, tasksInodeownerType)) + panic(fmt.Sprintf("Decrementing non-positive ref count %p, owned by %s", r, r.RefType())) case v == -1: - if refsvfs2.LeakCheckEnabled() { - refsvfs2.Unregister(r, fmt.Sprintf("%T", tasksInodeownerType)) - } + refsvfs2.Unregister(r) if destroy != nil { destroy() @@ -106,7 +122,7 @@ func (r *tasksInodeRefs) DecRef(destroy func()) { } func (r *tasksInodeRefs) afterLoad() { - if refsvfs2.LeakCheckEnabled() && r.ReadRefs() > 0 { + if r.ReadRefs() > 0 { r.EnableLeakCheck() } } |