Skip to content

Commit

Permalink
Merge pull request #1438 from huynhquangtoan/master
Browse files Browse the repository at this point in the history
Fix "panic: send on closed channel"
  • Loading branch information
AlexxIT authored Feb 24, 2025
2 parents 4bf9f0b + 6ee5247 commit e55c2e9
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 4 deletions.
11 changes: 7 additions & 4 deletions pkg/core/track.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ func (s *Sender) Start() {
s.done = make(chan struct{})

go func() {
// for range on nil chan is OK
for packet := range s.buf {
s.Output(packet)
}
Expand All @@ -148,7 +149,7 @@ func (s *Sender) Start() {
}

func (s *Sender) Wait() {
if done := s.done; s.done != nil {
if done := s.done; done != nil {
<-done
}
}
Expand All @@ -165,10 +166,12 @@ func (s *Sender) State() string {

func (s *Sender) Close() {
// close buffer if exists
if buf := s.buf; buf != nil {
s.buf = nil
defer close(buf)
s.mu.Lock()
if s.buf != nil {
close(s.buf) // exit from for range loop
s.buf = nil // prevent writing to closed chan
}
s.mu.Unlock()

s.Node.Close()
}
Expand Down
53 changes: 53 additions & 0 deletions pkg/core/track_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package core

import (
"testing"

"github.com/stretchr/testify/require"
)

func TestSenser(t *testing.T) {
recv := make(chan *Packet) // blocking receiver

sender := NewSender(nil, &Codec{})
sender.Output = func(packet *Packet) {
recv <- packet
}
require.Equal(t, "new", sender.State())

sender.Start()
require.Equal(t, "connected", sender.State())

sender.Input(&Packet{})
sender.Input(&Packet{})

require.Equal(t, 2, sender.Packets)
require.Equal(t, 0, sender.Drops)

// important to read one before close
// because goroutine in Start() can run with nil chan
// it's OK in real life, but bad for test
_, ok := <-recv
require.True(t, ok)

sender.Close()
require.Equal(t, "closed", sender.State())

sender.Input(&Packet{})

require.Equal(t, 2, sender.Packets)
require.Equal(t, 1, sender.Drops)

// read 2nd
_, ok = <-recv
require.True(t, ok)

// read 3rd
select {
case <-recv:
ok = true
default:
ok = false
}
require.False(t, ok)
}

0 comments on commit e55c2e9

Please sign in to comment.