Assuming all participating modules correctly handle Py_Finalize
, does C API allow this:
Py_Initialize();
...
PyObject* myObj = PyObject_Call(simple_class, empty_tuple, NULL);
Py_Finalize();
...
Py_Initialize();
Py_DecRef(myObj); // <--- is this safe by design?
Narrowed down example that crashes
Py_Initialize();
PyObject* builtins = PyEval_GetBuiltins();
PyObject* iter = PyDict_GetItemString(builtins, "iter");
Py_IncRef(iter);
Py_Finalize();
// ----- new run starts, iter should still be alive
Py_Initialize();
Py_DecRef(iter);
Py_Finalize(); // fails inside PyGC_Collect -> validate_list
Background (OLD, before narrowing down the problem)
I am debugging 3.9+ support in https://github.com/pythonnet/pythonnet
The issue I originally got is validate_list
from gcmodule.c
fails at
assert(prev == GC_PREV(head));
In debugging this, I sprinkled my code with calls to validate_list
, and found
that the assertion fails in the following scenario:
Py_Initialize();
...
PyObject* myObj = PyObject_Call(simple_class, args, NULL);
Py_Finalize();
...
Py_Initialize();
...
validate_list(gc.generations[2],
collecting_clear_unreachable_clear); // OK
Py_DecRef(myObj);
validate_list(gc.generations[2],
collecting_clear_unreachable_clear); // EXPLOSION
Now I have not yet tried to narrow down the steps further, because I realized
that I am unsure about the question in the title. E.g. is this use of myObj
supported by embedding API in general, or is this expected, that after
reinitializing the runtime Py_DecRef
on old objects would break GC?
In my scenario simple_class
is defined in Python as inheriting from object
, e.g. it is a heap type created by Python runtime from Python code:
class SimpleClass(object):
def __init__(self, type, tb):
self.type = type
self.traceback = tb
type
and tb
are values you get from PyErr_Fetch
when list ends.
The reason why I have to Py_DecRef
after Py_Finalize
+ Py_Initialize
is that myObj
actually gets collected by a different GC (.NET).