Skip to content

Commit 73bbaf3

Browse files
authored
gh-111178: fix UBSan failures in Modules/selectmodule.c (GH-129792)
Fix some UBSan failures for `pollObject`, `devpollObject`, `pyEpoll_Object` as well as for `kqueue_event_Object`, `kqueue_queue_Object` and `kqueue_tracking_after_fork`. Suppress unused return values. Rename the unused parameter in `METH_NOARGS` and getter/setter methods to `dummy` and `closure` respectively for semantic purposes. Explicitly declare `_select_exec` as a `static` function.
1 parent de13293 commit 73bbaf3

File tree

1 file changed

+65
-44
lines changed

1 file changed

+65
-44
lines changed

Modules/selectmodule.c

Lines changed: 65 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,8 @@ typedef struct {
439439
int poll_running;
440440
} pollObject;
441441

442+
#define pollObject_CAST(op) ((pollObject *)(op))
443+
442444
/* Update the malloc'ed array of pollfds to match the dictionary
443445
contained within a pollObject. Return 1 on success, 0 on an error.
444446
*/
@@ -772,11 +774,13 @@ newPollObject(PyObject *module)
772774
}
773775

774776
static void
775-
poll_dealloc(pollObject *self)
777+
poll_dealloc(PyObject *op)
776778
{
777-
PyObject* type = (PyObject *)Py_TYPE(self);
778-
if (self->ufds != NULL)
779+
pollObject *self = pollObject_CAST(op);
780+
PyTypeObject *type = Py_TYPE(self);
781+
if (self->ufds != NULL) {
779782
PyMem_Free(self->ufds);
783+
}
780784
Py_XDECREF(self->dict);
781785
PyObject_Free(self);
782786
Py_DECREF(type);
@@ -794,6 +798,8 @@ typedef struct {
794798
struct pollfd *fds;
795799
} devpollObject;
796800

801+
#define devpollObject_CAST(op) ((devpollObject *)(op))
802+
797803
static PyObject *
798804
devpoll_err_closed(void)
799805
{
@@ -1086,13 +1092,14 @@ select_devpoll_close_impl(devpollObject *self)
10861092
Py_RETURN_NONE;
10871093
}
10881094

1089-
static PyObject*
1090-
devpoll_get_closed(devpollObject *self, void *Py_UNUSED(ignored))
1095+
static PyObject *
1096+
devpoll_get_closed(PyObject *op, void *Py_UNUSED(closure))
10911097
{
1092-
if (self->fd_devpoll < 0)
1098+
devpollObject *self = devpollObject_CAST(op);
1099+
if (self->fd_devpoll < 0) {
10931100
Py_RETURN_TRUE;
1094-
else
1095-
Py_RETURN_FALSE;
1101+
}
1102+
Py_RETURN_FALSE;
10961103
}
10971104

10981105
/*[clinic input]
@@ -1112,7 +1119,7 @@ select_devpoll_fileno_impl(devpollObject *self)
11121119
}
11131120

11141121
static PyGetSetDef devpoll_getsetlist[] = {
1115-
{"closed", (getter)devpoll_get_closed, NULL,
1122+
{"closed", devpoll_get_closed, NULL,
11161123
"True if the devpoll object is closed"},
11171124
{0},
11181125
};
@@ -1163,9 +1170,10 @@ newDevPollObject(PyObject *module)
11631170
}
11641171

11651172
static void
1166-
devpoll_dealloc(devpollObject *self)
1173+
devpoll_dealloc(PyObject *op)
11671174
{
1168-
PyObject *type = (PyObject *)Py_TYPE(self);
1175+
devpollObject *self = devpollObject_CAST(op);
1176+
PyTypeObject *type = Py_TYPE(self);
11691177
(void)devpoll_internal_close(self);
11701178
PyMem_Free(self->fds);
11711179
PyObject_Free(self);
@@ -1275,6 +1283,8 @@ typedef struct {
12751283
SOCKET epfd; /* epoll control file descriptor */
12761284
} pyEpoll_Object;
12771285

1286+
#define pyEpoll_Object_CAST(op) ((pyEpoll_Object *)(op))
1287+
12781288
static PyObject *
12791289
pyepoll_err_closed(void)
12801290
{
@@ -1377,13 +1387,14 @@ select_epoll_impl(PyTypeObject *type, int sizehint, int flags)
13771387

13781388

13791389
static void
1380-
pyepoll_dealloc(pyEpoll_Object *self)
1390+
pyepoll_dealloc(PyObject *op)
13811391
{
1382-
PyTypeObject* type = Py_TYPE(self);
1392+
pyEpoll_Object *self = pyEpoll_Object_CAST(op);
1393+
PyTypeObject *type = Py_TYPE(self);
13831394
(void)pyepoll_internal_close(self);
13841395
freefunc epoll_free = PyType_GetSlot(type, Py_tp_free);
1385-
epoll_free((PyObject *)self);
1386-
Py_DECREF((PyObject *)type);
1396+
epoll_free(self);
1397+
Py_DECREF(type);
13871398
}
13881399

13891400
/*[clinic input]
@@ -1408,13 +1419,14 @@ select_epoll_close_impl(pyEpoll_Object *self)
14081419
}
14091420

14101421

1411-
static PyObject*
1412-
pyepoll_get_closed(pyEpoll_Object *self, void *Py_UNUSED(ignored))
1422+
static PyObject *
1423+
pyepoll_get_closed(PyObject *op, void *Py_UNUSED(closure))
14131424
{
1414-
if (self->epfd < 0)
1425+
pyEpoll_Object *self = pyEpoll_Object_CAST(op);
1426+
if (self->epfd < 0) {
14151427
Py_RETURN_TRUE;
1416-
else
1417-
Py_RETURN_FALSE;
1428+
}
1429+
Py_RETURN_FALSE;
14181430
}
14191431

14201432
/*[clinic input]
@@ -1707,7 +1719,7 @@ select_epoll___exit___impl(pyEpoll_Object *self, PyObject *exc_type,
17071719
}
17081720

17091721
static PyGetSetDef pyepoll_getsetlist[] = {
1710-
{"closed", (getter)pyepoll_get_closed, NULL,
1722+
{"closed", pyepoll_get_closed, NULL,
17111723
"True if the epoll handler is closed"},
17121724
{0},
17131725
};
@@ -1777,13 +1789,16 @@ typedef struct {
17771789
struct kevent e;
17781790
} kqueue_event_Object;
17791791

1780-
#define kqueue_event_Check(op, state) (PyObject_TypeCheck((op), state->kqueue_event_Type))
1792+
#define kqueue_event_Object_CAST(op) ((kqueue_event_Object *)(op))
1793+
#define kqueue_event_Check(op, state) (PyObject_TypeCheck((op), state->kqueue_event_Type))
17811794

17821795
typedef struct kqueue_queue_Object {
17831796
PyObject_HEAD
17841797
SOCKET kqfd; /* kqueue control fd */
17851798
} kqueue_queue_Object;
17861799

