Detecting races

suggest change

When 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.

Feedback about page:

Feedback:
Optional: your email if you want me to get back to you:



Table Of Contents