Browse Source

fix pointer issues

blueloveTH 3 years ago
parent
commit
1999726c18
3 changed files with 40 additions and 17 deletions
  1. 9 1
      src/obj.h
  2. 9 4
      src/pocketpy.h
  3. 22 12
      src/vm.h

+ 9 - 1
src/obj.h

@@ -14,13 +14,21 @@ const _Float _FLOAT_INF_NEG = -INFINITY;
 
 class CodeObject;
 class BasePointer;
+class Pointer;
 class VM;
+class Frame;
 class PkExportedResource {};
 
 typedef std::shared_ptr<const BasePointer> _Pointer;
 typedef PyVar (*_CppFunc)(VM*, const pkpy::ArgList&);
 typedef std::shared_ptr<CodeObject> _Code;
 
+struct Pointer {
+    Frame* frame;               // the frame that created this pointer
+    _Pointer ptr;               // the internal pointer
+    Pointer(Frame* frame, _Pointer ptr) : frame(frame), ptr(ptr) {}
+};
+
 struct Function {
     _Str name;
     _Code code;
@@ -72,7 +80,7 @@ public:
 };
 
 typedef std::shared_ptr<Function> _Func;
-typedef std::variant<_Int,_Float,bool,_Str,PyVarList,_CppFunc,_Func,std::shared_ptr<_Iterator>,_BoundedMethod,_Range,_Slice,_Pointer> _Value;
+typedef std::variant<_Int,_Float,bool,_Str,PyVarList,_CppFunc,_Func,std::shared_ptr<_Iterator>,_BoundedMethod,_Range,_Slice,_Pointer,Pointer> _Value;
 
 const int _SIZEOF_VALUE = sizeof(_Value);
 

+ 9 - 4
src/pocketpy.h

@@ -58,15 +58,19 @@ void __initializeBuiltinFunctions(VM* _vm) {
 
     _vm->bindMethod("pointer", "set", [](VM* vm, const pkpy::ArgList& args) {
         vm->__checkArgSize(args, 2, true);
-        _Pointer& p = std::get<_Pointer>(args[0]->_native);
-        p->set(vm, vm->topFrame(), args[1]);
+        Pointer& p = std::get<Pointer>(args[0]->_native);
+        // this check is unsafe, but it's the best we can do
+        if(!vm->__isFrameValid(p.frame)) vm->nullPointerError();
+        p.ptr->set(vm, p.frame, args[1]);
         return vm->None;
     });
 
     _vm->bindMethod("pointer", "get", [](VM* vm, const pkpy::ArgList& args) {
         vm->__checkArgSize(args, 1, true);
-        _Pointer& p = std::get<_Pointer>(args[0]->_native);
-        return p->get(vm, vm->topFrame());
+        Pointer& p = std::get<Pointer>(args[0]->_native);
+        // this check is unsafe, but it's the best we can do
+        if(!vm->__isFrameValid(p.frame)) vm->nullPointerError();
+        return p.ptr->get(vm, p.frame);
     });
 
     _vm->bindBuiltinFunc("eval", [](VM* vm, const pkpy::ArgList& args) {
@@ -131,6 +135,7 @@ void __initializeBuiltinFunctions(VM* _vm) {
         std::vector<_Str> names;
         for (auto& [k, _] : args[0]->attribs) names.push_back(k);
         for (auto& [k, _] : args[0]->_type->attribs) {
+            if (k.str().find("__") == 0) continue;
             if (std::find(names.begin(), names.end(), k) == names.end()) names.push_back(k);
         }
         PyVarList ret;

+ 22 - 12
src/vm.h

@@ -45,7 +45,7 @@ typedef void(*PrintFn)(const VM*, const char*);
 
 class VM: public PkExportedResource{
 private:
-    std::stack< std::unique_ptr<Frame> > callstack;
+    std::deque< std::unique_ptr<Frame> > callstack;
     PyVarDict _modules;       // 3rd modules
     PyVar __py2py_call_signal;
 
@@ -209,9 +209,8 @@ private:
                 } break;
             case OP_UNARY_REF:
                 {
-                    PyVar obj = frame->__pop();
-                    _Pointer p = PyPointer_AS_C(obj);
-                    frame->push(newObject(_tp_user_pointer, p));
+                    _Pointer p = PyPointer_AS_C(frame->__pop());
+                    frame->push(newObject(_tp_user_pointer, Pointer(frame, p)));
                 } break;
             case OP_POP_JUMP_IF_FALSE:
                 if(!PyBool_AS_C(asBool(frame->popValue(this)))) frame->jump(byte.arg);
@@ -365,9 +364,16 @@ public:
         return asRepr(obj);
     }
 
+    bool __isFrameValid(Frame* frame){
+        for(const auto& f : callstack){
+            if(f.get() == frame) return true;
+        }
+        return false;
+    }
+
     Frame* topFrame(){
         if(callstack.size() == 0) UNREACHABLE();
-        return callstack.top().get();
+        return callstack.back().get();
     }
 
     PyVar asRepr(const PyVar& obj){
@@ -504,7 +510,7 @@ public:
             throw RuntimeError("RecursionError", "maximum recursion depth exceeded", _cleanErrorAndGetSnapshots());
         }
         Frame* frame = new Frame(code.get(), _module, locals);
-        callstack.push(std::unique_ptr<Frame>(frame));
+        callstack.emplace_back(std::unique_ptr<Frame>(frame));
         return frame;
     }
 
@@ -519,16 +525,16 @@ public:
                 if(frame == frameBase){         // [ frameBase<- ]
                     break;
                 }else{
-                    callstack.pop();
-                    frame = callstack.top().get();
+                    callstack.pop_back();
+                    frame = callstack.back().get();
                     frame->push(ret);
                 }
             }else{
-                frame = callstack.top().get();  // [ frameBase, newFrame<- ]
+                frame = callstack.back().get();  // [ frameBase, newFrame<- ]
             }
         }
 
-        callstack.pop();
+        callstack.pop_back();
         return ret;
     }
 
@@ -772,9 +778,9 @@ private:
         std::stack<_Str> snapshots;
         while (!callstack.empty()){
             if(snapshots.size() < 8){
-                snapshots.push(callstack.top()->errorSnapshot());
+                snapshots.push(callstack.back()->errorSnapshot());
             }
-            callstack.pop();
+            callstack.pop_back();
         }
         return snapshots;
     }
@@ -788,6 +794,10 @@ public:
         _error("SystemError", msg);
     }
 
+    void nullPointerError(){
+        _error("NullPointerError", "pointer is invalid");
+    }
+
     void zeroDivisionError(){
         _error("ZeroDivisionError", "division by zero");
     }