Commit e8d417d2 authored by Fangming.Fang's avatar Fangming.Fang Committed by Ian Lance Taylor

runtime: enable memory sanitizer on arm64

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: default avatarIan Lance Taylor <iant@golang.org>
parent eff1e685
...@@ -676,7 +676,7 @@ func (t *tester) registerTests() { ...@@ -676,7 +676,7 @@ func (t *tester) registerTests() {
if gohostos == "linux" && goarch == "amd64" { if gohostos == "linux" && goarch == "amd64" {
t.registerTest("testasan", "../misc/cgo/testasan", "go", "run", "main.go") 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", ".") t.registerHostTest("testsanitizers/msan", "../misc/cgo/testsanitizers", "misc/cgo/testsanitizers", ".")
} }
if t.hasBash() && goos != "android" && !t.iOS() && gohostos != "windows" { if t.hasBash() && goos != "android" && !t.iOS() && gohostos != "windows" {
......
...@@ -105,7 +105,7 @@ ...@@ -105,7 +105,7 @@
// Supported only on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64. // Supported only on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64.
// -msan // -msan
// enable interoperation with memory sanitizer. // 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. // and only with Clang/LLVM as the host C compiler.
// -v // -v
// print the names of packages as they are compiled. // print the names of packages as they are compiled.
......
...@@ -65,7 +65,7 @@ and test commands: ...@@ -65,7 +65,7 @@ and test commands:
Supported only on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64. Supported only on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64.
-msan -msan
enable interoperation with memory sanitizer. 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. and only with Clang/LLVM as the host C compiler.
-v -v
print the names of packages as they are compiled. print the names of packages as they are compiled.
......
...@@ -39,12 +39,12 @@ func instrumentInit() { ...@@ -39,12 +39,12 @@ func instrumentInit() {
fmt.Fprintf(os.Stderr, "go %s: may not use -race and -msan simultaneously\n", flag.Args()[0]) fmt.Fprintf(os.Stderr, "go %s: may not use -race and -msan simultaneously\n", flag.Args()[0])
os.Exit(2) 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) fmt.Fprintf(os.Stderr, "-msan is not supported on %s/%s\n", cfg.Goos, cfg.Goarch)
os.Exit(2) os.Exit(2)
} }
if cfg.Goarch != "amd64" || cfg.Goos != "linux" && cfg.Goos != "freebsd" && cfg.Goos != "darwin" && cfg.Goos != "windows" { 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 and -msan are only supported on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64\n", flag.Args()[0]) 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) os.Exit(2)
} }
......
...@@ -3,8 +3,10 @@ ...@@ -3,8 +3,10 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
#include <pthread.h> #include <pthread.h>
#include <errno.h>
#include <string.h> #include <string.h>
#include <signal.h> #include <signal.h>
#include <stdlib.h>
#include "libcgo.h" #include "libcgo.h"
#include "libcgo_unix.h" #include "libcgo_unix.h"
...@@ -59,14 +61,34 @@ threadentry(void *v) ...@@ -59,14 +61,34 @@ threadentry(void *v)
void void
x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase) x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase)
{ {
pthread_attr_t attr; pthread_attr_t *attr;
size_t size; 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; setg_gcc = setg;
pthread_attr_init(&attr); attr = (pthread_attr_t*)malloc(sizeof *attr);
pthread_attr_getstacksize(&attr, &size); if (attr == NULL) {
g->stacklo = (uintptr)&attr - size + 4096; fatalf("malloc failed: %s", strerror(errno));
pthread_attr_destroy(&attr); }
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) { if (x_cgo_inittls) {
x_cgo_inittls(tlsg, tlsbase); x_cgo_inittls(tlsg, tlsbase);
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build linux,amd64 // +build linux,amd64 linux,arm64
#include <errno.h> #include <errno.h>
#include <stdint.h> #include <stdint.h>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build linux,amd64 // +build linux,amd64 linux,arm64
#include <errno.h> #include <errno.h>
#include <stddef.h> #include <stddef.h>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build linux,amd64 // +build linux,amd64 linux,arm64
package cgo package cgo
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build linux,amd64 freebsd,amd64 // +build linux,amd64 freebsd,amd64 linux,arm64
package cgo package cgo
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
// Support for memory sanitizer. See runtime/cgo/mmap.go. // Support for memory sanitizer. See runtime/cgo/mmap.go.
// +build linux,amd64 // +build linux,amd64 linux,arm64
package runtime package runtime
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
// Support for memory sanitizer. See runtime/cgo/sigaction.go. // Support for memory sanitizer. See runtime/cgo/sigaction.go.
// +build linux,amd64 freebsd,amd64 // +build linux,amd64 freebsd,amd64 linux,arm64
package runtime package runtime
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
// +build !windows // +build !windows
// +build !nacl // +build !nacl
// +build !linux !amd64 // +build !linux !amd64
// +build !linux !arm64
package runtime package runtime
......
...@@ -2,7 +2,8 @@ ...@@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build msan,linux,amd64 // +build msan,linux
// +build amd64 arm64
package msan package msan
......
// 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
...@@ -11,7 +11,7 @@ TEXT _rt0_arm64_linux(SB),NOSPLIT|NOFRAME,$0 ...@@ -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 // When building with -buildmode=c-shared, this symbol is called when the shared
// library is loaded. // library is loaded.
TEXT _rt0_arm64_linux_lib(SB),NOSPLIT,$168 TEXT _rt0_arm64_linux_lib(SB),NOSPLIT,$184
// Preserve callee-save registers. // Preserve callee-save registers.
MOVD R19, 24(RSP) MOVD R19, 24(RSP)
MOVD R20, 32(RSP) MOVD R20, 32(RSP)
...@@ -30,6 +30,10 @@ TEXT _rt0_arm64_linux_lib(SB),NOSPLIT,$168 ...@@ -30,6 +30,10 @@ TEXT _rt0_arm64_linux_lib(SB),NOSPLIT,$168
FMOVD F13, 136(RSP) FMOVD F13, 136(RSP)
FMOVD F14, 144(RSP) FMOVD F14, 144(RSP)
FMOVD F15, 152(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 R0, _rt0_arm64_linux_lib_argc<>(SB)
MOVD R1, _rt0_arm64_linux_lib_argv<>(SB) MOVD R1, _rt0_arm64_linux_lib_argv<>(SB)
...@@ -74,6 +78,7 @@ restore: ...@@ -74,6 +78,7 @@ restore:
FMOVD 136(RSP), F13 FMOVD 136(RSP), F13
FMOVD 144(RSP), F14 FMOVD 144(RSP), F14
FMOVD 152(RSP), F15 FMOVD 152(RSP), F15
MOVD 160(RSP), g
RET RET
TEXT _rt0_arm64_linux_lib_go(SB),NOSPLIT,$0 TEXT _rt0_arm64_linux_lib_go(SB),NOSPLIT,$0
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build linux,!amd64 freebsd,!amd64 // +build linux,!amd64,!arm64 freebsd,!amd64
package runtime package runtime
......
...@@ -292,6 +292,16 @@ TEXT runtime·rt_sigaction(SB),NOSPLIT|NOFRAME,$0-36 ...@@ -292,6 +292,16 @@ TEXT runtime·rt_sigaction(SB),NOSPLIT|NOFRAME,$0-36
MOVW R0, ret+32(FP) MOVW R0, ret+32(FP)
RET 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 TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
MOVW sig+8(FP), R0 MOVW sig+8(FP), R0
MOVD info+16(FP), R1 MOVD info+16(FP), R1
...@@ -320,7 +330,7 @@ TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0 ...@@ -320,7 +330,7 @@ TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0
MOVD $runtime·sigtramp(SB), R3 MOVD $runtime·sigtramp(SB), R3
B (R3) B (R3)
TEXT runtime·mmap(SB),NOSPLIT|NOFRAME,$0 TEXT runtime·sysMmap(SB),NOSPLIT|NOFRAME,$0
MOVD addr+0(FP), R0 MOVD addr+0(FP), R0
MOVD n+8(FP), R1 MOVD n+8(FP), R1
MOVW prot+16(FP), R2 MOVW prot+16(FP), R2
...@@ -341,7 +351,21 @@ ok: ...@@ -341,7 +351,21 @@ ok:
MOVD $0, err+40(FP) MOVD $0, err+40(FP)
RET 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 addr+0(FP), R0
MOVD n+8(FP), R1 MOVD n+8(FP), R1
MOVD $SYS_munmap, R8 MOVD $SYS_munmap, R8
...@@ -352,6 +376,15 @@ TEXT runtime·munmap(SB),NOSPLIT|NOFRAME,$0 ...@@ -352,6 +376,15 @@ TEXT runtime·munmap(SB),NOSPLIT|NOFRAME,$0
cool: cool:
RET 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 TEXT runtime·madvise(SB),NOSPLIT|NOFRAME,$0
MOVD addr+0(FP), R0 MOVD addr+0(FP), R0
MOVD n+8(FP), R1 MOVD n+8(FP), R1
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment