blueloveTH 1 bulan lalu
induk
melakukan
cf965a1957

+ 6 - 1
include/pocketpy/objects/codeobject.h

@@ -135,7 +135,7 @@ void FuncDecl__dtor(FuncDecl* self);
 typedef struct Function {
     FuncDecl_ decl;
     py_GlobalRef module;    // maybe NULL, weak ref
-    py_Ref globals;         // maybe NULL, strong ref
+    py_TValue globals;      // maybe nil, strong ref
     NameDict* closure;      // maybe NULL, strong ref
     PyObject* clazz;        // weak ref; for super()
     py_CFunction cfunc;     // wrapped C function; for decl-based binding
@@ -143,3 +143,8 @@ typedef struct Function {
 
 void Function__ctor(Function* self, FuncDecl_ decl, py_GlobalRef module, py_Ref globals);
 void Function__dtor(Function* self);
+
+
+// https://github.com/pocketpy/pocketpy/issues/456
+// Function may be created from `execdyn` and return
+// Weakrefs like `.globals` and `.clazz` may invalidate

+ 3 - 3
src/interpreter/vm.c

@@ -512,7 +512,7 @@ FrameResult VM__vectorcall(VM* self, uint16_t argc, uint16_t kwargc, bool opcall
                 // submit the call
                 if(!fn->cfunc) {
                     // python function
-                    VM__push_frame(self, Frame__new(co, p0, fn->module, fn->globals, argv, false));
+                    VM__push_frame(self, Frame__new(co, p0, fn->module, &fn->globals, argv, false));
                     return opcall ? RES_CALL : VM__run_top_frame(self);
                 } else {
                     // decl-based binding
@@ -541,7 +541,7 @@ FrameResult VM__vectorcall(VM* self, uint16_t argc, uint16_t kwargc, bool opcall
                 // submit the call
                 if(!fn->cfunc) {
                     // python function
-                    VM__push_frame(self, Frame__new(co, p0, fn->module, fn->globals, argv, false));
+                    VM__push_frame(self, Frame__new(co, p0, fn->module, &fn->globals, argv, false));
                     return opcall ? RES_CALL : VM__run_top_frame(self);
                 } else {
                     // decl-based binding
@@ -557,7 +557,7 @@ FrameResult VM__vectorcall(VM* self, uint16_t argc, uint16_t kwargc, bool opcall
                 // copy buffer back to stack
                 self->stack.sp = argv + co->nlocals;
                 memcpy(argv, self->vectorcall_buffer, co->nlocals * sizeof(py_TValue));
-                py_Frame* frame = Frame__new(co, p0, fn->module, fn->globals, argv, false);
+                py_Frame* frame = Frame__new(co, p0, fn->module, &fn->globals, argv, false);
                 pk_newgenerator(py_retval(), frame, p0, self->stack.sp);
                 self->stack.sp = p0;  // reset the stack
                 return RES_RETURN;

+ 1 - 1
src/modules/builtins.c

@@ -538,7 +538,7 @@ py_GlobalRef pk_builtins__register() {
 
 void function__gc_mark(void* ud, c11_vector* p_stack) {
     Function* func = ud;
-    if(func->globals) pk__mark_value(func->globals);
+    pk__mark_value(&func->globals);
     if(func->closure) {
         NameDict* dict = func->closure;
         for(int i = 0; i < dict->capacity; i++) {

+ 1 - 1
src/objects/codeobject.c

@@ -143,7 +143,7 @@ void Function__ctor(Function* self, FuncDecl_ decl, py_GlobalRef module, py_Ref
     PK_INCREF(decl);
     self->decl = decl;
     self->module = module;
-    self->globals = globals;
+    self->globals = globals != NULL ? *globals : *py_NIL();
     self->closure = NULL;
     self->clazz = NULL;
     self->cfunc = NULL;

+ 17 - 0
tests/661_exec_bug.py

@@ -0,0 +1,17 @@
+# https://github.com/pocketpy/pocketpy/issues/456
+
+module_code = '''
+CONSTANT = 42
+
+def hello(name):
+    return "Hello, " + name
+'''
+
+namespace = {}
+
+exec(module_code, namespace)
+
+assert namespace['CONSTANT'] == 42
+assert namespace['hello']('world') == "Hello, world"
+# print("Constant:", namespace['CONSTANT'])
+# print("Function result:", namespace['hello']('world'))