This commit is contained in:
Benjamin Peterson 2015-05-03 11:28:46 -04:00
commit 8c59816b70
3 changed files with 42 additions and 10 deletions

View File

@ -247,6 +247,18 @@ class FilterTests(BaseTest):
self.assertEqual(str(w[-1].message), text) self.assertEqual(str(w[-1].message), text)
self.assertTrue(w[-1].category is UserWarning) self.assertTrue(w[-1].category is UserWarning)
def test_mutate_filter_list(self):
class X:
def match(self, a):
L[:] = []
L = [("default",X(),UserWarning,X(),0) for i in range(2)]
with original_warnings.catch_warnings(record=True,
module=self.module) as w:
self.module.filters = L
self.module.warn_explicit(UserWarning("b"), None, "f.py", 42)
self.assertEqual(str(w[-1].message), "b")
class CFilterTests(FilterTests, unittest.TestCase): class CFilterTests(FilterTests, unittest.TestCase):
module = c_warnings module = c_warnings

View File

@ -10,6 +10,9 @@ Release date: tba
Core and Builtins Core and Builtins
----------------- -----------------
- Issue #24096: Make warnings.warn_explicit more robust against mutation of the
warnings.filters list.
- Issue #23996: Avoid a crash when a delegated generator raises an - Issue #23996: Avoid a crash when a delegated generator raises an
unnormalized StopIteration exception. Patch by Stefan Behnel. unnormalized StopIteration exception. Patch by Stefan Behnel.

View File

@ -101,7 +101,7 @@ get_default_action(void)
} }
/* The item is a borrowed reference. */ /* The item is a new reference. */
static PyObject* static PyObject*
get_filter(PyObject *category, PyObject *text, Py_ssize_t lineno, get_filter(PyObject *category, PyObject *text, Py_ssize_t lineno,
PyObject *module, PyObject **item) PyObject *module, PyObject **item)
@ -132,14 +132,15 @@ get_filter(PyObject *category, PyObject *text, Py_ssize_t lineno,
Py_ssize_t ln; Py_ssize_t ln;
int is_subclass, good_msg, good_mod; int is_subclass, good_msg, good_mod;
tmp_item = *item = PyList_GET_ITEM(_filters, i); tmp_item = PyList_GET_ITEM(_filters, i);
if (PyTuple_Size(tmp_item) != 5) { if (!PyTuple_Check(tmp_item) || PyTuple_GET_SIZE(tmp_item) != 5) {
PyErr_Format(PyExc_ValueError, PyErr_Format(PyExc_ValueError,
MODULE_NAME ".filters item %zd isn't a 5-tuple", i); MODULE_NAME ".filters item %zd isn't a 5-tuple", i);
return NULL; return NULL;
} }
/* Python code: action, msg, cat, mod, ln = item */ /* Python code: action, msg, cat, mod, ln = item */
Py_INCREF(tmp_item);
action = PyTuple_GET_ITEM(tmp_item, 0); action = PyTuple_GET_ITEM(tmp_item, 0);
msg = PyTuple_GET_ITEM(tmp_item, 1); msg = PyTuple_GET_ITEM(tmp_item, 1);
cat = PyTuple_GET_ITEM(tmp_item, 2); cat = PyTuple_GET_ITEM(tmp_item, 2);
@ -147,28 +148,43 @@ get_filter(PyObject *category, PyObject *text, Py_ssize_t lineno,
ln_obj = PyTuple_GET_ITEM(tmp_item, 4); ln_obj = PyTuple_GET_ITEM(tmp_item, 4);
good_msg = check_matched(msg, text); good_msg = check_matched(msg, text);
if (good_msg == -1) if (good_msg == -1) {
Py_DECREF(tmp_item);
return NULL; return NULL;
}
good_mod = check_matched(mod, module); good_mod = check_matched(mod, module);
if (good_mod == -1) if (good_mod == -1) {
Py_DECREF(tmp_item);
return NULL; return NULL;
}
is_subclass = PyObject_IsSubclass(category, cat); is_subclass = PyObject_IsSubclass(category, cat);
if (is_subclass == -1) if (is_subclass == -1) {
Py_DECREF(tmp_item);
return NULL; return NULL;
}
ln = PyLong_AsSsize_t(ln_obj); ln = PyLong_AsSsize_t(ln_obj);
if (ln == -1 && PyErr_Occurred()) if (ln == -1 && PyErr_Occurred()) {
Py_DECREF(tmp_item);
return NULL; return NULL;
}
if (good_msg && is_subclass && good_mod && (ln == 0 || lineno == ln)) if (good_msg && is_subclass && good_mod && (ln == 0 || lineno == ln)) {
*item = tmp_item;
return action; return action;
} }
Py_DECREF(tmp_item);
}
action = get_default_action(); action = get_default_action();
if (action != NULL) if (action != NULL) {
Py_INCREF(Py_None);
*item = Py_None;
return action; return action;
}
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
MODULE_NAME ".defaultaction not found"); MODULE_NAME ".defaultaction not found");
@ -349,7 +365,7 @@ warn_explicit(PyObject *category, PyObject *message,
PyObject *module, PyObject *registry, PyObject *sourceline) PyObject *module, PyObject *registry, PyObject *sourceline)
{ {
PyObject *key = NULL, *text = NULL, *result = NULL, *lineno_obj = NULL; PyObject *key = NULL, *text = NULL, *result = NULL, *lineno_obj = NULL;
PyObject *item = Py_None; PyObject *item = NULL;
PyObject *action; PyObject *action;
int rc; int rc;
@ -488,6 +504,7 @@ warn_explicit(PyObject *category, PyObject *message,
Py_INCREF(result); Py_INCREF(result);
cleanup: cleanup:
Py_XDECREF(item);
Py_XDECREF(key); Py_XDECREF(key);
Py_XDECREF(text); Py_XDECREF(text);
Py_XDECREF(lineno_obj); Py_XDECREF(lineno_obj);