Handle cross-package global guards.

Updates #7721

PiperOrigin-RevId: 455029306
This commit is contained in:
Adin Scannell
2022-06-14 21:23:28 -07:00
committed by gVisor bot
parent c54948f3c1
commit 1ff543e17e
6 changed files with 73 additions and 6 deletions
+11 -3
View File
@@ -322,9 +322,17 @@ func (pc *passContext) checkFieldAccess(inst almostInst, structObj ssa.Value, fi
pc.checkGuards(inst, structObj, fieldObj, ls, isWrite)
}
// noReferrers wraps an instruction as an almostInst.
type noReferrers struct {
ssa.Instruction
}
// Referrers implements almostInst.Referrers.
func (noReferrers) Referrers() *[]ssa.Instruction { return nil }
// checkGlobalAccess checks the validity of a global access.
func (pc *passContext) checkGlobalAccess(g *ssa.Global, ls *lockState, isWrite bool) {
pc.checkGuards(g, g, g.Object(), ls, isWrite)
func (pc *passContext) checkGlobalAccess(inst ssa.Instruction, g *ssa.Global, ls *lockState, isWrite bool) {
pc.checkGuards(noReferrers{inst}, g, g.Object(), ls, isWrite)
}
func (pc *passContext) checkCall(call callCommon, lff *lockFunctionFacts, ls *lockState) {
@@ -592,7 +600,7 @@ func (pc *passContext) checkInstruction(inst ssa.Instruction, lff *lockFunctionF
continue
}
_, isWrite := inst.(*ssa.Store)
pc.checkGlobalAccess(g, ls, isWrite)
pc.checkGlobalAccess(inst, g, ls, isWrite)
}
// Process the instruction.
+11 -3
View File
@@ -167,6 +167,9 @@ type globalGuard struct {
// ObjectName indicates the object from which resolution should occur.
ObjectName string
// PackageName is the package where the object lives.
PackageName string
// FieldList is the traversal path from object.
FieldList fieldList
}
@@ -179,7 +182,11 @@ type ssaPackager interface {
// resolveCommon implements resolution for all cases.
func (g *globalGuard) resolveCommon(pc *passContext, ls *lockState) resolvedValue {
state := pc.pass.ResultOf[buildssa.Analyzer].(*buildssa.SSA)
v := state.Pkg.Members[g.ObjectName].(ssa.Value)
pkg := state.Pkg
if g.PackageName != "" && g.PackageName != state.Pkg.Pkg.Path() {
pkg = state.Pkg.Prog.ImportedPackage(g.PackageName)
}
v := pkg.Members[g.ObjectName].(ssa.Value)
return makeResolvedValue(v, g.FieldList)
}
@@ -627,8 +634,9 @@ func (pc *passContext) findGlobalGuard(pos token.Pos, guardName string) (*global
return nil, false
}
return &globalGuard{
ObjectName: parts[0],
FieldList: fl,
ObjectName: parts[0],
PackageName: pc.pass.Pkg.Path(),
FieldList: fl,
}, true
}
+1
View File
@@ -27,4 +27,5 @@ go_library(
# control expected failures for analysis.
marshal = False,
stateify = False,
deps = ["//tools/checklocks/test/crosspkg"],
)
+12
View File
@@ -0,0 +1,12 @@
load("//tools:defs.bzl", "go_library")
package(licenses = ["notice"])
go_library(
name = "crosspkg",
srcs = ["crosspkg.go"],
# See next level up.
marshal = False,
stateify = False,
visibility = ["//tools/checklocks/test:__pkg__"],
)
@@ -0,0 +1,26 @@
// Copyright 2022 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package crosspkg is a second package for testing.
package crosspkg
import (
"sync"
)
var (
// +checklocks:FooMu
Foo int
FooMu sync.Mutex
)
+12
View File
@@ -16,6 +16,8 @@ package test
import (
"sync"
"gvisor.dev/gvisor/tools/checklocks/test/crosspkg"
)
var (
@@ -83,3 +85,13 @@ func testGlobalInvalid() {
otherStruct.guardedField2 = 1 // +checklocksfail
otherStruct.guardedField3 = 1 // +checklocksfail
}
func testCrosspkgGlobalValid() {
crosspkg.FooMu.Lock()
crosspkg.Foo = 1
crosspkg.FooMu.Unlock()
}
func testCrosspkgGlobalInvalid() {
crosspkg.Foo = 1 // +checklocksfail
}