pi-lens
Version:
Real-time code feedback for pi — LSP, linters, formatters, type-checking, structural analysis & booboo
61 lines (48 loc) • 1.51 kB
YAML
id: go-mutex-copy
name: Mutex Copied by Value
severity: warning
category: concurrency
defect_class: correctness
inline_tier: blocking
language: go
message: "sync.Mutex parameter taken by value — the callee locks a copy; take *sync.Mutex instead"
description: |
A sync.Mutex must never be copied after first use. Copying a mutex copies
its internal state, so both copies appear unlocked even if the original
was locked — leading to data races and deadlocks.
This fires on a parameter declared as a bare `sync.Mutex`/`sync.RWMutex`
value: the call copies the lock, so the callee locks its own copy. Copies
through a struct that embeds a mutex (a value receiver, or a struct-typed
parameter) are NOT detected — that needs the struct definition, which this
single-file query cannot resolve.
✅ FIX: take the mutex as *sync.Mutex, or reach it through a pointer receiver.
❌ NEVER:
func work(mu sync.Mutex) { mu.Lock() } // locks a copy!
✅ SAFE:
func work(mu *sync.Mutex) { mu.Lock() }
query: |
(parameter_declaration
type: (qualified_type
package: (package_identifier)
name: (type_identifier) )
(#eq? "sync")
(#match? "^(Mutex|RWMutex)$"))
metavars:
- PKG
- FN
- DECL
has_fix: false
tags:
- go
- concurrency
- mutex
- correctness
examples:
bad: |
func doWork(mu sync.Mutex) { // BAD - mu is a copy
mu.Lock()
}
good: |
func doWork(mu *sync.Mutex) {
mu.Lock()
}