Skip to content

Commit 39b37b0

Browse files
gh-128421: add critical section around traceback.tb_next (#131322)
1 parent b12af0a commit 39b37b0

File tree

2 files changed

+82
-14
lines changed

2 files changed

+82
-14
lines changed

Python/clinic/traceback.c.h

Lines changed: 52 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/traceback.c

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -99,10 +99,16 @@ tb_dir(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored))
9999
"tb_lasti", "tb_lineno");
100100
}
101101

102+
/*[clinic input]
103+
@critical_section
104+
@getter
105+
traceback.tb_next
106+
[clinic start generated code]*/
107+
102108
static PyObject *
103-
tb_next_get(PyObject *op, void *Py_UNUSED(_))
109+
traceback_tb_next_get_impl(PyTracebackObject *self)
110+
/*[clinic end generated code: output=963634df7d5fc837 input=8f6345f2b73cb965]*/
104111
{
105-
PyTracebackObject *self = _PyTracebackObject_CAST(op);
106112
PyObject* ret = (PyObject*)self->tb_next;
107113
if (!ret) {
108114
ret = Py_None;
@@ -133,37 +139,48 @@ tb_lineno_get(PyObject *op, void *Py_UNUSED(_))
133139
return PyLong_FromLong(lineno);
134140
}
135141

142+
/*[clinic input]
143+
@critical_section
144+
@setter
145+
traceback.tb_next
146+
[clinic start generated code]*/
147+
136148
static int
137-
tb_next_set(PyObject *op, PyObject *new_next, void *Py_UNUSED(_))
149+
traceback_tb_next_set_impl(PyTracebackObject *self, PyObject *value)
150+
/*[clinic end generated code: output=d4868cbc48f2adac input=ce66367f85e3c443]*/
138151
{
139-
if (!new_next) {
152+
if (!value) {
140153
PyErr_Format(PyExc_TypeError, "can't delete tb_next attribute");
141154
return -1;
142155
}
143156

144157
/* We accept None or a traceback object, and map None -> NULL (inverse of
145158
tb_next_get) */
146-
if (new_next == Py_None) {
147-
new_next = NULL;
148-
} else if (!PyTraceBack_Check(new_next)) {
159+
if (value == Py_None) {
160+
value = NULL;
161+
} else if (!PyTraceBack_Check(value)) {
149162
PyErr_Format(PyExc_TypeError,
150163
"expected traceback object, got '%s'",
151-
Py_TYPE(new_next)->tp_name);
164+
Py_TYPE(value)->tp_name);
152165
return -1;
153166
}
154167

155168
/* Check for loops */
156-
PyTracebackObject *self = _PyTracebackObject_CAST(op);
157-
PyTracebackObject *cursor = (PyTracebackObject *)new_next;
169+
PyTracebackObject *cursor = (PyTracebackObject *)value;
170+
Py_XINCREF(cursor);
158171
while (cursor) {
159172
if (cursor == self) {
160173
PyErr_Format(PyExc_ValueError, "traceback loop detected");
174+
Py_DECREF(cursor);
161175
return -1;
162176
}
163-
cursor = cursor->tb_next;
177+
Py_BEGIN_CRITICAL_SECTION(cursor);
178+
Py_XINCREF(cursor->tb_next);
179+
Py_SETREF(cursor, cursor->tb_next);
180+
Py_END_CRITICAL_SECTION();
164181
}
165182

166-
Py_XSETREF(self->tb_next, (PyTracebackObject *)Py_XNewRef(new_next));
183+
Py_XSETREF(self->tb_next, (PyTracebackObject *)Py_XNewRef(value));
167184

168185
return 0;
169186
}
@@ -181,7 +198,7 @@ static PyMemberDef tb_memberlist[] = {
181198
};
182199

183200
static PyGetSetDef tb_getsetters[] = {
184-
{"tb_next", tb_next_get, tb_next_set, NULL, NULL},
201+
TRACEBACK_TB_NEXT_GETSETDEF
185202
{"tb_lineno", tb_lineno_get, NULL, NULL, NULL},
186203
{NULL} /* Sentinel */
187204
};

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy