Skip to content

Commit c77121e

Browse files
authored
gh-111178: fix USAN failures for partialobject (#124733)
1 parent 6a08a75 commit c77121e

File tree

1 file changed

+34
-25
lines changed

1 file changed

+34
-25
lines changed

Modules/_functoolsmodule.c

+34-25
Original file line numberDiff line numberDiff line change
@@ -144,10 +144,13 @@ typedef struct {
144144
vectorcallfunc vectorcall;
145145
} partialobject;
146146

147+
// cast a PyObject pointer PTR to a partialobject pointer (no type checks)
148+
#define _PyPartialObject_CAST(PTR) ((partialobject *)(PTR))
149+
147150
static void partial_setvectorcall(partialobject *pto);
148151
static struct PyModuleDef _functools_module;
149152
static PyObject *
150-
partial_call(partialobject *pto, PyObject *args, PyObject *kwargs);
153+
partial_call(PyObject *pto, PyObject *args, PyObject *kwargs);
151154

152155
static inline _functools_state *
153156
get_functools_state_by_type(PyTypeObject *type)
@@ -307,8 +310,9 @@ partial_new(PyTypeObject *type, PyObject *args, PyObject *kw)
307310
}
308311

309312
static int
310-
partial_clear(partialobject *pto)
313+
partial_clear(PyObject *self)
311314
{
315+
partialobject *pto = _PyPartialObject_CAST(self);
312316
Py_CLEAR(pto->fn);
313317
Py_CLEAR(pto->args);
314318
Py_CLEAR(pto->kw);
@@ -317,8 +321,9 @@ partial_clear(partialobject *pto)
317321
}
318322

319323
static int
320-
partial_traverse(partialobject *pto, visitproc visit, void *arg)
324+
partial_traverse(PyObject *self, visitproc visit, void *arg)
321325
{
326+
partialobject *pto = _PyPartialObject_CAST(self);
322327
Py_VISIT(Py_TYPE(pto));
323328
Py_VISIT(pto->fn);
324329
Py_VISIT(pto->args);
@@ -328,16 +333,16 @@ partial_traverse(partialobject *pto, visitproc visit, void *arg)
328333
}
329334

330335
static void
331-
partial_dealloc(partialobject *pto)
336+
partial_dealloc(PyObject *self)
332337
{
333-
PyTypeObject *tp = Py_TYPE(pto);
338+
PyTypeObject *tp = Py_TYPE(self);
334339
/* bpo-31095: UnTrack is needed before calling any callbacks */
335-
PyObject_GC_UnTrack(pto);
336-
if (pto->weakreflist != NULL) {
337-
PyObject_ClearWeakRefs((PyObject *) pto);
340+
PyObject_GC_UnTrack(self);
341+
if (_PyPartialObject_CAST(self)->weakreflist != NULL) {
342+
PyObject_ClearWeakRefs(self);
338343
}
339-
(void)partial_clear(pto);
340-
tp->tp_free(pto);
344+
(void)partial_clear(self);
345+
tp->tp_free(self);
341346
Py_DECREF(tp);
342347
}
343348

@@ -360,14 +365,14 @@ partial_vectorcall_fallback(PyThreadState *tstate, partialobject *pto,
360365
{
361366
pto->vectorcall = NULL;
362367
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
363-
return _PyObject_MakeTpCall(tstate, (PyObject *)pto,
364-
args, nargs, kwnames);
368+
return _PyObject_MakeTpCall(tstate, (PyObject *)pto, args, nargs, kwnames);
365369
}
366370

367371
static PyObject *
368-
partial_vectorcall(partialobject *pto, PyObject *const *args,
372+
partial_vectorcall(PyObject *self, PyObject *const *args,
369373
size_t nargsf, PyObject *kwnames)
370374
{
375+
partialobject *pto = _PyPartialObject_CAST(self);;
371376
PyThreadState *tstate = _PyThreadState_GET();
372377
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
373378

@@ -468,15 +473,16 @@ partial_setvectorcall(partialobject *pto)
468473
* but that is unlikely (why use partial without arguments?),
469474
* so we don't optimize that */
470475
else {
471-
pto->vectorcall = (vectorcallfunc)partial_vectorcall;
476+
pto->vectorcall = partial_vectorcall;
472477
}
473478
}
474479

475480

476481
// Not converted to argument clinic, because of `*args, **kwargs` arguments.
477482
static PyObject *
478-
partial_call(partialobject *pto, PyObject *args, PyObject *kwargs)
483+
partial_call(PyObject *self, PyObject *args, PyObject *kwargs)
479484
{
485+
partialobject *pto = _PyPartialObject_CAST(self);
480486
assert(PyCallable_Check(pto->fn));
481487
assert(PyTuple_Check(pto->args));
482488
assert(PyDict_Check(pto->kw));
@@ -587,8 +593,9 @@ static PyGetSetDef partial_getsetlist[] = {
587593
};
588594

589595
static PyObject *
590-
partial_repr(partialobject *pto)
596+
partial_repr(PyObject *self)
591597
{
598+
partialobject *pto = _PyPartialObject_CAST(self);
592599
PyObject *result = NULL;
593600
PyObject *arglist;
594601
PyObject *mod;
@@ -597,7 +604,7 @@ partial_repr(partialobject *pto)
597604
PyObject *key, *value;
598605
int status;
599606

600-
status = Py_ReprEnter((PyObject *)pto);
607+
status = Py_ReprEnter(self);
601608
if (status != 0) {
602609
if (status < 0)
603610
return NULL;
@@ -608,7 +615,7 @@ partial_repr(partialobject *pto)
608615
if (arglist == NULL)
609616
goto done;
610617
/* Pack positional arguments */
611-
assert (PyTuple_Check(pto->args));
618+
assert(PyTuple_Check(pto->args));
612619
n = PyTuple_GET_SIZE(pto->args);
613620
for (i = 0; i < n; i++) {
614621
Py_SETREF(arglist, PyUnicode_FromFormat("%U, %R", arglist,
@@ -643,11 +650,11 @@ partial_repr(partialobject *pto)
643650
Py_DECREF(arglist);
644651

645652
done:
646-
Py_ReprLeave((PyObject *)pto);
653+
Py_ReprLeave(self);
647654
return result;
648655
error:
649656
Py_DECREF(arglist);
650-
Py_ReprLeave((PyObject *)pto);
657+
Py_ReprLeave(self);
651658
return NULL;
652659
}
653660

@@ -659,16 +666,18 @@ partial_repr(partialobject *pto)
659666
*/
660667

661668
static PyObject *
662-
partial_reduce(partialobject *pto, PyObject *unused)
669+
partial_reduce(PyObject *self, PyObject *Py_UNUSED(args))
663670
{
671+
partialobject *pto = _PyPartialObject_CAST(self);
664672
return Py_BuildValue("O(O)(OOOO)", Py_TYPE(pto), pto->fn, pto->fn,
665673
pto->args, pto->kw,
666674
pto->dict ? pto->dict : Py_None);
667675
}
668676

669677
static PyObject *
670-
partial_setstate(partialobject *pto, PyObject *state)
678+
partial_setstate(PyObject *self, PyObject *state)
671679
{
680+
partialobject *pto = _PyPartialObject_CAST(self);
672681
PyObject *fn, *fnargs, *kw, *dict;
673682

674683
if (!PyTuple_Check(state)) {
@@ -730,8 +739,8 @@ partial_setstate(partialobject *pto, PyObject *state)
730739
}
731740

732741
static PyMethodDef partial_methods[] = {
733-
{"__reduce__", (PyCFunction)partial_reduce, METH_NOARGS},
734-
{"__setstate__", (PyCFunction)partial_setstate, METH_O},
742+
{"__reduce__", partial_reduce, METH_NOARGS},
743+
{"__setstate__", partial_setstate, METH_O},
735744
{"__class_getitem__", Py_GenericAlias,
736745
METH_O|METH_CLASS, PyDoc_STR("See PEP 585")},
737746
{NULL, NULL} /* sentinel */
@@ -749,7 +758,7 @@ static PyType_Slot partial_type_slots[] = {
749758
{Py_tp_methods, partial_methods},
750759
{Py_tp_members, partial_memberlist},
751760
{Py_tp_getset, partial_getsetlist},
752-
{Py_tp_descr_get, (descrgetfunc)partial_descr_get},
761+
{Py_tp_descr_get, partial_descr_get},
753762
{Py_tp_new, partial_new},
754763
{Py_tp_free, PyObject_GC_Del},
755764
{0, 0}

0 commit comments

Comments
 (0)