]> granicus.if.org Git - python/commitdiff
Fix segfaults when running test_exceptions with coverage tracing, caused by wrongly...
authorGeorg Brandl <georg@python.org>
Tue, 31 Mar 2009 04:16:10 +0000 (04:16 +0000)
committerGeorg Brandl <georg@python.org>
Tue, 31 Mar 2009 04:16:10 +0000 (04:16 +0000)
Doc/c-api/exceptions.rst
Lib/test/test_exceptions.py
Misc/NEWS
Objects/exceptions.c

index f650cfdaada6e0a6d26fc3c8f560c4a6f5a8f04d..819e22e02c8bb4aa7a180d867d28a3caf4946512 100644 (file)
@@ -400,6 +400,52 @@ in various ways.  There is a separate error indicator for each thread.
    the warning message.
 
 
+Exception Objects
+=================
+
+.. cfunction:: PyObject* PyException_GetTraceback(PyObject *ex)
+
+   Return the traceback associated with the exception as a new reference, as
+   accessible from Python through :attr:`__traceback__`.  If there is no
+   traceback associated, this returns *NULL*.
+
+
+.. cfunction:: int PyException_SetTraceback(PyObject *ex, PyObject *tb)
+
+   Set the traceback associated with the exception to *tb*.  Use ``Py_None`` to
+   clear it.
+
+
+.. cfunction:: PyObject* PyException_GetContext(PyObject *ex)
+
+   Return the context (another exception instance during whose handling *ex* was
+   raised) associated with the exception as a new reference, as accessible from
+   Python through :attr:`__context__`.  If there is no context associated, this
+   returns *NULL*.
+
+
+.. cfunction:: void PyException_SetContext(PyObject *ex, PyObject *ctx)
+
+   Set the context associated with the exception to *ctx*.  Use *NULL* to clear
+   it.  There is no type check to make sure that *ctx* is an exception instance.
+   This steals a reference to *ctx*.
+
+
+.. cfunction:: PyObject* PyException_GetCause(PyObject *ex)
+
+   Return the cause (another exception instance set by ``raise ... from ...``)
+   associated with the exception as a new reference, as accessible from Python
+   through :attr:`__cause__`.  If there is no cause associated, this returns
+   *NULL*.
+
+
+.. cfunction:: void PyException_SetCause(PyObject *ex, PyObject *ctx)
+
+   Set the cause associated with the exception to *ctx*.  Use *NULL* to clear
+   it.  There is no type check to make sure that *ctx* is an exception instance.
+   This steals a reference to *ctx*.
+
+
 .. _standardexceptions:
 
 Standard Exceptions
index b671cbc12d5fdb7a0d3df011060d59d2d854cdd6..8bb20791d74a372a8d6cccbf8d4f0530cace3093 100644 (file)
@@ -341,6 +341,12 @@ class ExceptionTests(unittest.TestCase):
         else:
             self.fail("No exception raised")
 
+    def testInvalidAttrs(self):
+        self.assertRaises(TypeError, setattr, Exception(), '__cause__', 1)
+        self.assertRaises(TypeError, delattr, Exception(), '__cause__')
+        self.assertRaises(TypeError, setattr, Exception(), '__context__', 1)
+        self.assertRaises(TypeError, delattr, Exception(), '__context__')
+
     def testNoneClearsTracebackAttr(self):
         try:
             raise IndexError(4)
index 894aa71888136492d2eff941cb416d36d3dfc085..911e94470fc21ac169b467eb695f9ef9224296c9 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -1,4 +1,5 @@
-+++++++++++ Python News
++++++++++++
+Python News
 +++++++++++
 
 (editors: check NEWS.help for information about editing NEWS using ReST.)
@@ -11,6 +12,9 @@ What's New in Python 3.1 alpha 2?
 Core and Builtins
 -----------------
 
