Files
Adin ScannellandgVisor bot bd561fd3f9 Move from facts render to facts validation.
This allows fact information to be validated in the underlying source files,
but requires us to explicitly maintain this in appropriate version-tagged, and
architecture-tagged files. This is more explicit and safer.

This mechanism uses a special regular expression for matching a +checkconst
stanza to validate constant values, sizes and offsets. This applies to both Go
source files and assembly files.

PiperOrigin-RevId: 511867507
2023-02-23 13:17:49 -08:00

186 lines
6.0 KiB
Go

// Copyright 2019 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 check
import (
"encoding/gob"
"io"
"reflect"
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/asmdecl"
"golang.org/x/tools/go/analysis/passes/assign"
"golang.org/x/tools/go/analysis/passes/atomic"
"golang.org/x/tools/go/analysis/passes/bools"
"golang.org/x/tools/go/analysis/passes/buildtag"
"golang.org/x/tools/go/analysis/passes/cgocall"
"golang.org/x/tools/go/analysis/passes/composite"
"golang.org/x/tools/go/analysis/passes/copylock"
"golang.org/x/tools/go/analysis/passes/errorsas"
"golang.org/x/tools/go/analysis/passes/httpresponse"
"golang.org/x/tools/go/analysis/passes/loopclosure"
"golang.org/x/tools/go/analysis/passes/lostcancel"
"golang.org/x/tools/go/analysis/passes/nilfunc"
"golang.org/x/tools/go/analysis/passes/nilness"
"golang.org/x/tools/go/analysis/passes/printf"
"golang.org/x/tools/go/analysis/passes/shadow"
"golang.org/x/tools/go/analysis/passes/shift"
"golang.org/x/tools/go/analysis/passes/stdmethods"
"golang.org/x/tools/go/analysis/passes/stringintconv"
"golang.org/x/tools/go/analysis/passes/structtag"
"golang.org/x/tools/go/analysis/passes/tests"
"golang.org/x/tools/go/analysis/passes/unmarshal"
"golang.org/x/tools/go/analysis/passes/unreachable"
"golang.org/x/tools/go/analysis/passes/unsafeptr"
"golang.org/x/tools/go/analysis/passes/unusedresult"
"honnef.co/go/tools/staticcheck"
"honnef.co/go/tools/stylecheck"
"gvisor.dev/gvisor/tools/checkaligned"
"gvisor.dev/gvisor/tools/checkconst"
"gvisor.dev/gvisor/tools/checkescape"
"gvisor.dev/gvisor/tools/checklinkname"
"gvisor.dev/gvisor/tools/checklocks"
"gvisor.dev/gvisor/tools/checkunsafe"
)
// binaryAnalyzer is a special class of analyzer which supports an additional
// operation to run an analyzer with the object binary data.
type binaryAnalyzer interface {
// Run runs the analyzer with the given binary data.
Run(*analysis.Pass, io.Reader) (any, error)
}
// analyzer is a simple analysis.Analyzer interface.
//
// This is implemented by plainAnalyzer, and is used to allow calls to
// non-standard analyzers (e.g. checkescape, which requires the objdump output
// in addition to the existing pass information).
type analyzer interface {
Legacy() *analysis.Analyzer
}
// plainAnalyzer implements analyzer.
type plainAnalyzer struct {
*analysis.Analyzer
}
// Legacy implements analyzer.Legacy.
func (pa *plainAnalyzer) Legacy() *analysis.Analyzer {
return pa.Analyzer
}
var (
// allAnalyzers is a list of all available analyzers.
//
// This is guaranteed to be complete closure around the dependency
// graph of all analyzers (via the "Requires" attribute, below).
// Therefore, to map an *analysis.Analyzer to a runner, you may safely
// use "findAnalyzer".
allAnalyzers = make(map[*analysis.Analyzer]analyzer)
// allFactTypes is a list of all fact types, useful as a filter.
allFactTypes = make(map[reflect.Type]bool)
)
// findAnalyzer maps orig to an analyzer instance.
//
// This is guaranteed to work provided allAnalyzers is made into a transitive
// closure of all known analyzers (see init).
func findAnalyzer(orig *analysis.Analyzer) analyzer {
return allAnalyzers[orig]
}
// registerFactType registers an analysis.Fact.
func registerFactType(f analysis.Fact) {
// Already registered?
t := reflect.TypeOf(f)
if _, ok := allFactTypes[t]; ok {
return
}
// Register the type.
gob.Register(f)
allFactTypes[t] = true
}
// register recursively registers an analyzer.
func register(a analyzer) {
// Already registered?
if _, ok := allAnalyzers[a.Legacy()]; ok {
return
}
// Register all fact types.
for _, f := range a.Legacy().FactTypes {
registerFactType(f)
}
// Register dependencies.
for _, orig := range a.Legacy().Requires {
if findAnalyzer(orig) == nil {
register(&plainAnalyzer{orig})
}
}
// Save the analyzer.
allAnalyzers[a.Legacy()] = a
}
func init() {
// Standard & internal analyzers.
register(&plainAnalyzer{asmdecl.Analyzer})
register(&plainAnalyzer{assign.Analyzer})
register(&plainAnalyzer{atomic.Analyzer})
register(&plainAnalyzer{bools.Analyzer})
register(&plainAnalyzer{buildtag.Analyzer})
register(&plainAnalyzer{cgocall.Analyzer})
register(&plainAnalyzer{composite.Analyzer})
register(&plainAnalyzer{copylock.Analyzer})
register(&plainAnalyzer{errorsas.Analyzer})
register(&plainAnalyzer{httpresponse.Analyzer})
register(&plainAnalyzer{loopclosure.Analyzer})
register(&plainAnalyzer{lostcancel.Analyzer})
register(&plainAnalyzer{nilfunc.Analyzer})
register(&plainAnalyzer{nilness.Analyzer})
register(&plainAnalyzer{printf.Analyzer})
register(&plainAnalyzer{shift.Analyzer})
register(&plainAnalyzer{stdmethods.Analyzer})
register(&plainAnalyzer{stringintconv.Analyzer})
register(&plainAnalyzer{shadow.Analyzer})
register(&plainAnalyzer{structtag.Analyzer})
register(&plainAnalyzer{tests.Analyzer})
register(&plainAnalyzer{unmarshal.Analyzer})
register(&plainAnalyzer{unreachable.Analyzer})
register(&plainAnalyzer{unsafeptr.Analyzer})
register(&plainAnalyzer{unusedresult.Analyzer})
register(checkescape.Analyzer)
register(&plainAnalyzer{checkconst.Analyzer})
register(&plainAnalyzer{checkunsafe.Analyzer})
register(&plainAnalyzer{checklinkname.Analyzer})
register(&plainAnalyzer{checklocks.Analyzer})
register(&plainAnalyzer{checkaligned.Analyzer})
// Add all staticcheck analyzers.
for _, a := range staticcheck.Analyzers {
register(&plainAnalyzer{a.Analyzer})
}
// Add all stylecheck analyzers.
for _, a := range stylecheck.Analyzers {
register(&plainAnalyzer{a.Analyzer})
}
}