diff --git a/otto.go b/otto.go index 6135330..25ba706 100644 --- a/otto.go +++ b/otto.go @@ -367,6 +367,10 @@ func (self Otto) SetRandomSource(fn func() float64) { self.runtime.random = fn } +func (self Otto) SetStackDepthLimit(limit int) { + self.runtime.stackLimit = limit +} + // Context is a structure that contains information about the current execution // context. type Context struct { diff --git a/otto_test.go b/otto_test.go index ca0bd76..3737ea2 100644 --- a/otto_test.go +++ b/otto_test.go @@ -1650,6 +1650,56 @@ func Test_objectLength(t *testing.T) { }) } +func Test_stackLimit(t *testing.T) { + code := ` + function a() {} + function b() { a(); } + function c() { b(); } + function d() { c(); } + function e() { d(); } + e(); + ` + + tt(t, func() { + _, vm := test() + + _, err := vm.Run(code) + + is(err == nil, true) + }) + + tt(t, func() { + _, vm := test() + + vm.vm.SetStackDepthLimit(2) + + _, err := vm.Run(code) + + is(err == nil, false) + }) + + tt(t, func() { + _, vm := test() + + vm.vm.SetStackDepthLimit(6) + + _, err := vm.Run(code) + + is(err == nil, true) + }) + + tt(t, func() { + _, vm := test() + + vm.vm.SetStackDepthLimit(1) + vm.vm.SetStackDepthLimit(0) + + _, err := vm.Run(code) + + is(err == nil, true) + }) +} + func BenchmarkNew(b *testing.B) { for i := 0; i < b.N; i++ { New() diff --git a/runtime.go b/runtime.go index a998f7a..71e6de7 100644 --- a/runtime.go +++ b/runtime.go @@ -56,6 +56,7 @@ type _runtime struct { eval *_object // The builtin eval, for determine indirect versus direct invocation debugger func(*Otto) random func() float64 + stackLimit int labels []string // FIXME lck sync.Mutex @@ -63,6 +64,14 @@ type _runtime struct { func (self *_runtime) enterScope(scope *_scope) { scope.outer = self.scope + if self.scope != nil { + scope.depth = self.scope.depth + 1 + } + + if self.stackLimit != 0 && scope.depth >= self.stackLimit { + panic(self.panicRangeError("RangeError: Maximum call stack size exceeded")) + } + self.scope = scope } diff --git a/scope.go b/scope.go index b808084..465e6b9 100644 --- a/scope.go +++ b/scope.go @@ -21,6 +21,7 @@ type _scope struct { this *_object eval bool // Replace this with kind? outer *_scope + depth int frame _frame }