Skip to content

Commit 998cedb

Browse files
miss-islingtonencukouAA-Turner
authored
[3.14] gh-134160: Block multiple module initialization (GH-134773) (#134827)
gh-134160: Block multiple module initialization (GH-134773) (cherry picked from commit 469a564) Co-authored-by: Petr Viktorin <encukou@gmail.com> Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com>
1 parent 2194729 commit 998cedb

File tree

1 file changed

+24
-4
lines changed

1 file changed

+24
-4
lines changed

Doc/extending/extending.rst

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -204,17 +204,32 @@ value must be in a particular range or must satisfy other conditions,
204204
:c:data:`PyExc_ValueError` is appropriate.
205205

206206
You can also define a new exception that is unique to your module.
207-
For this, you can declare a static global object variable at the beginning
208-
of the file::
207+
The simplest way to do this is to declare a static global object variable at
208+
the beginning of the file::
209209

210-
static PyObject *SpamError;
210+
static PyObject *SpamError = NULL;
211211

212-
and initialize it with an exception object in the module's
212+
and initialize it by calling :c:func:`PyErr_NewException` in the module's
213213
:c:data:`Py_mod_exec` function (:c:func:`!spam_module_exec`)::
214214

215+
SpamError = PyErr_NewException("spam.error", NULL, NULL);
216+
217+
Since :c:data:`!SpamError` is a global variable, it will be overwitten every time
218+
the module is reinitialized, when the :c:data:`Py_mod_exec` function is called.
219+
220+
For now, let's avoid the issue: we will block repeated initialization by raising an
221+
:py:exc:`ImportError`::
222+
223+
static PyObject *SpamError = NULL;
224+
215225
static int
216226
spam_module_exec(PyObject *m)
217227
{
228+
if (SpamError != NULL) {
229+
PyErr_SetString(PyExc_ImportError,
230+
"cannot initialize spam module more than once");
231+
return -1;
232+
}
218233
SpamError = PyErr_NewException("spam.error", NULL, NULL);
219234
if (PyModule_AddObjectRef(m, "SpamError", SpamError) < 0) {
220235
return -1;
@@ -253,6 +268,11 @@ needed to ensure that it will not be discarded, causing :c:data:`!SpamError` to
253268
become a dangling pointer. Should it become a dangling pointer, C code which
254269
raises the exception could cause a core dump or other unintended side effects.
255270

271+
For now, the :c:func:`Py_DECREF` call to remove this reference is missing.
272+
Even when the Python interpreter shuts down, the global :c:data:`!SpamError`
273+
variable will not be garbage-collected. It will "leak".
274+
We did, however, ensure that this will happen at most once per process.
275+
256276
We discuss the use of :c:macro:`PyMODINIT_FUNC` as a function return type later in this
257277
sample.
258278

0 commit comments

Comments
 (0)