mirror of
https://github.com/robertkrimen/otto
synced 2025-10-19 19:55: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
|
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 {
|
for _, node := range body {
|
||||||
value := self.cmpl_evaluate_nodeStatement(node)
|
value := self.cmpl_evaluate_nodeStatement(node)
|
||||||
switch value.kind {
|
switch value.kind {
|
||||||
|
|
|
||||||
54
otto_test.go
54
otto_test.go
|
|
@ -2,10 +2,14 @@ package otto
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/robertkrimen/otto/parser"
|
"github.com/robertkrimen/otto/parser"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestOtto(t *testing.T) {
|
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) {
|
func BenchmarkNew(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
New()
|
New()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user