blueloveTH 2 лет назад
Родитель
Сommit
a1212fbf09
3 измененных файлов с 13 добавлено и 2 удалено
  1. 1 1
      src/frame.h
  2. 5 0
      src/pocketpy.h
  3. 7 1
      src/vm.h

+ 1 - 1
src/frame.h

@@ -130,7 +130,7 @@ template<> inline void gc_mark<Function>(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;

+ 5 - 0
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){

+ 7 - 1
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){