Reliability and safety
lockorder
Checks contradictory mutex acquisition order and unreleased return paths.
What it detects
Acquire locks consistently and release them on every return path. A missing unlock is reported only when another path demonstrates that the function owns the corresponding release policy.
Checks
| Check | What it detects |
|---|---|
missing-release |
Reports return paths that leave an owned lock held. |
recursive-acquire |
Reports attempts to acquire a lock that is already held. |
contradictory-order |
Reports inconsistent acquisition order for the same pair of locks. |
Why this is flagged
Two goroutines that acquire the same locks in different orders can wait on each other forever. Failing to unlock on one return path can similarly block every later caller that needs the lock.
How to fix it
Choose one order for acquiring multiple locks and use it everywhere. Arrange
the matching unlock as soon as each lock is acquired, commonly with defer, so
early returns cannot leave it held.
Examples
Flagged code
var first sync.Mutexvar second sync.Mutex
func forward() { first.Lock() defer first.Unlock() second.Lock() defer second.Unlock()}
func reverse() { second.Lock() defer second.Unlock() // gohawk: contradictory lock order: first and second first.Lock() defer first.Unlock()}Accepted code
var third sync.Mutexvar fourth sync.Mutex
func forwardSafely() { third.Lock() defer third.Unlock() fourth.Lock() defer fourth.Unlock()}
func reverseSafely() { third.Lock() defer third.Unlock() fourth.Lock() defer fourth.Unlock()}