UNPKG

pi-lens

Version:

Real-time code feedback for pi — LSP, linters, formatters, type-checking, structural analysis & booboo

61 lines (48 loc) • 1.51 kB
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) @PKG name: (type_identifier) @FN) (#eq? @PKG "sync") (#match? @FN "^(Mutex|RWMutex)$")) @DECL 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() }