From deff2b76ec3824ff238ad0812c29aca95534ecb4 Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Sun, 3 May 2015 11:23:37 -0400 Subject: [PATCH] be more robust against the filters list changing under us (closes #24096) --- Lib/test/test_warnings.py | 12 ++++++++++++ Misc/NEWS | 3 +++ Python/_warnings.c | 22 ++++++++++++++++------ 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_warnings.py b/Lib/test/test_warnings.py index 10076af3aab..68bac364ef4 100644 --- a/Lib/test/test_warnings.py +++ b/Lib/test/test_warnings.py @@ -185,6 +185,18 @@ class FilterTests(BaseTest): self.assertEqual(str(w[-1].message), text) 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): module = c_warnings diff --git a/Misc/NEWS b/Misc/NEWS index ca923fb18e3..827d761bf9f 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ What's New in Python 3.3.7? Core and Builtins ----------------- +- Issue #24096: Make warnings.warn_explicit more robust against mutation of the + warnings.filters list. + - Issue #24044: Fix possible null pointer dereference in list.sort in out of memory conditions. diff --git a/Python/_warnings.c b/Python/_warnings.c index f33e477ad7b..d274789f4a6 100644 --- a/Python/_warnings.c +++ b/Python/_warnings.c @@ -98,7 +98,7 @@ get_default_action(void) } -/* The item is a borrowed reference. */ +/* The item is a new reference. */ static const char * get_filter(PyObject *category, PyObject *text, Py_ssize_t lineno, PyObject *module, PyObject **item) @@ -129,14 +129,15 @@ get_filter(PyObject *category, PyObject *text, Py_ssize_t lineno, Py_ssize_t ln; int is_subclass, good_msg, good_mod; - tmp_item = *item = PyList_GET_ITEM(_filters, i); - if (PyTuple_Size(tmp_item) != 5) { + tmp_item = PyList_GET_ITEM(_filters, i); + if (!PyTuple_Check(tmp_item) || PyTuple_GET_SIZE(tmp_item) != 5) { PyErr_Format(PyExc_ValueError, MODULE_NAME ".filters item %zd isn't a 5-tuple", i); return NULL; } /* Python code: action, msg, cat, mod, ln = item */ + Py_INCREF(tmp_item); action = PyTuple_GET_ITEM(tmp_item, 0); msg = PyTuple_GET_ITEM(tmp_item, 1); cat = PyTuple_GET_ITEM(tmp_item, 2); @@ -148,15 +149,23 @@ get_filter(PyObject *category, PyObject *text, Py_ssize_t lineno, is_subclass = PyObject_IsSubclass(category, cat); ln = PyLong_AsSsize_t(ln_obj); if (good_msg == -1 || good_mod == -1 || is_subclass == -1 || - (ln == -1 && PyErr_Occurred())) + (ln == -1 && PyErr_Occurred())) { + Py_DECREF(tmp_item); 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 _PyUnicode_AsString(action); + } + + Py_DECREF(tmp_item); } action = get_default_action(); if (action != NULL) { + Py_INCREF(Py_None); + *item = Py_None; return _PyUnicode_AsString(action); } @@ -295,7 +304,7 @@ warn_explicit(PyObject *category, PyObject *message, PyObject *module, PyObject *registry, PyObject *sourceline) { PyObject *key = NULL, *text = NULL, *result = NULL, *lineno_obj = NULL; - PyObject *item = Py_None; + PyObject *item = NULL; const char *action; int rc; @@ -436,6 +445,7 @@ warn_explicit(PyObject *category, PyObject *message, Py_INCREF(result); cleanup: + Py_XDECREF(item); Py_XDECREF(key); Py_XDECREF(text); Py_XDECREF(lineno_obj);