Skip to content

Commit

Permalink
interp: Fix panic when trigger before any context has been pushed
Browse files Browse the repository at this point in the history
Make sure there is a top cancel function before calling it.
Fixes panic caused when interrupting decode before interp context has been pushed.

Also cleanup confusing naming a bit.

Thanks @pldin601 for reporting
  • Loading branch information
wader committed Nov 29, 2022
1 parent 73ec686 commit 568afff
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 5 deletions.
14 changes: 9 additions & 5 deletions internal/ctxstack/ctxstack.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,25 @@ import (
// Stack is a context stack
type Stack struct {
cancelFns []func()
closeCh chan struct{}
stopCh chan struct{}
}

// New context stack
func New(triggerCh func(stopCh chan struct{})) *Stack {
stopCh := make(chan struct{})
s := &Stack{closeCh: stopCh}
s := &Stack{stopCh: stopCh}

go func() {
for {
triggerCh(stopCh)
select {
case <-stopCh:
// stop if closed
// stop if stopCh closed
default:
s.cancelFns[len(s.cancelFns)-1]()
// ignore if triggered before any context pushed
if len(s.cancelFns) > 0 {
s.cancelFns[len(s.cancelFns)-1]()
}
continue
}
break
Expand All @@ -43,13 +46,14 @@ func (s *Stack) Stop() {
for i := len(s.cancelFns) - 1; i >= 0; i-- {
s.cancelFns[i]()
}
close(s.closeCh)
close(s.stopCh)
}

// Push creates, pushes and returns new context. Cancel pops it.
func (s *Stack) Push(parent context.Context) (context.Context, func()) {
stackCtx, stackCtxCancel := context.WithCancel(parent)
stackIdx := len(s.cancelFns)

s.cancelFns = append(s.cancelFns, stackCtxCancel)
cancelled := false

Expand Down
35 changes: 35 additions & 0 deletions internal/ctxstack/ctxstacl_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package ctxstack_test

import (
"testing"

"github.com/wader/fq/internal/ctxstack"
)

func TestCancelBeforePush(t *testing.T) {
// TODO: nicer way to test trigger before any push
waitTriggerFn := make(chan struct{})
triggerCh := make(chan struct{})
waitCh := make(chan struct{})
hasTriggeredOnce := false

ctxstack.New(func(stopCh chan struct{}) {
if hasTriggeredOnce {
close(stopCh)
close(waitCh)
return
}

close(waitTriggerFn)
<-triggerCh

hasTriggeredOnce = true
})

// wait for trigger func to be called
<-waitTriggerFn
// make trigger func return and cancel
close(triggerCh)

<-waitCh
}

0 comments on commit 568afff

Please sign in to comment.