Skip to content

Commit 4f07fd5

Browse files
authored
gh-111178: fix UBSan failures in Modules/_functoolsmodule.c (GH-129778)
Fix UBSan failures for `keyobject`, `lru_list_elem`, `lru_cache_object`. Suppress unused return values. Change `_PyPartialObject_CAST` (from #124733) to `partialobject_CAST` for consistency with the current style for these macros
1 parent f1b81c4 commit 4f07fd5

File tree

1 file changed

+46
-29
lines changed

1 file changed

+46
-29
lines changed

Modules/_functoolsmodule.c

Lines changed: 46 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ typedef struct {
145145
} partialobject;
146146

147147
// cast a PyObject pointer PTR to a partialobject pointer (no type checks)
148-
#define _PyPartialObject_CAST(PTR) ((partialobject *)(PTR))
148+
#define partialobject_CAST(op) ((partialobject *)(op))
149149

150150
static void partial_setvectorcall(partialobject *pto);
151151
static struct PyModuleDef _functools_module;
@@ -312,7 +312,7 @@ partial_new(PyTypeObject *type, PyObject *args, PyObject *kw)
312312
static int
313313
partial_clear(PyObject *self)
314314
{
315-
partialobject *pto = _PyPartialObject_CAST(self);
315+
partialobject *pto = partialobject_CAST(self);
316316
Py_CLEAR(pto->fn);
317317
Py_CLEAR(pto->args);
318318
Py_CLEAR(pto->kw);
@@ -323,7 +323,7 @@ partial_clear(PyObject *self)
323323
static int
324324
partial_traverse(PyObject *self, visitproc visit, void *arg)
325325
{
326-
partialobject *pto = _PyPartialObject_CAST(self);
326+
partialobject *pto = partialobject_CAST(self);
327327
Py_VISIT(Py_TYPE(pto));
328328
Py_VISIT(pto->fn);
329329
Py_VISIT(pto->args);
@@ -338,7 +338,7 @@ partial_dealloc(PyObject *self)
338338
PyTypeObject *tp = Py_TYPE(self);
339339
/* bpo-31095: UnTrack is needed before calling any callbacks */
340340
PyObject_GC_UnTrack(self);
341-
if (_PyPartialObject_CAST(self)->weakreflist != NULL) {
341+
if (partialobject_CAST(self)->weakreflist != NULL) {
342342
PyObject_ClearWeakRefs(self);
343343
}
344344
(void)partial_clear(self);
@@ -372,7 +372,7 @@ static PyObject *
372372
partial_vectorcall(PyObject *self, PyObject *const *args,
373373
size_t nargsf, PyObject *kwnames)
374374
{
375-
partialobject *pto = _PyPartialObject_CAST(self);;
375+
partialobject *pto = partialobject_CAST(self);;
376376
PyThreadState *tstate = _PyThreadState_GET();
377377
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
378378

@@ -482,7 +482,7 @@ partial_setvectorcall(partialobject *pto)
482482
static PyObject *
483483
partial_call(PyObject *self, PyObject *args, PyObject *kwargs)
484484
{
485-
partialobject *pto = _PyPartialObject_CAST(self);
485+
partialobject *pto = partialobject_CAST(self);
486486
assert(PyCallable_Check(pto->fn));
487487
assert(PyTuple_Check(pto->args));
488488
assert(PyDict_Check(pto->kw));
@@ -595,7 +595,7 @@ static PyGetSetDef partial_getsetlist[] = {
595595
static PyObject *
596596
partial_repr(PyObject *self)
597597
{
598-
partialobject *pto = _PyPartialObject_CAST(self);
598+
partialobject *pto = partialobject_CAST(self);
599599
PyObject *result = NULL;
600600
PyObject *arglist;
601601
PyObject *mod;
@@ -668,7 +668,7 @@ partial_repr(PyObject *self)
668668
static PyObject *
669669
partial_reduce(PyObject *self, PyObject *Py_UNUSED(args))
670670
{
671-
partialobject *pto = _PyPartialObject_CAST(self);
671+
partialobject *pto = partialobject_CAST(self);
672672
return Py_BuildValue("O(O)(OOOO)", Py_TYPE(pto), pto->fn, pto->fn,
673673
pto->args, pto->kw,
674674
pto->dict ? pto->dict : Py_None);
@@ -677,7 +677,7 @@ partial_reduce(PyObject *self, PyObject *Py_UNUSED(args))
677677
static PyObject *
678678
partial_setstate(PyObject *self, PyObject *state)
679679
{
680-
partialobject *pto = _PyPartialObject_CAST(self);
680+
partialobject *pto = partialobject_CAST(self);
681681
PyObject *fn, *fnargs, *kw, *dict;
682682

683683
if (!PyTuple_Check(state)) {
@@ -782,16 +782,19 @@ typedef struct {
782782
PyObject *object;
783783
} keyobject;
784784

785+
#define keyobject_CAST(op) ((keyobject *)(op))
786+
785787
static int
786-
keyobject_clear(keyobject *ko)
788+
keyobject_clear(PyObject *op)
787789
{
790+
keyobject *ko = keyobject_CAST(op);
788791
Py_CLEAR(ko->cmp);
789792
Py_CLEAR(ko->object);
790793
return 0;
791794
}
792795

793796
static void
794-
keyobject_dealloc(keyobject *ko)
797+
keyobject_dealloc(PyObject *ko)
795798
{
796799
PyTypeObject *tp = Py_TYPE(ko);
797800
PyObject_GC_UnTrack(ko);
@@ -801,8 +804,9 @@ keyobject_dealloc(keyobject *ko)
801804
}
802805

803806
static int
804-
keyobject_traverse(keyobject *ko, visitproc visit, void *arg)
807+
keyobject_traverse(PyObject *op, visitproc visit, void *arg)
805808
{
809+
keyobject *ko = keyobject_CAST(op);
806810
Py_VISIT(Py_TYPE(ko));
807811
Py_VISIT(ko->cmp);
808812
Py_VISIT(ko->object);
@@ -817,18 +821,18 @@ static PyMemberDef keyobject_members[] = {
817821
};
818822

819823
static PyObject *
820-
keyobject_text_signature(PyObject *self, void *Py_UNUSED(ignored))
824+
keyobject_text_signature(PyObject *Py_UNUSED(self), void *Py_UNUSED(ignored))
821825
{
822826
return PyUnicode_FromString("(obj)");
823827
}
824828

825829
static PyGetSetDef keyobject_getset[] = {
826-
{"__text_signature__", keyobject_text_signature, (setter)NULL},
830+
{"__text_signature__", keyobject_text_signature, NULL},
827831
{NULL}
828832
};
829833

830834
static PyObject *
831-
keyobject_call(keyobject *ko, PyObject *args, PyObject *kwds);
835+
keyobject_call(PyObject *ko, PyObject *args, PyObject *kwds);
832836

833837
static PyObject *
834838
keyobject_richcompare(PyObject *ko, PyObject *other, int op);
@@ -854,11 +858,12 @@ static PyType_Spec keyobject_type_spec = {
854858
};
855859

856860
static PyObject *
857-
keyobject_call(keyobject *ko, PyObject *args, PyObject *kwds)
861+
keyobject_call(PyObject *self, PyObject *args, PyObject *kwds)
858862
{
859863
PyObject *object;
860864
keyobject *result;
861865
static char *kwargs[] = {"obj", NULL};
866+
keyobject *ko = keyobject_CAST(self);
862867

863868
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:K", kwargs, &object))
864869
return NULL;
@@ -874,17 +879,20 @@ keyobject_call(keyobject *ko, PyObject *args, PyObject *kwds)
874879
}
875880

876881
static PyObject *
877-
keyobject_richcompare(PyObject *ko, PyObject *other, int op)
882+
keyobject_richcompare(PyObject *self, PyObject *other, int op)
878883
{
879-
if (!Py_IS_TYPE(other, Py_TYPE(ko))) {
884+
if (!Py_IS_TYPE(other, Py_TYPE(self))) {
880885
PyErr_Format(PyExc_TypeError, "other argument must be K instance");
881886
return NULL;
882887
}
883888

884-
PyObject *compare = ((keyobject *) ko)->cmp;
889+
keyobject *lhs = keyobject_CAST(self);
890+
keyobject *rhs = keyobject_CAST(other);
891+
892+
PyObject *compare = lhs->cmp;
885893
assert(compare != NULL);
886-
PyObject *x = ((keyobject *) ko)->object;
887-
PyObject *y = ((keyobject *) other)->object;
894+
PyObject *x = lhs->object;
895+
PyObject *y = rhs->object;
888896
if (!x || !y){
889897
PyErr_Format(PyExc_AttributeError, "object");
890898
return NULL;
@@ -1053,9 +1061,12 @@ typedef struct lru_list_elem {
10531061
PyObject *key, *result;
10541062
} lru_list_elem;
10551063

1064+
#define lru_list_elem_CAST(op) ((lru_list_elem *)(op))
1065+
10561066
static void
1057-
lru_list_elem_dealloc(lru_list_elem *link)
1067+
lru_list_elem_dealloc(PyObject *op)
10581068
{
1069+
lru_list_elem *link = lru_list_elem_CAST(op);
10591070
PyTypeObject *tp = Py_TYPE(link);
10601071
Py_XDECREF(link->key);
10611072
Py_XDECREF(link->result);
@@ -1096,6 +1107,8 @@ typedef struct lru_cache_object {
10961107
PyObject *weakreflist;
10971108
} lru_cache_object;
10981109

1110+
#define lru_cache_object_CAST(op) ((lru_cache_object *)(op))
1111+
10991112
static PyObject *
11001113
lru_cache_make_key(PyObject *kwd_mark, PyObject *args,
11011114
PyObject *kwds, int typed)
@@ -1531,8 +1544,9 @@ lru_cache_clear_list(lru_list_elem *link)
15311544
}
15321545

15331546
static int
1534-
lru_cache_tp_clear(lru_cache_object *self)
1547+
lru_cache_tp_clear(PyObject *op)
15351548
{
1549+
lru_cache_object *self = lru_cache_object_CAST(op);
15361550
lru_list_elem *list = lru_cache_unlink_list(self);
15371551
Py_CLEAR(self->cache);
15381552
Py_CLEAR(self->func);
@@ -1545,23 +1559,25 @@ lru_cache_tp_clear(lru_cache_object *self)
15451559
}
15461560

15471561
static void
1548-
lru_cache_dealloc(lru_cache_object *obj)
1562+
lru_cache_dealloc(PyObject *op)
15491563
{
1564+
lru_cache_object *obj = lru_cache_object_CAST(op);
15501565
PyTypeObject *tp = Py_TYPE(obj);
15511566
/* bpo-31095: UnTrack is needed before calling any callbacks */
15521567
PyObject_GC_UnTrack(obj);
15531568
if (obj->weakreflist != NULL) {
1554-
PyObject_ClearWeakRefs((PyObject*)obj);
1569+
PyObject_ClearWeakRefs(op);
15551570
}
15561571

1557-
(void)lru_cache_tp_clear(obj);
1572+
(void)lru_cache_tp_clear(op);
15581573
tp->tp_free(obj);
15591574
Py_DECREF(tp);
15601575
}
15611576

15621577
static PyObject *
1563-
lru_cache_call(lru_cache_object *self, PyObject *args, PyObject *kwds)
1578+
lru_cache_call(PyObject *op, PyObject *args, PyObject *kwds)
15641579
{
1580+
lru_cache_object *self = lru_cache_object_CAST(op);
15651581
PyObject *result;
15661582
Py_BEGIN_CRITICAL_SECTION(self);
15671583
result = self->wrapper(self, args, kwds);
@@ -1638,8 +1654,9 @@ lru_cache_deepcopy(PyObject *self, PyObject *unused)
16381654
}
16391655

16401656
static int
1641-
lru_cache_tp_traverse(lru_cache_object *self, visitproc visit, void *arg)
1657+
lru_cache_tp_traverse(PyObject *op, visitproc visit, void *arg)
16421658
{
1659+
lru_cache_object *self = lru_cache_object_CAST(op);
16431660
Py_VISIT(Py_TYPE(self));
16441661
lru_list_elem *link = self->root.next;
16451662
while (link != &self->root) {
@@ -1827,7 +1844,7 @@ _functools_clear(PyObject *module)
18271844
static void
18281845
_functools_free(void *module)
18291846
{
1830-
_functools_clear((PyObject *)module);
1847+
(void)_functools_clear((PyObject *)module);
18311848
}
18321849

18331850
static struct PyModuleDef_Slot _functools_slots[] = {

0 commit comments

Comments
 (0)