-
Notifications
You must be signed in to change notification settings - Fork 1.4k
fix(tools/checklocks): Add generics support #11740
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
This commit introduces support for Go generics in the checklocks analyzer, addressing issues with false-positive warnings and ensuring correct behavior with generic types. Key changes include: - Updated lock guard fact handling in analysis.go for generic types. - Added test cases for generics in tools/checklocks/test/generics.go. - Resolved regressions specific to generic value guards. All tests related to generics now pass. Pre-existing baseline failures in closure and defer handling are out of scope for this change. Fixes google#11671 Signed-off-by: Kemal Akkoyun <[email protected]>
e2bec2b
to
a195741
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for taking this on!
// This statement should be unreachable, but the Go compiler cannot prove | ||
// that the above type switch returns in all cases (due to `break` in some | ||
// branches). Provide a safe default to satisfy the type checker. | ||
return fmt.Sprintf("{unknown:%T:%p}", v, v), nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please panic instead, since this should be unreachable.
// itself. | ||
func genericInstantiate() { | ||
var _ genericGuardStruct[int] | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What would happen in the case where a library defines the genericGuardStruct
without ever instantiating it, as all instantiations of genericGuardStruct
would be in other libraries that import it? I think this would be a more common case than what this test file is doing.
@@ -495,39 +495,46 @@ func (pc *passContext) checkFunctionCall(call callCommon, fn *types.Func, lff *l | |||
// Update all lock state accordingly. | |||
pc.postFunctionCallUpdate(call, lff, ls, false /* aliases */) | |||
|
|||
// Fast-path handling for sync.(RW)Mutex/Locker helper methods. | |||
if fn == nil || fn.Pkg() == nil || len(args) == 0 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I understand how this works, but this feels brittle. What is this skipping over?
case *types.Named: | ||
obj := t.Obj() | ||
if obj != nil && obj.Pkg() != nil { | ||
if obj.Pkg().Path() == "sync" && (obj.Name() == "Mutex" || obj.Name() == "RWMutex") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will this work for the gVisor codebase, which uses import path gvisor.dev/gvisor/pkg/sync
?
https://github.com/search?q=repo%3Agoogle%2Fgvisor+%22%5C%22gvisor.dev%2Fgvisor%2Fpkg%2Fsync%5C%22%22&type=code
cur := typ | ||
for { | ||
if _, dup := seen[cur]; dup { | ||
// Cycle guard, should never happen. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Panic?
Summary
This PR introduces support for Go generics to the
tools/checklocks
static analysis tool. It resolves issues wherechecklocks
would produce false-positive warnings ("may require checklocks annotation") for mutex fields within generic types and ensures that+checklocksfail
annotations behave correctly with generic code.The core of the changes involves updating the type resolution and fact-finding logic within
analysis.go
andfacts.go
to correctly interpret lock annotations in the context of generic structs and their instantiations.Key Changes
analysis.go
to correctly resolve types and associate lock annotations for fields within generic structs. This includes improvements to how guarded-by facts are discovered and applied, particularly usingOrigin()
to trace back to generic definitions.isMutexType
to accurately identify mutex types, including those used within generic contexts.*ssa.Alloc
and*ssa.Store
operations instate.go
andanalysis.go
respectively, which was crucial for resolving a regression related to lock state propagation in generic helper functions.tools/checklocks/test/generics.go
with specific test cases to validatechecklocks
behavior with generic resources, including scenarios with+checklocks
and+checklocksfail
annotations.analysis.go
to use a canonical helper function (importLockGuardFacts
) for importing lock guard facts, reducing code duplication. Removed extensive debug logging now that the core functionality is stable.Impact & Testing
checklocks
no longer produces false-positive "may require checklocks annotation" warnings for mutex fields in generic types.+checklocksfail
annotation now correctly identifies (or not identify) violations in test cases involving generics.tools/checklocks/test/generics.go
now pass as expected.test/closures.go
andtest/defer.go
(which predate this work and exist in the main branch) are unaffected and considered out of scope for this PR.Fixes #11671
Signed-off-by: Kemal Akkoyun [email protected]