]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: enable memory sanitizer on arm64
authorFangming.Fang <fangming.fang@arm.com>
Sun, 8 Apr 2018 07:32:43 +0000 (07:32 +0000)
committerIan Lance Taylor <iant@golang.org>
Wed, 2 May 2018 17:52:14 +0000 (17:52 +0000)
Changes include:
1. open compilation option -msan for arm64
2. modify doc to explain -msan is also supported on linux/arm64
3. wrap msan lib API in msan_arm64.s
4. use libc for sigaction syscalls when cgo is enabled
5. use libc for mmap syscalls when cgo is enabled

Change-Id: I26ebe61ff7ce1906125f54a0182a720f9d58ec11
Reviewed-on: https://go-review.googlesource.com/109255
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
17 files changed:
src/cmd/dist/test.go
src/cmd/go/alldocs.go
src/cmd/go/internal/work/build.go
src/cmd/go/internal/work/init.go
src/runtime/cgo/gcc_linux_arm64.c
src/runtime/cgo/gcc_mmap.c
src/runtime/cgo/gcc_sigaction.c
src/runtime/cgo/mmap.go
src/runtime/cgo/sigaction.go
src/runtime/cgo_mmap.go
src/runtime/cgo_sigaction.go
src/runtime/mmap.go
src/runtime/msan/msan.go
src/runtime/msan_arm64.s [new file with mode: 0644]
src/runtime/rt0_linux_arm64.s
src/runtime/sigaction.go
src/runtime/sys_linux_arm64.s