+- Fix a segfault when running test_exceptions with coverage, caused by
+  insufficient checks in accessors of Exception.__context__.
+
 - Issue #5604: non-ASCII characters in module name passed to
   imp.find_module() were converted to UTF-8 while the path is
   converted to the default filesystem encoding, causing nonsense.
index 418bffb0a0732214b5c2abf4da0a5beeafc56956..9258ace50a10158d083eec7000a774ec42113a28 100644 (file)
@@ -250,11 +250,67 @@ BaseException_set_tb(PyBaseExceptionObject *self, PyObject *tb)
     return 0;
 }
 
+static PyObject *
+BaseException_get_context(PyObject *self) {
+    PyObject *res = PyException_GetContext(self);
+    if (res) return res;  /* new reference already returned above */
+    Py_RETURN_NONE;
+}
+
+static int
+BaseException_set_context(PyObject *self, PyObject *arg) {
+    if (arg == NULL) {
+        PyErr_SetString(PyExc_TypeError, "__context__ may not be deleted");
+        return -1;
+    } else if (arg == Py_None) {
+        arg = NULL;
+    } else if (!PyExceptionInstance_Check(arg)) {
+        PyErr_SetString(PyExc_TypeError, "exception context must be None "
+                        "or derive from BaseException");
+        return -1;
+    } else {
+        /* PyException_SetContext steals this reference */
+        Py_INCREF(arg);
+    } 
+    PyException_SetContext(self, arg);
+    return 0;
+}
+
+static PyObject *
+BaseException_get_cause(PyObject *self) {
+    PyObject *res = PyException_GetCause(self);
+    if (res) return res;  /* new reference already returned above */
+    Py_RETURN_NONE;
+}
+
+static int
+BaseException_set_cause(PyObject *self, PyObject *arg) {
+    if (arg == NULL) {
+        PyErr_SetString(PyExc_TypeError, "__cause__ may not be deleted");
+        return -1;
+    } else if (arg == Py_None) {
+        arg = NULL;
+    } else if (!PyExceptionInstance_Check(arg)) {
+        PyErr_SetString(PyExc_TypeError, "exception cause must be None "
+                        "or derive from BaseException");
+        return -1;
+    } else {
+        /* PyException_SetCause steals this reference */
+        Py_INCREF(arg);
+    } 
+    PyException_SetCause(self, arg);
+    return 0;
+}
+
 
 static PyGetSetDef BaseException_getset[] = {
     {"__dict__", (getter)BaseException_get_dict, (setter)BaseException_set_dict},
     {"args", (getter)BaseException_get_args, (setter)BaseException_set_args},
     {"__traceback__", (getter)BaseException_get_tb, (setter)BaseException_set_tb},
+    {"__context__", (getter)BaseException_get_context,
+     (setter)BaseException_set_context, PyDoc_STR("exception context")},
+    {"__cause__", (getter)BaseException_get_cause,
+     (setter)BaseException_set_cause, PyDoc_STR("exception cause")},
     {NULL},
 };
 
@@ -303,14 +359,6 @@ PyException_SetContext(PyObject *self, PyObject *context) {
 }
 
 
-static PyMemberDef BaseException_members[] = {
-    {"__context__", T_OBJECT, offsetof(PyBaseExceptionObject, context), 0,
-        PyDoc_STR("exception context")},
-    {"__cause__", T_OBJECT, offsetof(PyBaseExceptionObject, cause), 0,
-        PyDoc_STR("exception cause")},
-    {NULL}  /* Sentinel */
-};
-
 static PyTypeObject _PyExc_BaseException = {
     PyVarObject_HEAD_INIT(NULL, 0)
     "BaseException", /*tp_name*/
@@ -341,7 +389,7 @@ static PyTypeObject _PyExc_BaseException = {
     0,                          /* tp_iter */
     0,                          /* tp_iternext */
     BaseException_methods,      /* tp_methods */
-    BaseException_members,      /* tp_members */
+    0,                          /* tp_members */
     BaseException_getset,       /* tp_getset */
     0,                          /* tp_base */
     0,                          /* tp_dict */