resourcelifetime
Checks owned files, SQL handles, HTTP responses, and compressors are released on every path.
What it detects
Reports files, SQL rows, statements and transactions, HTTP response bodies, and gzip/zlib writers that are not released on every return path, and operations on them after release.
Some cases are deliberately not reported:
- a resource returned, stored somewhere that outlives the function, or handed to code gohawk cannot see into;
- channel timers and tickers, which the garbage collector reclaims;
- a file, response body, or rows value opened once in
main.main, which program exit closes.
The full list of precision boundaries, with the fixtures that pin each one, is in the resourcelifetime design notes.
Checks
| Check | Tier | Kind | What it detects |
|---|---|---|---|
missing-release |
core | defect | Reports owned resources that are not released on every return path. |
use-after-release |
core | hazard | Reports an invalidating operation on the same resource after a dominating release, with no intervening unknown effects. |
Why this is flagged
Owned resources are limited and often hold work open elsewhere. Missing cleanup on even one return path can leak file descriptors, database connections, network bodies or transactions until the program slows down or fails.
Further reading: Effective Go: Defer, Package net/http.
How to fix it
As soon as a resource is acquired successfully, arrange for its matching
cleanup on every later return path. Use defer when the current function owns
the resource, or transfer it only when the receiver clearly takes ownership.
Examples
Flagged code
Leaked file
func read(path string) error { // gohawk: owned resource from os.Open is not released on every return path file, err := os.Open(path) if err != nil { return err } _ = file return nil}Leaked database rows
func query(ctx context.Context, database *sql.DB) error { // gohawk: owned resource from sql.QueryContext is not released on every return path rows, err := database.QueryContext(ctx, "SELECT 1") if err != nil { return err } _ = rows return nil}Accepted code
func readSafely(path string) error { file, err := os.Open(path) if err != nil { return err } defer file.Close() return nil}