]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: add -msan option
authorIan Lance Taylor <iant@golang.org>
Wed, 21 Oct 2015 14:04:10 +0000 (07:04 -0700)
committerIan Lance Taylor <iant@golang.org>
Wed, 21 Oct 2015 14:58:53 +0000 (14:58 +0000)
The -msan option causes the compiler to add instrumentation for the
C/C++ memory sanitizer.  Every memory read/write will be preceded by
a call to msanread/msanwrite.

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

Change-Id: I3d517fb3e6e65d9bf9433db070a420fd11f57816
Reviewed-on: https://go-review.googlesource.com/16160
Reviewed-by: David Crawshaw <crawshaw@golang.org>
src/cmd/compile/doc.go
src/cmd/compile/internal/gc/builtin.go
src/cmd/compile/internal/gc/builtin/runtime.go
src/cmd/compile/internal/gc/go.go
src/cmd/compile/internal/gc/lex.go
src/cmd/compile/internal/gc/racewalk.go
src/cmd/compile/internal/gc/reflect.go
src/cmd/compile/internal/gc/subr.go
src/cmd/compile/internal/gc/walk.go

index 59c660b2d5b8aae1bf7e475ef95a8496cb13de05..f70c1cf6d46453d58d7797996e300d4c5d5b163f 100644 (file)
@@ -66,6 +66,8 @@ Flags:
                Write memory profile for the compilation to file.
        -memprofilerate rate
                Set runtime.MemProfileRate for the compilation to rate.
+       -msan
+               Insert calls to C/C++ memory sanitizer.
        -nolocalimports
                Disallow local (relative) imports.
        -o file
index f09dd5690f9b327f1a7801b5b3f5368560cc7b94..5b2ddbdfe3c0cc69473d969c40d74407964074cd 100644 (file)
@@ -155,6 +155,8 @@ const runtimeimport = "" +
        "func @\"\".racewrite (? uintptr)\n" +
        "func @\"\".racereadrange (@\"\".addr·1 uintptr, @\"\".size·2 uintptr)\n" +
        "func @\"\".racewriterange (@\"\".addr·1 uintptr, @\"\".size·2 uintptr)\n" +
+       "func @\"\".msanread (@\"\".addr·1 uintptr, @\"\".size·2 uintptr)\n" +
+       "func @\"\".msanwrite (@\"\".addr·1 uintptr, @\"\".size·2 uintptr)\n" +
        "\n" +
        "$$\n"
 
index 6210f10cdf457e45b34f2bf1a907cd6cb8e96fd5..930175781f5af5bb25e4e7362cd5473a20d72574 100644 (file)
@@ -193,3 +193,7 @@ func raceread(uintptr)
 func racewrite(uintptr)
 func racereadrange(addr, size uintptr)
 func racewriterange(addr, size uintptr)
+
+// memory sanitizer
+func msanread(addr, size uintptr)
+func msanwrite(addr, size uintptr)
index 79b9d9f692b0ba7b684270d46712dab0251b0cd2..c1899ef9808d7fde774df770490f1633173f9331 100644 (file)
@@ -511,6 +511,8 @@ var Runtimepkg *Pkg // package runtime
 
 var racepkg *Pkg // package runtime/race
 
+var msanpkg *Pkg // package runtime/msan
+
 var typepkg *Pkg // fake package for runtime type info (headers)
 
 var typelinkpkg *Pkg // fake package for runtime type info (data)
@@ -645,6 +647,8 @@ var flag_installsuffix string
 
 var flag_race int
 
+var flag_msan int
+
 var flag_largemodel int
 
 // Whether we are adding any sort of code instrumentation, such as
