Skip to content
Reliability and safety

lockorder

Checks contradictory mutex acquisition order and unreleased return paths.

Fix offeredNo

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.Mutex
var 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.Mutex
var 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()
}