1

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

LOST
  • 2,956
  • 3
  • 25
  • 40
  • 1
    I am pretty sure, most python object become invalid after finalize. For example part of their memory is from python’s memory manager, which was returned to OS at that point. You probably could create objects, which could outlive python interpreter, but for normal objects this is not the case. – ead Nov 09 '21 at 13:11

0 Answers0