Skip to content

Commit 1e4a434

Browse files
authored
gh-111178: fix UBSan failures in Modules/_struct.c (#129793)
Fix some UBSan failures for `PyStructObject` and `unpackiterobject`. We also perform some cleanup by suppressing unused return values and renaming the unused parameter in `METH_NOARGS` and getter methods to `dummy` and `closure` respectively for semantic purposes.
1 parent b8c313a commit 1e4a434

File tree

1 file changed

+45
-28
lines changed

1 file changed

+45
-28
lines changed

Modules/_struct.c

+45-28
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@ typedef struct {
7373
PyObject *weakreflist; /* List of weak references */
7474
} PyStructObject;
7575

76-
#define PyStruct_Check(op, state) PyObject_TypeCheck(op, (PyTypeObject *)(state)->PyStructType)
76+
#define PyStructObject_CAST(op) ((PyStructObject *)(op))
77+
#define PyStruct_Check(op, state) PyObject_TypeCheck(op, (PyTypeObject *)(state)->PyStructType)
7778

7879
/* Define various structs to figure out the alignments of types */
7980

@@ -1853,33 +1854,36 @@ Struct___init___impl(PyStructObject *self, PyObject *format)
18531854
}
18541855

18551856
static int
1856-
s_clear(PyStructObject *s)
1857+
s_clear(PyObject *op)
18571858
{
1859+
PyStructObject *s = PyStructObject_CAST(op);
18581860
Py_CLEAR(s->s_format);
18591861
return 0;
18601862
}
18611863

18621864
static int
1863-
s_traverse(PyStructObject *s, visitproc visit, void *arg)
1865+
s_traverse(PyObject *op, visitproc visit, void *arg)
18641866
{
1867+
PyStructObject *s = PyStructObject_CAST(op);
18651868
Py_VISIT(Py_TYPE(s));
18661869
Py_VISIT(s->s_format);
18671870
return 0;
18681871
}
18691872

18701873
static void
1871-
s_dealloc(PyStructObject *s)
1874+
s_dealloc(PyObject *op)
18721875
{
1876+
PyStructObject *s = PyStructObject_CAST(op);
18731877
PyTypeObject *tp = Py_TYPE(s);
18741878
PyObject_GC_UnTrack(s);
1875-
if (s->weakreflist != NULL)
1876-
PyObject_ClearWeakRefs((PyObject *)s);
1879+
if (s->weakreflist != NULL) {
1880+
PyObject_ClearWeakRefs(op);
1881+
}
18771882
if (s->s_codes != NULL) {
18781883
PyMem_Free(s->s_codes);
18791884
}
18801885
Py_XDECREF(s->s_format);
1881-
freefunc free_func = PyType_GetSlot(Py_TYPE(s), Py_tp_free);
1882-
free_func(s);
1886+
tp->tp_free(s);
18831887
Py_DECREF(tp);
18841888
}
18851889

@@ -2026,9 +2030,12 @@ typedef struct {
20262030
Py_ssize_t index;
20272031
} unpackiterobject;
20282032

2033+
#define unpackiterobject_CAST(op) ((unpackiterobject *)(op))
2034+
20292035
static void
2030-
unpackiter_dealloc(unpackiterobject *self)
2036+
unpackiter_dealloc(PyObject *op)
20312037
{
2038+
unpackiterobject *self = unpackiterobject_CAST(op);
20322039
/* bpo-31095: UnTrack is needed before calling any callbacks */
20332040
PyTypeObject *tp = Py_TYPE(self);
20342041
PyObject_GC_UnTrack(self);
@@ -2039,37 +2046,43 @@ unpackiter_dealloc(unpackiterobject *self)
20392046
}
20402047

20412048
static int
2042-
unpackiter_traverse(unpackiterobject *self, visitproc visit, void *arg)
2049+
unpackiter_traverse(PyObject *op, visitproc visit, void *arg)
20432050
{
2051+
unpackiterobject *self = unpackiterobject_CAST(op);
20442052
Py_VISIT(Py_TYPE(self));
20452053
Py_VISIT(self->so);
20462054
Py_VISIT(self->buf.obj);
20472055
return 0;
20482056
}
20492057

20502058
static PyObject *
2051-
unpackiter_len(unpackiterobject *self, PyObject *Py_UNUSED(ignored))
2059+
unpackiter_len(PyObject *op, PyObject *Py_UNUSED(dummy))
20522060
{
20532061
Py_ssize_t len;
2054-
if (self->so == NULL)
2062+
unpackiterobject *self = unpackiterobject_CAST(op);
2063+
if (self->so == NULL) {
20552064
len = 0;
2056-
else
2065+
}
2066+
else {
20572067
len = (self->buf.len - self->index) / self->so->s_size;
2068+
}
20582069
return PyLong_FromSsize_t(len);
20592070
}
20602071

20612072
static PyMethodDef unpackiter_methods[] = {
2062-
{"__length_hint__", (PyCFunction) unpackiter_len, METH_NOARGS, NULL},
2073+
{"__length_hint__", unpackiter_len, METH_NOARGS, NULL},
20632074
{NULL, NULL} /* sentinel */
20642075
};
20652076

