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)
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
}
} 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)
// 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.
// 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 != "" {
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)
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
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"