diff options
Diffstat (limited to 'tools/nogo')
-rw-r--r-- | tools/nogo/BUILD | 11 | ||||
-rw-r--r-- | tools/nogo/config.go | 1 | ||||
-rw-r--r-- | tools/nogo/defs.bzl | 96 | ||||
-rwxr-xr-x | tools/nogo/gentest.sh | 1 | ||||
-rw-r--r-- | tools/nogo/io_bazel_rules_go-visibility.patch | 25 | ||||
-rw-r--r-- | tools/nogo/nogo.go | 24 |
6 files changed, 104 insertions, 54 deletions
diff --git a/tools/nogo/BUILD b/tools/nogo/BUILD index dd4b46f58..3c6be3339 100644 --- a/tools/nogo/BUILD +++ b/tools/nogo/BUILD @@ -1,8 +1,15 @@ -load("//tools:defs.bzl", "bzl_library", "go_library") -load("//tools/nogo:defs.bzl", "nogo_objdump_tool", "nogo_stdlib") +load("//tools:defs.bzl", "bzl_library", "go_library", "select_goarch", "select_goos") +load("//tools/nogo:defs.bzl", "nogo_objdump_tool", "nogo_stdlib", "nogo_target") package(licenses = ["notice"]) +nogo_target( + name = "target", + goarch = select_goarch(), + goos = select_goos(), + visibility = ["//visibility:public"], +) + nogo_objdump_tool( name = "objdump_tool", visibility = ["//visibility:public"], diff --git a/tools/nogo/config.go b/tools/nogo/config.go index 8079618ab..0853f03cf 100644 --- a/tools/nogo/config.go +++ b/tools/nogo/config.go @@ -473,6 +473,7 @@ func init() { "pkg/shim/v2/options/options.go:24", "pkg/shim/v2/options/options.go:26", "pkg/shim/v2/runtimeoptions/runtimeoptions.go:16", + "pkg/shim/v2/runtimeoptions/runtimeoptions_cri.go", // Generated: exempt all. "pkg/shim/v2/runtimeoptions/runtimeoptions_test.go:22", "pkg/shim/v2/service.go:15", "pkg/shim/v2/service_linux.go:18", diff --git a/tools/nogo/defs.bzl b/tools/nogo/defs.bzl index c6fcfd402..543598b52 100644 --- a/tools/nogo/defs.bzl +++ b/tools/nogo/defs.bzl @@ -1,10 +1,34 @@ """Nogo rules.""" -load("//tools/bazeldefs:defs.bzl", "go_context", "go_importpath", "go_rule", "go_test_library") +load("//tools/bazeldefs:go.bzl", "go_context", "go_importpath", "go_rule", "go_test_library") -def _nogo_objdump_tool_impl(ctx): - go_ctx = go_context(ctx) +NogoTargetInfo = provider( + "information about the Go target", + fields = { + "goarch": "the build architecture (GOARCH)", + "goos": "the build OS target (GOOS)", + }, +) + +def _nogo_target_impl(ctx): + return [NogoTargetInfo( + goarch = ctx.attr.goarch, + goos = ctx.attr.goos, + )] +nogo_target = go_rule( + rule, + implementation = _nogo_target_impl, + attrs = { + # goarch is the build architecture. This will normally be provided by a + # select statement, but this information is propagated to other rules. + "goarch": attr.string(mandatory = True), + # goos is similarly the build operating system target. + "goos": attr.string(mandatory = True), + }, +) + +def _nogo_objdump_tool_impl(ctx): # Construct the magic dump command. # # Note that in some cases, the input is being fed into the tool via stdin. @@ -12,6 +36,8 @@ def _nogo_objdump_tool_impl(ctx): # we need the tool to handle this case by creating a temporary file. # # [1] https://github.com/golang/go/issues/41051 + nogo_target_info = ctx.attr._nogo_target[NogoTargetInfo] + go_ctx = go_context(ctx, goos = nogo_target_info.goos, goarch = nogo_target_info.goarch) env_prefix = " ".join(["%s=%s" % (key, value) for (key, value) in go_ctx.env.items()]) dumper = ctx.actions.declare_file(ctx.label.name) ctx.actions.write(dumper, "\n".join([ @@ -42,6 +68,12 @@ def _nogo_objdump_tool_impl(ctx): nogo_objdump_tool = go_rule( rule, implementation = _nogo_objdump_tool_impl, + attrs = { + "_nogo_target": attr.label( + default = "//tools/nogo:target", + cfg = "target", + ), + }, ) # NogoStdlibInfo is the set of standard library facts. @@ -54,9 +86,9 @@ NogoStdlibInfo = provider( ) def _nogo_stdlib_impl(ctx): - go_ctx = go_context(ctx) - # Build the standard library facts. + nogo_target_info = ctx.attr._nogo_target[NogoTargetInfo] + go_ctx = go_context(ctx, goos = nogo_target_info.goos, goarch = nogo_target_info.goarch) facts = ctx.actions.declare_file(ctx.label.name + ".facts") findings = ctx.actions.declare_file(ctx.label.name + ".findings") config = struct( @@ -70,12 +102,12 @@ def _nogo_stdlib_impl(ctx): ctx.actions.run( inputs = [config_file] + go_ctx.stdlib_srcs, outputs = [facts, findings], - tools = depset(go_ctx.runfiles.to_list() + ctx.files._objdump_tool), - executable = ctx.files._nogo[0], + tools = depset(go_ctx.runfiles.to_list() + ctx.files._nogo_objdump_tool), + executable = ctx.files._nogo_check[0], mnemonic = "GoStandardLibraryAnalysis", progress_message = "Analyzing Go Standard Library", arguments = go_ctx.nogo_args + [ - "-objdump_tool=%s" % ctx.files._objdump_tool[0].path, + "-objdump_tool=%s" % ctx.files._nogo_objdump_tool[0].path, "-stdlib=%s" % config_file.path, "-findings=%s" % findings.path, "-facts=%s" % facts.path, @@ -92,11 +124,17 @@ nogo_stdlib = go_rule( rule, implementation = _nogo_stdlib_impl, attrs = { - "_nogo": attr.label( + "_nogo_check": attr.label( default = "//tools/nogo/check:check", + cfg = "host", ), - "_objdump_tool": attr.label( + "_nogo_objdump_tool": attr.label( default = "//tools/nogo:objdump_tool", + cfg = "host", + ), + "_nogo_target": attr.label( + default = "//tools/nogo:target", + cfg = "target", ), }, ) @@ -113,20 +151,18 @@ NogoInfo = provider( "findings": "package findings (if relevant)", "importpath": "package import path", "binaries": "package binary files", - "srcs": "original source files (for go_test support)", - "deps": "original deps (for go_test support)", + "srcs": "srcs (for go_test support)", + "deps": "deps (for go_test support)", }, ) def _nogo_aspect_impl(target, ctx): - go_ctx = go_context(ctx) - # If this is a nogo rule itself (and not the shadow of a go_library or # go_binary rule created by such a rule), then we simply return nothing. # All work is done in the shadow properties for go rules. For a proto # library, we simply skip the analysis portion but still need to return a # valid NogoInfo to reference the generated binary. - if ctx.rule.kind in ("go_library", "go_binary", "go_test", "go_tool_library"): + if ctx.rule.kind in ("go_library", "go_tool_library", "go_binary", "go_test"): srcs = ctx.rule.files.srcs deps = ctx.rule.attr.deps elif ctx.rule.kind in ("go_proto_library", "go_wrap_cc"): @@ -200,10 +236,13 @@ def _nogo_aspect_impl(target, ctx): inputs += info.binaries # Add the standard library facts. - stdlib_facts = ctx.attr._nogo_stdlib[NogoStdlibInfo].facts + stdlib_info = ctx.attr._nogo_stdlib[NogoStdlibInfo] + stdlib_facts = stdlib_info.facts inputs.append(stdlib_facts) # The nogo tool operates on a configuration serialized in JSON format. + nogo_target_info = ctx.attr._nogo_target[NogoTargetInfo] + go_ctx = go_context(ctx, goos = nogo_target_info.goos, goarch = nogo_target_info.goarch) facts = ctx.actions.declare_file(target.label.name + ".facts") findings = ctx.actions.declare_file(target.label.name + ".findings") escapes = ctx.actions.declare_file(target.label.name + ".escapes") @@ -224,13 +263,13 @@ def _nogo_aspect_impl(target, ctx): ctx.actions.run( inputs = inputs, outputs = [facts, findings, escapes], - tools = depset(go_ctx.runfiles.to_list() + ctx.files._objdump_tool), - executable = ctx.files._nogo[0], + tools = depset(go_ctx.runfiles.to_list() + ctx.files._nogo_objdump_tool), + executable = ctx.files._nogo_check[0], mnemonic = "GoStaticAnalysis", progress_message = "Analyzing %s" % target.label, arguments = go_ctx.nogo_args + [ "-binary=%s" % target_objfile.path, - "-objdump_tool=%s" % ctx.files._objdump_tool[0].path, + "-objdump_tool=%s" % ctx.files._nogo_objdump_tool[0].path, "-package=%s" % config_file.path, "-findings=%s" % findings.path, "-facts=%s" % facts.path, @@ -266,9 +305,22 @@ nogo_aspect = go_rule( "embed", ], attrs = { - "_nogo": attr.label(default = "//tools/nogo/check:check"), - "_nogo_stdlib": attr.label(default = "//tools/nogo:stdlib"), - "_objdump_tool": attr.label(default = "//tools/nogo:objdump_tool"), + "_nogo_check": attr.label( + default = "//tools/nogo/check:check", + cfg = "host", + ), + "_nogo_stdlib": attr.label( + default = "//tools/nogo:stdlib", + cfg = "host", + ), + "_nogo_objdump_tool": attr.label( + default = "//tools/nogo:objdump_tool", + cfg = "host", + ), + "_nogo_target": attr.label( + default = "//tools/nogo:target", + cfg = "target", + ), }, ) diff --git a/tools/nogo/gentest.sh b/tools/nogo/gentest.sh index 033da11ad..0a762f9f6 100755 --- a/tools/nogo/gentest.sh +++ b/tools/nogo/gentest.sh @@ -34,6 +34,7 @@ for filename in "$@"; do continue fi while read -r line; do + line="${line@Q}" violations=$((${violations}+1)); echo "echo -e '\\033[0;31m${line}\\033[0;31m\\033[0m'" >> "${output}" done < "${filename}" diff --git a/tools/nogo/io_bazel_rules_go-visibility.patch b/tools/nogo/io_bazel_rules_go-visibility.patch deleted file mode 100644 index 6b64b2e85..000000000 --- a/tools/nogo/io_bazel_rules_go-visibility.patch +++ /dev/null @@ -1,25 +0,0 @@ -diff --git a/third_party/org_golang_x_tools-extras.patch b/third_party/org_golang_x_tools-extras.patch -index 133fbccc..5f0d9a47 100644 ---- a/third_party/org_golang_x_tools-extras.patch -+++ b/third_party/org_golang_x_tools-extras.patch -@@ -32,7 +32,7 @@ diff -urN c/go/analysis/internal/facts/BUILD.bazel d/go/analysis/internal/facts/ - - go_library( - name = "go_default_library", --@@ -14,6 +14,23 @@ -+@@ -14,6 +14,20 @@ - ], - ) - -@@ -43,10 +43,7 @@ diff -urN c/go/analysis/internal/facts/BUILD.bazel d/go/analysis/internal/facts/ - + "imports.go", - + ], - + importpath = "golang.org/x/tools/go/analysis/internal/facts", --+ visibility = [ --+ "//go/analysis:__subpackages__", --+ "@io_bazel_rules_go//go/tools/builders:__pkg__", --+ ], -++ visibility = ["//visibility:public"], - + deps = [ - + "//go/analysis:go_tool_library", - + "//go/types/objectpath:go_tool_library", diff --git a/tools/nogo/nogo.go b/tools/nogo/nogo.go index 120fdcff5..e19e3c237 100644 --- a/tools/nogo/nogo.go +++ b/tools/nogo/nogo.go @@ -264,12 +264,17 @@ func checkStdlib(config *stdlibConfig, ac map[*analysis.Analyzer]matcher) ([]str // Closure to check a single package. allFindings := make([]string, 0) stdlibFacts := make(map[string][]byte) + stdlibErrs := make(map[string]error) var checkOne func(pkg string) error // Recursive. checkOne = func(pkg string) error { // Is this already done? if _, ok := stdlibFacts[pkg]; ok { return nil } + // Did this fail previously? + if _, ok := stdlibErrs[pkg]; ok { + return nil + } // Lookup the configuration. config, ok := packages[pkg] @@ -283,6 +288,7 @@ func checkStdlib(config *stdlibConfig, ac map[*analysis.Analyzer]matcher) ([]str // If there's no binary for this package, it is likely // not built with the distribution. That's fine, we can // just skip analysis. + stdlibErrs[pkg] = err return nil } @@ -299,6 +305,7 @@ func checkStdlib(config *stdlibConfig, ac map[*analysis.Analyzer]matcher) ([]str if err != nil { // If we can't analyze a package from the standard library, // then we skip it. It will simply not have any findings. + stdlibErrs[pkg] = err return nil } stdlibFacts[pkg] = factData @@ -312,7 +319,9 @@ func checkStdlib(config *stdlibConfig, ac map[*analysis.Analyzer]matcher) ([]str // to evaluate in the order provided here. We do ensure however, that // all packages are evaluated. for pkg := range packages { - checkOne(pkg) + if err := checkOne(pkg); err != nil { + return nil, nil, err + } } // Sanity check. @@ -326,6 +335,11 @@ func checkStdlib(config *stdlibConfig, ac map[*analysis.Analyzer]matcher) ([]str return nil, nil, fmt.Errorf("error saving stdlib facts: %w", err) } + // Write out all errors. + for pkg, err := range stdlibErrs { + log.Printf("WARNING: error while processing %v: %v", pkg, err) + } + // Return all findings. return allFindings, factData, nil } @@ -522,15 +536,15 @@ func Main() { findings, factData, err = checkPackage(c, analyzerConfig, nil) // Do we need to do escape analysis? if *escapesOutput != "" { - escapes, _, err := checkPackage(c, escapesConfig, nil) - if err != nil { - log.Fatalf("error performing escape analysis: %v", err) - } f, err := os.OpenFile(*escapesOutput, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) if err != nil { log.Fatalf("unable to open output %q: %v", *escapesOutput, err) } defer f.Close() + escapes, _, err := checkPackage(c, escapesConfig, nil) + if err != nil { + log.Fatalf("error performing escape analysis: %v", err) + } for _, escape := range escapes { fmt.Fprintf(f, "%s\n", escape) } |