mirror of
https://github.com/python/cpython.git
synced 2025-10-02 05:12:23 +00:00
[3.14] gh-134160: Block multiple module initialization (GH-134773) (#134827)
gh-134160: Block multiple module initialization (GH-134773)
(cherry picked from commit 469a56470b
)
Co-authored-by: Petr Viktorin <encukou@gmail.com>
Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com>
This commit is contained in:
parent
2194729f3a
commit
998cedb9bc
1 changed files with 24 additions and 4 deletions
|
@ -204,17 +204,32 @@ value must be in a particular range or must satisfy other conditions,
|
||||||
:c:data:`PyExc_ValueError` is appropriate.
|
:c:data:`PyExc_ValueError` is appropriate.
|
||||||
|
|
||||||
You can also define a new exception that is unique to your module.
|
You can also define a new exception that is unique to your module.
|
||||||
For this, you can declare a static global object variable at the beginning
|
The simplest way to do this is to declare a static global object variable at
|
||||||
of the file::
|
the beginning of the file::
|
||||||
|
|
||||||
static PyObject *SpamError;
|
static PyObject *SpamError = NULL;
|
||||||
|
|
||||||
and initialize it with an exception object in the module's
|
and initialize it by calling :c:func:`PyErr_NewException` in the module's
|
||||||
:c:data:`Py_mod_exec` function (:c:func:`!spam_module_exec`)::
|
:c:data:`Py_mod_exec` function (:c:func:`!spam_module_exec`)::
|
||||||
|
|
||||||
|
SpamError = PyErr_NewException("spam.error", NULL, NULL);
|
||||||
|
|
||||||
|
Since :c:data:`!SpamError` is a global variable, it will be overwitten every time
|
||||||
|
the module is reinitialized, when the :c:data:`Py_mod_exec` function is called.
|
||||||
|
|
||||||
|
For now, let's avoid the issue: we will block repeated initialization by raising an
|
||||||
|
:py:exc:`ImportError`::
|
||||||
|
|
||||||
|
static PyObject *SpamError = NULL;
|
||||||
|
|
||||||
static int
|
static int
|
||||||
spam_module_exec(PyObject *m)
|
spam_module_exec(PyObject *m)
|
||||||
{
|
{
|
||||||
|
if (SpamError != NULL) {
|
||||||
|
PyErr_SetString(PyExc_ImportError,
|
||||||
|
"cannot initialize spam module more than once");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
SpamError = PyErr_NewException("spam.error", NULL, NULL);
|
SpamError = PyErr_NewException("spam.error", NULL, NULL);
|
||||||
if (PyModule_AddObjectRef(m, "SpamError", SpamError) < 0) {
|
if (PyModule_AddObjectRef(m, "SpamError", SpamError) < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -253,6 +268,11 @@ needed to ensure that it will not be discarded, causing :c:data:`!SpamError` to
|
||||||
become a dangling pointer. Should it become a dangling pointer, C code which
|
become a dangling pointer. Should it become a dangling pointer, C code which
|
||||||
raises the exception could cause a core dump or other unintended side effects.
|
raises the exception could cause a core dump or other unintended side effects.
|
||||||
|
|
||||||
|
For now, the :c:func:`Py_DECREF` call to remove this reference is missing.
|
||||||
|
Even when the Python interpreter shuts down, the global :c:data:`!SpamError`
|
||||||
|
variable will not be garbage-collected. It will "leak".
|
||||||
|
We did, however, ensure that this will happen at most once per process.
|
||||||
|
|
||||||
We discuss the use of :c:macro:`PyMODINIT_FUNC` as a function return type later in this
|
We discuss the use of :c:macro:`PyMODINIT_FUNC` as a function return type later in this
|
||||||
sample.
|
sample.
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue