From 56e5476e10db25ce71f562bd6ee0910a83532b04 Mon Sep 17 00:00:00 2001 From: Florian Zenker Date: Wed, 19 Mar 2025 10:55:55 +0000 Subject: [PATCH] runtime: in asan mode unregister root regions on free CL 651755 introduced registration of root regions when allocating memory. We also need to unregister that memory to avoid the leak sanitizer accessing unmapped memory. Issue #67833 Change-Id: I5d403d66e65a8a003492f4d79dad22d416fd8574 Reviewed-on: https://go-review.googlesource.com/c/go/+/659135 LUCI-TryBot-Result: Go LUCI Reviewed-by: Ian Lance Taylor --- src/runtime/asan.go | 4 ++++ src/runtime/asan/asan.go | 4 ++++ src/runtime/asan0.go | 1 + src/runtime/asan_amd64.s | 8 ++++++++ src/runtime/asan_arm64.s | 8 ++++++++ src/runtime/asan_loong64.s | 8 ++++++++ src/runtime/asan_ppc64le.s | 8 ++++++++ src/runtime/asan_riscv64.s | 8 ++++++++ src/runtime/mem.go | 7 +++++++ 9 files changed, 56 insertions(+) diff --git a/src/runtime/asan.go b/src/runtime/asan.go index adef8fa7bf..32d5f45225 100644 --- a/src/runtime/asan.go +++ b/src/runtime/asan.go @@ -64,6 +64,9 @@ func asanregisterglobals(addr unsafe.Pointer, n uintptr) //go:noescape func lsanregisterrootregion(addr unsafe.Pointer, n uintptr) +//go:noescape +func lsanunregisterrootregion(addr unsafe.Pointer, n uintptr) + func lsandoleakcheck() // These are called from asan_GOARCH.s @@ -74,4 +77,5 @@ func lsandoleakcheck() //go:cgo_import_static __asan_poison_go //go:cgo_import_static __asan_register_globals_go //go:cgo_import_static __lsan_register_root_region_go +//go:cgo_import_static __lsan_unregister_root_region_go //go:cgo_import_static __lsan_do_leak_check_go diff --git a/src/runtime/asan/asan.go b/src/runtime/asan/asan.go index efdd911f2b..fefc82b278 100644 --- a/src/runtime/asan/asan.go +++ b/src/runtime/asan/asan.go @@ -39,6 +39,10 @@ void __lsan_register_root_region_go(void *addr, uintptr_t sz) { __lsan_register_root_region(addr, sz); } +void __lsan_unregister_root_region_go(void *addr, uintptr_t sz) { + __lsan_unregister_root_region(addr, sz); +} + void __lsan_do_leak_check_go(void) { __lsan_do_leak_check(); } diff --git a/src/runtime/asan0.go b/src/runtime/asan0.go index eb70367a29..8331653982 100644 --- a/src/runtime/asan0.go +++ b/src/runtime/asan0.go @@ -22,4 +22,5 @@ func asanunpoison(addr unsafe.Pointer, sz uintptr) { throw("asan") } func asanpoison(addr unsafe.Pointer, sz uintptr) { throw("asan") } func asanregisterglobals(addr unsafe.Pointer, sz uintptr) { throw("asan") } func lsanregisterrootregion(unsafe.Pointer, uintptr) { throw("asan") } +func lsanunregisterrootregion(unsafe.Pointer, uintptr) { throw("asan") } func lsandoleakcheck() { throw("asan") } diff --git a/src/runtime/asan_amd64.s b/src/runtime/asan_amd64.s index 3f9df4fec8..30dd477c07 100644 --- a/src/runtime/asan_amd64.s +++ b/src/runtime/asan_amd64.s @@ -77,6 +77,14 @@ TEXT runtime·lsanregisterrootregion(SB), NOSPLIT, $0-16 MOVQ $__lsan_register_root_region_go(SB), AX JMP asancall<>(SB) +// func runtime·lsanunregisterrootregion(addr unsafe.Pointer, n uintptr) +TEXT runtime·lsanunregisterrootregion(SB), NOSPLIT, $0-16 + MOVQ addr+0(FP), RARG0 + MOVQ n+8(FP), RARG1 + // void __lsan_unregister_root_region_go(void *addr, uintptr_t sz) + MOVQ $__lsan_unregister_root_region_go(SB), AX + JMP asancall<>(SB) + // func runtime·lsandoleakcheck() TEXT runtime·lsandoleakcheck(SB), NOSPLIT, $0-0 // void __lsan_do_leak_check_go(void); diff --git a/src/runtime/asan_arm64.s b/src/runtime/asan_arm64.s index 5447d210e5..1f089d78d3 100644 --- a/src/runtime/asan_arm64.s +++ b/src/runtime/asan_arm64.s @@ -66,6 +66,14 @@ TEXT runtime·lsanregisterrootregion(SB), NOSPLIT, $0-16 MOVD $__lsan_register_root_region_go(SB), FARG JMP asancall<>(SB) +// func runtime·lsanunregisterrootregion(addr unsafe.Pointer, n uintptr) +TEXT runtime·lsanunregisterrootregion(SB), NOSPLIT, $0-16 + MOVD addr+0(FP), RARG0 + MOVD n+8(FP), RARG1 + // void __lsan_unregister_root_region_go(void *addr, uintptr_t n); + MOVD $__lsan_unregister_root_region_go(SB), FARG + JMP asancall<>(SB) + // func runtime·lsandoleakcheck() TEXT runtime·lsandoleakcheck(SB), NOSPLIT, $0-0 // void __lsan_do_leak_check_go(void); diff --git a/src/runtime/asan_loong64.s b/src/runtime/asan_loong64.s index 3abcf889b8..224d16ce2e 100644 --- a/src/runtime/asan_loong64.s +++ b/src/runtime/asan_loong64.s @@ -66,6 +66,14 @@ TEXT runtime·lsanregisterrootregion(SB), NOSPLIT, $0-16 MOVV $__lsan_register_root_region_go(SB), FARG JMP asancall<>(SB) +// func runtime·lsanunregisterrootregion(addr unsafe.Pointer, n uintptr) +TEXT runtime·lsanunregisterrootregion(SB), NOSPLIT, $0-16 + MOVV addr+0(FP), RARG0 + MOVV n+8(FP), RARG1 + // void __lsan_unregister_root_region_go(void *addr, uintptr_t n); + MOVV $__lsan_unregister_root_region_go(SB), FARG + JMP asancall<>(SB) + // func runtime·lsandoleakcheck() TEXT runtime·lsandoleakcheck(SB), NOSPLIT, $0-0 // void __lsan_do_leak_check_go(void); diff --git a/src/runtime/asan_ppc64le.s b/src/runtime/asan_ppc64le.s index 2fc5772a28..0c56a81991 100644 --- a/src/runtime/asan_ppc64le.s +++ b/src/runtime/asan_ppc64le.s @@ -66,6 +66,14 @@ TEXT runtime·lsanregisterrootregion(SB),NOSPLIT|NOFRAME,$0-16 MOVD $__lsan_register_root_region_go(SB), FARG BR asancall<>(SB) +// func runtime·lsanunregisterrootregion(addr unsafe.Pointer, n uintptr) +TEXT runtime·lsanunregisterrootregion(SB),NOSPLIT|NOFRAME,$0-16 + MOVD addr+0(FP), RARG0 + MOVD n+8(FP), RARG1 + // void __lsan_unregister_root_region_go(void *addr, uintptr_t n); + MOVD $__lsan_unregister_root_region_go(SB), FARG + BR asancall<>(SB) + // func runtime·lsandoleakcheck() TEXT runtime·lsandoleakcheck(SB), NOSPLIT|NOFRAME, $0-0 // void __lsan_do_leak_check_go(void); diff --git a/src/runtime/asan_riscv64.s b/src/runtime/asan_riscv64.s index f5ddb21a25..6c77f66348 100644 --- a/src/runtime/asan_riscv64.s +++ b/src/runtime/asan_riscv64.s @@ -60,6 +60,14 @@ TEXT runtime·lsanregisterrootregion(SB), NOSPLIT, $0-16 MOV $__lsan_register_root_region_go(SB), X14 JMP asancall<>(SB) +// func runtime·lsanunregisterrootregion(addr unsafe.Pointer, n uintptr) +TEXT runtime·lsanunregisterrootregion(SB), NOSPLIT, $0-16 + MOV addr+0(FP), X10 + MOV n+8(FP), X11 + // void __lsan_unregister_root_region_go(void *addr, uintptr_t n); + MOV $__lsan_unregister_root_region_go(SB), X14 + JMP asancall<>(SB) + // func runtime·lsandoleakcheck() TEXT runtime·lsandoleakcheck(SB), NOSPLIT, $0-0 // void __lsan_do_leak_check_go(void); diff --git a/src/runtime/mem.go b/src/runtime/mem.go index d45a0ccfb8..cd06ea323d 100644 --- a/src/runtime/mem.go +++ b/src/runtime/mem.go @@ -119,6 +119,13 @@ func sysHugePageCollapse(v unsafe.Pointer, n uintptr) { // //go:nosplit func sysFree(v unsafe.Pointer, n uintptr, sysStat *sysMemStat) { + // When using ASAN leak detection, the memory being freed is + // known by the sanitizer. We need to unregister it so it's + // not accessed by it. + if asanenabled { + lsanunregisterrootregion(v, n) + } + sysStat.add(-int64(n)) gcController.mappedReady.Add(-int64(n)) sysFreeOS(v, n)