|
12 | 12 | #include "pycore_pymem.h" // _PyMem_SetDefaultAllocator()
|
13 | 13 | #include "pycore_pystate.h" // _PyInterpreterState_GET()
|
14 | 14 | #include "pycore_sysmodule.h" // _PySys_Audit()
|
| 15 | +#include "pycore_weakref.h" // _PyWeakref_GET_REF() |
15 | 16 | #include "marshal.h" // PyMarshal_ReadObjectFromString()
|
16 | 17 | #include "importdl.h" // _PyImport_DynLoadFiletab
|
17 | 18 | #include "pydtrace.h" // PyDTrace_IMPORT_FIND_LOAD_START_ENABLED()
|
@@ -373,15 +374,30 @@ PyImport_AddModuleObject(PyObject *name)
|
373 | 374 | return NULL;
|
374 | 375 | }
|
375 | 376 |
|
376 |
| - // gh-86160: PyImport_AddModuleObject() returns a borrowed reference |
| 377 | + // gh-86160: PyImport_AddModuleObject() returns a borrowed reference. |
| 378 | + // Create a weak reference to produce a borrowed reference, since it can |
| 379 | + // become NULL. sys.modules type can be different than dict and it is not |
| 380 | + // guaranteed that it keeps a strong reference to the module. It can be a |
| 381 | + // custom mapping with __getitem__() which returns a new object or removes |
| 382 | + // returned object, or __setitem__ which does nothing. There is so much |
| 383 | + // unknown. With weakref we can be sure that we get either a reference to |
| 384 | + // live object or NULL. |
| 385 | + // |
| 386 | + // Use PyImport_AddModuleRef() to avoid these issues. |
377 | 387 | PyObject *ref = PyWeakref_NewRef(mod, NULL);
|
378 | 388 | Py_DECREF(mod);
|
379 | 389 | if (ref == NULL) {
|
380 | 390 | return NULL;
|
381 | 391 | }
|
382 |
| - |
383 |
| - mod = PyWeakref_GetObject(ref); |
| 392 | + mod = _PyWeakref_GET_REF(ref); |
384 | 393 | Py_DECREF(ref);
|
| 394 | + Py_XDECREF(mod); |
| 395 | + |
| 396 | + if (mod == NULL && !PyErr_Occurred()) { |
| 397 | + PyErr_SetString(PyExc_RuntimeError, |
| 398 | + "sys.modules does not hold a strong reference " |
| 399 | + "to the module"); |
| 400 | + } |
385 | 401 | return mod; /* borrowed reference */
|
386 | 402 | }
|
387 | 403 |
|
|
0 commit comments