]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: fix the issue that the -asan option cannot print where the error occurred
authorfanzha02 <fannie.zhang@arm.com>
Mon, 27 Dec 2021 08:38:48 +0000 (16:38 +0800)
committerFannie Zhang <Fannie.Zhang@arm.com>
Wed, 29 Dec 2021 04:10:07 +0000 (04:10 +0000)
The current -asan option does not print where the error occurred. The
reason is that the current implementation calls incorrect asan runtime
functions, which do not pass sp and pc where asan runtime functions are
called, and report the stack trace from the native code. But asan runtime
functions are called from cgo on a separated stack, so it cannot dump the
Go stack trace correctly.

The correct asan runtime function we should call is __asan_report_error,
which will pass sp and pc, and report where the error occurred correctly.

This patch fixes this issue.

Add the test cases.

Fixes #50362

Change-Id: I12ee1d46c7ae069ddef3d23f2fe86e112db60045
Reviewed-on: https://go-review.googlesource.com/c/go/+/374395
Trust: Fannie Zhang <Fannie.Zhang@arm.com>
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
misc/cgo/testsanitizers/asan_test.go
misc/cgo/testsanitizers/cc_test.go
misc/cgo/testsanitizers/testdata/asan1_fail.go
misc/cgo/testsanitizers/testdata/asan2_fail.go
src/runtime/asan.go
src/runtime/asan/asan.go
src/runtime/asan_amd64.s
src/runtime/asan_arm64.s

index dbcce2fe2881055d7a544fedcc3d69be1c8ecaf0..cd1e9f354b127bf6cbf3b1370a266250c43d86eb 100644 (file)
@@ -33,11 +33,12 @@ func TestASAN(t *testing.T) {
        cases := []struct {
                src               string
                memoryAccessError string
+               errorLocation     string
        }{
-               {src: "asan1_fail.go", memoryAccessError: "heap-use-after-free"},
-               {src: "asan2_fail.go", memoryAccessError: "heap-buffer-overflow"},
-               {src: "asan3_fail.go", memoryAccessError: "use-after-poison"},
-               {src: "asan4_fail.go", memoryAccessError: "use-after-poison"},
+               {src: "asan1_fail.go", memoryAccessError: "heap-use-after-free", errorLocation: "asan1_fail.go:25"},
+               {src: "asan2_fail.go", memoryAccessError: "heap-buffer-overflow", errorLocation: "asan2_fail.go:31"},
+               {src: "asan3_fail.go", memoryAccessError: "use-after-poison", errorLocation: "asan3_fail.go:13"},
+               {src: "asan4_fail.go", memoryAccessError: "use-after-poison", errorLocation: "asan4_fail.go:13"},
                {src: "asan_useAfterReturn.go"},
        }
        for _, tc := range cases {
@@ -56,6 +57,10 @@ func TestASAN(t *testing.T) {
                        if tc.memoryAccessError != "" {
                                out, err := cmd.CombinedOutput()
                                if err != nil && strings.Contains(string(out), tc.memoryAccessError) {
+                                       // Check if -asan option can correctly print where the error occured.
+                                       if tc.errorLocation != "" && !strings.Contains(string(out), tc.errorLocation) {
+                                               t.Errorf("%#q exited without expected location of the error\n%s; got failure\n%s", strings.Join(cmd.Args, " "), tc.errorLocation, out)
+                                       }
                                        return
                                }
                                t.Fatalf("%#q exited without expected memory access error\n%s; got failure\n%s", strings.Join(cmd.Args, " "), tc.memoryAccessError, out)
index b776afa3e63b319c0452e7ff307960b999690fc3..0ce4f75935ec4671ac14c36beb6109948be5c57c 100644 (file)
@@ -269,6 +269,8 @@ func configure(sanitizer string) *config {
 
        case "address":
                c.goFlags = append(c.goFlags, "-asan")
+               // Set the debug mode to print the C stack trace.
+               c.cFlags = append(c.cFlags, "-g")
 
        default:
                panic(fmt.Sprintf("unrecognized sanitizer: %q", sanitizer))
index e60db76981815711d09929df369969130d0b3171..80289e5c30452f697a9c4a0968854584e62b2d57 100644 (file)
@@ -22,7 +22,7 @@ func main() {
        // C passes Go an invalid pointer.
        a := C.test()
        // Use after free
-       *a = 2
+       *a = 2 // BOOM
        // We shouldn't get here; asan should stop us first.
        fmt.Println(*a)
 }
index e35670c440a14de820f18e85e06b33aa8ad9abe0..3ab060857107ae76fd4e834b85c2668c1743b83f 100644 (file)
@@ -28,7 +28,7 @@ func main() {
        a := C.f()
        q5 := (*C.int)(unsafe.Add(unsafe.Pointer(a), 4*5))
        // Access to C pointer out of bounds.
-       *q5 = 100
+       *q5 = 100 // BOOM
        // We shouldn't get here; asan should stop us first.
        fmt.Printf("q5: %d, %x\n", *q5, q5)
 }
index a22b56bb079e9c4c275aee7e5ee52d530911e401..affafd4d8df797ce248e9fbde7038381cf6e9443 100644 (file)
@@ -11,23 +11,38 @@ import (
 )
 
 // Public address sanitizer API.
-
 func ASanRead(addr unsafe.Pointer, len int) {
-       asanread(addr, uintptr(len))
+       sp := getcallersp()
+       pc := getcallerpc()
+       doasanread(addr, uintptr(len), sp, pc)
 }
 
 func ASanWrite(addr unsafe.Pointer, len int) {
-       asanwrite(addr, uintptr(len))
+       sp := getcallersp()
+       pc := getcallerpc()
+       doasanwrite(addr, uintptr(len), sp, pc)
 }
 
 // Private interface for the runtime.
 const asanenabled = true
 
+func asanread(addr unsafe.Pointer, sz uintptr) {
+       sp := getcallersp()
+       pc := getcallerpc()
+       doasanread(addr, sz, sp, pc)
+}
+
+func asanwrite(addr unsafe.Pointer, sz uintptr) {
+       sp := getcallersp()
+       pc := getcallerpc()
+       doasanwrite(addr, sz, sp, pc)
+}
+
 //go:noescape
-func asanread(addr unsafe.Pointer, sz uintptr)
+func doasanread(addr unsafe.Pointer, sz, sp, pc uintptr)
 
 //go:noescape
-func asanwrite(addr unsafe.Pointer, sz uintptr)
+func doasanwrite(addr unsafe.Pointer, sz, sp, pc uintptr)
 
 //go:noescape
 func asanunpoison(addr unsafe.Pointer, sz uintptr)
index eb66b3aab54711f6865cc07b5e011df89fd3c2bc..bab2362c51e3125865e88ce9c8b2f21c928e4060 100644 (file)
@@ -14,38 +14,15 @@ package asan
 #include <stdint.h>
 #include <sanitizer/asan_interface.h>
 
-extern void __asan_report_load1(void*);
-extern void __asan_report_load2(void*);
-extern void __asan_report_load4(void*);
-extern void __asan_report_load8(void*);
-extern void __asan_report_load_n(void*, uintptr_t);
-extern void __asan_report_store1(void*);
-extern void __asan_report_store2(void*);
-extern void __asan_report_store4(void*);
-extern void __asan_report_store8(void*);
-extern void __asan_report_store_n(void*, uintptr_t);
-
-void __asan_read_go(void *addr, uintptr_t sz) {
+void __asan_read_go(void *addr, uintptr_t sz, void *sp, void *pc) {
        if (__asan_region_is_poisoned(addr, sz)) {
-               switch (sz) {
-               case 1: __asan_report_load1(addr); break;
-               case 2: __asan_report_load2(addr); break;
-               case 4: __asan_report_load4(addr); break;
-               case 8: __asan_report_load8(addr); break;
-               default: __asan_report_load_n(addr, sz); break;
-               }
+               __asan_report_error(pc, 0, sp, addr, false, sz);
        }
 }
 
-void __asan_write_go(void *addr, uintptr_t sz) {
+void __asan_write_go(void *addr, uintptr_t sz, void *sp, void *pc) {
        if (__asan_region_is_poisoned(addr, sz)) {
-               switch (sz) {
-               case 1: __asan_report_store1(addr); break;
-               case 2: __asan_report_store2(addr); break;
-               case 4: __asan_report_store4(addr); break;
-               case 8: __asan_report_store8(addr); break;
-               default: __asan_report_store_n(addr, sz); break;
-               }
+               __asan_report_error(pc, 0, sp, addr, true, sz);
        }
 }
 
index e8de80399b7ca3a90f1e17e6a96030b38f3f2d9d..3857350020241c7b5506462610595257362b81ee 100644 (file)
 #ifdef GOOS_windows
 #define RARG0 CX
 #define RARG1 DX
+#define RARG2 R8
+#define RARG3 R9
 #else
 #define RARG0 DI
 #define RARG1 SI
+#define RARG2 DX
+#define RARG3 CX
 #endif
 
 // Called from intrumented code.
-// func runtime·asanread(addr unsafe.Pointer, sz uintptr)
-TEXT   runtime·asanread(SB), NOSPLIT, $0-16
+// func runtime·doasanread(addr unsafe.Pointer, sz, sp, pc uintptr)
+TEXT   runtime·doasanread(SB), NOSPLIT, $0-32
        MOVQ    addr+0(FP), RARG0
        MOVQ    size+8(FP), RARG1
-       // void __asan_read_go(void *addr, uintptr_t sz);
+       MOVQ    sp+16(FP), RARG2
+       MOVQ    pc+24(FP), RARG3
+       // void __asan_read_go(void *addr, uintptr_t sz, void *sp, void *pc);
        MOVQ    $__asan_read_go(SB), AX
        JMP     asancall<>(SB)
 
-// func runtime·asanwrite(addr unsafe.Pointer, sz uintptr)
-TEXT   runtime·asanwrite(SB), NOSPLIT, $0-16
+// func runtime·doasanwrite(addr unsafe.Pointer, sz, sp, pc uintptr)
+TEXT   runtime·doasanwrite(SB), NOSPLIT, $0-32
        MOVQ    addr+0(FP), RARG0
        MOVQ    size+8(FP), RARG1
-       // void __asan_write_go(void *addr, uintptr_t sz);
+       MOVQ    sp+16(FP), RARG2
+       MOVQ    pc+24(FP), RARG3
+       // void __asan_write_go(void *addr, uintptr_t sz, void *sp, void *pc);
        MOVQ    $__asan_write_go(SB), AX
        JMP     asancall<>(SB)
 
index acae200fb5ec894a006bf3754d89ce0cad433fd4..5ed03c932bd8803697e0af5e7679bbc36b527c3c 100644 (file)
@@ -9,22 +9,28 @@
 
 #define RARG0 R0
 #define RARG1 R1
-#define FARG R3
+#define RARG2 R2
+#define RARG3 R3
+#define FARG R4
 
 // Called from instrumented code.
-// func runtime·asanread(addr unsafe.Pointer, sz uintptr)
-TEXT   runtime·asanread(SB), NOSPLIT, $0-16
+// func runtime·doasanread(addr unsafe.Pointer, sz, sp, pc uintptr)
+TEXT   runtime·doasanread(SB), NOSPLIT, $0-32
        MOVD    addr+0(FP), RARG0
        MOVD    size+8(FP), RARG1
-       // void __asan_read_go(void *addr, uintptr_t sz);
+       MOVD    sp+16(FP), RARG2
+       MOVD    pc+24(FP), RARG3
+       // void __asan_read_go(void *addr, uintptr_t sz, void *sp, void *pc);
        MOVD    $__asan_read_go(SB), FARG
        JMP     asancall<>(SB)
 
-// func runtime·asanwrite(addr unsafe.Pointer, sz uintptr)
-TEXT   runtime·asanwrite(SB), NOSPLIT, $0-16
+// func runtime·doasanwrite(addr unsafe.Pointer, sz, sp, pc uintptr)
+TEXT   runtime·doasanwrite(SB), NOSPLIT, $0-32
        MOVD    addr+0(FP), RARG0
        MOVD    size+8(FP), RARG1
-       // void __asan_write_go(void *addr, uintptr_t sz);
+       MOVD    sp+16(FP), RARG2
+       MOVD    pc+24(FP), RARG3
+       // void __asan_write_go(void *addr, uintptr_t sz, void *sp, void *pc);
        MOVD    $__asan_write_go(SB), FARG
        JMP     asancall<>(SB)
 
@@ -53,8 +59,8 @@ TEXT  asancall<>(SB), NOSPLIT, $0-0
        CMP     R11, g
        BEQ     g0stack
 
-       MOVD    (g_sched+gobuf_sp)(R11), R4
-       MOVD    R4, RSP
+       MOVD    (g_sched+gobuf_sp)(R11), R5
+       MOVD    R5, RSP
 
 g0stack:
        BL      (FARG)