errors on thread interleavings, lock operations • Data races are explicitly on “data variables” https://www.cse.iitk.ac.in/users/swarnendu/courses/spring2021-cs636/concurrency-bugs.pdf
• Based on LLVM ThreadSanitizer race detector • The race detector is integrated with go tool chain ◦ go test -race ◦ go build -race ◦ go install -race ◦ go run -race https://talks.golang.org/2015/dynamic-tools.slide
by Go runtime • Go memory model (simplified version) ◦ Happens before ◦ Within a single goroutine ▪ Read + Write are ordered ▪ May reorder the reads and writes executed only when the reordering does not change the behavior ◦ Within multiple goroutines ▪ Shared variables should be synchronized
if count == 0 { count ++ } mu.Unlock() } func main() { go incrementCount() go incrementCount() } Lock Unlock R count W count G1 Lock Unlock R count G2 A B C D
count == 0 { count ++ } } func main() { go incrementCount() go incrementCount() } R count W count G1 G2 A B C D R count W count A < B (Same goroutines) C < D (Same goroutines) But A ? C and C ? A
count == 0 { count ++ } } func main() { go incrementCount() go incrementCount() } R count W count G1 G2 A B C D R count W count A < B (Same goroutines) C < D (Same goroutines) But A ? C and C ? A concurrent
detect data race depending on observed executions • FastTrack ◦ Further optimize time and space complexity of DJIT+ • ThreadSanitizer v2 ◦ Similar with FastTrack
thread has its own clock that is incremented at lock synchronization operations with release semantics • Each lock has a vector clock • Each shared variables x has two vector clock Rx and Wx • Check each memory access with all previous accesses DJIT+
{ // callerpc is the address of the go statement // that created this newg.racectx = racegostart(callerpc) } } runtime/proc.go func (m *Mutex) Lock() { if atomic.CompareAndSwapInt32(&m.state, 0, mutexLocked) { if race.Enabled { race.Acquire(unsafe.Pointer(m)) } return } m.lockSlow() mutex.go
racegostart(callerpc) } } Struct ThreadState { int tid u64 epoch ThreadClock clock } race.Acquire() race.Release() race.ReleaseMerge() Establish happens-before relations By updating vector clocks race.read() race.write() 1. Data race with previous access 2. Store information about this access for future comparisons
0x7fxxxxxxxxxx 0x1fxxxxxxxxxx tid epoch addr write • The shadow value represents 1 memory access (read or write) from one thread • For each 8bytes of user memory we maintain 4 shadow values (it’s tunable) Struct Shadow { u64 tid // thread id u64 epoch // thread’s clock time u64 addr // memory access address u64 write // read/write }
3 40 0:4 0 Compare: <current thread VC, new shadow state> vs <existing shadow states> [ ] access location overlap? [ ] any of these accesses is a write? [ ] are the tid different? [ ] unordered by happens before? 1 10 0:2 1 2 20 4:8 0
3 40 0:4 0 Compare: <current thread VC, new shadow state> vs <existing shadow states> [X] access location overlap? [X] any of these accesses is a write? [ ] are the tid different? [ ] unordered by happens before? 1 10 0:2 1 2 20 4:8 0
3 40 0:4 0 Compare: <current thread VC, new shadow state> vs <existing shadow states> [O] access location overlap? [O] any of these accesses is a write? [O] are the tid different? [ ] unordered by happens before? 1 10 0:2 1 2 20 4:8 0
3 40 0:4 0 Compare: <current thread VC, new shadow state> vs <existing shadow states> [O] access location overlap? [O] any of these accesses is a write? [O] are the tid different? [ ] unordered by happens before? 1 10 0:2 1 2 20 4:8 0 (10, ?, ?) < (5, 0, 40)
3 40 0:4 0 Compare: <current thread VC, new shadow state> vs <existing shadow states> [O] access location overlap? [O] any of these accesses is a write? [O] are the tid different? [O] unordered by happens before? 1 10 0:2 1 2 20 4:8 0 (10, ?, ?) < (5, 0, 40) Race
a shared memory location, at least one access is a write. • Go race detector can help you find out those bugs. • Race detector can be slow and memory-consuming • Algorithm is based on dynamic modelling of happens-before relation ◦ No false positive ◦ False negatives are possible