]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
warnings.warn_explicit() did not have the proper TypeErrors in place to prevent
authorBrett Cannon <bcannon@gmail.com>
Fri, 27 Jun 2008 00:31:13 +0000 (00:31 +0000)
committerBrett Cannon <bcannon@gmail.com>
Fri, 27 Jun 2008 00:31:13 +0000 (00:31 +0000)
bus errors or SystemError being raised. As a side effect of fixing this, a bad
DECREF that could be triggered when 'message' and 'category' were both None was
fixed.

Closes issue 3211. Thanks JP Calderone for the bug report.

Lib/test/test_warnings.py
Lib/warnings.py
Misc/NEWS
Python/_warnings.c

index fdb003fe2b761d451fec2374237a33556bbb7a99..ed498e00aae7815cf1ec5b79888a4795202b5adf 100644 (file)
@@ -301,6 +301,21 @@ class WarnTests(unittest.TestCase):
             warning_tests.__name__ = module_name
             sys.argv = argv
 
+    def test_warn_explicit_type_errors(self):
+        # warn_explicit() shoud error out gracefully if it is given objects
+        # of the wrong types.
+        # lineno is expected to be an integer.
+        self.assertRaises(TypeError, self.module.warn_explicit,
+                            None, UserWarning, None, None)
+        # Either 'message' needs to be an instance of Warning or 'category'
+        # needs to be a subclass.
+        self.assertRaises(TypeError, self.module.warn_explicit,
+                            None, None, None, 1)
+        # 'registry' must be a dict or None.
+        self.assertRaises((TypeError, AttributeError),
+                            self.module.warn_explicit,
+                            None, Warning, None, 1, registry=42)
+
 
 
 class CWarnTests(BaseTest, WarnTests):
index d9e6e4458722276ca7a04e2f6d384b8b431b76a4..2e5c51270f6e7119a077d4a3eecf143854aacfb1 100644 (file)
@@ -202,6 +202,7 @@ def warn(message, category=None, stacklevel=1):
 
 def warn_explicit(message, category, filename, lineno,
                   module=None, registry=None, module_globals=None):
+    lineno = int(lineno)
     if module is None:
         module = filename or "<unknown>"
         if module[-3:].lower() == ".py":
index e91b6962e48ce3d23866165544ef2759eb2f25e3..69a9e381c29b48da059cb2043bedc8ce63c9ff15 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -25,6 +25,11 @@ What's New in Python 2.6 beta 1?
 Core and Builtins
 -----------------
 
+- Issue #3211: warnings.warn_explicit() did not guard against its 'registry'
+  argument being anything other than a dict or None. Also fixed a bug in error
+  handling when 'message' and 'category' were both set to None, triggering a
+  bus error.
+
 - Issue #3100: Corrected a crash on deallocation of a subclassed weakref which
   holds the last (strong) reference to its referent.
 
index e3daf77b97d0715cd540806a66666c09441ed5f2..07b98efb2bebdff88be2cd132e2978bfad095b53 100644 (file)
@@ -280,6 +280,11 @@ warn_explicit(PyObject *category, PyObject *message,
     PyObject *item = Py_None;
     const char *action;
     int rc;
+    
+    if (registry && !PyDict_Check(registry) && (registry != Py_None)) {
+        PyErr_SetString(PyExc_TypeError, "'registry' must be a dict");
+        return NULL;
+    }
 
     /* Normalize module. */
     if (module == NULL) {
@@ -303,6 +308,8 @@ warn_explicit(PyObject *category, PyObject *message,
     else {
         text = message;
         message = PyObject_CallFunction(category, "O", message);
+        if (message == NULL)
+            goto cleanup;
     }
 
     lineno_obj = PyInt_FromLong(lineno);
@@ -314,7 +321,7 @@ warn_explicit(PyObject *category, PyObject *message,
     if (key == NULL)
         goto cleanup;
 
-    if (registry != NULL) {
+    if ((registry != NULL) && (registry != Py_None)) {
         rc = already_warned(registry, key, 0);
         if (rc == -1)
             goto cleanup;
@@ -336,12 +343,13 @@ warn_explicit(PyObject *category, PyObject *message,
        is "always". */
     rc = 0;
     if (strcmp(action, "always") != 0) {
-        if (registry != NULL && PyDict_SetItem(registry, key, Py_True) < 0)
+        if (registry != NULL && registry != Py_None &&
+                PyDict_SetItem(registry, key, Py_True) < 0)
             goto cleanup;
         else if (strcmp(action, "ignore") == 0)
             goto return_none;
         else if (strcmp(action, "once") == 0) {
-            if (registry == NULL) {
+            if (registry == NULL || registry == Py_None) {
                 registry = get_once_registry();
                 if (registry == NULL)
                     goto cleanup;
@@ -351,7 +359,7 @@ warn_explicit(PyObject *category, PyObject *message,
         }
         else if (strcmp(action, "module") == 0) {
             /* registry[(text, category, 0)] = 1 */
-            if (registry != NULL)
+            if (registry != NULL && registry != Py_None)
                 rc = update_registry(registry, text, category, 0);
         }
         else if (strcmp(action, "default") != 0) {
@@ -435,7 +443,7 @@ warn_explicit(PyObject *category, PyObject *message,
     Py_XDECREF(text);
     Py_XDECREF(lineno_obj);
     Py_DECREF(module);
-    Py_DECREF(message);
+    Py_XDECREF(message);
     return result;  /* Py_None or NULL. */
 }