Description
Throughout the codebase, sync.Pool.Get() results are cast to concrete types using bare type assertions (no comma-ok):
zr := v.(*brotli.Reader) // panics if v is wrong type
sw := v.(stackless.Writer) // panics if v is wrong type
If a pool is ever corrupted (wrong type Put back, double-release, or nil stored where a typed value is expected), these panic immediately with no recovery context — crashing the server.
Affected Locations (44 instances)
| File |
Line |
Assertion |
stream.go |
39 |
v.(*bufio.Writer) |
brotli.go |
31, 53, 73, 148 |
v.(*brotli.Reader), v.(stackless.Writer), v.(*brotli.Writer), ctxv.(*compressCtx) |
compress.go |
31, 54, 86, 116, 193, 300, 398, 428 |
v.(*gzip.Reader), v.(io.ReadCloser), v.(stackless.Writer), v.(*gzip.Writer), ctxv.(*compressCtx), v.(*zlib.Writer) |
zstd.go |
33, 53, 76, 128 |
v.(*zstd.Decoder), v.(stackless.Writer), v.(*zstd.Encoder), ctxv.(*compressCtx) |
http.go |
1700, 1718 |
v.(*statsWriter), v.(*bufio.Writer) |
server.go |
42, 2278, 2727, 2829, 2847, 2866 |
v.(*Server), v.(*atomic.Int64), v.(*hijackConn), v.(*bufio.Reader), v.(*bufio.Writer), v.(*RequestCtx) |
timer.go |
40 |
v.(*time.Timer) |
peripconn.go |
67, 81 |
v.(*perIPTLSConn), v.(*perIPConn) |
fs.go |
655, 1933 |
v.(*fsSmallFileReader), v.(*sync.Mutex) |
client.go |
1343, 1365, 1933, 2000, 2028, 2654 |
v.(*Request), v.(*Response), v.(*clientConn), v.(*bufio.Writer), v.(*bufio.Reader), v.(*pipelineWork) |
fasthttpproxy/dialer.go |
252 |
v.(*proxyInfo) |
workerpool.go |
195 |
vch.(*workerChan) |
stackless/func.go |
67 |
v.(*funcWork) |
stackless/writer.go |
123 |
ctx.(*writer) |
Current State
All are guarded by preceding nil checks and pool types are controlled (only known types are Put back). However:
- No compile-time safety — a refactoring mistake silently becomes a runtime panic
forcetypeassert linter is explicitly disabled in .golangci.yml (line 15), which would catch exactly this class of bug
- No debug context when panic occurs — bare assertion panics give only the type mismatch, not which pool or why
Suggested Fix
Option A (minimal): Re-enable the forcetypeassert linter with //nolint:forcetypeassert annotations on the known-safe pool assertions. This ensures new non-pool assertions are caught in CI.
Option B (robust): Wrap pool assertions in a helper:
func poolGet[T any](p *sync.Pool) T {
v := p.Get()
if v == nil {
var zero T
return zero
}
t, ok := v.(T)
if !ok {
panic(fmt.Sprintf("BUG: pool corruption: expected %T, got %T", zero, v))
}
return t
}
This provides a clear diagnostic message instead of a bare type assertion panic.
Impact
- Low probability today (controlled pool types), but HIGH severity when triggered — unhandled panic crashes the server
- Disabling
forcetypeassert means future regressions in non-pool code won't be caught by CI
Description
Throughout the codebase,
sync.Pool.Get()results are cast to concrete types using bare type assertions (no comma-ok):If a pool is ever corrupted (wrong type Put back, double-release, or nil stored where a typed value is expected), these panic immediately with no recovery context — crashing the server.
Affected Locations (44 instances)
stream.gov.(*bufio.Writer)brotli.gov.(*brotli.Reader),v.(stackless.Writer),v.(*brotli.Writer),ctxv.(*compressCtx)compress.gov.(*gzip.Reader),v.(io.ReadCloser),v.(stackless.Writer),v.(*gzip.Writer),ctxv.(*compressCtx),v.(*zlib.Writer)zstd.gov.(*zstd.Decoder),v.(stackless.Writer),v.(*zstd.Encoder),ctxv.(*compressCtx)http.gov.(*statsWriter),v.(*bufio.Writer)server.gov.(*Server),v.(*atomic.Int64),v.(*hijackConn),v.(*bufio.Reader),v.(*bufio.Writer),v.(*RequestCtx)timer.gov.(*time.Timer)peripconn.gov.(*perIPTLSConn),v.(*perIPConn)fs.gov.(*fsSmallFileReader),v.(*sync.Mutex)client.gov.(*Request),v.(*Response),v.(*clientConn),v.(*bufio.Writer),v.(*bufio.Reader),v.(*pipelineWork)fasthttpproxy/dialer.gov.(*proxyInfo)workerpool.govch.(*workerChan)stackless/func.gov.(*funcWork)stackless/writer.goctx.(*writer)Current State
All are guarded by preceding nil checks and pool types are controlled (only known types are Put back). However:
forcetypeassertlinter is explicitly disabled in.golangci.yml(line 15), which would catch exactly this class of bugSuggested Fix
Option A (minimal): Re-enable the
forcetypeassertlinter with//nolint:forcetypeassertannotations on the known-safe pool assertions. This ensures new non-pool assertions are caught in CI.Option B (robust): Wrap pool assertions in a helper:
This provides a clear diagnostic message instead of a bare type assertion panic.
Impact
forcetypeassertmeans future regressions in non-pool code won't be caught by CI