mirror of
https://github.com/robertkrimen/otto
synced 2025-10-12 20:27:30 +08:00
fix: timeout on empty loop (#440)
Prevent loop statements with no body hanging forever Co-authored-by: Stefano Fratini <stefano.fratini@nnnco.com.au> Co-authored-by: tkpd-richard-putra <83326962+tkpd-richard-putra@users.noreply.github.com>
This commit is contained in:
parent
b87d35c0b8
commit
201ab5b34f
|
@ -259,6 +259,17 @@ resultBreak:
|
|||
break
|
||||
}
|
||||
}
|
||||
|
||||
// this is to prevent for cycles with no body from running forever
|
||||
if len(body) == 0 && self.otto.Interrupt != nil {
|
||||
runtime.Gosched()
|
||||
select {
|
||||
case value := <-self.otto.Interrupt:
|
||||
value()
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
for _, node := range body {
|
||||
value := self.cmpl_evaluate_nodeStatement(node)
|
||||
switch value.kind {
|
||||
|
|
54
otto_test.go
54
otto_test.go
|
@ -2,10 +2,14 @@ package otto
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/robertkrimen/otto/parser"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestOtto(t *testing.T) {
|
||||
|
@ -1738,6 +1742,56 @@ func Test_stackLimit(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestOttoInterrupt(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
script string
|
||||
}{
|
||||
{
|
||||
name: "empty-for-loop",
|
||||
script: "for(;;) {}",
|
||||
},
|
||||
{
|
||||
name: "empty-do-while",
|
||||
script: "do{} while(true)",
|
||||
},
|
||||
}
|
||||
|
||||
halt := errors.New("interrupt")
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
vm := New()
|
||||
vm.Interrupt = make(chan func(), 1)
|
||||
ec := make(chan error, 1)
|
||||
go func() {
|
||||
defer func() {
|
||||
if caught := recover(); caught != nil {
|
||||
if caught == halt {
|
||||
fmt.Println(caught)
|
||||
ec <- nil
|
||||
return
|
||||
}
|
||||
panic(caught)
|
||||
}
|
||||
}()
|
||||
_, err := vm.Run(tc.script)
|
||||
ec <- err
|
||||
}()
|
||||
|
||||
// Give the vm chance to execute the loop.
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
vm.Interrupt <- func() { panic(halt) }
|
||||
|
||||
select {
|
||||
case <-time.After(time.Second):
|
||||
t.Fatal("timeout")
|
||||
case err := <-ec:
|
||||
require.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkNew(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
New()
|
||||
|
|
Loading…
Reference in New Issue
Block a user