index 948c6f890fb290faa412cf05d63bb8e5e1a5146e..393af1ecd10752d17e4afa743aa110b1236f84cb 100644 (file)
@@ -676,7 +676,7 @@ func (t *tester) registerTests() {
                if gohostos == "linux" && goarch == "amd64" {
                        t.registerTest("testasan", "../misc/cgo/testasan", "go", "run", "main.go")
                }
-               if goos == "linux" && goarch == "amd64" {
+               if goos == "linux" && (goarch == "amd64" || goarch == "arm64") {
                        t.registerHostTest("testsanitizers/msan", "../misc/cgo/testsanitizers", "misc/cgo/testsanitizers", ".")
                }
                if t.hasBash() && goos != "android" && !t.iOS() && gohostos != "windows" {
index fa8c02cc4bbd49e09691d6d7f972608237299655..d50eb1fc0898c8b9299226a8c96609d486bd7f2b 100644 (file)
 //             Supported only on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64.
 //     -msan
 //             enable interoperation with memory sanitizer.
-//             Supported only on linux/amd64,
+//             Supported only on linux/amd64, linux/arm64
 //             and only with Clang/LLVM as the host C compiler.
 //     -v
 //             print the names of packages as they are compiled.
index 57b7b00879121a6ca1acf919ff773e23a3bb1c9b..86972cb61b423708cdd3e6a4adb5768f3306d7fb 100644 (file)
@@ -65,7 +65,7 @@ and test commands:
                Supported only on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64.
        -msan
                enable interoperation with memory sanitizer.
-               Supported only on linux/amd64,
+               Supported only on linux/amd64, linux/arm64
                and only with Clang/LLVM as the host C compiler.
        -v
                print the names of packages as they are compiled.
index c820e0bec07548f52e0431d4fe4087289e3069ce..3eb98381bd6e4ba6aab5e3120791d4eda5362d01 100644 (file)
@@ -39,12 +39,12 @@ func instrumentInit() {
                fmt.Fprintf(os.Stderr, "go %s: may not use -race and -msan simultaneously\n", flag.Args()[0])
                os.Exit(2)
        }
-       if cfg.BuildMSan && (cfg.Goos != "linux" || cfg.Goarch != "amd64") {
+       if cfg.BuildMSan && (cfg.Goos != "linux" || cfg.Goarch != "amd64" && cfg.Goarch != "arm64") {
                fmt.Fprintf(os.Stderr, "-msan is not supported on %s/%s\n", cfg.Goos, cfg.Goarch)
                os.Exit(2)
        }
-       if cfg.Goarch != "amd64" || cfg.Goos != "linux" && cfg.Goos != "freebsd" && cfg.Goos != "darwin" && cfg.Goos != "windows" {
-               fmt.Fprintf(os.Stderr, "go %s: -race and -msan are only supported on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64\n", flag.Args()[0])
+       if cfg.BuildRace && (cfg.Goarch != "amd64" || cfg.Goos != "linux" && cfg.Goos != "freebsd" && cfg.Goos != "darwin" && cfg.Goos != "windows") {
+               fmt.Fprintf(os.Stderr, "go %s: -race is only supported on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64\n", flag.Args()[0])
                os.Exit(2)
        }
 
index b328407f39ed6ac5146bdf535417d924266c2017..8630f2f03e36f02a7d324e109374f2ad12b5bd43 100644 (file)
@@ -3,8 +3,10 @@
 // license that can be found in the LICENSE file.
 
 #include <pthread.h>
+#include <errno.h>
 #include <string.h>
 #include <signal.h>
+#include <stdlib.h>
 #include "libcgo.h"
 #include "libcgo_unix.h"
 
@@ -59,14 +61,34 @@ threadentry(void *v)
 void
 x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase)
 {
-       pthread_attr_t attr;
+       pthread_attr_t *attr;
        size_t size;
 
+       /* The memory sanitizer distributed with versions of clang
+          before 3.8 has a bug: if you call mmap before malloc, mmap
+          may return an address that is later overwritten by the msan
+          library.  Avoid this problem by forcing a call to malloc
+          here, before we ever call malloc.
+
+          This is only required for the memory sanitizer, so it's
+          unfortunate that we always run it.  It should be possible
+          to remove this when we no longer care about versions of
+          clang before 3.8.  The test for this is
+          misc/cgo/testsanitizers.
+
+          GCC works hard to eliminate a seemingly unnecessary call to
+          malloc, so we actually use the memory we allocate.  */
+
        setg_gcc = setg;
-       pthread_attr_init(&attr);
-       pthread_attr_getstacksize(&attr, &size);
-       g->stacklo = (uintptr)&attr - size + 4096;
-       pthread_attr_destroy(&attr);
+       attr = (pthread_attr_t*)malloc(sizeof *attr);
+       if (attr == NULL) {
+               fatalf("malloc failed: %s", strerror(errno));
+       }
+       pthread_attr_init(attr);
+       pthread_attr_getstacksize(attr, &size);
+       g->stacklo = (uintptr)&size - size + 4096;
+       pthread_attr_destroy(attr);
+       free(attr);
 
        if (x_cgo_inittls) {
                x_cgo_inittls(tlsg, tlsbase);
index 5cf6bdf8cf937355e0d55a71eb01558e46079f6d..e6a621d5a37a5b3026faed560866eaf6922f9d14 100644 (file)
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build linux,amd64
+// +build linux,amd64 linux,arm64
 
 #include <errno.h>
 #include <stdint.h>
index 72fb08d720ea6ab90fdd35cb3845fcd65535af77..05dee2affe04db8dd83844dd5e912c20670dde89 100644 (file)
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build linux,amd64
+// +build linux,amd64 linux,arm64
 
 #include <errno.h>
 #include <stddef.h>
index ad5f6df70a333a7e8449ab747291e9128de2c981..00fb7fced6f9cbc24089e7f327e15ce21d39f374 100644 (file)
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build linux,amd64
+// +build linux,amd64 linux,arm64
 
 package cgo
 
index e25f4ff2f3e340886340359e1d05493579423782..076fbc1a0a57011796bfe4317c5d7b2814aa6ead 100644 (file)
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build linux,amd64 freebsd,amd64
+// +build linux,amd64 freebsd,amd64 linux,arm64
 
 package cgo
 
index b7c70c6fffcd097d087f75348b816e089e363157..048621f3065f3c0dd08cdedc50f509460d79f140 100644 (file)
@@ -4,7 +4,7 @@
 
 // Support for memory sanitizer. See runtime/cgo/mmap.go.
 
-// +build linux,amd64
+// +build linux,amd64 linux,arm64
 
 package runtime
 
index 9832d35f03b6d1fc88f372511b12b2bfda4d949c..3ef6800cd98475f376c0bbd65ea372331bf2fcb5 100644 (file)
@@ -4,7 +4,7 @@
 
 // Support for memory sanitizer. See runtime/cgo/sigaction.go.
 
-// +build linux,amd64 freebsd,amd64
+// +build linux,amd64 freebsd,amd64 linux,arm64
 
 package runtime
 
index e1333c62fe7f95b6f537c601e296a3d714216f04..152cbcdae5f5c7be4f3c843ddb3977e48deb163e 100644 (file)
@@ -7,6 +7,7 @@
 // +build !windows
 // +build !nacl
 // +build !linux !amd64
+// +build !linux !arm64
 
 package runtime
 
index b6ea3f0d168bbe1b1e201b263540e502a7f11413..c81577dddac08ca2992ccafb349df182a86561d7 100644 (file)
@@ -2,7 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build msan,linux,amd64
+// +build msan,linux
+// +build amd64 arm64
 
 package msan
 
diff --git a/src/runtime/msan_arm64.s b/src/runtime/msan_arm64.s
new file mode 100644 (file)
index 0000000..4dfe5e3
--- /dev/null
@@ -0,0 +1,62 @@
+// Copyright 2018 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.
+
+// +build msan
+
+#include "go_asm.h"
+#include "textflag.h"
+
+#define RARG0 R0
+#define RARG1 R1
+#define FARG R3
+
+// func runtime·domsanread(addr unsafe.Pointer, sz uintptr)
+// Called from msanread.
+TEXT   runtime·domsanread(SB), NOSPLIT, $0-16
+       MOVD    addr+0(FP), RARG0
+       MOVD    size+8(FP), RARG1
+       // void __msan_read_go(void *addr, uintptr_t sz);
+       MOVD    $__msan_read_go(SB), FARG
+       JMP     msancall<>(SB)
+
+// func runtime·msanwrite(addr unsafe.Pointer, sz uintptr)
+// Called from instrumented code.
+TEXT   runtime·msanwrite(SB), NOSPLIT, $0-16
+       MOVD    addr+0(FP), RARG0
+       MOVD    size+8(FP), RARG1
+       // void __msan_write_go(void *addr, uintptr_t sz);
+       MOVD    $__msan_write_go(SB), FARG
+       JMP     msancall<>(SB)
+
+// func runtime·msanmalloc(addr unsafe.Pointer, sz uintptr)
+TEXT   runtime·msanmalloc(SB), NOSPLIT, $0-16
+       MOVD    addr+0(FP), RARG0
+       MOVD    size+8(FP), RARG1
+       // void __msan_malloc_go(void *addr, uintptr_t sz);
+       MOVD    $__msan_malloc_go(SB), FARG
+       JMP     msancall<>(SB)
+
+// func runtime·msanfree(addr unsafe.Pointer, sz uintptr)
+TEXT   runtime·msanfree(SB), NOSPLIT, $0-16
+       MOVD    addr+0(FP), RARG0
+       MOVD    size+8(FP), RARG1
+       // void __msan_free_go(void *addr, uintptr_t sz);
+       MOVD    $__msan_free_go(SB), FARG
+       JMP     msancall<>(SB)
+
+// Switches SP to g0 stack and calls (FARG). Arguments already set.
+TEXT   msancall<>(SB), NOSPLIT, $0-0
+       MOVD    g_m(g), R10
+       MOVD    m_g0(R10), R11
+       MOVD    RSP, R19        // callee-saved
+       CMP     R11, g
+       BEQ     g0stack
+
+       MOVD    (g_sched+gobuf_sp)(R11), R4
+       MOVD    R4, RSP
+
+g0stack:
+       BL      (FARG)
+       MOVD    R19, RSP
+       RET
index e81e598d3ac060168dc99f0421de753e28bf23c2..458f082159dae9c99a698a352a9510e14d365a35 100644 (file)
@@ -11,7 +11,7 @@ TEXT _rt0_arm64_linux(SB),NOSPLIT|NOFRAME,$0
 
 // When building with -buildmode=c-shared, this symbol is called when the shared
 // library is loaded.
-TEXT _rt0_arm64_linux_lib(SB),NOSPLIT,$168
+TEXT _rt0_arm64_linux_lib(SB),NOSPLIT,$184
        // Preserve callee-save registers.
        MOVD R19, 24(RSP)
        MOVD R20, 32(RSP)
@@ -30,6 +30,10 @@ TEXT _rt0_arm64_linux_lib(SB),NOSPLIT,$168
        FMOVD F13, 136(RSP)
        FMOVD F14, 144(RSP)
        FMOVD F15, 152(RSP)
+       MOVD g, 160(RSP)
+
+       // Initialize g as null in case of using g later e.g. sigaction in cgo_sigaction.go
+       MOVD    ZR, g
 
        MOVD    R0, _rt0_arm64_linux_lib_argc<>(SB)
        MOVD    R1, _rt0_arm64_linux_lib_argv<>(SB)
@@ -74,6 +78,7 @@ restore:
        FMOVD 136(RSP), F13
        FMOVD 144(RSP), F14
        FMOVD 152(RSP), F15
+       MOVD 160(RSP), g
        RET
 
 TEXT _rt0_arm64_linux_lib_go(SB),NOSPLIT,$0
index eb454f9327074d9024a942c94681299a1db6e9e5..3c888579d0e6667fe2452bcb3349a5d2914204ad 100644 (file)
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build linux,!amd64 freebsd,!amd64
+// +build linux,!amd64,!arm64 freebsd,!amd64
 
 package runtime
 
index f930d1f044ed8be53fa4f90f0a02b22d3d250105..c6afd76a657e27e45f404b6c97aa4871c180917c 100644 (file)
@@ -292,6 +292,16 @@ TEXT runtime·rt_sigaction(SB),NOSPLIT|NOFRAME,$0-36
        MOVW    R0, ret+32(FP)
        RET
 
+// Call the function stored in _cgo_sigaction using the GCC calling convention.
+TEXT runtime·callCgoSigaction(SB),NOSPLIT,$0
+       MOVD    sig+0(FP), R0
+       MOVD    new+8(FP), R1
+       MOVD    old+16(FP), R2
+       MOVD     _cgo_sigaction(SB), R3
+       BL      R3
+       MOVW    R0, ret+24(FP)
+       RET
+
 TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
        MOVW    sig+8(FP), R0
        MOVD    info+16(FP), R1
@@ -320,7 +330,7 @@ TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0
        MOVD    $runtime·sigtramp(SB), R3
        B       (R3)
 
-TEXT runtime·mmap(SB),NOSPLIT|NOFRAME,$0
+TEXT runtime·sysMmap(SB),NOSPLIT|NOFRAME,$0
        MOVD    addr+0(FP), R0
        MOVD    n+8(FP), R1
        MOVW    prot+16(FP), R2
@@ -341,7 +351,21 @@ ok:
        MOVD    $0, err+40(FP)
        RET
 
-TEXT runtime·munmap(SB),NOSPLIT|NOFRAME,$0
+// Call the function stored in _cgo_mmap using the GCC calling convention.
+// This must be called on the system stack.
+TEXT runtime·callCgoMmap(SB),NOSPLIT,$0
+       MOVD    addr+0(FP), R0
+       MOVD    n+8(FP), R1
+       MOVW    prot+16(FP), R2
+       MOVW    flags+20(FP), R3
+       MOVW    fd+24(FP), R4
+       MOVW    off+28(FP), R5
+       MOVD    _cgo_mmap(SB), R9
+       BL      R9
+       MOVD    R0, ret+32(FP)
+       RET
+
+TEXT runtime·sysMunmap(SB),NOSPLIT|NOFRAME,$0
        MOVD    addr+0(FP), R0
        MOVD    n+8(FP), R1
        MOVD    $SYS_munmap, R8
@@ -352,6 +376,15 @@ TEXT runtime·munmap(SB),NOSPLIT|NOFRAME,$0
 cool:
        RET
 
+// Call the function stored in _cgo_munmap using the GCC calling convention.
+// This must be called on the system stack.
+TEXT runtime·callCgoMunmap(SB),NOSPLIT,$0
+       MOVD    addr+0(FP), R0
+       MOVD    n+8(FP), R1
+       MOVD    _cgo_munmap(SB), R9
+       BL      R9
+       RET
+
 TEXT runtime·madvise(SB),NOSPLIT|NOFRAME,$0
        MOVD    addr+0(FP), R0
        MOVD    n+8(FP), R1