gvisor/tools/checklinkname
Michael Pratt 62ea5c0a22 checklinkname: rudimentary type-checking of linkname directives
This CL introduces a 'checklinkname' analyzer, which provides rudimentary
type-checking that verifies that function signatures on the local and remote
sides of //go:linkname directives match expected values.

If the Go standard library changes the definitions of any of these function,
checklinkname will flag the change as a finding, providing an error informing
the gVisor team to adapt to the upstream changes. This allows us to eliminate
the majority of gVisor's forward-looking negative build tags, as we can catch
mismatches in testing [1].

The remaining forward-looking negative build tags are covering shared struct
definitions, which I hope to add to checklinkname in a future CL.

[1] Of course, semantics/requirements can change without the signature
changing, so we still must be careful, but this covers the common case.

PiperOrigin-RevId: 387873847
2021-07-30 13:42:15 -07:00
..
test checklinkname: rudimentary type-checking of linkname directives 2021-07-30 13:42:15 -07:00
BUILD checklinkname: rudimentary type-checking of linkname directives 2021-07-30 13:42:15 -07:00
README.md checklinkname: rudimentary type-checking of linkname directives 2021-07-30 13:42:15 -07:00
check_linkname.go checklinkname: rudimentary type-checking of linkname directives 2021-07-30 13:42:15 -07:00
known.go checklinkname: rudimentary type-checking of linkname directives 2021-07-30 13:42:15 -07:00

README.md

checklinkname Analyzer

checklinkname is an analyzer to provide rudimentary type-checking for //go:linkname directives. Since //go:linkname only affects linker behavior, there is no built-in type safety and it is the programmer's responsibility to ensure the types on either side are compatible.

checklinkname helps with this by checking that uses match expectations, as defined in this package.

known.go contains the set of known linkname targets. For most functions, we expect identical types on both sides of the linkname. In a few cases, the types may be slightly different (e.g., local redefinition of internal type). It is still the responsibility of the programmer to ensure the signatures in known.go are compatible and safe.

Findings

Here are the most common findings from this package, and how to resolve them.

runtime.foo signature got "BAR" want "BAZ"; stdlib type changed?

The definition of runtime.foo in the standard library does not match the expected type in known.go. This means that the function signature in the standard library changed.

Addressing this will require creating a new linkname directive in a new Go version build-tagged in any packages using this symbol. Be sure to also check to ensure use with the new version is safe, as function constraints may have changed in addition to the signature.

known.go will also need to be updated to accept the new signature for the new version of Go.

Cannot find known symbol "runtime.foo"

The standard library has removed runtime.foo entirely. Handling is similar to above, except existing code must transition away from the symbol entirely (note that is may simply be renamed).

linkname to unknown symbol "mypkg.foo"; add this symbol to checklinkname.knownLinknames type-check against the remote type

A package has added a new linkname directive for a symbol not listed in known.go. Address this by adding a new entry for the target symbol. The local field should be the expected type in your package, while remote should be expected type in the remote package (e.g., in the standard library). These are typically identical, in which case remote can be omitted.

usage: //go:linkname localname [linkname]

Malformed //go:linkname directive. This should be accompanied by a build failure in the package.