fix recursion bug

This commit is contained in:
blueloveTH 2022-11-12 15:43:11 +08:00
parent 1cfa339ac2
commit 9256186cb1
3 changed files with 54 additions and 13 deletions

View File

@ -69,7 +69,7 @@ void setStackSize(_Float mb){
int main(int argc, char** argv){ int main(int argc, char** argv){
#ifdef PK_DEBUG_STACK #ifdef PK_DEBUG_STACK
setStackSize(1); setStackSize(0.5);
#endif #endif
if(argc == 1){ if(argc == 1){

View File

@ -542,6 +542,18 @@ void __addModuleSys(VM* vm){
vm->__checkArgSize(args, 1); vm->__checkArgSize(args, 1);
return vm->PyInt(args[0].use_count()); return vm->PyInt(args[0].use_count());
}); });
vm->bindFunc(mod, "getrecursionlimit", [](VM* vm, PyVarList args) {
vm->__checkArgSize(args, 0);
return vm->PyInt(vm->maxRecursionDepth);
});
vm->bindFunc(mod, "setrecursionlimit", [](VM* vm, PyVarList args) {
vm->__checkArgSize(args, 1);
vm->maxRecursionDepth = vm->PyInt_AS_C(args[0]);
return vm->None;
});
vm->setAttr(mod, "version", vm->PyStr(PK_VERSION)); vm->setAttr(mod, "version", vm->PyStr(PK_VERSION));
} }

View File

@ -29,6 +29,8 @@ private:
std::vector<PyObject*> numPool; std::vector<PyObject*> numPool;
PyVarDict _modules; // 3rd modules PyVarDict _modules; // 3rd modules
PyVar __py2py_call_signal;
PyVar runFrame(Frame* frame){ PyVar runFrame(Frame* frame){
while(!frame->isCodeEnd()){ while(!frame->isCodeEnd()){
const ByteCode& byte = frame->readCode(); const ByteCode& byte = frame->readCode();
@ -213,7 +215,9 @@ private:
{ {
PyVarList args = frame->popNValuesReversed(this, byte.arg); PyVarList args = frame->popNValuesReversed(this, byte.arg);
PyVar callable = frame->popValue(this); PyVar callable = frame->popValue(this);
frame->push(call(callable, args)); PyVar ret = call(callable, args, true);
if(ret == __py2py_call_signal) return ret;
frame->push(ret);
} break; } break;
case OP_JUMP_ABSOLUTE: frame->jumpTo(byte.arg); break; case OP_JUMP_ABSOLUTE: frame->jumpTo(byte.arg); break;
case OP_GET_ITER: case OP_GET_ITER:
@ -293,6 +297,8 @@ public:
PyVar builtins; // builtins module PyVar builtins; // builtins module
PyVar _main; // __main__ module PyVar _main; // __main__ module
int maxRecursionDepth = 1000;
VM(){ VM(){
initializeBuiltinClasses(); initializeBuiltinClasses();
} }
@ -340,7 +346,7 @@ public:
return nullptr; return nullptr;
} }
PyVar call(PyVar callable, PyVarList args){ PyVar call(PyVar callable, PyVarList args, bool opCall=false){
if(callable->isType(_tp_type)){ if(callable->isType(_tp_type)){
auto it = callable->attribs.find(__new__); auto it = callable->attribs.find(__new__);
PyVar obj; PyVar obj;
@ -394,11 +400,12 @@ public:
if(i < args.size()) typeError("too many arguments"); if(i < args.size()) typeError("too many arguments");
auto it_m = callable->attribs.find(__module__); auto it_m = callable->attribs.find(__module__);
if(it_m != callable->attribs.end()){ PyVar _module = it_m != callable->attribs.end() ? it_m->second : topFrame()->_module;
return _exec(fn->code, it_m->second, locals); if(opCall){
}else{ __pushNewFrame(fn->code, _module, locals);
return _exec(fn->code, topFrame()->_module, locals); return __py2py_call_signal;
} }
return _exec(fn->code, _module, locals);
} }
typeError("'" + callable->getTypeName() + "' object is not callable"); typeError("'" + callable->getTypeName() + "' object is not callable");
return None; return None;
@ -424,16 +431,36 @@ public:
} }
} }
PyVar _exec(const _Code& code, PyVar _module, const PyVarDict& locals={}){ Frame* __pushNewFrame(const _Code& code, PyVar _module, const PyVarDict& locals){
if(code == nullptr) UNREACHABLE(); if(code == nullptr) UNREACHABLE();
if(callstack.size() > maxRecursionDepth){
if(callstack.size() > 1000){
throw RuntimeError("RecursionError", "maximum recursion depth exceeded", _cleanErrorAndGetSnapshots()); throw RuntimeError("RecursionError", "maximum recursion depth exceeded", _cleanErrorAndGetSnapshots());
} }
Frame* frame = new Frame(code.get(), _module, locals); Frame* frame = new Frame(code.get(), _module, locals);
callstack.push(std::unique_ptr<Frame>(frame)); callstack.push(std::unique_ptr<Frame>(frame));
PyVar ret = runFrame(frame); return frame;
}
PyVar _exec(const _Code& code, PyVar _module, const PyVarDict& locals={}){
Frame* frame = __pushNewFrame(code, _module, locals);
Frame* frameBase = frame;
PyVar ret = nullptr;
while(true){
ret = runFrame(frame);
if(ret != __py2py_call_signal){
if(frame == frameBase){ // [ frameBase<- ]
break;
}else{
callstack.pop();
frame = callstack.top().get();
frame->push(ret);
}
}else{
frame = callstack.top().get(); // [ frameBase, newFrame<- ]
}
}
callstack.pop(); callstack.pop();
return ret; return ret;
} }
@ -621,7 +648,7 @@ public:
this->False = newObject(_tp_bool, false); this->False = newObject(_tp_bool, false);
this->builtins = newModule("builtins"); this->builtins = newModule("builtins");
this->_main = newModule("__main__", false); this->_main = newModule("__main__", false);
setAttr(_tp_type, __base__, _tp_object); setAttr(_tp_type, __base__, _tp_object);
setAttr(_tp_type, __class__, _tp_type); setAttr(_tp_type, __class__, _tp_type);
setAttr(_tp_object, __base__, None); setAttr(_tp_object, __base__, None);
@ -631,6 +658,8 @@ public:
setAttr(type, "__name__", PyStr(name)); setAttr(type, "__name__", PyStr(name));
} }
this->__py2py_call_signal = newObject(_tp_object, (_Int)7);
std::vector<_Str> publicTypes = {"type", "object", "bool", "int", "float", "str", "list", "tuple", "range"}; std::vector<_Str> publicTypes = {"type", "object", "bool", "int", "float", "str", "list", "tuple", "range"};
for (auto& name : publicTypes) { for (auto& name : publicTypes) {
setAttr(builtins, name, _types[name]); setAttr(builtins, name, _types[name]);