index b9ce4cb0108d0729de2caa9436c2b75997c7c8e2..0093e1b67696913664ead727a68751d7ad68f237 100644 (file)
@@ -200,6 +200,7 @@ func Main() {
        obj.Flagcount("l", "disable inlining", &Debug['l'])
        obj.Flagcount("live", "debug liveness analysis", &debuglive)
        obj.Flagcount("m", "print optimization decisions", &Debug['m'])
+       obj.Flagcount("msan", "build code compatible with C/C++ memory sanitizer", &flag_msan)
        obj.Flagcount("nolocalimports", "reject local (relative) imports", &nolocalimports)
        obj.Flagstr("o", "write output to `file`", &outfile)
        obj.Flagstr("p", "set expected package import `path`", &myimportpath)
@@ -249,6 +250,14 @@ func Main() {
        if flag_race != 0 {
                racepkg = mkpkg("runtime/race")
                racepkg.Name = "race"
+       }
+       if flag_msan != 0 {
+               msanpkg = mkpkg("runtime/msan")
+               msanpkg.Name = "msan"
+       }
+       if flag_race != 0 && flag_msan != 0 {
+               log.Fatal("can not use both -race and -msan")
+       } else if flag_race != 0 || flag_msan != 0 {
                instrumenting = true
        }
 
@@ -623,6 +632,9 @@ func findpkg(name string) (file string, ok bool) {
                } else if flag_race != 0 {
                        suffixsep = "_"
                        suffix = "race"
+               } else if flag_msan != 0 {
+                       suffixsep = "_"
+                       suffix = "msan"
                }
 
                file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.a", goroot, goos, goarch, suffixsep, suffix, name)
index a2b09cdf28c81241ad7854b3ff2cf04f54c7f866..7770f741df71720e7a39a340f1a15f19de281519 100644 (file)
@@ -18,6 +18,11 @@ import (
 // 3. It inserts a call to raceread before each memory read.
 // 4. It inserts a call to racewrite before each memory write.
 //
+// For flag_msan:
+//
+// 1. It inserts a call to msanread before each memory read.
+// 2. It inserts a call to msanwrite before each memory write.
+//
 // The rewriting is not yet complete. Certain nodes are not rewritten
 // but should be.
 
@@ -26,11 +31,11 @@ import (
 
 // Do not instrument the following packages at all,
 // at best instrumentation would cause infinite recursion.
-var omit_pkgs = []string{"runtime", "runtime/race"}
+var omit_pkgs = []string{"runtime", "runtime/race", "runtime/msan"}
 
 // Only insert racefuncenter/racefuncexit into the following packages.
 // Memory accesses in the packages are either uninteresting or will cause false positives.
-var noinst_pkgs = []string{"sync", "sync/atomic"}
+var norace_inst_pkgs = []string{"sync", "sync/atomic"}
 
 func ispkgin(pkgs []string) bool {
        if myimportpath != "" {
@@ -49,25 +54,27 @@ func instrument(fn *Node) {
                return
        }
 
-       if !ispkgin(noinst_pkgs) {
+       if flag_race == 0 || !ispkgin(norace_inst_pkgs) {
                instrumentlist(fn.Nbody, nil)
 
                // nothing interesting for race detector in fn->enter
                instrumentlist(fn.Func.Exit, nil)
        }
 
-       // nodpc is the PC of the caller as extracted by
-       // getcallerpc. We use -widthptr(FP) for x86.
-       // BUG: this will not work on arm.
-       nodpc := Nod(OXXX, nil, nil)
-
-       *nodpc = *nodfp
-       nodpc.Type = Types[TUINTPTR]
-       nodpc.Xoffset = int64(-Widthptr)
-       nd := mkcall("racefuncenter", nil, nil, nodpc)
-       fn.Func.Enter = concat(list1(nd), fn.Func.Enter)
-       nd = mkcall("racefuncexit", nil, nil)
-       fn.Func.Exit = list(fn.Func.Exit, nd)
+       if flag_race != 0 {
+               // nodpc is the PC of the caller as extracted by
+               // getcallerpc. We use -widthptr(FP) for x86.
+               // BUG: this will not work on arm.
+               nodpc := Nod(OXXX, nil, nil)
+
+               *nodpc = *nodfp
+               nodpc.Type = Types[TUINTPTR]
+               nodpc.Xoffset = int64(-Widthptr)
+               nd := mkcall("racefuncenter", nil, nil, nodpc)
+               fn.Func.Enter = concat(list1(nd), fn.Func.Enter)
+               nd = mkcall("racefuncexit", nil, nil)
+               fn.Func.Exit = list(fn.Func.Exit, nd)
+       }
 
        if Debug['W'] != 0 {
                s := fmt.Sprintf("after instrument %v", fn.Func.Nname.Sym)
@@ -427,7 +434,8 @@ ret:
 
 func isartificial(n *Node) bool {
        // compiler-emitted artificial things that we do not want to instrument,
-       // cant' possibly participate in a data race.
+       // can't possibly participate in a data race.
+       // can't be seen by C/C++ and therefore irrelevant for msan.
        if n.Op == ONAME && n.Sym != nil && n.Sym.Name != "" {
                if n.Sym.Name == "_" {
                        return true
@@ -489,13 +497,19 @@ func callinstr(np **Node, init **NodeList, wr int, skip int) bool {
                n = treecopy(n, 0)
                makeaddable(n)
                var f *Node
-               if t.Etype == TSTRUCT || Isfixedarray(t) {
+               if flag_msan != 0 {
+                       name := "msanread"
+                       if wr != 0 {
+                               name = "msanwrite"
+                       }
+                       f = mkcall(name, nil, init, uintptraddr(n), Nodintconst(t.Width))
+               } else if flag_race != 0 && (t.Etype == TSTRUCT || Isfixedarray(t)) {
                        name := "racereadrange"
                        if wr != 0 {
                                name = "racewriterange"
                        }
                        f = mkcall(name, nil, init, uintptraddr(n), Nodintconst(t.Width))
-               } else {
+               } else if flag_race != 0 {
                        name := "raceread"
                        if wr != 0 {
                                name = "racewrite"
index e7138d9c58858c7cac7e22ec65b34880bdddf02d..d507949f600a289ef57f10cc3de3a39b017d44be 100644 (file)
@@ -1292,6 +1292,9 @@ func dumptypestructs() {
                if flag_race != 0 {
                        dimportpath(racepkg)
                }
+               if flag_msan != 0 {
+                       dimportpath(msanpkg)
+               }
                dimportpath(mkpkg("main"))
        }
 }
index c73c67588474b04a6595a3f50b31459bdb7cadd9..33b7dba81b4f3bc6a013475ad1b2a002842c4791 100644 (file)
@@ -1643,7 +1643,7 @@ func ullmancalc(n *Node) {
                ul = UINF
                goto out
 
-               // hard with race detector
+               // hard with instrumented code
        case OANDAND, OOROR:
                if instrumenting {
                        ul = UINF
index f0a1ddc6e443f06cb5b5945474809012018acfe0..b1068dc37072d47e4965fd63113af5517a0df11b 100644 (file)
@@ -3037,7 +3037,7 @@ func walkappend(n *Node, init **NodeList, dst *Node) *Node {
        }
 
        // General case, with no function calls left as arguments.
-       // Leave for gen, except that race detector requires old form
+       // Leave for gen, except that instrumentation requires old form.
        if !instrumenting {
                return n
        }