From c4772d30bfbed6cfbfdf92066990b5c6dc4065bb Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Tue, 14 May 2024 00:01:49 -0400 Subject: cmd/link: disallow pull-only linknames As mentioned in CL 584598, linkname is a mechanism that, when abused, can break API integrity and even safety of Go programs. CL 584598 is a first step to restrict the use of linknames, by implementing a blocklist. This CL takes a step further, tightening up the restriction by allowing linkname references ("pull") only when the definition side explicitly opts into it, by having a linkname on the definition (possibly to itself). This way, it is at least clear on the definition side that the symbol, despite being unexported, is accessed outside of the package. Unexported symbols without linkname can now be actually private. This is similar to the symbol visibility rule used by gccgo for years (which defines unexported non-linknamed symbols as C static symbols). As there can be pull-only linknames in the wild that may be broken by this change, we currently only enforce this rule for symbols defined in the standard library. Push linknames are added in the standard library to allow things build. Linkname references to external (non-Go) symbols are still allowed, as their visibility is controlled by the C symbol visibility rules and enforced by the C (static or dynamic) linker. Assembly symbols are treated similar to linknamed symbols. This is controlled by -checklinkname linker flag, currently not enabled by default. A follow-up CL will enable it by default. Change-Id: I07344f5c7a02124dbbef0fbc8fec3b666a4b2b0e Reviewed-on: https://go-review.googlesource.com/c/go/+/585358 LUCI-TryBot-Result: Go LUCI Reviewed-by: Than McIntosh Reviewed-by: Russ Cox --- src/runtime/coverage/emit.go | 3 +++ src/runtime/coverage/testsupport.go | 6 ++++++ 2 files changed, 9 insertions(+) (limited to 'src/runtime/coverage') diff --git a/src/runtime/coverage/emit.go b/src/runtime/coverage/emit.go index 6fe04daea8..6510c889ea 100644 --- a/src/runtime/coverage/emit.go +++ b/src/runtime/coverage/emit.go @@ -574,6 +574,9 @@ func (s *emitState) emitCounterDataFile(finalHash [16]byte, w io.Writer) error { return nil } +// markProfileEmitted is injected to testmain via linkname. +//go:linkname markProfileEmitted + // markProfileEmitted signals the runtime/coverage machinery that // coverage data output files have already been written out, and there // is no need to take any additional action at exit time. This diff --git a/src/runtime/coverage/testsupport.go b/src/runtime/coverage/testsupport.go index 4b00f3a0f7..b673d3cd2c 100644 --- a/src/runtime/coverage/testsupport.go +++ b/src/runtime/coverage/testsupport.go @@ -22,6 +22,9 @@ import ( "unsafe" ) +// processCoverTestDir is injected in testmain. +//go:linkname processCoverTestDir + // processCoverTestDir is called (via a linknamed reference) from // testmain code when "go test -cover" is in effect. It is not // intended to be used other than internally by the Go command's @@ -277,6 +280,9 @@ func (ts *tstate) readAuxMetaFiles(metafiles string, importpaths map[string]stru return nil } +// snapshot is injected in testmain. +//go:linkname snapshot + // snapshot returns a snapshot of coverage percentage at a moment of // time within a running test, so as to support the testing.Coverage() // function. This version doesn't examine coverage meta-data, so the -- cgit v1.3