Skip to content

Commit

Permalink
bpo-31572: Don't silence unexpected errors in the _warnings module. (#…
Browse files Browse the repository at this point in the history
…3731)

Get rid of _PyObject_HasAttrId() and PyDict_GetItemString().
Silence only expected AttributeError, KeyError and ImportError when
get an attribute, look up in a dict or import a module.
  • Loading branch information
serhiy-storchaka authored Nov 11, 2017
1 parent e2f92de commit d4f8480
Showing 1 changed file with 89 additions and 68 deletions.
157 changes: 89 additions & 68 deletions Python/_warnings.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,9 @@ get_warnings_attr(const char *attr, int try_import)
if (warnings_module == NULL) {
/* Fallback to the C implementation if we cannot get
the Python implementation */
PyErr_Clear();
if (PyErr_ExceptionMatches(PyExc_ImportError)) {
PyErr_Clear();
}
return NULL;
}
}
Expand All @@ -62,13 +64,11 @@ get_warnings_attr(const char *attr, int try_import)
return NULL;
}

if (!PyObject_HasAttrString(warnings_module, attr)) {
Py_DECREF(warnings_module);
return NULL;
}

obj = PyObject_GetAttrString(warnings_module, attr);
Py_DECREF(warnings_module);
if (obj == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) {
PyErr_Clear();
}
return obj;
}

Expand All @@ -82,16 +82,18 @@ get_once_registry(void)
if (registry == NULL) {
if (PyErr_Occurred())
return NULL;
assert(_PyRuntime.warnings.once_registry);
return _PyRuntime.warnings.once_registry;
}
if (!PyDict_Check(registry)) {
PyErr_SetString(PyExc_TypeError,
"warnings.onceregistry must be a dict");
PyErr_Format(PyExc_TypeError,
MODULE_NAME ".onceregistry must be a dict, "
"not '%.200s'",
Py_TYPE(registry)->tp_name);
Py_DECREF(registry);
return NULL;
}
Py_DECREF(_PyRuntime.warnings.once_registry);
_PyRuntime.warnings.once_registry = registry;
Py_SETREF(_PyRuntime.warnings.once_registry, registry);
return registry;
}

Expand All @@ -106,6 +108,7 @@ get_default_action(void)
if (PyErr_Occurred()) {
return NULL;
}
assert(_PyRuntime.warnings.default_action);
return _PyRuntime.warnings.default_action;
}
if (!PyUnicode_Check(default_action)) {
Expand All @@ -116,8 +119,7 @@ get_default_action(void)
Py_DECREF(default_action);
return NULL;
}
Py_DECREF(_PyRuntime.warnings.default_action);
_PyRuntime.warnings.default_action = default_action;
Py_SETREF(_PyRuntime.warnings.default_action, default_action);
return default_action;
}

Expand All @@ -137,8 +139,7 @@ get_filter(PyObject *category, PyObject *text, Py_ssize_t lineno,
return NULL;
}
else {
Py_DECREF(_PyRuntime.warnings.filters);
_PyRuntime.warnings.filters = warnings_filters;
Py_SETREF(_PyRuntime.warnings.filters, warnings_filters);
}

