https://github.com/python/cpython/commit/39b37b0110d0faaa25d7cdaab008f856eec8173c
commit: 39b37b0110d0faaa25d7cdaab008f856eec8173c
branch: main
author: Kumar Aditya <kumaradi...@python.org>
committer: kumaraditya303 <kumaradi...@python.org>
date: 2025-03-20T12:03:54+05:30
summary:

gh-128421: add critical section around `traceback.tb_next` (#131322)

files:
M Python/clinic/traceback.c.h
M Python/traceback.c

diff --git a/Python/clinic/traceback.c.h b/Python/clinic/traceback.c.h
index 9607e773f4be88..5eb31a189467b3 100644
--- a/Python/clinic/traceback.c.h
+++ b/Python/clinic/traceback.c.h
@@ -6,6 +6,7 @@ preserve
 #  include "pycore_gc.h"          // PyGC_Head
 #  include "pycore_runtime.h"     // _Py_ID()
 #endif
+#include "pycore_critical_section.h"// Py_BEGIN_CRITICAL_SECTION()
 #include "pycore_modsupport.h"    // _PyArg_UnpackKeywords()
 
 PyDoc_STRVAR(tb_new__doc__,
@@ -79,4 +80,54 @@ tb_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
 exit:
     return return_value;
 }
-/*[clinic end generated code: output=62ebc0196940f663 input=a9049054013a1b77]*/
+
+#if !defined(traceback_tb_next_DOCSTR)
+#  define traceback_tb_next_DOCSTR NULL
+#endif
+#if defined(TRACEBACK_TB_NEXT_GETSETDEF)
+#  undef TRACEBACK_TB_NEXT_GETSETDEF
+#  define TRACEBACK_TB_NEXT_GETSETDEF {"tb_next", 
(getter)traceback_tb_next_get, (setter)traceback_tb_next_set, 
traceback_tb_next_DOCSTR},
+#else
+#  define TRACEBACK_TB_NEXT_GETSETDEF {"tb_next", 
(getter)traceback_tb_next_get, NULL, traceback_tb_next_DOCSTR},
+#endif
+
+static PyObject *
+traceback_tb_next_get_impl(PyTracebackObject *self);
+
+static PyObject *
+traceback_tb_next_get(PyObject *self, void *Py_UNUSED(context))
+{
+    PyObject *return_value = NULL;
+
+    Py_BEGIN_CRITICAL_SECTION(self);
+    return_value = traceback_tb_next_get_impl((PyTracebackObject *)self);
+    Py_END_CRITICAL_SECTION();
+
+    return return_value;
+}
+
+#if !defined(traceback_tb_next_DOCSTR)
+#  define traceback_tb_next_DOCSTR NULL
+#endif
+#if defined(TRACEBACK_TB_NEXT_GETSETDEF)
+#  undef TRACEBACK_TB_NEXT_GETSETDEF
+#  define TRACEBACK_TB_NEXT_GETSETDEF {"tb_next", 
(getter)traceback_tb_next_get, (setter)traceback_tb_next_set, 
traceback_tb_next_DOCSTR},
+#else
+#  define TRACEBACK_TB_NEXT_GETSETDEF {"tb_next", NULL, 
(setter)traceback_tb_next_set, NULL},
+#endif
+
+static int
+traceback_tb_next_set_impl(PyTracebackObject *self, PyObject *value);
+
+static int
+traceback_tb_next_set(PyObject *self, PyObject *value, void 
*Py_UNUSED(context))
+{
+    int return_value;
+
+    Py_BEGIN_CRITICAL_SECTION(self);
+    return_value = traceback_tb_next_set_impl((PyTracebackObject *)self, 
value);
+    Py_END_CRITICAL_SECTION();
+
+    return return_value;
+}
+/*[clinic end generated code: output=ca43786e235e38f4 input=a9049054013a1b77]*/
diff --git a/Python/traceback.c b/Python/traceback.c
index e53d87d52f9c33..07a7ca8e7d63e4 100644
--- a/Python/traceback.c
+++ b/Python/traceback.c
@@ -99,10 +99,16 @@ tb_dir(PyObject *Py_UNUSED(self), PyObject 
*Py_UNUSED(ignored))
                                    "tb_lasti", "tb_lineno");
 }
 
+/*[clinic input]
+@critical_section
+@getter
+traceback.tb_next
+[clinic start generated code]*/
+
 static PyObject *
-tb_next_get(PyObject *op, void *Py_UNUSED(_))
+traceback_tb_next_get_impl(PyTracebackObject *self)
+/*[clinic end generated code: output=963634df7d5fc837 input=8f6345f2b73cb965]*/
 {
-    PyTracebackObject *self = _PyTracebackObject_CAST(op);
     PyObject* ret = (PyObject*)self->tb_next;
     if (!ret) {
         ret = Py_None;
@@ -133,37 +139,48 @@ tb_lineno_get(PyObject *op, void *Py_UNUSED(_))
     return PyLong_FromLong(lineno);
 }
 
+/*[clinic input]
+@critical_section
+@setter
+traceback.tb_next
+[clinic start generated code]*/
+
 static int
-tb_next_set(PyObject *op, PyObject *new_next, void *Py_UNUSED(_))
+traceback_tb_next_set_impl(PyTracebackObject *self, PyObject *value)
+/*[clinic end generated code: output=d4868cbc48f2adac input=ce66367f85e3c443]*/
 {
-    if (!new_next) {
+    if (!value) {
         PyErr_Format(PyExc_TypeError, "can't delete tb_next attribute");
         return -1;
     }
 
     /* We accept None or a traceback object, and map None -> NULL (inverse of
        tb_next_get) */
-    if (new_next == Py_None) {
-        new_next = NULL;
-    } else if (!PyTraceBack_Check(new_next)) {
+    if (value == Py_None) {
+        value = NULL;
+    } else if (!PyTraceBack_Check(value)) {
         PyErr_Format(PyExc_TypeError,
                      "expected traceback object, got '%s'",
-                     Py_TYPE(new_next)->tp_name);
+                     Py_TYPE(value)->tp_name);
         return -1;
     }
 
     /* Check for loops */
-    PyTracebackObject *self = _PyTracebackObject_CAST(op);
-    PyTracebackObject *cursor = (PyTracebackObject *)new_next;
+    PyTracebackObject *cursor = (PyTracebackObject *)value;
+    Py_XINCREF(cursor);
     while (cursor) {
         if (cursor == self) {
             PyErr_Format(PyExc_ValueError, "traceback loop detected");
+            Py_DECREF(cursor);
             return -1;
         }
-        cursor = cursor->tb_next;
+        Py_BEGIN_CRITICAL_SECTION(cursor);
+        Py_XINCREF(cursor->tb_next);
+        Py_SETREF(cursor, cursor->tb_next);
+        Py_END_CRITICAL_SECTION();
     }
 
-    Py_XSETREF(self->tb_next, (PyTracebackObject *)Py_XNewRef(new_next));
+    Py_XSETREF(self->tb_next, (PyTracebackObject *)Py_XNewRef(value));
 
     return 0;
 }
@@ -181,7 +198,7 @@ static PyMemberDef tb_memberlist[] = {
 };
 
 static PyGetSetDef tb_getsetters[] = {
-    {"tb_next", tb_next_get, tb_next_set, NULL, NULL},
+    TRACEBACK_TB_NEXT_GETSETDEF
     {"tb_lineno", tb_lineno_get, NULL, NULL, NULL},
     {NULL}      /* Sentinel */
 };

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-le...@python.org
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: arch...@mail-archive.com

Reply via email to