1800+
#define kqueue_queue_Object_CAST(op) ((kqueue_queue_Object *)(op))
1801+
17871802
#if (SIZEOF_UINTPTR_T != SIZEOF_VOID_P)
17881803
# error uintptr_t does not match void *!
17891804
#elif (SIZEOF_UINTPTR_T == SIZEOF_LONG_LONG)
@@ -1876,9 +1891,9 @@ static struct PyMemberDef kqueue_event_members[] = {
18761891
#undef KQ_OFF
18771892

18781893
static PyObject *
1879-
1880-
kqueue_event_repr(kqueue_event_Object *s)
1894+
kqueue_event_repr(PyObject *op)
18811895
{
1896+
kqueue_event_Object *s = kqueue_event_Object_CAST(op);
18821897
return PyUnicode_FromFormat(
18831898
"<select.kevent ident=%zu filter=%d flags=0x%x fflags=0x%x "
18841899
"data=0x%llx udata=%p>",
@@ -1887,7 +1902,7 @@ kqueue_event_repr(kqueue_event_Object *s)
18871902
}
18881903

18891904
static int
1890-
kqueue_event_init(kqueue_event_Object *self, PyObject *args, PyObject *kwds)
1905+
kqueue_event_init(PyObject *op, PyObject *args, PyObject *kwds)
18911906
{
18921907
PyObject *pfd;
18931908
static char *kwlist[] = {"ident", "filter", "flags", "fflags",
@@ -1896,11 +1911,14 @@ kqueue_event_init(kqueue_event_Object *self, PyObject *args, PyObject *kwds)
18961911
FILTER_FMT_UNIT FLAGS_FMT_UNIT FFLAGS_FMT_UNIT DATA_FMT_UNIT
18971912
UINTPTRT_FMT_UNIT ":kevent";
18981913

1914+
kqueue_event_Object *self = kqueue_event_Object_CAST(op);
18991915
EV_SET(&(self->e), 0, EVFILT_READ, EV_ADD, 0, 0, 0); /* defaults */
19001916

19011917
if (!PyArg_ParseTupleAndKeywords(args, kwds, fmt, kwlist,
1902-
&pfd, &(self->e.filter), &(self->e.flags),
1903-
&(self->e.fflags), &(self->e.data), &(self->e.udata))) {
1918+
&pfd, &(self->e.filter),
1919+
&(self->e.flags), &(self->e.fflags),
1920+
&(self->e.data), &(self->e.udata)))
1921+
{
19041922
return -1;
19051923
}
19061924

@@ -1917,15 +1935,16 @@ kqueue_event_init(kqueue_event_Object *self, PyObject *args, PyObject *kwds)
19171935
}
19181936

19191937
static PyObject *
1920-
kqueue_event_richcompare(kqueue_event_Object *s, kqueue_event_Object *o,
1921-
int op)
1938+
kqueue_event_richcompare(PyObject *lhs, PyObject *rhs, int op)
19221939
{
19231940
int result;
1941+
kqueue_event_Object *s = kqueue_event_Object_CAST(lhs);
19241942
_selectstate *state = _selectstate_by_type(Py_TYPE(s));
19251943

1926-
if (!kqueue_event_Check(o, state)) {
1944+
if (!kqueue_event_Check(rhs, state)) {
19271945
Py_RETURN_NOTIMPLEMENTED;
19281946
}
1947+
kqueue_event_Object *o = (kqueue_event_Object *)rhs; // fast cast
19291948

19301949
#define CMP(a, b) ((a) != (b)) ? ((a) < (b) ? -1 : 1)
19311950
result = CMP(s->e.ident, o->e.ident)
@@ -1965,8 +1984,8 @@ kqueue_queue_err_closed(void)
19651984
return NULL;
19661985
}
19671986

1968-
static PyObject*
1969-
kqueue_tracking_after_fork(PyObject *module) {
1987+
static PyObject *
1988+
kqueue_tracking_after_fork(PyObject *module, PyObject *Py_UNUSED(dummy)) {
19701989
_selectstate *state = get_select_state(module);
19711990
_kqueue_list_item *item = state->kqueue_open_list;
19721991
state->kqueue_open_list = NULL;
@@ -1984,7 +2003,7 @@ kqueue_tracking_after_fork(PyObject *module) {
19842003
}
19852004

19862005
static PyMethodDef kqueue_tracking_after_fork_def = {
1987-
"kqueue_tracking_after_fork", (PyCFunction)kqueue_tracking_after_fork,
2006+
"kqueue_tracking_after_fork", kqueue_tracking_after_fork,
19882007
METH_NOARGS, "Invalidate open select.kqueue objects after fork."
19892008
};
19902009

@@ -2173,10 +2192,11 @@ select_kqueue_impl(PyTypeObject *type)
21732192
}
21742193

21752194
static void
2176-
kqueue_queue_finalize(kqueue_queue_Object *self)
2195+
kqueue_queue_finalize(PyObject *op)
21772196
{
2178-
PyObject* error = PyErr_GetRaisedException();
2179-
kqueue_queue_internal_close(self);
2197+
kqueue_queue_Object *self = kqueue_queue_Object_CAST(op);
2198+
PyObject *error = PyErr_GetRaisedException();
2199+
(void)kqueue_queue_internal_close(self);
21802200
PyErr_SetRaisedException(error);
21812201
}
21822202

@@ -2201,13 +2221,14 @@ select_kqueue_close_impl(kqueue_queue_Object *self)
22012221
Py_RETURN_NONE;
22022222
}
22032223

2204-
static PyObject*
2205-
kqueue_queue_get_closed(kqueue_queue_Object *self, void *Py_UNUSED(ignored))
2224+
static PyObject *
2225+
kqueue_queue_get_closed(PyObject *op, void *Py_UNUSED(closure))
22062226
{
2207-
if (self->kqfd < 0)
2227+
kqueue_queue_Object *self = kqueue_queue_Object_CAST(op);
2228+
if (self->kqfd < 0) {
22082229
Py_RETURN_TRUE;
2209-
else
2210-
Py_RETURN_FALSE;
2230+
}
2231+
Py_RETURN_FALSE;
22112232
}
22122233

22132234
/*[clinic input]
@@ -2414,7 +2435,7 @@ select_kqueue_control_impl(kqueue_queue_Object *self, PyObject *changelist,
24142435
}
24152436

24162437
static PyGetSetDef kqueue_queue_getsetlist[] = {
2417-
{"closed", (getter)kqueue_queue_get_closed, NULL,
2438+
{"closed", kqueue_queue_get_closed, NULL,
24182439
"True if the kqueue handler is closed"},
24192440
{0},
24202441
};
@@ -2588,10 +2609,10 @@ _select_clear(PyObject *module)
25882609
static void
25892610
_select_free(void *module)
25902611
{
2591-
_select_clear((PyObject *)module);
2612+
(void)_select_clear((PyObject *)module);
25922613
}
25932614

2594-
int
2615+
static int
25952616
_select_exec(PyObject *m)
25962617
{
25972618
_selectstate *state = get_select_state(m);

0 commit comments

Comments
 (0)