Detecting races
suggest changeWhen you don’t use sync.Mutex
to ensure exclusive access to data between goroutines or forget to lock in parts of the program, you’ll get data races.
Data races might lead to memory corruption or crashes.
Go makes it easy to instrument the code with additional checks that are very likely to catch data races.
Use -race
flag to go build
or go run
.
Here’s a program with intentional data races.
When you run it with go run -race data_race.go
the runtime will notice memory corruption.
var (
n int
)
func main() {
var wg sync.WaitGroup
nCPU := runtime.NumCPU()
nIter := 10
for i := 0; i < nCPU; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for j := 0; j < nIter; j++ {
n++
time.Sleep(time.Microsecond * 10)
}
}()
}
wg.Wait()
fmt.Printf("n is: %d, expected: %d\n", n, nCPU*nIter)
}
# runtime/race
/usr/lib/gcc/x86_64-alpine-linux-musl/8.3.0/../../../../x86_64-alpine-linux-musl/bin/ld: race_linux_amd64.syso: in function `__sanitizer::GetArgv()':
gotsan.cc:(.text+0x4183): undefined reference to `__libc_stack_end'
/usr/lib/gcc/x86_64-alpine-linux-musl/8.3.0/../../../../x86_64-alpine-linux-musl/bin/ld: race_linux_amd64.syso: in function `__sanitizer::ReExec()':
gotsan.cc:(.text+0x9797): undefined reference to `__libc_stack_end'
/usr/lib/gcc/x86_64-alpine-linux-musl/8.3.0/../../../../x86_64-alpine-linux-musl/bin/ld: race_linux_amd64.syso: in function `__sanitizer::InternalAlloc(unsigned long, __sanitizer::SizeClassAllocatorLocalCache<__sanitizer::SizeClassAllocator32<__sanitizer::AP32> >*, unsigned long)':
gotsan.cc:(.text+0xaac1): undefined reference to `__libc_malloc'
/usr/lib/gcc/x86_64-alpine-linux-musl/8.3.0/../../../../x86_64-alpine-linux-musl/bin/ld: race_linux_amd64.syso: in function `__sanitizer::InternalRealloc(void*, unsigned long, __sanitizer::SizeClassAllocatorLocalCache<__sanitizer::SizeClassAllocator32<__sanitizer::AP32> >*)':
gotsan.cc:(.text+0xca20): undefined reference to `__libc_realloc'
/usr/lib/gcc/x86_64-alpine-linux-musl/8.3.0/../../../../x86_64-alpine-linux-musl/bin/ld: race_linux_amd64.syso: in function `__sanitizer::InternalFree(void*, __sanitizer::SizeClassAllocatorLocalCache<__sanitizer::SizeClassAllocator32<__sanitizer::AP32> >*)':
gotsan.cc:(.text+0x66e8): undefined reference to `__libc_free'
collect2: error: ld returned 1 exit status
exit status 2
This examples shows that memory for variable n
is corrupted because the final value of n
is not what we expect.
It also shows that instrumentation added with -race
can catch memory corruption and points out which part of program caused the corruption.
When to use -race
Additional instrumentation added by -race
flag makes the program slower so it’s not usually used when compiling shipping binaries.
It’s a good idea to use on your CI (continous integration) servers when running your test suite.
Race detector and Windows
Race detector requires gcc
to be installed on your machine.
gcc
is typically installed on Mac OS and Linux but usually not on Windows.
To install gcc
on Windows, you can use a window-specific distribution of gcc
, like MinGW. Make sure gcc
is in PATH
.