]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: add -asan option
authorfanzha02 <fannie.zhang@arm.com>
Mon, 4 Jan 2021 09:14:35 +0000 (17:14 +0800)
committerIan Lance Taylor <iant@golang.org>
Mon, 25 Oct 2021 21:51:20 +0000 (21:51 +0000)
The -asan option causes the compiler to add instrumentation for the
C/C++ address sanitizer.  Every memory read/write will be replaced
by a call to asanread/asanwrite.

This CL also inserts asan instrumentation during SSA building.

This CL passes tests but is not usable by itself. The actual
implementation of asanread/asanwrite in the runtime package, and
support for -asan in the go tool and tests, will follow in subsequent
CLs.

Updates #44853.

Change-Id: Ia18c9c5d5c351857420d2f6835f0daec2ad31096
Reviewed-on: https://go-review.googlesource.com/c/go/+/298611
Trust: fannie zhang <Fannie.Zhang@arm.com>
Run-TryBot: fannie zhang <Fannie.Zhang@arm.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
12 files changed:
src/cmd/compile/doc.go
src/cmd/compile/internal/base/base.go
src/cmd/compile/internal/base/flag.go
src/cmd/compile/internal/gc/main.go
src/cmd/compile/internal/ir/func.go
src/cmd/compile/internal/ir/symtab.go
src/cmd/compile/internal/noder/import.go
src/cmd/compile/internal/reflectdata/reflect.go
src/cmd/compile/internal/ssagen/ssa.go
src/cmd/compile/internal/typecheck/builtin.go
src/cmd/compile/internal/typecheck/builtin/runtime.go
src/cmd/internal/sys/supported.go

index b68ef274f379e0fa932b54307afafb0b8db1cfdf..ef7fa86749f0137d03c949a08dcf504cb58bb56f 100644 (file)
@@ -44,6 +44,8 @@ Flags:
                Print compiler version and exit.
        -asmhdr file
                Write assembly header to file.
+       -asan
+               Insert calls to C/C++ address sanitizer.
        -buildid id
                Record id as the build id in the export metadata.
        -blockprofile file
index 4c2516f60e364b5d177707daaa8584c0e1920777..be6d49fac766db1d846ad5a376e4e0d8297ece0e 100644 (file)
@@ -67,6 +67,7 @@ var NoInstrumentPkgs = []string{
        "runtime",
        "runtime/race",
        "runtime/msan",
+       "runtime/asan",
        "internal/cpu",
 }
 
index 241f5da1855f5361fed36056f27d0395b0768901..51938e8fd5693e846269937b4512f73b3ea6469d 100644 (file)
@@ -84,6 +84,7 @@ type CmdFlags struct {
 
        // Longer names
        AsmHdr             string       "help:\"write assembly header to `file`\""
+       ASan               bool         "help:\"build code compatible with C/C++ address sanitizer\""
        Bench              string       "help:\"append benchmark times to `file`\""
        BlockProfile       string       "help:\"write block profile to `file`\""
        BuildID            string       "help:\"record `id` as the build id in the export metadata\""
@@ -177,6 +178,9 @@ func ParseFlags() {
        if Flag.MSan && !sys.MSanSupported(buildcfg.GOOS, buildcfg.GOARCH) {
                log.Fatalf("%s/%s does not support -msan", buildcfg.GOOS, buildcfg.GOARCH)
        }
+       if Flag.ASan && !sys.ASanSupported(buildcfg.GOOS, buildcfg.GOARCH) {
+               log.Fatalf("%s/%s does not support -asan", buildcfg.GOOS, buildcfg.GOARCH)
+       }
        if Flag.Race && !sys.RaceDetectorSupported(buildcfg.GOOS, buildcfg.GOARCH) {
                log.Fatalf("%s/%s does not support -race", buildcfg.GOOS, buildcfg.GOARCH)
        }
@@ -217,12 +221,16 @@ func ParseFlags() {
                }
                Flag.LowerO = p + suffix
        }
-
-       if Flag.Race && Flag.MSan {
+       switch {
+       case Flag.Race && Flag.MSan:
                log.Fatal("cannot use both -race and -msan")
+       case Flag.Race && Flag.ASan:
+               log.Fatal("cannot use both -race and -asan")
+       case Flag.MSan && Flag.ASan:
+               log.Fatal("cannot use both -msan and -asan")
        }
-       if Flag.Race || Flag.MSan {
-               // -race and -msan imply -d=checkptr for now.
+       if Flag.Race || Flag.MSan || Flag.ASan {
+               // -race, -msan and -asan imply -d=checkptr for now.
                if Debug.Checkptr == -1 { // if not set explicitly
                        Debug.Checkptr = 1
                }
index 74b21571b3a8f74160e50975572929c07074241c..ed81ef7bc0471458df4387387a3466c1979badf6 100644 (file)
@@ -107,7 +107,7 @@ func Main(archInit func(*ssagen.ArchInfo)) {
        // Record flags that affect the build result. (And don't
        // record flags that don't, since that would cause spurious
        // changes in the binary.)
-       dwarfgen.RecordFlags("B", "N", "l", "msan", "race", "shared", "dynlink", "dwarf", "dwarflocationlists", "dwarfbasentries", "smallframes", "spectre")
+       dwarfgen.RecordFlags("B", "N", "l", "msan", "race", "asan", "shared", "dynlink", "dwarf", "dwarflocationlists", "dwarfbasentries", "smallframes", "spectre")
 
        if !base.EnableTrace && base.Flag.LowerT {
                log.Fatalf("compiler not built with support for -t")
@@ -149,11 +149,12 @@ func Main(archInit func(*ssagen.ArchInfo)) {
        if base.Compiling(base.NoInstrumentPkgs) {
                base.Flag.Race = false
                base.Flag.MSan = false
+               base.Flag.ASan = false
        }
 
        ssagen.Arch.LinkArch.Init(base.Ctxt)
        startProfile()
-       if base.Flag.Race || base.Flag.MSan {
+       if base.Flag.Race || base.Flag.MSan || base.Flag.ASan {
                base.Flag.Cfg.Instrumenting = true
        }
        if base.Flag.Dwarf {
index 18d0b023ad6e916c94cc98bec2787e6cba4bff15..41c96079f75df3ceed4c695ed686f89f939a5415 100644 (file)
@@ -201,7 +201,7 @@ const (
        funcNilCheckDisabled         // disable nil checks when compiling this function
        funcInlinabilityChecked      // inliner has already determined whether the function is inlinable
        funcExportInline             // include inline body in export data
-       funcInstrumentBody           // add race/msan instrumentation during SSA construction
+       funcInstrumentBody           // add race/msan/asan instrumentation during SSA construction
        funcOpenCodedDeferDisallowed // can't do open-coded defers
        funcClosureCalled            // closure is only immediately called; used by escape analysis
 )
index 1435e4313e000d070365d5d944ce24e4c1664e37..b204a1d544e7b4e2ba9835d1b7c27f529082adf6 100644 (file)
@@ -15,6 +15,8 @@ var Syms struct {
        AssertE2I2        *obj.LSym
        AssertI2I         *obj.LSym
        AssertI2I2        *obj.LSym
+       Asanread          *obj.LSym
+       Asanwrite         *obj.LSym
        CheckPtrAlignment *obj.LSym
        Deferproc         *obj.LSym
        DeferprocStack    *obj.LSym
index 0aaf894641337f062f595d312bd2025ec0a2ae50..58dffbad1e4d5c0c11850383ea5e391d9d6ea59d 100644 (file)
@@ -127,6 +127,8 @@ func openPackage(path string) (*os.File, error) {
                        suffix = "_race"
                } else if base.Flag.MSan {
                        suffix = "_msan"
+               } else if base.Flag.ASan {
+                       suffix = "_asan"
                }
 
                if file, err := os.Open(fmt.Sprintf("%s/pkg/%s_%s%s/%s.a", buildcfg.GOROOT, buildcfg.GOOS, buildcfg.GOARCH, suffix, path)); err == nil {
index b4ed96c18a103944ff49a42fefe1323cd52a6c35..ce41b8c9344a1dcee8d800e93c9123a732f47f0d 100644 (file)
@@ -1413,6 +1413,9 @@ func WriteBasicTypes() {
                if base.Flag.MSan {
                        dimportpath(types.NewPkg("runtime/msan", ""))
                }
+               if base.Flag.ASan {
+                       dimportpath(types.NewPkg("runtime/asan", ""))
+               }
 
                dimportpath(types.NewPkg("main", ""))
        }
index 5a958a569d24eba24606b5a7897a6ae87610fb24..6b595ea75d4b54494300ac81eb4d1e3f96e844ee 100644 (file)
@@ -108,6 +108,8 @@ func InitConfig() {
        ir.Syms.Msanread = typecheck.LookupRuntimeFunc("msanread")
        ir.Syms.Msanwrite = typecheck.LookupRuntimeFunc("msanwrite")
        ir.Syms.Msanmove = typecheck.LookupRuntimeFunc("msanmove")
+       ir.Syms.Asanread = typecheck.LookupRuntimeFunc("asanread")
+       ir.Syms.Asanwrite = typecheck.LookupRuntimeFunc("asanwrite")
        ir.Syms.Newobject = typecheck.LookupRuntimeFunc("newobject")
        ir.Syms.Newproc = typecheck.LookupRuntimeFunc("newproc")
        ir.Syms.Panicdivide = typecheck.LookupRuntimeFunc("panicdivide")
@@ -1245,10 +1247,10 @@ func (s *state) instrument(t *types.Type, addr *ssa.Value, kind instrumentKind)
 }
 
 // instrumentFields instruments a read/write operation on addr.
-// If it is instrumenting for MSAN and t is a struct type, it instruments
+// If it is instrumenting for MSAN or ASAN and t is a struct type, it instruments
 // operation for each field, instead of for the whole struct.
 func (s *state) instrumentFields(t *types.Type, addr *ssa.Value, kind instrumentKind) {
-       if !base.Flag.MSan || !t.IsStruct() {
+       if !(base.Flag.MSan || base.Flag.ASan) || !t.IsStruct() {
                s.instrument(t, addr, kind)
                return
        }
@@ -1327,6 +1329,16 @@ func (s *state) instrument2(t *types.Type, addr, addr2 *ssa.Value, kind instrume
                default:
                        panic("unreachable")
                }
+       } else if base.Flag.ASan {
+               switch kind {
+               case instrumentRead:
+                       fn = ir.Syms.Asanread
+               case instrumentWrite:
+                       fn = ir.Syms.Asanwrite
+               default:
+                       panic("unreachable")
+               }
+               needWidth = true
        } else {
                panic("unreachable")
        }
@@ -3002,7 +3014,7 @@ func (s *state) exprCheckPtr(n ir.Node, checkPtrOK bool) *ssa.Value {
                }
                // If n is addressable and can't be represented in
                // SSA, then load just the selected field. This
-               // prevents false memory dependencies in race/msan
+               // prevents false memory dependencies in race/msan/asan
                // instrumentation.
                if ir.IsAddressable(n) && !s.canSSA(n) {
                        p := s.addr(n)
index 524360e8dfc7fe4b9b4d5366fbe8d99fef5a2b74..67597cebb463025cc3db34e74b052eec973b83ca 100644 (file)
@@ -192,6 +192,8 @@ var runtimeDecls = [...]struct {
        {"msanread", funcTag, 140},
        {"msanwrite", funcTag, 140},
        {"msanmove", funcTag, 141},
+       {"asanread", funcTag, 140},
+       {"asanwrite", funcTag, 140},
        {"checkptrAlignment", funcTag, 142},
        {"checkptrArithmetic", funcTag, 144},
        {"libfuzzerTraceCmp1", funcTag, 145},
index 66641fb5aacb99a1db654006822f149951a05845..04ae4f23a387790c11cc5d9e98360c55beff5019 100644 (file)
@@ -250,6 +250,10 @@ func msanread(addr, size uintptr)
 func msanwrite(addr, size uintptr)
 func msanmove(dst, src, size uintptr)
 
+// address sanitizer
+func asanread(addr, size uintptr)
+func asanwrite(addr, size uintptr)
+
 func checkptrAlignment(unsafe.Pointer, *byte, uintptr)
 func checkptrArithmetic(unsafe.Pointer, []unsafe.Pointer)
 
index 0d2bad961278f4392c3c27a1ecc4617ac2d9b74c..e6c56fbc567dd78e546bc8e33a2355dc4e983891 100644 (file)
@@ -34,6 +34,17 @@ func MSanSupported(goos, goarch string) bool {
        }
 }
 
+// ASanSupported reports whether goos/goarch supports the address
+// sanitizer option.
+func ASanSupported(goos, goarch string) bool {
+       switch goos {
+       case "linux":
+               return goarch == "arm64" || goarch == "amd64"
+       default:
+               return false
+       }
+}
+
 // MustLinkExternal reports whether goos/goarch requires external linking.
 // (This is the opposite of internal/testenv.CanInternalLink. Keep them in sync.)
 func MustLinkExternal(goos, goarch string) bool {