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.
This commit is contained in:
Barry Warsaw 1998-09-14 18:51:11 +00:00
parent d24d3fcd03
commit 98b6246c0c

View File

@ -1987,40 +1987,43 @@ bltin_exc[] = {
}; };
/* import exceptions module to extract class exceptions */ /* import exceptions module to extract class exceptions. on success,
static void * return 1. on failure return 0 which signals _PyBuiltin_Init_2 to fall
* back to using old-style string based exceptions.
*/
static int
init_class_exc(dict) init_class_exc(dict)
PyObject *dict; PyObject *dict;
{ {
int i; int i;
PyObject *m = PyImport_ImportModule("exceptions"); PyObject *m = PyImport_ImportModule("exceptions");
PyObject *d; PyObject *args = NULL;
PyObject *args; PyObject *d = NULL;
/* make sure we got the module and its dictionary */
if (m == NULL || if (m == NULL ||
(d = PyModule_GetDict(m)) == NULL) (d = PyModule_GetDict(m)) == NULL)
{ {
/* XXX Should use PySys_WriteStderr here */ PySys_WriteStderr("'import exceptions' failed; ");
PyObject *f = PySys_GetObject("stderr");
if (Py_VerboseFlag) { if (Py_VerboseFlag) {
PyFile_WriteString( PySys_WriteStderr("traceback:\n");
"'import exceptions' failed; traceback:\n", f);
PyErr_Print(); PyErr_Print();
} }
else { else {
PyFile_WriteString( PySys_WriteStderr("use -v for traceback\n");
"'import exceptions' failed; use -v for traceback\n", f);
PyErr_Clear();
} }
PyFile_WriteString("defaulting to old style exceptions\n", f); goto finally;
return;
} }
for (i = 0; bltin_exc[i].name; i++) { for (i = 0; bltin_exc[i].name; i++) {
/* dig the exception out of the module */ /* dig the exception out of the module */
PyObject *exc = PyDict_GetItemString(d, bltin_exc[i].name); PyObject *exc = PyDict_GetItemString(d, bltin_exc[i].name);
if (!exc) if (!exc) {
Py_FatalError("built-in exception cannot be initialized"); PySys_WriteStderr(
"Built-in exception class not found: %s. Library mismatch?\n",
bltin_exc[i].name);
goto finally;
}
/* free the old-style exception string object */
Py_XDECREF(*bltin_exc[i].exc); Py_XDECREF(*bltin_exc[i].exc);
/* squirrel away a pointer to the exception */ /* squirrel away a pointer to the exception */
@ -2028,22 +2031,44 @@ init_class_exc(dict)
*bltin_exc[i].exc = exc; *bltin_exc[i].exc = exc;
/* and insert the name in the __builtin__ module */ /* and insert the name in the __builtin__ module */
PyDict_SetItemString(dict, bltin_exc[i].name, exc); if (PyDict_SetItemString(dict, bltin_exc[i].name, exc)) {
PySys_WriteStderr(
"Cannot insert exception into __builtin__: %s\n",
bltin_exc[i].name);
goto finally;
}
} }
/* we need one pre-allocated instance */ /* we need one pre-allocated instance */
args = Py_BuildValue("()"); args = Py_BuildValue("()");
if (args) { if (!args ||
PyExc_MemoryErrorInst = !(PyExc_MemoryErrorInst =
PyEval_CallObject(PyExc_MemoryError, args); PyEval_CallObject(PyExc_MemoryError, args)))
Py_DECREF(args); {
PySys_WriteStderr("Cannot pre-allocate MemoryError instance\n");
goto finally;
} }
Py_DECREF(args);
/* we're done with the exceptions module */ /* we're done with the exceptions module */
Py_DECREF(m); Py_DECREF(m);
if (PyErr_Occurred()) if (PyErr_Occurred()) {
Py_FatalError("can't instantiate standard exceptions"); PySys_WriteStderr("Cannot initialize standard class exceptions; ");
if (Py_VerboseFlag) {
PySys_WriteStderr("traceback:\n");
PyErr_Print();
}
else
PySys_WriteStderr("use -v for traceback\n");
goto finally;
}
return 1;
finally:
Py_XDECREF(m);
Py_XDECREF(args);
PyErr_Clear();
return 0;
} }
@ -2062,7 +2087,7 @@ newstdexception(dict, name)
{ {
PyObject *v = PyString_FromString(name); PyObject *v = PyString_FromString(name);
if (v == NULL || PyDict_SetItemString(dict, name, v) != 0) if (v == NULL || PyDict_SetItemString(dict, name, v) != 0)
Py_FatalError("no mem for new standard exception"); Py_FatalError("Cannot create string-based exceptions");
return v; return v;
} }
@ -2073,6 +2098,7 @@ initerrors(dict)
int i; int i;
int exccnt = 0; int exccnt = 0;
for (i = 0; bltin_exc[i].name; i++, exccnt++) { for (i = 0; bltin_exc[i].name; i++, exccnt++) {
Py_XDECREF(*bltin_exc[i].exc);
if (bltin_exc[i].leaf_exc) if (bltin_exc[i].leaf_exc)
*bltin_exc[i].exc = *bltin_exc[i].exc =
newstdexception(dict, bltin_exc[i].name); newstdexception(dict, bltin_exc[i].name);
@ -2166,8 +2192,17 @@ _PyBuiltin_Init_2(dict)
PyObject *dict; PyObject *dict;
{ {
/* if Python was started with -X, initialize the class exceptions */ /* if Python was started with -X, initialize the class exceptions */
if (Py_UseClassExceptionsFlag) if (Py_UseClassExceptionsFlag) {
init_class_exc(dict); if (!init_class_exc(dict)) {
/* class based exceptions could not be
* initialized. Fall back to using string based
* exceptions.
*/
PySys_WriteStderr(
"Warning! Falling back to string-based exceptions\n");
initerrors(dict);
}
}
} }