1
0
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:
Richard Putra 2022-10-06 18:45:23 +07:00 committed by GitHub
parent b87d35c0b8
commit 201ab5b34f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 65 additions and 0 deletions

View File

@ -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 {

View File

@ -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()