]> granicus.if.org Git - python/commitdiff
Merged revisions 64549 via svnmerge from
authorBrett Cannon <bcannon@gmail.com>
Fri, 27 Jun 2008 00:52:15 +0000 (00:52 +0000)
committerBrett Cannon <bcannon@gmail.com>
Fri, 27 Jun 2008 00:52:15 +0000 (00:52 +0000)
svn+ssh://pythondev@svn.python.org/python/trunk

........
  r64549 | brett.cannon | 2008-06-26 17:31:13 -0700 (Thu, 26 Jun 2008) | 7 lines

  warnings.warn_explicit() did not have the proper TypeErrors in place to prevent
  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 6fb3c0ea3e25e425d931538b71589cceb6298bb2..1e17313a6804b23433a68e6f1772aecff95fc98a 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 9353bfa1095a56397bdabd2a2600ee5eb34f61ce..bcd702c99377b55355bc09ca4f5178eb42f39db5 100644 (file)
@@ -188,6 +188,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 0656041f8a21ff8570c0c011e8665114f82c1749..0ba9a9c001c3ca8d3127e7cbe40a99ae74c16473 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -27,6 +27,11 @@ What's new in Python 3.0b1?
 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 6cc493bea585f5a77a5da098ffa75b3159cac7ea..23223faa1bd655ab9075208505e642f22b38fc1e 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 = PyLong_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. */
 }