From 54bd41d81b23eb5d7f7a5f71fa2ceec28fb60296 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Tue, 2 Sep 2008 04:01:42 +0000 Subject: The _warnings module did not properly handle cases where strings were not being passed in as the message to use for a warning. Fixed along with making the code more robust against other errors where return values were not checked. Closes issue 3639. Code review by Benjamin Peterson. --- Lib/test/test_warnings.py | 11 ++++++++++- Misc/NEWS | 3 +++ Python/_warnings.c | 16 ++++++++++++---- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_warnings.py b/Lib/test/test_warnings.py index cd408cf..087bf3d 100644 --- a/Lib/test/test_warnings.py +++ b/Lib/test/test_warnings.py @@ -202,6 +202,16 @@ class WarnTests(unittest.TestCase): self.assertEqual(str(w.message), text) self.assert_(w.category is UserWarning) + # Issue 3639 + def test_warn_nonstandard_types(self): + # warn() should handle non-standard types without issue. + for ob in (Warning, None, 42): + with support.catch_warning(self.module) as w: + self.module.warn(ob) + # Don't directly compare objects since + # ``Warning() != Warning()``. + self.assertEquals(str(w.message), str(UserWarning(ob))) + def test_filename(self): with warnings_state(self.module): with support.catch_warning(self.module) as w: @@ -315,7 +325,6 @@ class WarnTests(unittest.TestCase): self.module.warn_explicit, None, Warning, None, 1, registry=42) - class CWarnTests(BaseTest, WarnTests): module = c_warnings diff --git a/Misc/NEWS b/Misc/NEWS index 5290a83..366fc54 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -12,6 +12,9 @@ What's New in Python 3.0 release candidate 1 Core and Builtins ----------------- +- Issue 3639: The _warnings module could segfault the interpreter when + unexpected types were passed in as arguments. + - Issue #3712: The memoryview object had a reference leak and didn't support cyclic garbage collection. diff --git a/Python/_warnings.c b/Python/_warnings.c index a08219e..84558d1 100644 --- a/Python/_warnings.c +++ b/Python/_warnings.c @@ -258,6 +258,8 @@ show_warning(PyObject *filename, int lineno, PyObject *text, PyObject /* Print " source_line\n" */ if (sourceline) { char *source_line_str = _PyUnicode_AsString(sourceline); + if (source_line_str == NULL) + return; while (*source_line_str == ' ' || *source_line_str == '\t' || *source_line_str == '\014') source_line_str++; @@ -266,8 +268,9 @@ show_warning(PyObject *filename, int lineno, PyObject *text, PyObject PyFile_WriteString("\n", f_stderr); } else - _Py_DisplaySourceLine(f_stderr, _PyUnicode_AsString(filename), - lineno, 2); + if (_Py_DisplaySourceLine(f_stderr, _PyUnicode_AsString(filename), + lineno, 2) < 0) + return; PyErr_Clear(); } @@ -366,8 +369,11 @@ warn_explicit(PyObject *category, PyObject *message, PyObject *to_str = PyObject_Str(item); const char *err_str = "???"; - if (to_str != NULL) + if (to_str != NULL) { err_str = _PyUnicode_AsString(to_str); + if (err_str == NULL) + goto cleanup; + } PyErr_Format(PyExc_RuntimeError, "Unrecognized action (%s) in warnings.filters:\n %s", action, err_str); @@ -498,7 +504,9 @@ setup_context(Py_ssize_t stack_level, PyObject **filename, int *lineno, } else { const char *module_str = _PyUnicode_AsString(*module); - if (module_str && strcmp(module_str, "__main__") == 0) { + if (module_str == NULL) + goto handle_error; + if (strcmp(module_str, "__main__") == 0) { PyObject *argv = PySys_GetObject("argv"); if (argv != NULL && PyList_Size(argv) > 0) { int is_true; -- cgit v0.12