| // Copyright 2023 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| package objabi | |
| import "sync" | |
| // PkgSpecial indicates special build properties of a given runtime-related | |
| // package. | |
| type PkgSpecial struct { | |
| // Runtime indicates that this package is "runtime" or imported by | |
| // "runtime". This has several effects (which maybe should be split out): | |
| // | |
| // - Implicit allocation is disallowed. | |
| // | |
| // - Various runtime pragmas are enabled. | |
| // | |
| // - Optimizations are always enabled. | |
| // | |
| // - Checkptr is always disabled. | |
| // | |
| // This should be set for runtime and all packages it imports, and may be | |
| // set for additional packages. | |
| Runtime bool | |
| // NoInstrument indicates this package should not receive sanitizer | |
| // instrumentation. In many of these, instrumentation could cause infinite | |
| // recursion. This is all runtime packages, plus those that support the | |
| // sanitizers. | |
| NoInstrument bool | |
| // NoRaceFunc indicates functions in this package should not get | |
| // racefuncenter/racefuncexit instrumentation Memory accesses in these | |
| // packages are either uninteresting or will cause false positives. | |
| NoRaceFunc bool | |
| // AllowAsmABI indicates that assembly in this package is allowed to use ABI | |
| // selectors in symbol names. Generally this is needed for packages that | |
| // interact closely with the runtime package or have performance-critical | |
| // assembly. | |
| AllowAsmABI bool | |
| } | |
| var runtimePkgs = []string{ | |
| // TODO(panjf2000): consider syncing the list inside the | |
| // isAsyncSafePoint in preempt.go based on this list? | |
| "runtime", | |
| "internal/runtime/atomic", | |
| "internal/runtime/cgroup", | |
| "internal/runtime/exithook", | |
| "internal/runtime/gc", | |
| "internal/runtime/gc/scan", | |
| "internal/runtime/maps", | |
| "internal/runtime/math", | |
| "internal/runtime/sys", | |
| "internal/runtime/syscall/linux", | |
| "internal/runtime/syscall/windows", | |
| "internal/abi", | |
| "internal/bytealg", | |
| "internal/byteorder", | |
| "internal/chacha8rand", | |
| "internal/coverage/rtcov", | |
| "internal/cpu", | |
| "internal/goarch", | |
| "internal/godebugs", | |
| "internal/goexperiment", | |
| "internal/goos", | |
| "internal/profilerecord", | |
| "internal/strconv", | |
| "internal/stringslite", | |
| } | |
| // extraNoInstrumentPkgs is the set of packages in addition to runtimePkgs that | |
| // should have NoInstrument set. | |
| var extraNoInstrumentPkgs = []string{ | |
| "runtime/race", | |
| "runtime/msan", | |
| "runtime/asan", | |
| // We omit bytealg even though it's imported by runtime because it also | |
| // backs a lot of package bytes. Currently we don't have a way to omit race | |
| // instrumentation when used from the runtime while keeping race | |
| // instrumentation when used from user code. Somehow this doesn't seem to | |
| // cause problems, though we may be skating on thin ice. See #61204. | |
| "-internal/bytealg", | |
| } | |
| var noRaceFuncPkgs = []string{"sync", "sync/atomic", "internal/sync", "internal/runtime/atomic"} | |
| var allowAsmABIPkgs = []string{ | |
| "runtime", | |
| "reflect", | |
| "syscall", | |
| "internal/bytealg", | |
| "internal/chacha8rand", | |
| "internal/runtime/syscall/linux", | |
| "internal/runtime/syscall/windows", | |
| "internal/runtime/startlinetest", | |
| } | |
| // LookupPkgSpecial returns special build properties for the given package path. | |
| func LookupPkgSpecial(pkgPath string) PkgSpecial { | |
| return pkgSpecialsOnce()[pkgPath] | |
| } | |
| var pkgSpecialsOnce = sync.OnceValue(func() map[string]PkgSpecial { | |
| // Construct pkgSpecials from various package lists. This lets us use | |
| // more flexible logic, while keeping the final map simple, and avoids | |
| // the init-time cost of a map. | |
| pkgSpecials := make(map[string]PkgSpecial) | |
| set := func(elt string, f func(*PkgSpecial)) { | |
| s := pkgSpecials[elt] | |
| f(&s) | |
| pkgSpecials[elt] = s | |
| } | |
| for _, pkg := range runtimePkgs { | |
| set(pkg, func(ps *PkgSpecial) { ps.Runtime = true; ps.NoInstrument = true }) | |
| } | |
| for _, pkg := range extraNoInstrumentPkgs { | |
| if pkg[0] == '-' { | |
| set(pkg[1:], func(ps *PkgSpecial) { ps.NoInstrument = false }) | |
| } else { | |
| set(pkg, func(ps *PkgSpecial) { ps.NoInstrument = true }) | |
| } | |
| } | |
| for _, pkg := range noRaceFuncPkgs { | |
| set(pkg, func(ps *PkgSpecial) { ps.NoRaceFunc = true }) | |
| } | |
| for _, pkg := range allowAsmABIPkgs { | |
| set(pkg, func(ps *PkgSpecial) { ps.AllowAsmABI = true }) | |
| } | |
| return pkgSpecials | |
| }) | |