https://github.com/tkdn/deferargs
deferargs is a static analysis tool to detect defer statements that call a function with variable arguments.
https://github.com/tkdn/deferargs
Last synced: 3 months ago
JSON representation
deferargs is a static analysis tool to detect defer statements that call a function with variable arguments.
- Host: GitHub
- URL: https://github.com/tkdn/deferargs
- Owner: tkdn
- License: mit
- Created: 2025-06-22T05:04:47.000Z (about 1 year ago)
- Default Branch: main
- Last Pushed: 2026-03-20T21:50:37.000Z (3 months ago)
- Last Synced: 2026-03-21T12:57:51.322Z (3 months ago)
- Language: Go
- Size: 53.7 KB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# deferargs
`deferargs` is a static analysis tool to detect `defer` statements that call a function with variable arguments.
Since arguments in `defer` calls are evaluated immediately, passing variables may lead to unexpected behavior if their values change afterward.
## Problem
In Go, the arguments to a `defer` call are evaluated **at the point of the `defer` statement**, not when the deferred function is executed.
This can cause subtle bugs when passing a variable whose value is expected to change later.
For example:
```go
func fn() (err error) {
defer dump(err) // ❗️ evaluated now (likely nil), not at the end
err = errors.New("something failed")
return
}
```
The call to `dump(err)` will receive `nil`, because `err` is evaluated at the point of the `defer`, before `err` is set.
## Recommendation
To avoid this issue, wrap the call in a closure:
```go
func f() (err error) {
defer func() {
dump(err) // ✅ evaluated at the time of execution
}()
err = errors.New("something failed")
return
}
```
## Detected Code
This tool reports `defer` statements where:
- The deferred function is **not** an anonymous function (`func() { ... }`)
- At least one argument is a **variable reference** (`x`, `obj.Field`, etc.)
### Reported:
```go
defer fn(err)
defer close(ch)
defer logf("fail: %v", err)
```
### Not Reported:
```go
defer fn() // no arguments
defer fn(errors.New("boom")) // function call
defer fn(nil) // literal
defer func() { fn(err) }() // wrapped in closure
```
## Installation
```bash
go install github.com/tkdn/deferargs/cmd/deferargs@latest
```
## Usage
### As `go vet` plugin (with [staticcheck.io](https://staticcheck.io/)):
```bash
go vet -vettool=$(which deferargs) ./...
```
### Standalone
```bash
deferargs ./...
```
## License
MIT