fix(push): Broadcast shares one payload slice across dispatch goroutines — data race #109

Open
opened 2026-07-10 17:45:31 +02:00 by dominik.polakovics · 0 comments

Found while landing PR #103 (out of scope for that change; internal/push is untouched by it — this is pre-existing #98 code).

Symptom

go test -race ./internal/push/ fails on main.

Repro:

go test -race -run TestBroadcastHappyPath ./internal/push/

Root cause

Sender.Broadcast marshals the payload once and hands the same []byte to every dispatch goroutine (internal/push/sender.go ~L103-113). webpush-go v1.4.0 then does bytes.NewBuffer(message) and appends padding into the slice's spare capacity (webpush.go ~L179-186). Since json.Marshal routinely returns a slice with cap > len, N subscriptions means N goroutines writing into the same backing array concurrently.

Fix

Give each dispatch its own copy of the bytes, e.g.:

s.dispatch(sub, bytes.Clone(body))

One line; a -race test over a multi-subscription broadcast should regress it.

Found while landing PR #103 (out of scope for that change; `internal/push` is untouched by it — this is pre-existing #98 code). ## Symptom `go test -race ./internal/push/` fails on `main`. Repro: go test -race -run TestBroadcastHappyPath ./internal/push/ ## Root cause `Sender.Broadcast` marshals the payload once and hands the **same** `[]byte` to every dispatch goroutine (`internal/push/sender.go` ~L103-113). webpush-go v1.4.0 then does `bytes.NewBuffer(message)` and **appends padding into the slice's spare capacity** (`webpush.go` ~L179-186). Since `json.Marshal` routinely returns a slice with `cap > len`, N subscriptions means N goroutines writing into the same backing array concurrently. ## Fix Give each dispatch its own copy of the bytes, e.g.: s.dispatch(sub, bytes.Clone(body)) One line; a `-race` test over a multi-subscription broadcast should regress it.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Cloonar/coding-lab#109
No description provided.