From c829d82a8f189b6f76cf834019675d5014fa9fef Mon Sep 17 00:00:00 2001 From: Adin Scannell Date: Fri, 17 Feb 2023 14:36:48 -0800 Subject: [PATCH] Update checklinkname to avoid hard-coded names. PiperOrigin-RevId: 510524474 --- nogo.yaml | 25 +- tools/checklinkname/BUILD | 10 +- tools/checklinkname/check_linkname.go | 455 +++++++++++++++++++----- tools/checklinkname/known.go | 119 ------- tools/checklinkname/test/test_unsafe.go | 6 +- tools/nogo/check/check.go | 6 + tools/nogo/defs.bzl | 1 - 7 files changed, 394 insertions(+), 228 deletions(-) delete mode 100644 tools/checklinkname/known.go diff --git a/nogo.yaml b/nogo.yaml index e01df6902..a0c48c43b 100644 --- a/nogo.yaml +++ b/nogo.yaml @@ -62,6 +62,7 @@ global: - "panic recovered: no type for \\*ast.SelectorExpr" - "panic recovered: no types.Object for ast.Ident SetTypeErrors" - "panic recovered: unexpected CompositeLit type: invalid type" + - "panic recovered: interface conversion: ssa.Member is \\*ssa.NamedConst" exclude: - ".*/vet/testdata/.*" - ".*/runtime/testdata/.*" @@ -79,6 +80,8 @@ global: - "return with unexpected locks held.*" - "incompatible return states.*" - "may require checklocks annotation for.*" + # For some reason, the types package falls down. + - "panic recovered: .*types/sizes.go:82: assertion failed" exclude: # Generated: exempt all. - pkg/shim/runtimeoptions/runtimeoptions_cri.go @@ -184,16 +187,22 @@ analyzers: checklinkname: external: # Enabled. suppress: - # We don't care to check every single linkname in the Go standard - # library. Suppress findings about stdlib linkname targets we haven't - # described in checklinkname. - # - # Note that we _do_ want to check the signature of the known linkname - # targets in the standard library, so we still need to run - # checklinkname on stdlib generally. - - "linkname to unknown symbol" + # Suppress bad linkname directives in the internals. This may be fixed + # by the patch: https://go-review.googlesource.com/c/go/+/466615 + - "symbol \"runtime_pollWaitCanceled\".*" + - "symbol \"runtime_procPin\".*" exclude: - ".*/containerd/sys/subprocess_unsafe_linux.go" + internal: + suppress: + # See above. + - "symbol \"runtime_pollWaitCanceled\".*" + - "symbol \"runtime_procPin\".*" + generated: + suppress: + # See above. + - "symbol \"runtime_pollWaitCanceled\".*" + - "symbol \"runtime_procPin\".*" SA1019: # Use of deprecated identifier. # disable for now due to misattribution from golang.org/issue/44195. generated: diff --git a/tools/checklinkname/BUILD b/tools/checklinkname/BUILD index 0f1b07e24..1ae3cbc83 100644 --- a/tools/checklinkname/BUILD +++ b/tools/checklinkname/BUILD @@ -4,13 +4,9 @@ package(licenses = ["notice"]) go_library( name = "checklinkname", - srcs = [ - "check_linkname.go", - "known.go", - ], + srcs = ["check_linkname.go"], nogo = False, + stateify = False, visibility = ["//tools/nogo:__subpackages__"], - deps = [ - "@org_golang_x_tools//go/analysis:go_default_library", - ], + deps = ["@org_golang_x_tools//go/analysis:go_default_library"], ) diff --git a/tools/checklinkname/check_linkname.go b/tools/checklinkname/check_linkname.go index f342ce87e..91069f739 100644 --- a/tools/checklinkname/check_linkname.go +++ b/tools/checklinkname/check_linkname.go @@ -30,6 +30,105 @@ var Analyzer = &analysis.Analyzer{ Name: "checklinkname", Doc: "verifies that linkname declarations match their source", Run: run, + FactTypes: []analysis.Fact{ + (*UnresolvedLinknames)(nil), + (*ResolvedSymbols)(nil), + }, +} + +// symbolMap is a map of all known or unknown symbols, with their signature. +// +// It is keyed by package, then symbol, with the simplified signature as the value. +type symbolMap map[string]map[string]string + +// mergeOrResolve checks all symbol signatures. +// +// If merge is true, then the resulting map will be the union of the two maps. +// If merge is false, then the resulting map will be the first with the second +// symbolMap subtracted. +func (s *symbolMap) mergeOrResolve(pass *analysis.Pass, other symbolMap, merge bool, resolvePos func(pkgName, symbolName string) token.Pos) { + for pkgName, symbols := range other { + localSymbols, ok := (*s)[pkgName] + if !ok { + if merge { + (*s)[pkgName] = symbols + } + continue + } + var resolved []string // Used only if !merge. + for symbolName, otherSig := range symbols { + localSig, ok := localSymbols[symbolName] + if !ok { + if merge { + localSymbols[symbolName] = otherSig + } + continue + } + if localSig != otherSig { + switch { + case symbolName == "ifaceE2I": + // The runtime uses a different signature for this than other packages, e.g. + // the runtime has func(uintptr, eface, uintptr) whereas externally it is + // declared as func(uintptr, any, uintptr). This is a clever way to directly + // access the interface object, but breaks this change. We ignore this. + default: + pass.Reportf(resolvePos(pkgName, symbolName), "symbol %q has signature %q, expected signature %q", symbolName, localSig, otherSig) + } + } + if !merge { + resolved = append(resolved, symbolName) + } + } + for _, symbolName := range resolved { + delete(localSymbols, symbolName) + } + } +} + +// ResolvedSymbols is a fact containing known symbols and their simplified type. +type ResolvedSymbols symbolMap + +// AFact implements analysis.Fact.AFact. +func (*ResolvedSymbols) AFact() {} + +// merge merges all known symbols. +func (r *ResolvedSymbols) merge(pass *analysis.Pass, other ResolvedSymbols, resolvePos func(pkgName, symbolName string) token.Pos) { + ((*symbolMap)(r)).mergeOrResolve(pass, (symbolMap)(other), true /* merge */, resolvePos) +} + +// UnresolvedLinknames is a fact containing symbols that have not been validated. +type UnresolvedLinknames symbolMap + +// AFact implements analysis.Fact.AFact. +func (*UnresolvedLinknames) AFact() {} + +// merge merges all unknown symbols. +func (u *UnresolvedLinknames) merge(pass *analysis.Pass, other UnresolvedLinknames, resolvePos func(pkgName, symbolName string) token.Pos) { + ((*symbolMap)(u)).mergeOrResolve(pass, (symbolMap)(other), true /* merge */, resolvePos) +} + +// resolve resolves all known symbols. +func (u *UnresolvedLinknames) resolve(pass *analysis.Pass, other ResolvedSymbols, resolvePos func(pkgName, symbolName string) token.Pos) { + ((*symbolMap)(u)).mergeOrResolve(pass, (symbolMap)(other), false /* merge */, resolvePos) +} + +// resolveRemaining resolves all remaining names. +// +// This should be called only for final linking, when we expect that all symbols +// have been included directly or indirectly. +func (u *UnresolvedLinknames) resolveRemaining(pass *analysis.Pass, resolvePos func(pkgName, symbolName string) token.Pos) { + for pkgName, pur := range *u { + for symbolName := range pur { + switch { + case pkgName == "main" && symbolName == ".inittask": + // This seems like a special case; it is not available for analysis. + case pkgName == "runtime" && strings.HasPrefix(symbolName, "_cgo_"): + // Ignore all _cgo_-related symbols; see below. + default: + pass.Reportf(resolvePos(pkgName, symbolName), "remote symbol %q not defined in package %q", symbolName, pkgName) + } + } + } } // go:linkname can be rather confusing. https://pkg.go.dev/cmd/compile says: @@ -46,29 +145,10 @@ var Analyzer = &analysis.Analyzer{ // system and package modularity, it is only enabled in files that have // imported "unsafe". // -// In this package we use the term "local" to refer to the symbol name in the -// same package as the //go:linkname directive, whose name will be changed by -// the linker. We use the term "remote" to refer to the symbol name that we are -// changing to. -// // In the general case, the local symbol is a function declaration, and the // remote symbol is a real function in the standard library. -// linknameSignatures describes a the type signatures of the symbols in a -// //go:linkname directive. -type linknameSignatures struct { - local string - remote string // equivalent to local if "". -} - -func (l *linknameSignatures) Remote() string { - if l.remote == "" { - return l.local - } - return l.remote -} - -// linknameSymbols describes the symbol namess in a single //go:linkname +// linknameSymbol describes the symbol names in a single //go:linkname // directive. type linknameSymbols struct { pos token.Pos @@ -76,9 +156,7 @@ type linknameSymbols struct { remote string } -func findLinknames(pass *analysis.Pass, f *ast.File) []linknameSymbols { - var names []linknameSymbols - +func findLinknames(pass *analysis.Pass, f *ast.File) (names []linknameSymbols) { for _, cg := range f.Comments { for _, c := range cg.List { if len(c.Text) <= 2 || !strings.HasPrefix(c.Text[2:], "go:linkname ") { @@ -130,100 +208,297 @@ func splitSymbol(pkg *types.Package, symbol string) (packagePath, name string) { } } -func findObject(pkg *types.Package, symbol string) (types.Object, error) { - packagePath, symbolName := splitSymbol(pkg, symbol) - return findPackageObject(pkg, packagePath, symbolName) +// kindStr stores strings for basic kinds. +var kindStr = map[types.BasicKind]string{ + types.Bool: "bool", + types.Int: "int", + types.Int8: "int8", + types.Int16: "int16", + types.Int32: "int32", + types.Int64: "int64", + types.Uint: "uint", + types.Uint8: "uint8", + types.Uint16: "uint16", + types.Uint32: "uint32", + types.Uint64: "uint64", + types.Uintptr: "uintptr", + types.Float32: "float32", + types.Float64: "float64", + types.Complex64: "complex64", + types.Complex128: "complex128", + types.String: "string", + types.UnsafePointer: "uintptr", // See simplifyType; we cheat for pointers. } -func findPackageObject(pkg *types.Package, packagePath, symbolName string) (types.Object, error) { - if pkg.Path() == packagePath { - o := pkg.Scope().Lookup(symbolName) - if o == nil { - return nil, fmt.Errorf("%q not found in %q (names: %+v)", symbolName, packagePath, pkg.Scope().Names()) - } - return o, nil - } +type memoizer[T comparable] struct { + recentKeys [8]T + recentValues [8]string + nextEviction int +} - for _, p := range pkg.Imports() { - if o, err := findPackageObject(p, packagePath, symbolName); err == nil { - return o, nil +func (m *memoizer[T]) get(x T) (string, bool) { + for i, v := range m.recentKeys { + if v == x { + return m.recentValues[i], true } } - - return nil, fmt.Errorf("package %q not found", packagePath) + return "", false } -// checkOneLinkname verifies that the type of sym.local matches the type from -// knownLinknames. -func checkOneLinkname(pass *analysis.Pass, f *ast.File, sym linknameSymbols) { - remotePackage, remoteName := splitSymbol(pass.Pkg, sym.remote) +func (m *memoizer[T]) add(x T, s string) { + m.recentKeys[m.nextEviction%len(m.recentKeys)] = x + m.recentValues[m.nextEviction%len(m.recentValues)] = s + m.nextEviction++ +} - m, ok := knownLinknames[remotePackage] - if !ok { - pass.Reportf(sym.pos, "linkname to unknown symbol %q; add this symbol to checklinkname.knownLinknames type-check against the remote type", sym.remote) - return +func min(a, b int) int { + if a < b { + return a } + return b +} - linkname, ok := m[remoteName] - if !ok { - pass.Reportf(sym.pos, "linkname to unknown symbol %q; add this symbol to checklinkname.knownLinknames type-check against the remote type", sym.remote) - return +var ( + memoizedSlices memoizer[*types.Slice] + memoizedArrays memoizer[*types.Array] + memoizedMaps memoizer[*types.Map] + memoizedStructs memoizer[*types.Struct] + memoizedInterfaces memoizer[*types.Interface] + memoizedSignatures memoizer[*types.Signature] +) + +// simplifyType returns a simplified type string. +func simplifyType(t types.Type, maxDepth int) (string, int) { + if maxDepth <= 0 { + return fmt.Sprintf("..."), maxDepth // Don't bother. } - - local, err := findObject(pass.Pkg, sym.local) - if err != nil { - pass.Reportf(sym.pos, "Unable to find symbol %q: %v", sym.local, err) - return - } - - localSig, ok := local.Type().(*types.Signature) - if !ok { - pass.Reportf(local.Pos(), "%q object is not a signature: %+#v", sym.local, local) - return - } - - if linkname.local != localSig.String() { - pass.Reportf(local.Pos(), "%q signature got %q want %q; mismatched types?", sym.local, localSig.String(), linkname.local) - return + switch x := t.Underlying().(type) { + case *types.Pointer: + // Allow cheating for pointers. + return "uintptr", maxDepth + case *types.Signature: + // For functions, recursively simplify. + if s, ok := memoizedSignatures.get(x); ok { + return s, maxDepth + } + s, minDepth := makeSignature(x, maxDepth-1) + if minDepth > 0 { + memoizedSignatures.add(x, s) + } + return s, minDepth + case *types.Struct: + // Build the simplified struct definition. + if s, ok := memoizedStructs.get(x); ok { + return s, maxDepth + } + s, minDepth := makeStructSignature(x, maxDepth-1) + if minDepth > 0 { + memoizedStructs.add(x, s) + } + return s, minDepth + case *types.Basic: + // For any basic type (Int8, etc.), we represent as the kind. + if s, ok := kindStr[x.Kind()]; ok { + return s, maxDepth + } + return fmt.Sprintf("kind#%d", t), maxDepth + case *types.Interface: + // Write the interface declaration, it's usually empty. + if s, ok := memoizedInterfaces.get(x); ok { + return s, maxDepth + } + s, minDepth := makeInterfaceSignature(x, maxDepth-1) + if minDepth > 0 { + memoizedInterfaces.add(x, s) + } + return s, minDepth + case *types.Slice: + // List as a standard slice. + if s, ok := memoizedSlices.get(x); ok { + return s, maxDepth + } + s, minDepth := simplifyType(x.Elem(), maxDepth-1) + s = fmt.Sprintf("[]%s", s) + if minDepth > 0 { + memoizedSlices.add(x, s) + } + return s, minDepth + case *types.Array: + // List as an inline array definition. + if s, ok := memoizedArrays.get(x); ok { + return s, maxDepth + } + s, minDepth := simplifyType(x.Elem(), maxDepth-1) + s = fmt.Sprintf("[%d]%s", x.Len(), s) + if minDepth > 0 { + memoizedArrays.add(x, s) + } + return s, minDepth + case *types.Map: + // List as the standard map. + if s, ok := memoizedMaps.get(x); ok { + return s, maxDepth + } + keyS, minDepthKey := simplifyType(x.Key(), maxDepth-1) + valS, minDepthVal := simplifyType(x.Elem(), maxDepth-1) + s := fmt.Sprintf("map[%s]%s", keyS, valS) + minDepth := min(minDepthKey, minDepthVal) + if minDepth > 0 { + memoizedMaps.add(x, s) + } + return s, minDepth + default: + // Anything else, use the full string. + return t.String(), maxDepth } } -// checkOneRemote verifies that the type of sym matches wantSig. -func checkOneRemote(pass *analysis.Pass, sym, wantSig string) { - o := pass.Pkg.Scope().Lookup(sym) - if o == nil { - pass.Reportf(pass.Files[0].Package, "Cannot find known symbol %q", sym) - return +// makeStructSignature makes a struct signature. +func makeStructSignature(str *types.Struct, maxDepth int) (string, int) { + parts := make([]string, 0, str.NumFields()) + minDepth := maxDepth + for i := 0; i < len(parts); i++ { + s, localMinDepth := simplifyType(str.Field(i).Type(), maxDepth) + parts = append(parts, s) + minDepth = min(localMinDepth, minDepth) } + return fmt.Sprintf("struct{%s}", strings.Join(parts, ", ")), minDepth +} - sig, ok := o.Type().(*types.Signature) - if !ok { - pass.Reportf(o.Pos(), "%q object is not a signature: %+#v", sym, o) - return +// makeInterfaceSignature makes an interface signature. +func makeInterfaceSignature(iface *types.Interface, maxDepth int) (string, int) { + parts := make([]string, 0, iface.NumMethods()) + minDepth := maxDepth + for i := 0; i < len(parts); i++ { + s, localMinDepth := makeSignature(iface.Method(i).Type().(*types.Signature), maxDepth) + parts = append(parts, s) + minDepth = min(localMinDepth, minDepth) } + return fmt.Sprintf("interface{%s}", strings.Join(parts, ",")), minDepth +} - if sig.String() != wantSig { - pass.Reportf(o.Pos(), "%q signature got %q want %q; stdlib type changed?", sym, sig.String(), wantSig) - return +// makeSignature builds the special signature. +// +// This function preserves sensitive to basic types, but relaxes specifics around pointers. +func makeSignature(sig *types.Signature, maxDepth int) (string, int) { + params := make([]string, 0) + results := make([]string, 0) + minDepth := maxDepth + if r := sig.Recv(); r != nil { + s, localMinDepth := simplifyType(r.Type(), maxDepth) + params = append(params, s) + minDepth = min(localMinDepth, minDepth) + } + if p := sig.Params(); p != nil { + for i := 0; i < p.Len(); i++ { + s, localMinDepth := simplifyType(p.At(i).Type(), maxDepth) + params = append(params, s) + minDepth = min(localMinDepth, minDepth) + } + } + if r := sig.Results(); r != nil { + for i := 0; i < r.Len(); i++ { + s, localMinDepth := simplifyType(r.At(i).Type(), maxDepth) + results = append(results, s) + minDepth = min(localMinDepth, minDepth) + } + } + return fmt.Sprintf("func (%s) (%s)", strings.Join(params, ", "), strings.Join(results, ", ")), minDepth +} + +// findAllSymbols finds all package-local symbols. +func findAllSymbols(pkg *types.Package) ResolvedSymbols { + const initialMaxDepth = 4 // Don't allow infinite recursion. + localSymbols := make(map[string]string) + for _, name := range pkg.Scope().Names() { + obj := pkg.Scope().Lookup(name) + // Only include unexported, top-level functions. It is possible + // to define linknames against other types, but we avoid excessive + // excess data by not type checking these cases, which are rare. + if _, ok := obj.(*types.Func); !ok || obj.Exported() { + continue + } + localSymbols[name], _ = simplifyType(obj.Type(), initialMaxDepth) + } + return ResolvedSymbols{ + pkg.Path(): localSymbols, } } func run(pass *analysis.Pass) (any, error) { - // First, check if any remote symbols are in this package. - p, ok := knownLinknames[pass.Pkg.Path()] - if ok { - for sym, l := range p { - checkOneRemote(pass, sym, l.Remote()) + // Grab all local symbols. + rs := findAllSymbols(pass.Pkg) + + // Check for local //go:linkname directives in this package. + localSymbols := rs[pass.Pkg.Path()] + localPos := make(map[string]token.Pos) + ur := make(UnresolvedLinknames) + for _, f := range pass.Files { + for _, sym := range findLinknames(pass, f) { + localSig, ok := localSymbols[sym.local] + if !ok { + // The localSymbols only include unexported functions. If we don't + // match either of those, then this is a case which can be ignored. + continue + } + + // Note that some of these remote packages may in fact be this + // package. We still use a single consistent pass for resolution, + // and just use the location of the declaration if it is local. + remotePackage, remoteName := splitSymbol(pass.Pkg, sym.remote) + if _, ok := ur[remotePackage]; !ok { + ur[remotePackage] = make(map[string]string) + } + ur[remotePackage][remoteName] = localSig + localPos[sym.local] = sym.pos + + // Remap the local symbols, if required. + if remotePackage == pass.Pkg.Path() { + localPos[remoteName] = sym.pos + localSymbols[remoteName] = localSymbols[sym.local] + delete(localSymbols, sym.local) + } } } - // Then check for local //go:linkname directives in this package. - for _, f := range pass.Files { - names := findLinknames(pass, f) - for _, n := range names { - checkOneLinkname(pass, f, n) + // Build our resolution function. + resolvePos := func(pkgName, symbolName string) token.Pos { + if pkgName == pass.Pkg.Path() { + return localPos[symbolName] + } + // Scan the top-level scope for a relevant import. + for _, name := range pass.Pkg.Scope().Names() { + obj := pass.Pkg.Scope().Lookup(name) + if pn, ok := obj.(*types.PkgName); ok && pn.Pkg().Path() == pkgName { + return pn.Pos() + } + } + return 0 // No valid location. + } + + // Merge in all underlying facts. + for _, importPkg := range pass.Pkg.Imports() { + var ( + iur UnresolvedLinknames + irs ResolvedSymbols + ) + if pass.ImportPackageFact(importPkg, &iur) { + ur.merge(pass, iur, resolvePos) + } + if pass.ImportPackageFact(importPkg, &irs) { + rs.merge(pass, irs, resolvePos) } } + // Attempt to resolve the facts. + ur.resolve(pass, rs, resolvePos) + if pass.Pkg.Path() == "main" { + ur.resolveRemaining(pass, resolvePos) + } + + // Export all facts. + pass.ExportPackageFact(&ur) + pass.ExportPackageFact(&rs) + return nil, nil } diff --git a/tools/checklinkname/known.go b/tools/checklinkname/known.go deleted file mode 100644 index 1164cd02b..000000000 --- a/tools/checklinkname/known.go +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright 2021 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 checklinkname - -// knownLinknames is the set of the symbols for which we can do a rudimentary -// type-check on. -// -// When analyzing the remote package (e.g., runtime), we verify the symbol -// signature matches 'remote'. When analyzing local packages with //go:linkname -// directives, we verify the symbol signature matches 'local'. -// -// Usually these are identical, but may differ slightly if equivalent -// replacement types are used in the local packages, such as a copy of a struct -// or uintptr instead of a pointer type. -// -// NOTE: It is the responsibility of the developer to verify the safety of the -// signatures used here! This analyzer only checks that types match this map; -// it does not verify compatibility of the entries themselves. -// -// //go:linkname directives with no corresponding entry here will trigger a -// finding. -// -// We preform only rudimentary string-based type-checking due to limitations in -// the analysis framework. Ideally, from the local package we'd lookup the -// remote symbol's types.Object and perform robust type-checking. -// Unfortunately, remote symbols are typically loaded from the remote package's -// gcexportdata. Since //go:linkname targets are usually not exported symbols, -// they are no included in gcexportdata and we cannot load their types.Object. -// -// TODO(b/165820485): Add option to specific per-version signatures. -var knownLinknames = map[string]map[string]linknameSignatures{ - "runtime": { - "cputicks": { - local: "func() int64", - }, - "entersyscall": { - local: "func()", - }, - "entersyscallblock": { - local: "func()", - }, - "exitsyscall": { - local: "func()", - }, - "fastrand": { - local: "func() uint32", - }, - "gopark": { - // TODO(b/165820485): add verification of waitReason - // size and reason and traceEv values. - local: "func(unlockf func(uintptr, unsafe.Pointer) bool, lock unsafe.Pointer, reason uint8, traceEv byte, traceskip int)", - remote: "func(unlockf func(*runtime.g, unsafe.Pointer) bool, lock unsafe.Pointer, reason runtime.waitReason, traceEv byte, traceskip int)", - }, - "goready": { - local: "func(gp uintptr, traceskip int)", - remote: "func(gp *runtime.g, traceskip int)", - }, - "goyield": { - local: "func()", - }, - "memmove": { - local: "func(to unsafe.Pointer, from unsafe.Pointer, n uintptr)", - }, - "throw": { - local: "func(s string)", - }, - "wakep": { - local: "func()", - }, - "nanotime": { - local: "func() int64", - }, - }, - "sync": { - "runtime_canSpin": { - local: "func(i int) bool", - }, - "runtime_doSpin": { - local: "func()", - }, - "runtime_Semacquire": { - // The only difference here is the parameter names. We - // can't just change our local use to match remote, as - // the stdlib runtime and sync packages also disagree - // on the name, and the analyzer checks that use as - // well. - local: "func(addr *uint32)", - remote: "func(s *uint32)", - }, - "runtime_Semrelease": { - // See above. - local: "func(addr *uint32, handoff bool, skipframes int)", - remote: "func(s *uint32, handoff bool, skipframes int)", - }, - }, - "syscall": { - "runtime_BeforeFork": { - local: "func()", - }, - "runtime_AfterFork": { - local: "func()", - }, - "runtime_AfterForkInChild": { - local: "func()", - }, - }, -} diff --git a/tools/checklinkname/test/test_unsafe.go b/tools/checklinkname/test/test_unsafe.go index a7504591c..672ef79af 100644 --- a/tools/checklinkname/test/test_unsafe.go +++ b/tools/checklinkname/test/test_unsafe.go @@ -19,7 +19,7 @@ import ( _ "unsafe" // for go:linkname. ) -//go:linkname DetachedLinkname runtime.fastrand +//go:linkname detachedLinkname runtime.fastrand //go:linkname attachedLinkname runtime.entersyscall func attachedLinkname() @@ -30,5 +30,5 @@ func AttachedLinkname() { attachedLinkname() } -// DetachedLinkname has a linkname elsewhere in the file. -func DetachedLinkname() uint32 +// detachedLinkname has a linkname elsewhere in the file. +func detachedLinkname() uint32 diff --git a/tools/nogo/check/check.go b/tools/nogo/check/check.go index c3fd0e9df..f156e8dd4 100644 --- a/tools/nogo/check/check.go +++ b/tools/nogo/check/check.go @@ -727,6 +727,12 @@ func SplitPackages(srcs []string, srcRootPrefix string) map[string][]string { continue } + // Place the special runtime package (functions emitted by the + // compiler itself) into the runtime packages. + if strings.Contains(filename, "cmd/compile/internal/typecheck/_builtin/runtime.go") { + pkg = "runtime" + } + // Add to the package. sources[pkg] = append(sources[pkg], filename) } diff --git a/tools/nogo/defs.bzl b/tools/nogo/defs.bzl index afecb7445..e23e56a06 100644 --- a/tools/nogo/defs.bzl +++ b/tools/nogo/defs.bzl @@ -342,7 +342,6 @@ nogo_aspect = go_rule( def _nogo_test_impl(ctx): """Check nogo findings.""" - nogo_target_info = ctx.attr._target[NogoTargetInfo] # Ensure there's a single dependency. if len(ctx.attr.deps) != 1: