Skip to content

Commit f37cdae

Browse files
josharianbradfitz
authored andcommitted
wgengine/magicsock: fix deadlock on shutdown
This fixes a deadlock on shutdown. One goroutine is waiting to send on c.derpRecvCh before unlocking c.mu. The other goroutine is waiting to lock c.mu before receiving from c.derpRecvCh. tailscale#3736 has a more detailed explanation of the sequence of events. Fixes tailscale#3736 Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com> (cherry picked from commit de4696d)
1 parent 1e6ca50 commit f37cdae

File tree

1 file changed

+3
-1
lines changed

1 file changed

+3
-1
lines changed

wgengine/magicsock/magicsock.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,7 @@ type Conn struct {
265265
stunReceiveFunc atomic.Value // of func(p []byte, fromAddr *net.UDPAddr)
266266

267267
// derpRecvCh is used by receiveDERP to read DERP messages.
268+
// It must have buffer size > 0; see issue 3736.
268269
derpRecvCh chan derpReadResult
269270

270271
// bind is the wireguard-go conn.Bind for Conn.
@@ -529,7 +530,7 @@ func (o *Options) derpActiveFunc() func() {
529530
// of NewConn. Mostly for tests.
530531
func newConn() *Conn {
531532
c := &Conn{
532-
derpRecvCh: make(chan derpReadResult),
533+
derpRecvCh: make(chan derpReadResult, 1), // must be buffered, see issue 3736
533534
derpStarted: make(chan struct{}),
534535
peerLastDerp: make(map[key.NodePublic]int),
535536
peerMap: newPeerMap(),
@@ -2641,6 +2642,7 @@ func (c *connBind) Close() error {
26412642
}
26422643
// Send an empty read result to unblock receiveDERP,
26432644
// which will then check connBind.Closed.
2645+
// connBind.Closed takes c.mu, but c.derpRecvCh is buffered.
26442646
c.derpRecvCh <- derpReadResult{}
26452647
return nil
26462648
}

0 commit comments

Comments
 (0)