STINNER Victor <[email protected]> added the comment:
Hum, some clarification is needed here.
"Port xxx extension module to multiphase initialization (PEP 489)" changes are
helping to fix "Py_Finalize() doesn't clear all Python objects at exit", but
alone they don't fix all issues.
--
For example, if a module still uses globals using "static ..." in C, these
globals will not be cleared magically. Example with _datetimemodule.c:
static PyObject *us_per_hour = NULL; /* 1e6 * 3600 as Python int */
static PyObject *us_per_day = NULL; /* 1e6 * 3600 * 24 as Python int */
static PyObject *us_per_week = NULL; /* 1e6*3600*24*7 as Python int */
These variables initialized once in PyInit__datetime():
us_per_hour = PyLong_FromDouble(3600000000.0);
us_per_day = PyLong_FromDouble(86400000000.0);
us_per_week = PyLong_FromDouble(604800000000.0);
Converting the module to multiphase initialization will not magically clear
these variables at exit. The _datetime module should be modified to store these
variables in a module state: this module could be cleared at exit.
The binascii is a good example: it has a module state, traverse, clear and free
methods, and it uses the multiphase initialization. This module can be fully
unloaded at exit.
It's a "simple" module: it doesn't define types for example.
--
Another issue is that converting a module to the multiphase initialization
doesn't magically fully isolate two instances of the module. For exmaple, the
_abc module still uses a type defined statically:
static PyTypeObject _abc_data_type = {
PyVarObject_HEAD_INIT(NULL, 0)
"_abc_data", /*tp_name*/
sizeof(_abc_data), /*tp_basicsize*/
.tp_dealloc = (destructor)abc_data_dealloc,
.tp_flags = Py_TPFLAGS_DEFAULT,
.tp_alloc = PyType_GenericAlloc,
.tp_new = abc_data_new,
};
Example:
vstinner@apu$ ./python
Python 3.9.0a5+ (heads/pr/19122:0ac3031a80, Mar 25 2020, 02:25:19)
>>> import _abc
>>> class Bla: pass
...
>>> _abc._abc_init(Bla)
>>> type(Bla._abc_impl)
<class '_abc_data'>
# load a second instance of the module
>>> import sys; del sys.modules['_abc']
>>> import _abc as _abc2
>>> class Bla2: pass
...
>>> _abc._abc_init(Bla2)
>>> type(Bla2._abc_impl)
<class '_abc_data'>
# _abc and _abc2 have exactly the same type,
# they are not fully isolated
>>> type(Bla2._abc_impl) is type(Bla._abc_impl)
True
That's more an issue for subinterpreters: each interpreter should have its own
fully isolated instance of an C extension module.
----------
_______________________________________
Python tracker <[email protected]>
<https://bugs.python.org/issue1635741>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe:
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com