summaryrefslogtreecommitdiffhomepage
path: root/tools/nogo/check/main.go
diff options
context:
space:
mode:
authorAdin Scannell <ascannell@google.com>2020-10-26 11:09:34 -0700
committergVisor bot <gvisor-bot@google.com>2020-10-26 11:11:46 -0700
commit7926a9e28da8852954961af2aea0a280b6bbd210 (patch)
treed2c87f7108aa207b0c2c87410d12c3f952a56689 /tools/nogo/check/main.go
parente2dce046037c30b585cc62db45d517f59d1a08fc (diff)
Add nogo configuration.
This splits the nogo rules into a separate configuration yaml file, and allows for multiple files to be provided. Because attrs cannot be passed down to aspects, this required that all findings are propagated up the aspect Provider. This doesn't mean that any extra work must be done, just that this information must be carried through the graph, and some additional starlark complexity is required. PiperOrigin-RevId: 339076357
Diffstat (limited to 'tools/nogo/check/main.go')
-rw-r--r--tools/nogo/check/main.go92
1 files changed, 91 insertions, 1 deletions
diff --git a/tools/nogo/check/main.go b/tools/nogo/check/main.go
index 3828edf3a..69bdfe502 100644
--- a/tools/nogo/check/main.go
+++ b/tools/nogo/check/main.go
@@ -16,9 +16,99 @@
package main
import (
+ "encoding/json"
+ "flag"
+ "fmt"
+ "io/ioutil"
+ "log"
+ "os"
+
"gvisor.dev/gvisor/tools/nogo"
)
+var (
+ packageFile = flag.String("package", "", "package configuration file (in JSON format)")
+ stdlibFile = flag.String("stdlib", "", "stdlib configuration file (in JSON format)")
+ findingsOutput = flag.String("findings", "", "output file (or stdout, if not specified)")
+ factsOutput = flag.String("facts", "", "output file for facts (optional)")
+ escapesOutput = flag.String("escapes", "", "output file for escapes (optional)")
+)
+
+func loadConfig(file string, config interface{}) interface{} {
+ // Load the configuration.
+ f, err := os.Open(file)
+ if err != nil {
+ log.Fatalf("unable to open configuration %q: %v", file, err)
+ }
+ defer f.Close()
+ dec := json.NewDecoder(f)
+ dec.DisallowUnknownFields()
+ if err := dec.Decode(config); err != nil {
+ log.Fatalf("unable to decode configuration: %v", err)
+ }
+ return config
+}
+
func main() {
- nogo.Main()
+ // Parse all flags.
+ flag.Parse()
+
+ var (
+ findings []nogo.Finding
+ factData []byte
+ err error
+ )
+
+ // Check & load the configuration.
+ if *packageFile != "" && *stdlibFile != "" {
+ log.Fatalf("unable to perform stdlib and package analysis; provide only one!")
+ }
+
+ // Run the configuration.
+ if *stdlibFile != "" {
+ // Perform basic analysis.
+ c := loadConfig(*stdlibFile, new(nogo.StdlibConfig)).(*nogo.StdlibConfig)
+ findings, factData, err = nogo.CheckStdlib(c, nogo.AllAnalyzers)
+
+ } else if *packageFile != "" {
+ // Perform basic analysis.
+ c := loadConfig(*packageFile, new(nogo.PackageConfig)).(*nogo.PackageConfig)
+ findings, factData, err = nogo.CheckPackage(c, nogo.AllAnalyzers, nil)
+
+ // Do we need to do escape analysis?
+ if *escapesOutput != "" {
+ escapes, _, err := nogo.CheckPackage(c, nogo.EscapeAnalyzers, nil)
+ if err != nil {
+ log.Fatalf("error performing escape analysis: %v", err)
+ }
+ if err := nogo.WriteFindingsToFile(escapes, *escapesOutput); err != nil {
+ log.Fatalf("error writing escapes to %q: %v", *escapesOutput, err)
+ }
+ }
+ } else {
+ log.Fatalf("please provide at least one of package or stdlib!")
+ }
+
+ // Check that analysis was successful.
+ if err != nil {
+ log.Fatalf("error performing analysis: %v", err)
+ }
+
+ // Save facts.
+ if *factsOutput != "" {
+ if err := ioutil.WriteFile(*factsOutput, factData, 0644); err != nil {
+ log.Fatalf("error saving findings to %q: %v", *factsOutput, err)
+ }
+ }
+
+ // Write all findings.
+ if *findingsOutput != "" {
+ if err := nogo.WriteFindingsToFile(findings, *findingsOutput); err != nil {
+ log.Fatalf("error writing findings to %q: %v", *findingsOutput, err)
+ }
+ } else {
+ for _, finding := range findings {
+ fmt.Fprintf(os.Stdout, "%s\n", finding.String())
+ }
+ }
}