Summary
Escape analysis incorrectly skips instrumentation for pointer dereferences when the pointer variable itself doesn't escape, but the memory it points to can be shared.
Reported by
@thepudds in golang/go#6508 (comment)
Reproduction
//go:noinline
func update(ptr *int) { // -gcflags=-m: "ptr does not escape"
*ptr++
}
func main() {
var shared int
var wg sync.WaitGroup
for range 2 {
wg.Go(func() {
for range 100 {
update(&shared)
}
})
}
wg.Wait()
}
Expected
Race detected on *ptr++ (TSAN reports correctly)
Actual
No race reported (v0.8.1)
Root Cause
Our escape analysis skips instrumentation when a variable "doesn't escape", but:
ptr is a local parameter (doesn't escape)
*ptr dereferences to shared which IS accessed by multiple goroutines
Fix
Only skip direct local variable access (x = 5), NOT pointer dereferences (*ptr = 5).
Pointer dereferences must always be instrumented regardless of escape analysis.
Priority
P0 - Critical regression in v0.8.0
Summary
Escape analysis incorrectly skips instrumentation for pointer dereferences when the pointer variable itself doesn't escape, but the memory it points to can be shared.
Reported by
@thepudds in golang/go#6508 (comment)
Reproduction
Expected
Race detected on
*ptr++(TSAN reports correctly)Actual
No race reported (v0.8.1)
Root Cause
Our escape analysis skips instrumentation when a variable "doesn't escape", but:
ptris a local parameter (doesn't escape)*ptrdereferences tosharedwhich IS accessed by multiple goroutinesFix
Only skip direct local variable access (
x = 5), NOT pointer dereferences (*ptr = 5).Pointer dereferences must always be instrumented regardless of escape analysis.
Priority
P0 - Critical regression in v0.8.0