Skip to content

Commit edd0773

Browse files
committed
Fix [ 771097 ] frozen programs fail due to implicit import of "warnings".
If the initial import of warnings fails, clear the error. When the module is actually needed, if the original import failed, see if it has managed to find its way to sys.modules yet and if so, remember it.
1 parent d51ce7d commit edd0773

File tree

2 files changed

+40
-8
lines changed

2 files changed

+40
-8
lines changed

Python/errors.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -599,16 +599,17 @@ PyErr_WriteUnraisable(PyObject *obj)
599599
Py_XDECREF(tb);
600600
}
601601

602-
extern PyObject *PyModule_WarningsModule;
602+
extern PyObject *PyModule_GetWarningsModule();
603603

604604
/* Function to issue a warning message; may raise an exception. */
605605
int
606606
PyErr_Warn(PyObject *category, char *message)
607607
{
608608
PyObject *dict, *func = NULL;
609+
PyObject *warnings_module = PyModule_GetWarningsModule();
609610

610-
if (PyModule_WarningsModule != NULL) {
611-
dict = PyModule_GetDict(PyModule_WarningsModule);
611+
if (warnings_module != NULL) {
612+
dict = PyModule_GetDict(warnings_module);
612613
func = PyDict_GetItemString(dict, "warn");
613614
}
614615
if (func == NULL) {

Python/pythonrun.c

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,38 @@ int Py_IgnoreEnvironmentFlag; /* e.g. PYTHONPATH, PYTHONHOME */
6969
int _Py_QnewFlag = 0;
7070

7171
/* Reference to 'warnings' module, to avoid importing it
72-
on the fly when the import lock may be held. See 683658
72+
on the fly when the import lock may be held. See 683658/771097
7373
*/
74-
PyObject *PyModule_WarningsModule = NULL;
74+
static PyObject *warnings_module = NULL;
75+
76+
/* Returns a borrowed reference to the 'warnings' module, or NULL.
77+
If the module is returned, it is guaranteed to have been obtained
78+
without acquiring the import lock
79+
*/
80+
PyObject *PyModule_GetWarningsModule()
81+
{
82+
PyObject *typ, *val, *tb;
83+
PyObject *all_modules;
84+
/* If we managed to get the module at init time, just use it */
85+
if (warnings_module)
86+
return warnings_module;
87+
/* If it wasn't available at init time, it may be available
88+
now in sys.modules (common scenario is frozen apps: import
89+
at init time fails, but the frozen init code sets up sys.path
90+
correctly, then does an implicit import of warnings for us
91+
*/
92+
/* Save and restore any exceptions */
93+
PyErr_Fetch(&typ, &val, &tb);
94+
95+
all_modules = PySys_GetObject("__modules__");
96+
if (all_modules) {
97+
warnings_module = PyDict_GetItemString(all_modules, "warnings");
98+
/* We keep a ref in the global */
99+
Py_XINCREF(warnings_module);
100+
}
101+
PyErr_Restore(typ, val, tb);
102+
return warnings_module;
103+
}
75104

76105
static int initialized = 0;
77106

@@ -190,7 +219,9 @@ Py_Initialize(void)
190219
_PyGILState_Init(interp, tstate);
191220
#endif /* WITH_THREAD */
192221

193-
PyModule_WarningsModule = PyImport_ImportModule("warnings");
222+
warnings_module = PyImport_ImportModule("warnings");
223+
if (!warnings_module)
224+
PyErr_Clear();
194225

195226
#if defined(Py_USING_UNICODE) && defined(HAVE_LANGINFO_H) && defined(CODESET)
196227
/* On Unix, set the file system encoding according to the
@@ -262,8 +293,8 @@ Py_Finalize(void)
262293
PyOS_FiniInterrupts();
263294

264295
/* drop module references we saved */
265-
Py_XDECREF(PyModule_WarningsModule);
266-
PyModule_WarningsModule = NULL;
296+
Py_XDECREF(warnings_module);
297+
warnings_module = NULL;
267298

268299
/* Collect garbage. This may call finalizers; it's nice to call these
269300
before all modules are destroyed. */

0 commit comments

Comments
 (0)