resourceclose
About 355 wordsAbout 1 min
2025-01-16
Detects unclosed resources like HTTP response bodies and files.
Category
Resources
What It Checks
This analyzer detects resources that are opened but not closed:
- HTTP response bodies (
resp.Body) - Files (
os.Open,os.Create) - Database connections
- Network connections
Why It Matters
Unclosed resources cause:
- Connection pool exhaustion
- File descriptor leaks
- Memory leaks
- Eventually, service failure
Examples
Bad: Response Body Not Closed
func fetchData(url string) ([]byte, error) {
resp, err := http.Get(url)
if err != nil {
return nil, err
}
// Body never closed - connection leaks!
return io.ReadAll(resp.Body)
}Good: Response Body Closed
func fetchData(url string) ([]byte, error) {
resp, err := http.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
return io.ReadAll(resp.Body)
}Bad: File Not Closed
func readConfig(path string) ([]byte, error) {
f, err := os.Open(path)
if err != nil {
return nil, err
}
// File never closed!
return io.ReadAll(f)
}Good: File Closed
func readConfig(path string) ([]byte, error) {
f, err := os.Open(path)
if err != nil {
return nil, err
}
defer f.Close()
return io.ReadAll(f)
}Good: Using os.ReadFile
func readConfig(path string) ([]byte, error) {
return os.ReadFile(path) // Handles close internally
}The Defer Pattern
Always close resources with defer immediately after opening:
resource, err := openResource()
if err != nil {
return err
}
defer resource.Close() // Immediately after error check
// Use resource...Deferred Anonymous Functions
The analyzer also detects close calls inside deferred anonymous functions:
resp, err := http.Get(url)
if err != nil {
return nil, err
}
defer func() { _ = resp.Body.Close() }() // Also detectedTest Cleanup
In tests, t.Cleanup() is recognized as a valid close pattern:
func TestFetch(t *testing.T) {
f, err := os.CreateTemp("", "test")
require.NoError(t, err)
t.Cleanup(func() { _ = f.Close() }) // Recognized as close
}Excluded Resources
Standard streams (os.Stdout, os.Stderr, os.Stdin) are excluded - these should never be closed by user code:
func printOutput() {
output := os.Stdout // Not flagged - shouldn't close stdout
fmt.Fprintln(output, "message")
}Configuration
# .golint-sl.yaml
analyzers:
resourceclose: true # enabled by defaultWhen to Disable
This analyzer should rarely be disabled. Resource leaks are serious bugs.
analyzers:
resourceclose: false # Not recommendedRelated Analyzers
- httpclient - HTTP client practices
- goroutineleak - Goroutine leaks
