From 5c8027fef233a52a1a2e9cb75a83341096d2961d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Thu, 6 Feb 2025 16:35:21 +0100 Subject: [PATCH 1/7] fix UBSan failures for `typealiasobject` --- Objects/typevarobject.c | 51 ++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/Objects/typevarobject.c b/Objects/typevarobject.c index 4ed40aa71a595e..9dc8981d012a81 100644 --- a/Objects/typevarobject.c +++ b/Objects/typevarobject.c @@ -57,6 +57,8 @@ typedef struct { PyObject *module; } typealiasobject; +#define typealiasobject_CAST(op) ((typealiasobject *)(op)) + #include "clinic/typevarobject.c.h" /* NoDefault is a marker object to indicate that a parameter has no default. */ @@ -1822,7 +1824,7 @@ typealias_dealloc(PyObject *self) { PyTypeObject *tp = Py_TYPE(self); _PyObject_GC_UNTRACK(self); - typealiasobject *ta = (typealiasobject *)self; + typealiasobject *ta = typealiasobject_CAST(self); Py_DECREF(ta->name); Py_XDECREF(ta->type_params); Py_XDECREF(ta->compute_value); @@ -1859,16 +1861,16 @@ static PyMemberDef typealias_members[] = { }; static PyObject * -typealias_value(PyObject *self, void *unused) +typealias_value(PyObject *self, void *Py_UNUSED(closure)) { - typealiasobject *ta = (typealiasobject *)self; + typealiasobject *ta = typealiasobject_CAST(self); return typealias_get_value(ta); } static PyObject * -typealias_evaluate_value(PyObject *self, void *unused) +typealias_evaluate_value(PyObject *self, void *Py_UNUSED(closure)) { - typealiasobject *ta = (typealiasobject *)self; + typealiasobject *ta = typealiasobject_CAST(self); if (ta->compute_value != NULL) { return Py_NewRef(ta->compute_value); } @@ -1877,9 +1879,9 @@ typealias_evaluate_value(PyObject *self, void *unused) } static PyObject * -typealias_parameters(PyObject *self, void *unused) +typealias_parameters(PyObject *self, void *Py_UNUSED(closure)) { - typealiasobject *ta = (typealiasobject *)self; + typealiasobject *ta = typealiasobject_CAST(self); if (ta->type_params == NULL) { return PyTuple_New(0); } @@ -1887,9 +1889,9 @@ typealias_parameters(PyObject *self, void *unused) } static PyObject * -typealias_type_params(PyObject *self, void *unused) +typealias_type_params(PyObject *self, void *Py_UNUSED(closure)) { - typealiasobject *ta = (typealiasobject *)self; + typealiasobject *ta = typealiasobject_CAST(self); if (ta->type_params == NULL) { return PyTuple_New(0); } @@ -1897,9 +1899,9 @@ typealias_type_params(PyObject *self, void *unused) } static PyObject * -typealias_module(PyObject *self, void *unused) +typealias_module(PyObject *self, void *Py_UNUSED(closure)) { - typealiasobject *ta = (typealiasobject *)self; + typealiasobject *ta = typealiasobject_CAST(self); if (ta->module != NULL) { return Py_NewRef(ta->module); } @@ -1916,11 +1918,11 @@ typealias_module(PyObject *self, void *unused) } static PyGetSetDef typealias_getset[] = { - {"__parameters__", typealias_parameters, (setter)NULL, NULL, NULL}, - {"__type_params__", typealias_type_params, (setter)NULL, NULL, NULL}, - {"__value__", typealias_value, (setter)NULL, NULL, NULL}, - {"evaluate_value", typealias_evaluate_value, (setter)NULL, NULL, NULL}, - {"__module__", typealias_module, (setter)NULL, NULL, NULL}, + {"__parameters__", typealias_parameters, NULL, NULL, NULL}, + {"__type_params__", typealias_type_params, NULL, NULL, NULL}, + {"__value__", typealias_value, NULL, NULL, NULL}, + {"evaluate_value", typealias_evaluate_value, NULL, NULL, NULL}, + {"__module__", typealias_module, NULL, NULL, NULL}, {0} }; @@ -2001,8 +2003,9 @@ typealias_alloc(PyObject *name, PyObject *type_params, PyObject *compute_value, } static int -typealias_traverse(typealiasobject *self, visitproc visit, void *arg) +typealias_traverse(PyObject *op, visitproc visit, void *arg) { + typealiasobject *self = typealiasobject_CAST(op); Py_VISIT(self->type_params); Py_VISIT(self->compute_value); Py_VISIT(self->value); @@ -2011,8 +2014,9 @@ typealias_traverse(typealiasobject *self, visitproc visit, void *arg) } static int -typealias_clear(typealiasobject *self) +typealias_clear(PyObject *op) { + typealiasobject *self = typealiasobject_CAST(op); Py_CLEAR(self->type_params); Py_CLEAR(self->compute_value); Py_CLEAR(self->value); @@ -2033,14 +2037,15 @@ typealias_reduce_impl(typealiasobject *self) } static PyObject * -typealias_subscript(PyObject *self, PyObject *args) +typealias_subscript(PyObject *op, PyObject *args) { - if (((typealiasobject *)self)->type_params == NULL) { + typealiasobject *self = typealiasobject_CAST(op); + if (self->type_params == NULL) { PyErr_SetString(PyExc_TypeError, "Only generic type aliases are subscriptable"); return NULL; } - return Py_GenericAlias(self, args); + return Py_GenericAlias(op, args); } static PyMethodDef typealias_methods[] = { @@ -2133,8 +2138,8 @@ PyTypeObject _PyTypeAlias_Type = { .tp_dealloc = typealias_dealloc, .tp_new = typealias_new, .tp_free = PyObject_GC_Del, - .tp_traverse = (traverseproc)typealias_traverse, - .tp_clear = (inquiry)typealias_clear, + .tp_traverse = typealias_traverse, + .tp_clear = typealias_clear, .tp_repr = typealias_repr, .tp_as_number = &typealias_as_number, .tp_as_mapping = &typealias_as_mapping, From a0733f515d2cb66004154f1eee0491da157ab9ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Thu, 6 Feb 2025 16:41:44 +0100 Subject: [PATCH 2/7] fix UBSan failures for `paramspecobject` --- Objects/typevarobject.c | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/Objects/typevarobject.c b/Objects/typevarobject.c index 9dc8981d012a81..d0c6af8cc732fc 100644 --- a/Objects/typevarobject.c +++ b/Objects/typevarobject.c @@ -57,6 +57,7 @@ typedef struct { PyObject *module; } typealiasobject; +#define paramspecobject_CAST(op) ((paramspecobject *)(op)) #define typealiasobject_CAST(op) ((typealiasobject *)(op)) #include "clinic/typevarobject.c.h" @@ -1147,7 +1148,7 @@ static void paramspec_dealloc(PyObject *self) { PyTypeObject *tp = Py_TYPE(self); - paramspecobject *ps = (paramspecobject *)self; + paramspecobject *ps = paramspecobject_CAST(self); _PyObject_GC_UNTRACK(self); @@ -1166,7 +1167,7 @@ static int paramspec_traverse(PyObject *self, visitproc visit, void *arg) { Py_VISIT(Py_TYPE(self)); - paramspecobject *ps = (paramspecobject *)self; + paramspecobject *ps = paramspecobject_CAST(self); Py_VISIT(ps->bound); Py_VISIT(ps->default_value); Py_VISIT(ps->evaluate_default); @@ -1175,19 +1176,20 @@ paramspec_traverse(PyObject *self, visitproc visit, void *arg) } static int -paramspec_clear(paramspecobject *self) +paramspec_clear(PyObject *op) { + paramspecobject *self = paramspecobject_CAST(op); Py_CLEAR(self->bound); Py_CLEAR(self->default_value); Py_CLEAR(self->evaluate_default); - PyObject_ClearManagedDict((PyObject *)self); + PyObject_ClearManagedDict(op); return 0; } static PyObject * paramspec_repr(PyObject *self) { - paramspecobject *ps = (paramspecobject *)self; + paramspecobject *ps = paramspecobject_CAST(self); if (ps->infer_variance) { return Py_NewRef(ps->name); @@ -1207,22 +1209,23 @@ static PyMemberDef paramspec_members[] = { }; static PyObject * -paramspec_args(PyObject *self, void *unused) +paramspec_args(PyObject *self, void *Py_UNUSED(closure)) { PyTypeObject *tp = _PyInterpreterState_GET()->cached_objects.paramspecargs_type; return (PyObject *)paramspecattr_new(tp, self); } static PyObject * -paramspec_kwargs(PyObject *self, void *unused) +paramspec_kwargs(PyObject *self, void *Py_UNUSED(closure)) { PyTypeObject *tp = _PyInterpreterState_GET()->cached_objects.paramspeckwargs_type; return (PyObject *)paramspecattr_new(tp, self); } static PyObject * -paramspec_default(paramspecobject *self, void *unused) +paramspec_default(PyObject *op, void *Py_UNUSED(closure)) { + paramspecobject *self = paramspecobject_CAST(op); if (self->default_value != NULL) { return Py_NewRef(self->default_value); } @@ -1235,8 +1238,9 @@ paramspec_default(paramspecobject *self, void *unused) } static PyObject * -paramspec_evaluate_default(paramspecobject *self, void *unused) +paramspec_evaluate_default(PyObject *op, void *Py_UNUSED(closure)) { + paramspecobject *self = paramspecobject_CAST(op); if (self->evaluate_default != NULL) { return Py_NewRef(self->evaluate_default); } @@ -1247,10 +1251,10 @@ paramspec_evaluate_default(paramspecobject *self, void *unused) } static PyGetSetDef paramspec_getset[] = { - {"args", (getter)paramspec_args, NULL, PyDoc_STR("Represents positional arguments."), NULL}, - {"kwargs", (getter)paramspec_kwargs, NULL, PyDoc_STR("Represents keyword arguments."), NULL}, - {"__default__", (getter)paramspec_default, NULL, "The default value for this ParamSpec.", NULL}, - {"evaluate_default", (getter)paramspec_evaluate_default, NULL, NULL, NULL}, + {"args", paramspec_args, NULL, PyDoc_STR("Represents positional arguments."), NULL}, + {"kwargs", paramspec_kwargs, NULL, PyDoc_STR("Represents keyword arguments."), NULL}, + {"__default__", paramspec_default, NULL, "The default value for this ParamSpec.", NULL}, + {"evaluate_default", paramspec_evaluate_default, NULL, NULL, NULL}, {0}, }; @@ -1808,7 +1812,7 @@ get_type_param_default(PyThreadState *ts, PyObject *typeparam) { return typevar_default((typevarobject *)typeparam, NULL); } else if (Py_IS_TYPE(typeparam, ts->interp->cached_objects.paramspec_type)) { - return paramspec_default((paramspecobject *)typeparam, NULL); + return paramspec_default(typeparam, NULL); } else if (Py_IS_TYPE(typeparam, ts->interp->cached_objects.typevartuple_type)) { return typevartuple_default((typevartupleobject *)typeparam, NULL); From 549148742dd749a4c5f2f5e2b1801cd5c71f0ccf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Thu, 6 Feb 2025 16:44:06 +0100 Subject: [PATCH 3/7] fix UBSan failures for `typevarobject` --- Objects/typevarobject.c | 46 ++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/Objects/typevarobject.c b/Objects/typevarobject.c index d0c6af8cc732fc..47f0f335f194c0 100644 --- a/Objects/typevarobject.c +++ b/Objects/typevarobject.c @@ -57,6 +57,7 @@ typedef struct { PyObject *module; } typealiasobject; +#define typevarobject_CAST(op) ((typevarobject *)(op)) #define paramspecobject_CAST(op) ((paramspecobject *)(op)) #define typealiasobject_CAST(op) ((typealiasobject *)(op)) @@ -456,7 +457,7 @@ static void typevar_dealloc(PyObject *self) { PyTypeObject *tp = Py_TYPE(self); - typevarobject *tv = (typevarobject *)self; + typevarobject *tv = typevarobject_CAST(self); _PyObject_GC_UNTRACK(self); @@ -478,7 +479,7 @@ static int typevar_traverse(PyObject *self, visitproc visit, void *arg) { Py_VISIT(Py_TYPE(self)); - typevarobject *tv = (typevarobject *)self; + typevarobject *tv = typevarobject_CAST(self); Py_VISIT(tv->bound); Py_VISIT(tv->evaluate_bound); Py_VISIT(tv->constraints); @@ -490,22 +491,23 @@ typevar_traverse(PyObject *self, visitproc visit, void *arg) } static int -typevar_clear(typevarobject *self) +typevar_clear(PyObject *op) { + typevarobject *self = typevarobject_CAST(op); Py_CLEAR(self->bound); Py_CLEAR(self->evaluate_bound); Py_CLEAR(self->constraints); Py_CLEAR(self->evaluate_constraints); Py_CLEAR(self->default_value); Py_CLEAR(self->evaluate_default); - PyObject_ClearManagedDict((PyObject *)self); + PyObject_ClearManagedDict(op); return 0; } static PyObject * typevar_repr(PyObject *self) { - typevarobject *tv = (typevarobject *)self; + typevarobject *tv = typevarobject_CAST(self); if (tv->infer_variance) { return Py_NewRef(tv->name); @@ -524,8 +526,9 @@ static PyMemberDef typevar_members[] = { }; static PyObject * -typevar_bound(typevarobject *self, void *Py_UNUSED(ignored)) +typevar_bound(PyObject *op, void *Py_UNUSED(closure)) { + typevarobject *self = typevarobject_CAST(op); if (self->bound != NULL) { return Py_NewRef(self->bound); } @@ -538,8 +541,9 @@ typevar_bound(typevarobject *self, void *Py_UNUSED(ignored)) } static PyObject * -typevar_default(typevarobject *self, void *unused) +typevar_default(PyObject *op, void *Py_UNUSED(closure)) { + typevarobject *self = typevarobject_CAST(op); if (self->default_value != NULL) { return Py_NewRef(self->default_value); } @@ -552,8 +556,9 @@ typevar_default(typevarobject *self, void *unused) } static PyObject * -typevar_constraints(typevarobject *self, void *Py_UNUSED(ignored)) +typevar_constraints(PyObject *op, void *Py_UNUSED(closure)) { + typevarobject *self = typevarobject_CAST(op); if (self->constraints != NULL) { return Py_NewRef(self->constraints); } @@ -566,8 +571,9 @@ typevar_constraints(typevarobject *self, void *Py_UNUSED(ignored)) } static PyObject * -typevar_evaluate_bound(typevarobject *self, void *Py_UNUSED(ignored)) +typevar_evaluate_bound(PyObject *op, void *Py_UNUSED(closure)) { + typevarobject *self = typevarobject_CAST(op); if (self->evaluate_bound != NULL) { return Py_NewRef(self->evaluate_bound); } @@ -578,8 +584,9 @@ typevar_evaluate_bound(typevarobject *self, void *Py_UNUSED(ignored)) } static PyObject * -typevar_evaluate_constraints(typevarobject *self, void *Py_UNUSED(ignored)) +typevar_evaluate_constraints(PyObject *op, void *Py_UNUSED(closure)) { + typevarobject *self = typevarobject_CAST(op); if (self->evaluate_constraints != NULL) { return Py_NewRef(self->evaluate_constraints); } @@ -590,8 +597,9 @@ typevar_evaluate_constraints(typevarobject *self, void *Py_UNUSED(ignored)) } static PyObject * -typevar_evaluate_default(typevarobject *self, void *Py_UNUSED(ignored)) +typevar_evaluate_default(PyObject *op, void *Py_UNUSED(closure)) { + typevarobject *self = typevarobject_CAST(op); if (self->evaluate_default != NULL) { return Py_NewRef(self->evaluate_default); } @@ -602,12 +610,12 @@ typevar_evaluate_default(typevarobject *self, void *Py_UNUSED(ignored)) } static PyGetSetDef typevar_getset[] = { - {"__bound__", (getter)typevar_bound, NULL, NULL, NULL}, - {"__constraints__", (getter)typevar_constraints, NULL, NULL, NULL}, - {"__default__", (getter)typevar_default, NULL, NULL, NULL}, - {"evaluate_bound", (getter)typevar_evaluate_bound, NULL, NULL, NULL}, - {"evaluate_constraints", (getter)typevar_evaluate_constraints, NULL, NULL, NULL}, - {"evaluate_default", (getter)typevar_evaluate_default, NULL, NULL, NULL}, + {"__bound__", typevar_bound, NULL, NULL, NULL}, + {"__constraints__", typevar_constraints, NULL, NULL, NULL}, + {"__default__", typevar_default, NULL, NULL, NULL}, + {"evaluate_bound", typevar_evaluate_bound, NULL, NULL, NULL}, + {"evaluate_constraints", typevar_evaluate_constraints, NULL, NULL, NULL}, + {"evaluate_default", typevar_evaluate_default, NULL, NULL, NULL}, {0} }; @@ -775,7 +783,7 @@ typevar_typing_prepare_subst_impl(typevarobject *self, PyObject *alias, } else if (i == args_len) { // If the TypeVar has a default, use it. - PyObject *dflt = typevar_default(self, NULL); + PyObject *dflt = typevar_default((PyObject *)self, NULL); if (dflt == NULL) { Py_DECREF(params); return NULL; @@ -1809,7 +1817,7 @@ static PyObject * get_type_param_default(PyThreadState *ts, PyObject *typeparam) { // Does not modify refcount of existing objects. if (Py_IS_TYPE(typeparam, ts->interp->cached_objects.typevar_type)) { - return typevar_default((typevarobject *)typeparam, NULL); + return typevar_default(typeparam, NULL); } else if (Py_IS_TYPE(typeparam, ts->interp->cached_objects.paramspec_type)) { return paramspec_default(typeparam, NULL); From aea56055586a11271cb650d48942cc405bc1021f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Thu, 6 Feb 2025 16:46:30 +0100 Subject: [PATCH 4/7] fix UBSan failures for `typevartupleobject` --- Objects/typevarobject.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/Objects/typevarobject.c b/Objects/typevarobject.c index 47f0f335f194c0..8e3b51a4931a82 100644 --- a/Objects/typevarobject.c +++ b/Objects/typevarobject.c @@ -58,6 +58,7 @@ typedef struct { } typealiasobject; #define typevarobject_CAST(op) ((typevarobject *)(op)) +#define typevartupleobject_CAST(op) ((typevartupleobject *)(op)) #define paramspecobject_CAST(op) ((paramspecobject *)(op)) #define typealiasobject_CAST(op) ((typealiasobject *)(op)) @@ -1506,7 +1507,7 @@ typevartuple_dealloc(PyObject *self) { PyTypeObject *tp = Py_TYPE(self); _PyObject_GC_UNTRACK(self); - typevartupleobject *tvt = (typevartupleobject *)self; + typevartupleobject *tvt = typevartupleobject_CAST(self); Py_DECREF(tvt->name); Py_XDECREF(tvt->default_value); @@ -1539,8 +1540,7 @@ typevartuple_iter(PyObject *self) static PyObject * typevartuple_repr(PyObject *self) { - typevartupleobject *tvt = (typevartupleobject *)self; - + typevartupleobject *tvt = typevartupleobject_CAST(self); return Py_NewRef(tvt->name); } @@ -1672,8 +1672,9 @@ static int typevartuple_traverse(PyObject *self, visitproc visit, void *arg) { Py_VISIT(Py_TYPE(self)); - Py_VISIT(((typevartupleobject *)self)->default_value); - Py_VISIT(((typevartupleobject *)self)->evaluate_default); + typevartupleobject *tvt = typevartupleobject_CAST(self); + Py_VISIT(tvt->default_value); + Py_VISIT(tvt->evaluate_default); PyObject_VisitManagedDict(self, visit, arg); return 0; } @@ -1681,15 +1682,17 @@ typevartuple_traverse(PyObject *self, visitproc visit, void *arg) static int typevartuple_clear(PyObject *self) { - Py_CLEAR(((typevartupleobject *)self)->default_value); - Py_CLEAR(((typevartupleobject *)self)->evaluate_default); + typevartupleobject *tvt = typevartupleobject_CAST(self); + Py_CLEAR(tvt->default_value); + Py_CLEAR(tvt->evaluate_default); PyObject_ClearManagedDict(self); return 0; } static PyObject * -typevartuple_default(typevartupleobject *self, void *unused) +typevartuple_default(PyObject *op, void *Py_UNUSED(closure)) { + typevartupleobject *self = typevartupleobject_CAST(op); if (self->default_value != NULL) { return Py_NewRef(self->default_value); } @@ -1702,8 +1705,9 @@ typevartuple_default(typevartupleobject *self, void *unused) } static PyObject * -typevartuple_evaluate_default(typevartupleobject *self, void *unused) +typevartuple_evaluate_default(PyObject *op, void *Py_UNUSED(closure)) { + typevartupleobject *self = typevartupleobject_CAST(op); if (self->evaluate_default != NULL) { return Py_NewRef(self->evaluate_default); } @@ -1714,8 +1718,8 @@ typevartuple_evaluate_default(typevartupleobject *self, void *unused) } static PyGetSetDef typevartuple_getset[] = { - {"__default__", (getter)typevartuple_default, NULL, "The default value for this TypeVarTuple.", NULL}, - {"evaluate_default", (getter)typevartuple_evaluate_default, NULL, NULL, NULL}, + {"__default__", typevartuple_default, NULL, "The default value for this TypeVarTuple.", NULL}, + {"evaluate_default", typevartuple_evaluate_default, NULL, NULL, NULL}, {0}, }; @@ -1823,7 +1827,7 @@ get_type_param_default(PyThreadState *ts, PyObject *typeparam) { return paramspec_default(typeparam, NULL); } else if (Py_IS_TYPE(typeparam, ts->interp->cached_objects.typevartuple_type)) { - return typevartuple_default((typevartupleobject *)typeparam, NULL); + return typevartuple_default(typeparam, NULL); } else { PyErr_Format(PyExc_TypeError, "Expected a type param, got %R", typeparam); From 7ab32c59fa86ca70e592635738f9137ec6aa9c59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Thu, 6 Feb 2025 16:54:35 +0100 Subject: [PATCH 5/7] fix UBSan failures for `paramspecattrobject` This is the common interface for ParamSpec args and kwargs. --- Objects/typevarobject.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/Objects/typevarobject.c b/Objects/typevarobject.c index 8e3b51a4931a82..6734e17b0a6aed 100644 --- a/Objects/typevarobject.c +++ b/Objects/typevarobject.c @@ -930,11 +930,13 @@ typedef struct { PyObject *__origin__; } paramspecattrobject; +#define paramspecattrobject_CAST(op) ((paramspecattrobject *)(op)) + static void paramspecattr_dealloc(PyObject *self) { PyTypeObject *tp = Py_TYPE(self); - paramspecattrobject *psa = (paramspecattrobject *)self; + paramspecattrobject *psa = paramspecattrobject_CAST(self); _PyObject_GC_UNTRACK(self); @@ -947,14 +949,15 @@ paramspecattr_dealloc(PyObject *self) static int paramspecattr_traverse(PyObject *self, visitproc visit, void *arg) { - paramspecattrobject *psa = (paramspecattrobject *)self; + paramspecattrobject *psa = paramspecattrobject_CAST(self); Py_VISIT(psa->__origin__); return 0; } static int -paramspecattr_clear(paramspecattrobject *self) +paramspecattr_clear(PyObject *op) { + paramspecattrobject *self = paramspecattrobject_CAST(op); Py_CLEAR(self->__origin__); return 0; } @@ -968,11 +971,9 @@ paramspecattr_richcompare(PyObject *a, PyObject *b, int op) if (op != Py_EQ && op != Py_NE) { Py_RETURN_NOTIMPLEMENTED; } - return PyObject_RichCompare( - ((paramspecattrobject *)a)->__origin__, - ((paramspecattrobject *)b)->__origin__, - op - ); + paramspecattrobject *lhs = paramspecattrobject_CAST(a); // may be unsafe + paramspecattrobject *rhs = (paramspecattrobject *)b; // safe fast cast + return PyObject_RichCompare(lhs->__origin__, rhs->__origin__, op); } static PyMemberDef paramspecattr_members[] = { @@ -995,8 +996,7 @@ paramspecattr_new(PyTypeObject *tp, PyObject *origin) static PyObject * paramspecargs_repr(PyObject *self) { - paramspecattrobject *psa = (paramspecattrobject *)self; - + paramspecattrobject *psa = paramspecattrobject_CAST(self); PyTypeObject *tp = _PyInterpreterState_GET()->cached_objects.paramspec_type; if (Py_IS_TYPE(psa->__origin__, tp)) { return PyUnicode_FromFormat("%U.args", @@ -1058,7 +1058,7 @@ static PyType_Slot paramspecargs_slots[] = { {Py_tp_alloc, PyType_GenericAlloc}, {Py_tp_free, PyObject_GC_Del}, {Py_tp_traverse, paramspecattr_traverse}, - {Py_tp_clear, (inquiry)paramspecattr_clear}, + {Py_tp_clear, paramspecattr_clear}, {Py_tp_repr, paramspecargs_repr}, {Py_tp_members, paramspecattr_members}, {Py_tp_richcompare, paramspecattr_richcompare}, @@ -1076,7 +1076,7 @@ PyType_Spec paramspecargs_spec = { static PyObject * paramspeckwargs_repr(PyObject *self) { - paramspecattrobject *psk = (paramspecattrobject *)self; + paramspecattrobject *psk = paramspecattrobject_CAST(self); PyTypeObject *tp = _PyInterpreterState_GET()->cached_objects.paramspec_type; if (Py_IS_TYPE(psk->__origin__, tp)) { @@ -1138,7 +1138,7 @@ static PyType_Slot paramspeckwargs_slots[] = { {Py_tp_alloc, PyType_GenericAlloc}, {Py_tp_free, PyObject_GC_Del}, {Py_tp_traverse, paramspecattr_traverse}, - {Py_tp_clear, (inquiry)paramspecattr_clear}, + {Py_tp_clear, paramspecattr_clear}, {Py_tp_repr, paramspeckwargs_repr}, {Py_tp_members, paramspecattr_members}, {Py_tp_richcompare, paramspecattr_richcompare}, From 7d5768ac3d5bf7db61c2d2d259660d6bcba32632 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Thu, 6 Feb 2025 16:56:55 +0100 Subject: [PATCH 6/7] use _PyCFunction_CAST macros --- Objects/typevarobject.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Objects/typevarobject.c b/Objects/typevarobject.c index 6734e17b0a6aed..686869a451b191 100644 --- a/Objects/typevarobject.c +++ b/Objects/typevarobject.c @@ -2273,10 +2273,10 @@ _Py_subscript_generic(PyThreadState* unused, PyObject *params) } static PyMethodDef generic_methods[] = { - {"__class_getitem__", (PyCFunction)(void (*)(void))generic_class_getitem, + {"__class_getitem__", _PyCFunction_CAST(generic_class_getitem), METH_VARARGS | METH_KEYWORDS | METH_CLASS, generic_class_getitem_doc}, - {"__init_subclass__", (PyCFunction)(void (*)(void))generic_init_subclass, + {"__init_subclass__", _PyCFunction_CAST(generic_init_subclass), METH_VARARGS | METH_KEYWORDS | METH_CLASS, PyDoc_STR("Function to initialize subclasses.")}, {NULL} /* Sentinel */ From c8cbe9bf8ee4f4b82b4b55b7591d9490535b75b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Thu, 6 Feb 2025 16:58:40 +0100 Subject: [PATCH 7/7] use macro for `constevaluatorobject` casts --- Objects/typevarobject.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/Objects/typevarobject.c b/Objects/typevarobject.c index 686869a451b191..d8158293acaabd 100644 --- a/Objects/typevarobject.c +++ b/Objects/typevarobject.c @@ -126,11 +126,13 @@ typedef struct { PyObject *value; } constevaluatorobject; +#define constevaluatorobject_CAST(op) ((constevaluatorobject *)(op)) + static void constevaluator_dealloc(PyObject *self) { PyTypeObject *tp = Py_TYPE(self); - constevaluatorobject *ce = (constevaluatorobject *)self; + constevaluatorobject *ce = constevaluatorobject_CAST(self); _PyObject_GC_UNTRACK(self); @@ -143,7 +145,7 @@ constevaluator_dealloc(PyObject *self) static int constevaluator_traverse(PyObject *self, visitproc visit, void *arg) { - constevaluatorobject *ce = (constevaluatorobject *)self; + constevaluatorobject *ce = constevaluatorobject_CAST(self); Py_VISIT(ce->value); return 0; } @@ -151,20 +153,22 @@ constevaluator_traverse(PyObject *self, visitproc visit, void *arg) static int constevaluator_clear(PyObject *self) { - Py_CLEAR(((constevaluatorobject *)self)->value); + constevaluatorobject *ce = constevaluatorobject_CAST(self); + Py_CLEAR(ce->value); return 0; } static PyObject * constevaluator_repr(PyObject *self) { - PyObject *value = ((constevaluatorobject *)self)->value; - return PyUnicode_FromFormat("", value); + constevaluatorobject *ce = constevaluatorobject_CAST(self); + return PyUnicode_FromFormat("", ce->value); } static PyObject * constevaluator_call(PyObject *self, PyObject *args, PyObject *kwargs) { + constevaluatorobject *ce = constevaluatorobject_CAST(self); if (!_PyArg_NoKeywords("constevaluator.__call__", kwargs)) { return NULL; } @@ -172,7 +176,7 @@ constevaluator_call(PyObject *self, PyObject *args, PyObject *kwargs) if (!PyArg_ParseTuple(args, "i:constevaluator.__call__", &format)) { return NULL; } - PyObject *value = ((constevaluatorobject *)self)->value; + PyObject *value = ce->value; if (format == _Py_ANNOTATE_FORMAT_STRING) { PyUnicodeWriter *writer = PyUnicodeWriter_Create(5); // cannot be <5 if (writer == NULL) {