20662077
static PyObject *
2067-
unpackiter_iternext(unpackiterobject *self)
2078+
unpackiter_iternext(PyObject *op)
20682079
{
2080+
unpackiterobject *self = unpackiterobject_CAST(op);
20692081
_structmodulestate *state = get_struct_state_iterinst(self);
20702082
PyObject *result;
2071-
if (self->so == NULL)
2083+
if (self->so == NULL) {
20722084
return NULL;
2085+
}
20732086
if (self->index >= self->buf.len) {
20742087
/* Iterator exhausted */
20752088
Py_CLEAR(self->so);
@@ -2078,7 +2091,7 @@ unpackiter_iternext(unpackiterobject *self)
20782091
}
20792092
assert(self->index + self->so->s_size <= self->buf.len);
20802093
result = s_unpack_internal(self->so,
2081-
(char*) self->buf.buf + self->index,
2094+
(char*)self->buf.buf + self->index,
20822095
state);
20832096
self->index += self->so->s_size;
20842097
return result;
@@ -2264,7 +2277,7 @@ s_pack(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
22642277
_structmodulestate *state = get_struct_state_structinst(self);
22652278

22662279
/* Validate arguments. */
2267-
soself = (PyStructObject *)self;
2280+
soself = PyStructObject_CAST(self);
22682281
assert(PyStruct_Check(self, state));
22692282
assert(soself->s_codes != NULL);
22702283
if (nargs != soself->s_len)
@@ -2309,7 +2322,7 @@ s_pack_into(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
23092322
_structmodulestate *state = get_struct_state_structinst(self);
23102323

23112324
/* Validate arguments. +1 is for the first arg as buffer. */
2312-
soself = (PyStructObject *)self;
2325+
soself = PyStructObject_CAST(self);
23132326
assert(PyStruct_Check(self, state));
23142327
assert(soself->s_codes != NULL);
23152328
if (nargs != (soself->s_len + 2))
@@ -2395,24 +2408,27 @@ s_pack_into(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
23952408
}
23962409

23972410
static PyObject *
2398-
s_get_format(PyStructObject *self, void *unused)
2411+
s_get_format(PyObject *op, void *Py_UNUSED(closure))
23992412
{
2413+
PyStructObject *self = PyStructObject_CAST(op);
24002414
return PyUnicode_FromStringAndSize(PyBytes_AS_STRING(self->s_format),
24012415
PyBytes_GET_SIZE(self->s_format));
24022416
}
24032417

24042418
static PyObject *
2405-
s_get_size(PyStructObject *self, void *unused)
2419+
s_get_size(PyObject *op, void *Py_UNUSED(closure))
24062420
{
2421+
PyStructObject *self = PyStructObject_CAST(op);
24072422
return PyLong_FromSsize_t(self->s_size);
24082423
}
24092424

24102425
PyDoc_STRVAR(s_sizeof__doc__,
24112426
"S.__sizeof__() -> size of S in memory, in bytes");
24122427

24132428
static PyObject *
2414-
s_sizeof(PyStructObject *self, void *unused)
2429+
s_sizeof(PyObject *op, PyObject *Py_UNUSED(dummy))
24152430
{
2431+
PyStructObject *self = PyStructObject_CAST(op);
24162432
size_t size = _PyObject_SIZE(Py_TYPE(self)) + sizeof(formatcode);
24172433
for (formatcode *code = self->s_codes; code->fmtdef != NULL; code++) {
24182434
size += sizeof(formatcode);
@@ -2421,8 +2437,9 @@ s_sizeof(PyStructObject *self, void *unused)
24212437
}
24222438

24232439
static PyObject *
2424-
s_repr(PyStructObject *self)
2440+
s_repr(PyObject *op)
24252441
{
2442+
PyStructObject *self = PyStructObject_CAST(op);
24262443
PyObject* fmt = PyUnicode_FromStringAndSize(
24272444
PyBytes_AS_STRING(self->s_format), PyBytes_GET_SIZE(self->s_format));
24282445
if (fmt == NULL) {
@@ -2441,7 +2458,7 @@ static struct PyMethodDef s_methods[] = {
24412458
{"pack_into", _PyCFunction_CAST(s_pack_into), METH_FASTCALL, s_pack_into__doc__},
24422459
STRUCT_UNPACK_METHODDEF
24432460
STRUCT_UNPACK_FROM_METHODDEF
2444-
{"__sizeof__", (PyCFunction)s_sizeof, METH_NOARGS, s_sizeof__doc__},
2461+
{"__sizeof__", s_sizeof, METH_NOARGS, s_sizeof__doc__},
24452462
{NULL, NULL} /* sentinel */
24462463
};
24472464

@@ -2451,8 +2468,8 @@ static PyMemberDef s_members[] = {
24512468
};
24522469

24532470
static PyGetSetDef s_getsetlist[] = {
2454-
{"format", (getter)s_get_format, (setter)NULL, PyDoc_STR("struct format string"), NULL},
2455-
{"size", (getter)s_get_size, (setter)NULL, PyDoc_STR("struct size in bytes"), NULL},
2471+
{"format", s_get_format, NULL, PyDoc_STR("struct format string"), NULL},
2472+
{"size", s_get_size, NULL, PyDoc_STR("struct size in bytes"), NULL},
24562473
{NULL} /* sentinel */
24572474
};
24582475

@@ -2508,7 +2525,7 @@ cache_struct_converter(PyObject *module, PyObject *fmt, PyStructObject **ptr)
25082525
return 0;
25092526
}
25102527
if (s_object != NULL) {
2511-
*ptr = (PyStructObject *)s_object;
2528+
*ptr = PyStructObject_CAST(s_object);
25122529
return Py_CLEANUP_SUPPORTED;
25132530
}
25142531

@@ -2751,7 +2768,7 @@ _structmodule_clear(PyObject *module)
27512768
static void
27522769
_structmodule_free(void *module)
27532770
{
2754-
_structmodule_clear((PyObject *)module);
2771+
(void)_structmodule_clear((PyObject *)module);
27552772
}
27562773

27572774
static int

0 commit comments

Comments
 (0)