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
staticPyObject*
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
returnPyLong_FromLong(lineno);
134140
}
135141

142+
/*[clinic input]
143+
@critical_section
144+
@setter
145+
traceback.tb_next
146+
[clinic start generated code]*/
147+
136148
staticint
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-
} elseif (!PyTraceBack_Check(new_next)){
159+
if (value==Py_None){
160+
value=NULL;
161+
} elseif (!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
return0;
169186
}
@@ -181,7 +198,7 @@ static PyMemberDef tb_memberlist[] ={
181198
};
182199

183200
staticPyGetSetDeftb_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)