Skip to content

Commit 98b6246

Browse files
committed
Several changes that Python carry on in the face of errors in the
initialization of class exceptions. Specifically: init_class_exc(): This function now returns an integer status of the class exception initialization. No fatal errors in this method now. Also, use PySys_WriteStderr() when writing error messages. When an error occurs in this function, 0 is returned, but the partial creation of the exception classes is not undone (this happens elsewhere). Things that could trigger the fallback: - exceptions.py fails to be imported (due to syntax error, etc.) - one of the exception classes is missing (e.g. due to library version mismatch) - exception class can't be inserted into __builtin__'s dictionary - MemoryError instance can't be pre-allocated - some other PyErr_Occurred newstdexception(): Changed the error message. This is still a fatal error because if the string based exceptions can't be created, we really can't continue. initerrors(): Be sure to xdecref the .exc field, which might be non-NULL if class exceptions init was aborted. _PyBuiltin_Init_2(): If class exception init fails, print a warning message and reinstate the string based exceptions.
1 parent d24d3fc commit 98b6246

1 file changed

Lines changed: 61 additions & 26 deletions

File tree

‎Python/bltinmodule.c‎

Lines changed: 61 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1987,63 +1987,88 @@ bltin_exc[] = {
19871987
};
19881988

19891989

1990-
/* import exceptions module to extract class exceptions */
1991-
static void
1990+
/* import exceptions module to extract class exceptions. on success,
1991+
* return 1. on failure return 0 which signals _PyBuiltin_Init_2 to fall
1992+
* back to using old-style string based exceptions.
1993+
*/
1994+
static int
19921995
init_class_exc(dict)
19931996
PyObject *dict;
19941997
{
19951998
int i;
19961999
PyObject *m = PyImport_ImportModule("exceptions");
1997-
PyObject *d;
1998-
PyObject *args;
2000+
PyObject *args = NULL;
2001+
PyObject *d = NULL;
19992002

2003+
/* make sure we got the module and its dictionary */
20002004
if (m == NULL ||
20012005
(d = PyModule_GetDict(m)) == NULL)
20022006
{
2003-
/* XXX Should use PySys_WriteStderr here */
2004-
PyObject *f = PySys_GetObject("stderr");
2007+
PySys_WriteStderr("'import exceptions' failed; ");
20052008
if (Py_VerboseFlag) {
2006-
PyFile_WriteString(
2007-
"'import exceptions' failed; traceback:\n", f);
2009+
PySys_WriteStderr("traceback:\n");
20082010
PyErr_Print();
20092011
}
20102012
else {
2011-
PyFile_WriteString(
2012-
"'import exceptions' failed; use -v for traceback\n", f);
2013-
PyErr_Clear();
2013+
PySys_WriteStderr("use -v for traceback\n");
20142014
}
2015-
PyFile_WriteString("defaulting to old style exceptions\n", f);
2016-
return;
2015+
goto finally;
20172016
}
20182017
for (i = 0; bltin_exc[i].name; i++) {
20192018
/* dig the exception out of the module */
20202019
PyObject *exc = PyDict_GetItemString(d, bltin_exc[i].name);
2021-
if (!exc)
2022-
Py_FatalError("built-in exception cannot be initialized");
2023-
2020+
if (!exc) {
2021+
PySys_WriteStderr(
2022+
"Built-in exception class not found: %s. Library mismatch?\n",
2023+
bltin_exc[i].name);
2024+
goto finally;
2025+
}
2026+
/* free the old-style exception string object */
20242027
Py_XDECREF(*bltin_exc[i].exc);
20252028

20262029
/* squirrel away a pointer to the exception */
20272030
Py_INCREF(exc);
20282031
*bltin_exc[i].exc = exc;
20292032

20302033
/* and insert the name in the __builtin__ module */
2031-
PyDict_SetItemString(dict, bltin_exc[i].name, exc);
2034+
if (PyDict_SetItemString(dict, bltin_exc[i].name, exc)) {
2035+
PySys_WriteStderr(
2036+
"Cannot insert exception into __builtin__: %s\n",
2037+
bltin_exc[i].name);
2038+
goto finally;
2039+
}
20322040
}
20332041

20342042
/* we need one pre-allocated instance */
20352043
args = Py_BuildValue("()");
2036-
if (args) {
2037-
PyExc_MemoryErrorInst =
2038-
PyEval_CallObject(PyExc_MemoryError, args);
2039-
Py_DECREF(args);
2044+
if (!args ||
2045+
!(PyExc_MemoryErrorInst =
2046+
PyEval_CallObject(PyExc_MemoryError, args)))
2047+
{
2048+
PySys_WriteStderr("Cannot pre-allocate MemoryError instance\n");
2049+
goto finally;
20402050
}
2051+
Py_DECREF(args);
20412052

20422053
/* we're done with the exceptions module */
20432054
Py_DECREF(m);
20442055

2045-
if (PyErr_Occurred())
2046-
Py_FatalError("can't instantiate standard exceptions");
2056+
if (PyErr_Occurred()) {
2057+
PySys_WriteStderr("Cannot initialize standard class exceptions; ");
2058+
if (Py_VerboseFlag) {
2059+
PySys_WriteStderr("traceback:\n");
2060+
PyErr_Print();
2061+
}
2062+
else
2063+
PySys_WriteStderr("use -v for traceback\n");
2064+
goto finally;
2065+
}
2066+
return 1;
2067+
finally:
2068+
Py_XDECREF(m);
2069+
Py_XDECREF(args);
2070+
PyErr_Clear();
2071+
return 0;
20472072
}
20482073

20492074

@@ -2062,7 +2087,7 @@ newstdexception(dict, name)
20622087
{
20632088
PyObject *v = PyString_FromString(name);
20642089
if (v == NULL || PyDict_SetItemString(dict, name, v) != 0)
2065-
Py_FatalError("no mem for new standard exception");
2090+
Py_FatalError("Cannot create string-based exceptions");
20662091
return v;
20672092
}
20682093

@@ -2073,6 +2098,7 @@ initerrors(dict)
20732098
int i;
20742099
int exccnt = 0;
20752100
for (i = 0; bltin_exc[i].name; i++, exccnt++) {
2101+
Py_XDECREF(*bltin_exc[i].exc);
20762102
if (bltin_exc[i].leaf_exc)
20772103
*bltin_exc[i].exc =
20782104
newstdexception(dict, bltin_exc[i].name);
@@ -2166,8 +2192,17 @@ _PyBuiltin_Init_2(dict)
21662192
PyObject *dict;
21672193
{
21682194
/* if Python was started with -X, initialize the class exceptions */
2169-
if (Py_UseClassExceptionsFlag)
2170-
init_class_exc(dict);
2195+
if (Py_UseClassExceptionsFlag) {
2196+
if (!init_class_exc(dict)) {
2197+
/* class based exceptions could not be
2198+
* initialized. Fall back to using string based
2199+
* exceptions.
2200+
*/
2201+
PySys_WriteStderr(
2202+
"Warning! Falling back to string-based exceptions\n");
2203+
initerrors(dict);
2204+
}
2205+
}
21712206
}
21722207

21732208

0 commit comments

Comments
 (0)