Skip to content

Commit

Permalink
gh-111178: fix UBSan failures in Python/traceback.c (GH-128259)
Browse files Browse the repository at this point in the history
  • Loading branch information
picnixz authored Jan 27, 2025
1 parent 6bb03c7 commit ced296d
Showing 1 changed file with 26 additions and 16 deletions.
42 changes: 26 additions & 16 deletions Python/traceback.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 *
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}
Expand All @@ -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");
Expand All @@ -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) {
Expand All @@ -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},
};

Expand All @@ -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);
Expand All @@ -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;
Expand All @@ -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*/
Expand All @@ -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 */
Expand Down Expand Up @@ -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 ||
Expand Down

0 comments on commit ced296d

Please sign in to comment.