-
Notifications
You must be signed in to change notification settings - Fork 17.8k
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
runtime: OS thread appears to be re-used despite never releasing runtime.LockOSThread() #28979
Comments
Additionally, it seems that if I make a seemingly unrelated change, the issue is no longer reproducible. The change is to just remove the
I obviously can't know whether removing the channel changes the behavior due to a timing difference or whether there could be a bug related to a locked go routine sharing a channel with an unlocked go routine, but seems worth mentioning. |
CC @aclements |
If helpful, I got some strace output showing a pid, 22828, that did unshare+mount calls followed up by a clone(2) to make a new thread (right before it calls
|
I think the problem is that |
@gopherbot Please open a backport issue for 1.10 and 1.11. |
Backport issue(s) opened: #28985 (for 1.10), #28986 (for 1.11). Remember to create the cherry-pick CL(s) as soon as the patch is submitted to master, according to https://golang.org/wiki/MinorReleases. |
Change https://golang.org/cl/153078 mentions this issue: |
@ianlancetaylor, thanks for finding the problem! I think the solution is to just keep Anyway, I put up a change. I was able to reproduce the original issue and can confirm that with my change, it's fixed. |
What did you do?
In Go 1.11.2, spawned a goroutine, called
runtime.LockOSThread()
and entered a new mount namespace viasyscall.Unshare
.runtime.UnlockOSThread()
was never called, which according to the docs should mean that the locked thread is never re-used.However, it appears that a separate goroutine started at the beginning of the process (which never calls unshare or does anything with mounts) will after some time be executing in a mount namespace that was created by the independent goroutine mentioned above (which is not expected to be leaking OS threads). This seems to indicate that the OS thread is somehow leaking for re-use by other goroutines despite never calling
runtime.UnlockOSThread()
.This behavior was originally observed in a larger piece of software, but I was able to reproduce it using the code below. The code:
/tmp/test-go-thread-leak/source
, with file contents "source"/tmp/test-go-thread-leak/dest
, with file contents "dest"/tmp/test-go-thread-leak/dest
have not changed. If the contents changed from the expected value "dest" to "source", it panics, crashing the program.runtime.LockOSThread()
/tmp/test-go-thread-leak/source
to/tmp/test-go-thread-leak/dest
. This means that any threads/processes in the newly created mount namespace will now see the contents of "dest" have changed to be "source".The goroutine that checks the contents of
/tmp/test-go-thread-leak/dest
should never read the contents as "source" unless it has suddenly begun executing on an OS thread using one of the mount namespaces created by the other goroutine. However, after 1-10s of execution, the program will crash due to the goroutine reading "source" instead of destination, indicating the OS thread leaked.Code was compiled with just
go build main.go
and then run withsudo ./main
(sudo
needed to make the unshare call).What did you expect to see?
That the program executed indefinitely, never crashing due to the a goroutine unexpectedly executing in a mount namespace created by a different goroutine locked to its os thread.
What did you see instead?
A mount namespace leaks to the separate go routine, causing the program to crash. The time it takes for this to occur is variable but between 1 and 10 seconds. One example:
System details
The text was updated successfully, but these errors were encountered: