gh-111178: fix UBSan failures in Python/traceback.c (GH-128259)

This commit is contained in:
Bénédikt Tran 2025-01-27 15:07:39 +01:00 committed by GitHub
parent 6bb03c7490
commit ced296d2c0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -38,6 +38,8 @@ class traceback "PyTracebackObject *" "&PyTraceback_Type"
[clinic start generated code]*/
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=cf96294b2bebc811]*/
#define _PyTracebackObject_CAST(op) ((PyTracebackObject *)(op))
#include "clinic/traceback.c.h"
static PyObject *
@ -91,15 +93,16 @@ tb_new_impl(PyTypeObject *type, PyObject *tb_next, PyFrameObject *tb_frame,
}
static PyObject *
tb_dir(PyTracebackObject *self, PyObject *Py_UNUSED(ignored))
tb_dir(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored))
{
return Py_BuildValue("[ssss]", "tb_frame", "tb_next",
"tb_lasti", "tb_lineno");
}
static PyObject *
tb_next_get(PyTracebackObject *self, void *Py_UNUSED(_))
tb_next_get(PyObject *op, void *Py_UNUSED(_))
{
PyTracebackObject *self = _PyTracebackObject_CAST(op);
PyObject* ret = (PyObject*)self->tb_next;
if (!ret) {
ret = Py_None;
@ -108,18 +111,21 @@ tb_next_get(PyTracebackObject *self, void *Py_UNUSED(_))
}
static int
tb_get_lineno(PyTracebackObject* tb) {
tb_get_lineno(PyObject *op)
{
PyTracebackObject *tb = _PyTracebackObject_CAST(op);
_PyInterpreterFrame* frame = tb->tb_frame->f_frame;
assert(frame != NULL);
return PyCode_Addr2Line(_PyFrame_GetCode(frame), tb->tb_lasti);
}
static PyObject *
tb_lineno_get(PyTracebackObject *self, void *Py_UNUSED(_))
tb_lineno_get(PyObject *op, void *Py_UNUSED(_))
{
PyTracebackObject *self = _PyTracebackObject_CAST(op);
int lineno = self->tb_lineno;
if (lineno == -1) {
lineno = tb_get_lineno(self);
lineno = tb_get_lineno(op);
if (lineno < 0) {
Py_RETURN_NONE;
}
@ -128,7 +134,7 @@ tb_lineno_get(PyTracebackObject *self, void *Py_UNUSED(_))
}
static int
tb_next_set(PyTracebackObject *self, PyObject *new_next, void *Py_UNUSED(_))
tb_next_set(PyObject *op, PyObject *new_next, void *Py_UNUSED(_))
{
if (!new_next) {
PyErr_Format(PyExc_TypeError, "can't delete tb_next attribute");
@ -147,6 +153,7 @@ tb_next_set(PyTracebackObject *self, PyObject *new_next, void *Py_UNUSED(_))
}
/* Check for loops */
PyTracebackObject *self = _PyTracebackObject_CAST(op);
PyTracebackObject *cursor = (PyTracebackObject *)new_next;
while (cursor) {
if (cursor == self) {
@ -163,7 +170,7 @@ tb_next_set(PyTracebackObject *self, PyObject *new_next, void *Py_UNUSED(_))
static PyMethodDef tb_methods[] = {
{"__dir__", _PyCFunction_CAST(tb_dir), METH_NOARGS},
{"__dir__", tb_dir, METH_NOARGS, NULL},
{NULL, NULL, 0, NULL},
};
@ -174,14 +181,15 @@ static PyMemberDef tb_memberlist[] = {
};
static PyGetSetDef tb_getsetters[] = {
{"tb_next", (getter)tb_next_get, (setter)tb_next_set, NULL, NULL},
{"tb_lineno", (getter)tb_lineno_get, NULL, NULL, NULL},
{"tb_next", tb_next_get, tb_next_set, NULL, NULL},
{"tb_lineno", tb_lineno_get, NULL, NULL, NULL},
{NULL} /* Sentinel */
};
static void
tb_dealloc(PyTracebackObject *tb)
tb_dealloc(PyObject *op)
{
PyTracebackObject *tb = _PyTracebackObject_CAST(op);
PyObject_GC_UnTrack(tb);
Py_TRASHCAN_BEGIN(tb, tb_dealloc)
Py_XDECREF(tb->tb_next);
@ -191,16 +199,18 @@ tb_dealloc(PyTracebackObject *tb)
}
static int
tb_traverse(PyTracebackObject *tb, visitproc visit, void *arg)
tb_traverse(PyObject *op, visitproc visit, void *arg)
{
PyTracebackObject *tb = _PyTracebackObject_CAST(op);
Py_VISIT(tb->tb_next);
Py_VISIT(tb->tb_frame);
return 0;
}
static int
tb_clear(PyTracebackObject *tb)
tb_clear(PyObject *op)
{
PyTracebackObject *tb = _PyTracebackObject_CAST(op);
Py_CLEAR(tb->tb_next);
Py_CLEAR(tb->tb_frame);
return 0;
@ -211,7 +221,7 @@ PyTypeObject PyTraceBack_Type = {
"traceback",
sizeof(PyTracebackObject),
0,
(destructor)tb_dealloc, /*tp_dealloc*/
tb_dealloc, /*tp_dealloc*/
0, /*tp_vectorcall_offset*/
0, /*tp_getattr*/
0, /*tp_setattr*/
@ -228,8 +238,8 @@ PyTypeObject PyTraceBack_Type = {
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
tb_new__doc__, /* tp_doc */
(traverseproc)tb_traverse, /* tp_traverse */
(inquiry)tb_clear, /* tp_clear */
tb_traverse, /* tp_traverse */
tb_clear, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
@ -663,7 +673,7 @@ tb_printinternal(PyTracebackObject *tb, PyObject *f, long limit)
code = PyFrame_GetCode(tb->tb_frame);
int tb_lineno = tb->tb_lineno;
if (tb_lineno == -1) {
tb_lineno = tb_get_lineno(tb);
tb_lineno = tb_get_lineno((PyObject *)tb);
}
if (last_file == NULL ||
code->co_filename != last_file ||