diff --git a/src/frame.h b/src/frame.h index 3a6daa3e..67973685 100644 --- a/src/frame.h +++ b/src/frame.h @@ -130,7 +130,7 @@ template<> inline void gc_mark(Function& t){ } struct ValueStack { - static const size_t MAX_SIZE = 32768; + static const size_t MAX_SIZE = 16384; // We allocate 512 more bytes to keep `_sp` valid when `is_overflow() == true`. PyObject* _begin[MAX_SIZE + 512]; PyObject** _sp; diff --git a/src/pocketpy.h b/src/pocketpy.h index d1e642a8..8b15bf5a 100644 --- a/src/pocketpy.h +++ b/src/pocketpy.h @@ -590,6 +590,11 @@ inline void add_module_time(VM* vm){ inline void add_module_sys(VM* vm){ PyObject* mod = vm->new_module("sys"); vm->setattr(mod, "version", VAR(PK_VERSION)); + vm->bind_func<0>(mod, "getrecursionlimit", CPP_LAMBDA(VAR(vm->recursionlimit))); + vm->bind_func<1>(mod, "setrecursionlimit", [](VM* vm, ArgsView args) { + vm->recursionlimit = CAST(int, args[0]); + return vm->None; + }); } inline void add_module_json(VM* vm){ diff --git a/src/vm.h b/src/vm.h index 3cd4e11c..35f8a334 100644 --- a/src/vm.h +++ b/src/vm.h @@ -104,6 +104,8 @@ public: Type tp_slice, tp_range, tp_module; Type tp_super, tp_exception; + i64 recursionlimit = 1000; + VM(bool use_stdio) : heap(this){ this->vm = this; this->_stdout = use_stdio ? &std::cout : &_stdout_buffer; @@ -329,6 +331,7 @@ public: } void StackOverflowError() { _error("StackOverflowError", ""); } + void RecursionError() { _error("RecursionError", "maximum recursion depth exceeded"); } void IOError(const Str& msg) { _error("IOError", msg); } void NotImplementedError(){ _error("NotImplementedError", ""); } void TypeError(const Str& msg){ _error("TypeError", msg); } @@ -863,6 +866,8 @@ inline PyObject* VM::_vectorcall(int ARGC, int KWARGC, bool op_call){ inline PyObject* VM::_py_call(PyObject** sp_base, PyObject* callable, ArgsView args, ArgsView kwargs){ // callable must be a `function` object + if(callstack.size() >= recursionlimit) RecursionError(); + const Function& fn = CAST(Function&, callable); const CodeObject* co = fn.decl->code.get(); FastLocals locals(co); @@ -907,7 +912,8 @@ inline PyObject* VM::_py_call(PyObject** sp_base, PyObject* callable, ArgsView a } PyObject* _module = fn._module != nullptr ? fn._module : top_frame()->_module; - // TODO: callable may be garbage collected + // TODO: callable may be garbage collected if it is a temporary object + // very unlikely to happen, but still possible s_data.reset(sp_base); PyObject** curr_sp = s_data._sp; if(co->is_generator){