Is it possible that the race detector is wrong here, or that I misunderstand what the ack gives me? This is pushgate, a small service that checks HMAC signatures on device tokens for push notifications in my mobile app. The caller sends a Request on an unbuffered channel, the worker fills in a Result, then sends the ID on an ack channel. The caller reads the Result only after receiving the ack. I wrote the tests like this on purpose so there is no time.Sleep. The select with time.After is only there so a stuck test dies.
Plain go test is always green. Today before tagging a release I ran go test -race -count=200 ./.... About one run in 30-40 prints WARNING: DATA RACE, with a read in the test goroutine and a write in the worker goroutine. The worker side points into verify.go, the test side at the t.Logf line in verify_test.go. It seems to come more from TestWorkerRejectsBadSig, but I am not sure.
What I tried:
- buffered ack channel: race showed up more often, so I put it back
-cpu 1: race disappears, but I don't trust that- the old Result had two fields, and I added a timestamp last week for audit logs. I don't see why that would matter
The worker:
for r := range in {
want := sign(secret, r.Token)
ok := hmac.Equal([]byte(want), []byte(r.Sig))
r.Result.DeviceID = r.ID
r.Result.Valid = ok
ack <- r.ID
// stamp after the ack so the caller is not kept waiting
r.Result.Checked = time.Now()
if verbose {
log.Printf("checked device=%d valid=%v", r.ID, ok)
}
}
The test that fails more often:
func TestWorkerRejectsBadSig(t *testing.T) {
res := runOne(t, 9, "apns-abc123", "deadbeef")
t.Logf("result for bad sig: %+v", *res)
if res.Valid {
t.Fatal("bad signature accepted")
}
if res.DeviceID != 9 {
t.Fatalf("device id %d", res.DeviceID)
}
}
runOne makes both channels with plain make(chan ...), starts the worker, sends the Request, then selects on ack vs time.After(2 * time.Second) and returns res. I was reading https://go.dev/ref/mem but still don't see where the ordering breaks. Is the pointer inside the struct hiding something from the detector?