Is it safe to call `Py_DecRef` on an object created before the last Py_Initialize?

Viewed 72

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).

0 Answers
Related