PyObject *filters = _PyRuntime.warnings.filters;
Expand Down Expand Up @@ -408,8 +409,10 @@ call_show_warning(PyObject *category, PyObject *text, PyObject *message,

warnmsg_cls = get_warnings_attr("WarningMessage", 0);
if (warnmsg_cls == NULL) {
PyErr_SetString(PyExc_RuntimeError,
"unable to get warnings.WarningMessage");
if (!PyErr_Occurred()) {
PyErr_SetString(PyExc_RuntimeError,
"unable to get warnings.WarningMessage");
}
goto error;
}

Expand Down Expand Up @@ -837,6 +840,68 @@ warnings_warn_impl(PyObject *module, PyObject *message, PyObject *category,
return do_warn(message, category, stacklevel, source);
}

static PyObject *
get_source_line(PyObject *module_globals, int lineno)
{
_Py_IDENTIFIER(get_source);
_Py_IDENTIFIER(__loader__);
_Py_IDENTIFIER(__name__);
PyObject *loader;
PyObject *module_name;
PyObject *get_source;
PyObject *source;
PyObject *source_list;
PyObject *source_line;

/* Check/get the requisite pieces needed for the loader. */
loader = _PyDict_GetItemIdWithError(module_globals, &PyId___loader__);
if (loader == NULL) {
return NULL;
}
Py_INCREF(loader);
module_name = _PyDict_GetItemIdWithError(module_globals, &PyId___name__);
if (!module_name) {
Py_DECREF(loader);
return NULL;
}
Py_INCREF(module_name);

/* Make sure the loader implements the optional get_source() method. */
get_source = _PyObject_GetAttrId(loader, &PyId_get_source);
Py_DECREF(loader);
if (!get_source) {
Py_DECREF(module_name);
if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
PyErr_Clear();
}
return NULL;
}
/* Call get_source() to get the source code. */
source = PyObject_CallFunctionObjArgs(get_source, module_name, NULL);
Py_DECREF(get_source);
Py_DECREF(module_name);
if (!source) {
return NULL;
}
if (source == Py_None) {
Py_DECREF(source);
return NULL;
}

/* Split the source into lines. */
source_list = PyUnicode_Splitlines(source, 0);
Py_DECREF(source);
if (!source_list) {
return NULL;
}

/* Get the source line. */
source_line = PyList_GetItem(source_list, lineno-1);
Py_XINCREF(source_line);
Py_DECREF(source_list);
return source_line;
}

static PyObject *
warnings_warn_explicit(PyObject *self, PyObject *args, PyObject *kwds)
{
Expand All @@ -851,68 +916,24 @@ warnings_warn_explicit(PyObject *self, PyObject *args, PyObject *kwds)
PyObject *registry = NULL;
PyObject *module_globals = NULL;
PyObject *sourceobj = NULL;
PyObject *source_line = NULL;
PyObject *returned;

if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOUi|OOOO:warn_explicit",
kwd_list, &message, &category, &filename, &lineno, &module,
&registry, &module_globals, &sourceobj))
return NULL;

if (module_globals) {
_Py_IDENTIFIER(get_source);
PyObject *tmp;
PyObject *loader;
PyObject *module_name;
PyObject *source;
PyObject *source_list;
PyObject *source_line;
PyObject *returned;

if ((tmp = _PyUnicode_FromId(&PyId_get_source)) == NULL)
return NULL;

/* Check/get the requisite pieces needed for the loader. */
loader = PyDict_GetItemString(module_globals, "__loader__");
module_name = PyDict_GetItemString(module_globals, "__name__");

if (loader == NULL || module_name == NULL)
goto standard_call;

/* Make sure the loader implements the optional get_source() method. */
if (!_PyObject_HasAttrId(loader, &PyId_get_source))
goto standard_call;
/* Call get_source() to get the source code. */
source = PyObject_CallMethodObjArgs(loader, PyId_get_source.object,
module_name, NULL);
if (!source)
source_line = get_source_line(module_globals, lineno);
if (source_line == NULL && PyErr_Occurred()) {
return NULL;
else if (source == Py_None) {
Py_DECREF(Py_None);
goto standard_call;
}

/* Split the source into lines. */
source_list = PyUnicode_Splitlines(source, 0);
Py_DECREF(source);
if (!source_list)
return NULL;

/* Get the source line. */
source_line = PyList_GetItem(source_list, lineno-1);
if (!source_line) {
Py_DECREF(source_list);
return NULL;
}

/* Handle the warning. */
returned = warn_explicit(category, message, filename, lineno, module,
registry, source_line, sourceobj);
Py_DECREF(source_list);
return returned;
}

standard_call:
return warn_explicit(category, message, filename, lineno, module,
registry, NULL, sourceobj);
returned = warn_explicit(category, message, filename, lineno, module,
registry, source_line, sourceobj);
Py_XDECREF(source_line);
return returned;
}

static PyObject *
Expand Down

0 comments on commit d4f8480

Please sign in to comment.