From cf965a19576b8f4ccf5a3860ea182086cd18ffc1 Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Fri, 30 Jan 2026 14:40:05 +0800 Subject: [PATCH] fix #456 --- include/pocketpy/objects/codeobject.h | 7 ++++++- src/interpreter/vm.c | 6 +++--- src/modules/builtins.c | 2 +- src/objects/codeobject.c | 2 +- tests/661_exec_bug.py | 17 +++++++++++++++++ 5 files changed, 28 insertions(+), 6 deletions(-) create mode 100644 tests/661_exec_bug.py diff --git a/include/pocketpy/objects/codeobject.h b/include/pocketpy/objects/codeobject.h index 6faae33d..6691eb68 100644 --- a/include/pocketpy/objects/codeobject.h +++ b/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 diff --git a/src/interpreter/vm.c b/src/interpreter/vm.c index 22852942..64b87973 100644 --- a/src/interpreter/vm.c +++ b/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; diff --git a/src/modules/builtins.c b/src/modules/builtins.c index 56d66167..b664a154 100644 --- a/src/modules/builtins.c +++ b/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++) { diff --git a/src/objects/codeobject.c b/src/objects/codeobject.c index 68524a05..3ba251a5 100644 --- a/src/objects/codeobject.c +++ b/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; diff --git a/tests/661_exec_bug.py b/tests/661_exec_bug.py new file mode 100644 index 00000000..f2dda404 --- /dev/null +++ b/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'))