Issue 1: Infinite recursion if c.cancelCtx()
If c.cancelCtx() panics and len(c.cleanups) > 0, the following happens:
- c.cancelCtx() panics
- The deferred function checks len(c.cleanups) > 0 → true
- Recursively calls runCleanup(normalPanic)
- c.cancelCtx is still not nil, calls c.cancelCtx() again
- Panics again → infinite recursion → stack overflow
Suggested fix:
if c.cancelCtx != nil {
cancel := c.cancelCtx
c.cancelCtx = nil // clear before calling to prevent repeated calls
cancel()
}
Issue 2: Incorrect nil check conflates empty slice with nil element
https://github.com/golang/go/blob/ad91f5d241f3b8e85dc866d0087c3f13af96ef33/src/testing/testing.go#L1655C1-L1668C3
The current logic cannot distinguish between:
- Case A: c.cleanups is empty (cleanup stays default nil)
- Case B: c.cleanups contains a nil function pointer
In Case B, returning early would skip remaining cleanup functions.
Suggested fix:
for {
c.mu.Lock()
if len(c.cleanups) == 0 {
c.mu.Unlock()
return nil
}
last := len(c.cleanups) - 1
cleanup := c.cleanups[last]
c.cleanups = c.cleanups[:last]
c.mu.Unlock()
if cleanup != nil {
cleanup()
}
// continue to process remaining cleanups even if this one was nil
}
Issue 1: Infinite recursion if
c.cancelCtx()go/src/testing/testing.go
Line 1651 in ad91f5d
If c.cancelCtx() panics and len(c.cleanups) > 0, the following happens:
Suggested fix:
Issue 2: Incorrect nil check conflates empty slice with nil element
https://github.com/golang/go/blob/ad91f5d241f3b8e85dc866d0087c3f13af96ef33/src/testing/testing.go#L1655C1-L1668C3
The current logic cannot distinguish between:
In Case B, returning early would skip remaining cleanup functions.
Suggested fix: