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 <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Ian Lance Taylor <iant@google.com>
This commit is contained in:
Florian Zenker 2025-03-19 10:55:55 +00:00
parent 1aee4f3464
commit 56e5476e10
9 changed files with 56 additions and 0 deletions

View File

@ -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

View File

@ -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();
}

View File

@ -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") }

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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)