Repository navigation
runtime: FreeBSD memory corruption involving fork system call #15658
Description
Please answer these questions before submitting your issue. Thanks!
- What version of Go are you using (
go version)?
go version go1.6.2 freebsd/amd64
- What operating system and processor architecture are you using (
go env)?
GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="freebsd"
GOOS="freebsd"
GOPATH=""
GORACE=""
GOROOT="/usr/local/go"
GOTOOLDIR="/usr/local/go/pkg/tool/freebsd_amd64"
GO15VENDOREXPERIMENT="1"
CC="cc"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0"
CXX="clang++"- What did you do?
package main
/* stdlib includes */
import (
"fmt"
"os/exec"
)
func run(done chan struct{}) {
cmd := exec.Command("true")
if err := cmd.Start(); err != nil {
goto finished
}
cmd.Wait()
finished:
done <- struct{}{}
return
}
func main() {
fmt.Println("Starting a bunch of goroutines...")
// 8 & 16 are arbitrary
done := make(chan struct{}, 16)
for i := 0; i < 8; i++ {
go run(done)
}
for {
select {
case <-done:
go run(done)
}
}
}- What did you expect to see?
I expect this strange program to spawn instances of /bin/true in parallel, until I stop it.
- What did you see instead?
Various types of panics caused by what looks to be corruption within the finalizer lists, caused by what I am assuming is based on race conditions. These panics can happen as quickly as 2 minutes, or much longer. 10 minutes seems a good round number.
Occasionally addspecial gets stuck in an infinite loop holding the lock, and the process wedges. This is illustrated in log 1462933614, with x.next pointing to x. This appears to be corruption of that data structure. I have seen processes in this state run for 22 hours.
I understand there is some trepidation expressed in issue #11485 around the locking of the data structures involved.
Here are some sample messages:
fatal error: runtime.SetFinalizer: finalizer already setruntime: nonempty check fails b.log[0]= 0 b.log[1]= 0 b.log[2]= 0 b.log[3]= 0 fatal error: workbuf is empty
1462926841-SetFinalizer-ex1.txt
1462926969-SetFinalizer-ex2.txt
1462933295-nonempty-check-fails.txt
1462933614-wedged.txt
This was run on an 8-core processor, and a 4-core 8-thread processor with ECC RAM, similar results.
Additionally, while this example is an extreme, it also represents the core functionality of a project I've been working on part-time for many months. I'm happy to provide any further assistance diagnosing this issue - I'm very invested!
Activity
derekmarcotte commentedon May 12, 2016
Here's another panic experienced in mallocgc by the same sample code:
1463046620-malloc-panic.txt
bradfitz commentedon May 12, 2016
@derekmarcotte, can you also reproduce this at master? (which will become Go 1.7)
And do you only see it on FreeBSD, or other operating systems as well?
/cc @aclements @ianlancetaylor
aclements commentedon May 12, 2016
@RLH, weren't you seeing "finalizer already set" failures a little while ago? Did you track that down? Could it have been related?
aclements commentedon May 12, 2016
On closer inspection of the failures you posted (thanks for collecting several, BTW), this smells like memory corruption. Just guessing, there are a few likely culprits. It may be the finalizer code, but I actually think that's less likely. More likely is that it's the fork/exec code: that code is really subtle, mucks with the address space, and contains system-specific parts (which would explain why it's showing up on FreeBSD, but I haven't been able to reproduce it on Linux yet).
@derekmarcotte, can you try commenting out the runtime.SetFinalizer call in newProcess in os/exec.go (your test doesn't need that finalizer) and see if you can still reproduce it? If you can, that will rule out finalizers.
bradfitz commentedon May 12, 2016
Note that FreeBSD runs via gomote, if this is that easily reproducible. I haven't yet tried.
derekmarcotte commentedon May 13, 2016
Just got a golang/go dev environment set up on my machine (was from FreeBSD packages). Will report back soon.
derekmarcotte commentedon May 13, 2016
Here's the heads of a bunch of logs with the epoch at the start of the process, so you can see the interval. I suspected a race vs. memory corruption because by and large it is the finalizer already set that crashes the process. I thought maybe the gc was setting these as free (or otherwise touching them) before the SetFinalizer had a chance to set their value.
I didn't include too many of them in my initial report, because I thought they were largely redundant.
@bradfitz: these logs are against master:
@aclements: I will try your patch next. One variable at a time.
RLH commentedon May 14, 2016
The "fatal error: runtime.SetFinalizer: finalizer already set" bug I was
seeing a few days ago were on the 1.8 dev.garbage branch and the result of
a TOC write barrier not marking an object as being published, TOC doing a
rollback, and reallocating a new object over an old one. Both objects had
finalizers and the bug was tripped.
None of the TOC code is in 1.7 or for that matter on TIP. I can force
myself to imagine that the 1.7 allocCache code could cause a similar
situation if the allocCache and bitmaps were not coherent. but if that were
the case it would expect lots of failures all over the place and across all
platforms, not just freeBSD.
On Fri, May 13, 2016 at 6:47 PM, Derek Marcotte notifications@github.com
wrote:
derekmarcotte commentedon May 15, 2016
@aclements: I've run it with your patch, although I haven't been able to babysit it too much.
The first time, all threads were idle after a number of hours (i.e. 0% cpu across the board). Connecting gdb to that process gave me trouble, and I couldn't get any logging out of it.
This morning, I was able to connect to a different process that looks a lot like 1462933614-wedged.txt. I've attached a log from gdb there:
1463270694.txt
Will keep trying to come up with more info.
derekmarcotte commentedon May 16, 2016
@aclements: Here's some more logs from a binary build with the patch:
1463315708-finalizer-already-set.txt
1463349807-finalizer-already-set.txt
1463352601-workbuf-not-empty.txt
1463362849-workbuf-empty.txt
1463378745-wedged-gdb.txt
Please let me know if I can be of further assistance?
aclements commentedon May 16, 2016
Thanks for the logs! I hadn't realized there were two finalizers involved here. Could you also comment out the SetFinalizer in NewFile in os/file_unix.go and see if it's still reproducible? (Your test also doesn't need that finalizer.)
aclements commentedon May 16, 2016
I didn't mean to say that it isn't necessarily a race. It's actually quite likely a race, but it's resulting in corruption of internal runtime structures, which suggests that the race is happening on freed memory. The "workbuf is empty" failure mode especially points at memory corruption, which is why my initial guess is that the finalizers (and the specials queue in general) may be victims rather than perpetrators. It's also easy to get finalizers out of the picture, while it's harder to get fork/exec out of the picture without completely changing the program. :)
derekmarcotte commentedon May 17, 2016
Thanks @aclements !
One crash, ~4 hours into running, since removing the SetFinalizer in NewFile.
1463429459.txt
I have a second process running for almost 11 hours, with 4 of the threads wedged, but it is still doing work.
252 remaining items
mattmacy commentedon Jul 6, 2018
@stevenh is there any correlation with the amount of memory in the system or the number of cores? For example, would lowering hw.physmem on a 48-way help?
stevenh commentedon Jul 7, 2018
stevenh commentedon Nov 28, 2018
I've been running the usual tests on 11.2-RELEASE-p3 with go1.11.1 and have not managed to reproduce after a weeks run.
Has anyone else seen a crash with these updated versions?
stevenh commentedon Dec 21, 2018
Ok still no issues triggered on my test box and its been running forks in a loop since 18th and 20th of November
Given this I'm tempted to say that the issue has been fixed either in FreeBSD or golang runtime.
ianlancetaylor commentedon Dec 21, 2018
Thanks very much for following up on this., I'm going to close the issues in the hopes that it is indeed fixed. Anyone, please comment if you find future failures.
stevenh commentedon Jan 3, 2019
While updating our test box to 12.0 from 11.2 I noticed that this latest test was running with a potentially relevant kernel patch on top of 11.2-RELEASE.
If anyone can reproduce this issue on 11.2 then they should try applying the following to see if was indeed the fix:
https://svnweb.freebsd.org/base?view=revision&revision=335171
This is already included in 12.0-RELEASE and was MFC'ed to 11-stable as of:
https://svnweb.freebsd.org/base?view=revision&revision=335508