Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 469a564

Browse filesBrowse files
encukouAA-Turner
andauthored
gh-134160: Block multiple module initialization (#134773)
Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com>
1 parent 21672b6 commit 469a564
Copy full SHA for 469a564

File tree

Expand file treeCollapse file tree

1 file changed

+24
-4
lines changed
Filter options
Expand file treeCollapse file tree

1 file changed

+24
-4
lines changed

‎Doc/extending/extending.rst

Copy file name to clipboardExpand all lines: Doc/extending/extending.rst
+24-4Lines 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 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.