Skip to content

runtime: enable leak sanitizer in Go #67833

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
znkr opened this issue Jun 5, 2024 · 8 comments
Closed

runtime: enable leak sanitizer in Go #67833

znkr opened this issue Jun 5, 2024 · 8 comments
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. FeatureRequest Issues asking for a new feature that does not need a proposal. FixPending Issues that have a fix which has not yet been reviewed or submitted.
Milestone

Comments

@znkr
Copy link
Contributor

znkr commented Jun 5, 2024

Proposal Details

This is follow-up to #44853 which proposed to enable ASAN for Go.

One type of error in Go / C interop are memory leaks. These can be detected by ASAN using ASAN_OPTIONS=detect_leaks=1. Unfortunately, this doesn't fully work with Go's ASAN integration. For example, allocating a C object and storing it in a global variable in Go is detected as a leak.

I believe to make LSAN work, all we need to do is to tell it about memory regions that Go manages to consider as roots using __lsan_register_root_region.

@znkr znkr added the Proposal label Jun 5, 2024
@gopherbot gopherbot added the compiler/runtime Issues related to the Go compiler and/or runtime. label Jun 5, 2024
@ianlancetaylor
Copy link
Member

I don't think this has to be a proposal, taking it out of the proposal process. We should just do this as part of our ordinary sanitizer support.

It sounds like this will be pretty loose, unless there is some way to tell the sanitizer which pointers are live. But a conservative leak detector is still better than no leak detector at all.

@mknyszek mknyszek added this to the Unplanned milestone Jun 5, 2024
@mknyszek mknyszek added NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. FeatureRequest Issues asking for a new feature that does not need a proposal. labels Jun 5, 2024
@znkr
Copy link
Contributor Author

znkr commented Jun 6, 2024

I took another look into LSAN, to understand how conservative it would be. https://maskray.me/blog/2023-02-12-all-about-leak-sanitizer was quite helpful. What that article doesn't document is the use_poisoned flag. IIUC, LSAN can use ASAN poisoning information when scanning for pointers and will ignore pointers in poisoned memory. I think that Go already poisons freed memory, so it might be possible to make this pretty accurate.

@ruyi789
Copy link

ruyi789 commented Jun 6, 2024

It's a completely redundant feature, the example code doesn't detect the array size at all, and of course it's also your freedom, so why should you be reminded of it

@qmuntal
Copy link
Member

qmuntal commented Feb 20, 2025

Enabling the leak sanitizer would be a nice improvement. Note that some (see list) Go projects are already sidestepping this limitation by manually calling __lsan_do_leak_check at program exit.

@ianlancetaylor
Copy link
Member

Does anybody happen to know which versions of clang and GCC added support for __lsan_do_leak_check? Can we just assume it is present?

@qmuntal
Copy link
Member

qmuntal commented Feb 21, 2025

Does anybody happen to know which versions of clang and GCC added support for __lsan_do_leak_check? Can we just assume it is present?

LLVM introduced it in version 3.4 (source), which was released in 2015. GCC followed suite in version 5 (source), released also in 2015.

I've been using __lsan_do_leak_check for a while with great results, catching real memory leaks in production. You can see its useful by executing the following sample with go run -asan .:

package main

// void __lsan_do_leak_check(void);
import "C"

func main() {
	defer C.__lsan_do_leak_check()
	C.CString("foo")
}

Which on my machine outputs:

=================================================================
==13248==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 4 byte(s) in 1 object(s) allocated from:
    #0 0x7f127460a24f in malloc (/usr/lib/libasan.so.8+0xe124f) (BuildId: ccf997b37481b6e7b757519a36b110bee0a850cd)
    #1 0x472c7b  (/tmp/go-build1729442831/b001/exe/test+0x472c7b) (BuildId: 2adb13e01facb758d13955e5fc42872f5ec67f1f)

SUMMARY: AddressSanitizer: 4 byte(s) leaked in 1 allocation(s).
exit status 1

Note that the memory leak sanitizer is enabled by default on Linux when using the address sanitizer, so Go apps built with -asan are already tracking down memory leaks. The problem is that these are not reported because atexit doesn't work with cgo (see #5948), and the address sanitizer registers __lsan_do_leak_check using atexit (source). My bet is that is we fix atexit, then the memory leak detector will start reporting memory leaks without any additional change. If that's too much work, then manually calling __lsan_do_leak_check when the Go runtime is exiting is also an option.

@gopherbot
Copy link
Contributor

Change https://go.dev/cl/651755 mentions this issue: runtime: in asan mode call __lsan_do_leak_check when exiting

@qmuntal qmuntal removed the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Feb 24, 2025
@prattmic prattmic added the FixPending Issues that have a fix which has not yet been reviewed or submitted. label Feb 24, 2025
@prattmic prattmic modified the milestones: Unplanned, Go1.25 Feb 24, 2025
@dmitshur dmitshur moved this from Todo to In Progress in Go Compiler / Runtime Mar 4, 2025
@github-project-automation github-project-automation bot moved this from In Progress to Done in Go Compiler / Runtime Mar 6, 2025
@gopherbot
Copy link
Contributor

Change https://go.dev/cl/659135 mentions this issue: runtime: in asan mode unregister root regions on free

gopherbot pushed a commit that referenced this issue Mar 19, 2025
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. FeatureRequest Issues asking for a new feature that does not need a proposal. FixPending Issues that have a fix which has not yet been reviewed or submitted.
Projects
Development

No branches or pull requests

7 participants