Go: Race Detector with ThreadSanitizer

Vincent
A Journey With Go
Published in
4 min readJun 26, 2019

--

Illustration created for “A Journey With Go”, made from the original Go Gopher, created by Renee French.

Go provides a powerful tool to detect race conditions. This tool can be enabled by the flag -race that you can use with your tests or during compilation.

Let’s create a simple example of data race and analyze how Go does the detection and what tool it uses. Our following program will increment a variable until it reaches the value 100k thanks to two goroutines:

var foo = 0

func main() {
var wg sync.WaitGroup

wg.Add(2)
go func() {
defer wg.Done()
for i := 0; i < 50000 ;i++ {
foo++
}
}()
go func() {
defer wg.Done()
for i := 0; i < 50000 ;i++ {
foo++
}
}()
wg.Wait()
println(foo)
}

The result will always change due to the concurrency read/write on the variable. If you do not fully understand this example, I suggest you read the introduction to the race detector.

Race detector functions

In order to understand how Go internally manages the race condition detections, let’s generate the asm code thanks to the command go tool compile -S -race main.go. Here is an extract of the output with the instructions related to foo++:

(main.go:14)   CALL   runtime.raceread(SB)
(main.go:14) CALL runtime.racewrite(SB)
(main.go:16) CALL…

--

--