bpo-46417: Add _PyType_CAST() macro (GH-30760)

In debug mode, the macro makes sure that its argument is a type using
an assertion.
This commit is contained in:
Victor Stinner 2022-01-21 21:39:01 +01:00 committed by GitHub
parent 60705cff70
commit bc67f189fd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 50 additions and 58 deletions

View File

@ -755,6 +755,8 @@ static inline int _PyType_Check(PyObject *op) {
} }
#define PyType_Check(op) _PyType_Check(_PyObject_CAST(op)) #define PyType_Check(op) _PyType_Check(_PyObject_CAST(op))
#define _PyType_CAST(op) (assert(PyType_Check(op)), (PyTypeObject*)(op))
static inline int _PyType_CheckExact(PyObject *op) { static inline int _PyType_CheckExact(PyObject *op) {
return Py_IS_TYPE(op, &PyType_Type); return Py_IS_TYPE(op, &PyType_Type);
} }

View File

@ -77,7 +77,7 @@ typedef struct {
static void **PyCurses_API; static void **PyCurses_API;
#define PyCursesWindow_Type (*(PyTypeObject *) PyCurses_API[0]) #define PyCursesWindow_Type (*_PyType_CAST(PyCurses_API[0]))
#define PyCursesSetupTermCalled {if (! ((int (*)(void))PyCurses_API[1]) () ) return NULL;} #define PyCursesSetupTermCalled {if (! ((int (*)(void))PyCurses_API[1]) () ) return NULL;}
#define PyCursesInitialised {if (! ((int (*)(void))PyCurses_API[2]) () ) return NULL;} #define PyCursesInitialised {if (! ((int (*)(void))PyCurses_API[2]) () ) return NULL;}
#define PyCursesInitialisedColor {if (! ((int (*)(void))PyCurses_API[3]) () ) return NULL;} #define PyCursesInitialisedColor {if (! ((int (*)(void))PyCurses_API[3]) () ) return NULL;}

View File

@ -342,7 +342,7 @@ PyType_Modified(PyTypeObject *type)
assert(PyWeakref_CheckRef(ref)); assert(PyWeakref_CheckRef(ref));
ref = PyWeakref_GET_OBJECT(ref); ref = PyWeakref_GET_OBJECT(ref);
if (ref != Py_None) { if (ref != Py_None) {
PyType_Modified((PyTypeObject *)ref); PyType_Modified(_PyType_CAST(ref));
} }
} }
} }
@ -387,10 +387,7 @@ type_mro_modified(PyTypeObject *type, PyObject *bases) {
n = PyTuple_GET_SIZE(bases); n = PyTuple_GET_SIZE(bases);
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
PyObject *b = PyTuple_GET_ITEM(bases, i); PyObject *b = PyTuple_GET_ITEM(bases, i);
PyTypeObject *cls; PyTypeObject *cls = _PyType_CAST(b);
assert(PyType_Check(b));
cls = (PyTypeObject *)b;
if (!PyType_IsSubtype(type, cls)) { if (!PyType_IsSubtype(type, cls)) {
goto clear; goto clear;
@ -431,8 +428,7 @@ assign_version_tag(struct type_cache *cache, PyTypeObject *type)
n = PyTuple_GET_SIZE(bases); n = PyTuple_GET_SIZE(bases);
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
PyObject *b = PyTuple_GET_ITEM(bases, i); PyObject *b = PyTuple_GET_ITEM(bases, i);
assert(PyType_Check(b)); if (!assign_version_tag(cache, _PyType_CAST(b)))
if (!assign_version_tag(cache, (PyTypeObject *)b))
return 0; return 0;
} }
type->tp_flags |= Py_TPFLAGS_VALID_VERSION_TAG; type->tp_flags |= Py_TPFLAGS_VALID_VERSION_TAG;
@ -736,8 +732,7 @@ mro_hierarchy(PyTypeObject *type, PyObject *temp)
return -1; return -1;
n = PyList_GET_SIZE(subclasses); n = PyList_GET_SIZE(subclasses);
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
PyTypeObject *subclass; PyTypeObject *subclass = _PyType_CAST(PyList_GET_ITEM(subclasses, i));
subclass = (PyTypeObject *)PyList_GET_ITEM(subclasses, i);
res = mro_hierarchy(subclass, temp); res = mro_hierarchy(subclass, temp);
if (res < 0) if (res < 0)
break; break;
@ -771,18 +766,15 @@ type_set_bases(PyTypeObject *type, PyObject *new_bases, void *context)
return -1; return -1;
} }
for (i = 0; i < PyTuple_GET_SIZE(new_bases); i++) { for (i = 0; i < PyTuple_GET_SIZE(new_bases); i++) {
PyObject *ob; PyObject *ob = PyTuple_GET_ITEM(new_bases, i);
PyTypeObject *base;
ob = PyTuple_GET_ITEM(new_bases, i);
if (!PyType_Check(ob)) { if (!PyType_Check(ob)) {
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"%s.__bases__ must be tuple of classes, not '%s'", "%s.__bases__ must be tuple of classes, not '%s'",
type->tp_name, Py_TYPE(ob)->tp_name); type->tp_name, Py_TYPE(ob)->tp_name);
return -1; return -1;
} }
PyTypeObject *base = (PyTypeObject*)ob;
base = (PyTypeObject*)ob;
if (PyType_IsSubtype(base, type) || if (PyType_IsSubtype(base, type) ||
/* In case of reentering here again through a custom mro() /* In case of reentering here again through a custom mro()
the above check is not enough since it relies on the above check is not enough since it relies on
@ -1947,7 +1939,7 @@ mro_implementation(PyTypeObject *type)
assert(PyTuple_Check(bases)); assert(PyTuple_Check(bases));
n = PyTuple_GET_SIZE(bases); n = PyTuple_GET_SIZE(bases);
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
PyTypeObject *base = (PyTypeObject *)PyTuple_GET_ITEM(bases, i); PyTypeObject *base = _PyType_CAST(PyTuple_GET_ITEM(bases, i));
if (base->tp_mro == NULL) { if (base->tp_mro == NULL) {
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"Cannot extend an incomplete type '%.100s'", "Cannot extend an incomplete type '%.100s'",
@ -1961,7 +1953,7 @@ mro_implementation(PyTypeObject *type)
/* Fast path: if there is a single base, constructing the MRO /* Fast path: if there is a single base, constructing the MRO
* is trivial. * is trivial.
*/ */
PyTypeObject *base = (PyTypeObject *)PyTuple_GET_ITEM(bases, 0); PyTypeObject *base = _PyType_CAST(PyTuple_GET_ITEM(bases, 0));
Py_ssize_t k = PyTuple_GET_SIZE(base->tp_mro); Py_ssize_t k = PyTuple_GET_SIZE(base->tp_mro);
result = PyTuple_New(k + 1); result = PyTuple_New(k + 1);
if (result == NULL) { if (result == NULL) {
@ -1998,7 +1990,7 @@ mro_implementation(PyTypeObject *type)
} }
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
PyTypeObject *base = (PyTypeObject *)PyTuple_GET_ITEM(bases, i); PyTypeObject *base = _PyType_CAST(PyTuple_GET_ITEM(bases, i));
to_merge[i] = base->tp_mro; to_merge[i] = base->tp_mro;
} }
to_merge[n] = bases; to_merge[n] = bases;
@ -2047,19 +2039,16 @@ mro_check(PyTypeObject *type, PyObject *mro)
n = PyTuple_GET_SIZE(mro); n = PyTuple_GET_SIZE(mro);
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
PyTypeObject *base; PyObject *obj = PyTuple_GET_ITEM(mro, i);
PyObject *tmp; if (!PyType_Check(obj)) {
tmp = PyTuple_GET_ITEM(mro, i);
if (!PyType_Check(tmp)) {
PyErr_Format( PyErr_Format(
PyExc_TypeError, PyExc_TypeError,
"mro() returned a non-class ('%.500s')", "mro() returned a non-class ('%.500s')",
Py_TYPE(tmp)->tp_name); Py_TYPE(obj)->tp_name);
return -1; return -1;
} }
PyTypeObject *base = (PyTypeObject*)obj;
base = (PyTypeObject*)tmp;
if (!PyType_IsSubtype(solid, solid_base(base))) { if (!PyType_IsSubtype(solid, solid_base(base))) {
PyErr_Format( PyErr_Format(
PyExc_TypeError, PyExc_TypeError,
@ -2196,8 +2185,7 @@ static PyTypeObject *
best_base(PyObject *bases) best_base(PyObject *bases)
{ {
Py_ssize_t i, n; Py_ssize_t i, n;
PyTypeObject *base, *winner, *candidate, *base_i; PyTypeObject *base, *winner, *candidate;
PyObject *base_proto;
assert(PyTuple_Check(bases)); assert(PyTuple_Check(bases));
n = PyTuple_GET_SIZE(bases); n = PyTuple_GET_SIZE(bases);
@ -2205,14 +2193,15 @@ best_base(PyObject *bases)
base = NULL; base = NULL;
winner = NULL; winner = NULL;
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
base_proto = PyTuple_GET_ITEM(bases, i); PyObject *base_proto = PyTuple_GET_ITEM(bases, i);
if (!PyType_Check(base_proto)) { if (!PyType_Check(base_proto)) {
PyErr_SetString( PyErr_SetString(
PyExc_TypeError, PyExc_TypeError,
"bases must be types"); "bases must be types");
return NULL; return NULL;
} }
base_i = (PyTypeObject *)base_proto; PyTypeObject *base_i = (PyTypeObject *)base_proto;
if (!_PyType_IsReady(base_i)) { if (!_PyType_IsReady(base_i)) {
if (PyType_Ready(base_i) < 0) if (PyType_Ready(base_i) < 0)
return NULL; return NULL;
@ -2663,9 +2652,8 @@ type_new_slots_bases(type_new_ctx *ctx)
/* Skip primary base */ /* Skip primary base */
continue; continue;
} }
PyTypeObject *type = _PyType_CAST(base);
assert(PyType_Check(base));
PyTypeObject *type = (PyTypeObject *)base;
if (ctx->may_add_dict && ctx->add_dict == 0 && if (ctx->may_add_dict && ctx->add_dict == 0 &&
type->tp_dictoffset != 0) type->tp_dictoffset != 0)
{ {
@ -3754,7 +3742,7 @@ _PyType_GetModuleByDef(PyTypeObject *type, struct PyModuleDef *def)
// by PyType_FromModuleAndSpec() or on its subclasses. // by PyType_FromModuleAndSpec() or on its subclasses.
// type_ready_mro() ensures that a static type cannot inherit from a // type_ready_mro() ensures that a static type cannot inherit from a
// heap type. // heap type.
assert(_PyType_HasFeature((PyTypeObject *)type, Py_TPFLAGS_HEAPTYPE)); assert(_PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE));
PyHeapTypeObject *ht = (PyHeapTypeObject*)super; PyHeapTypeObject *ht = (PyHeapTypeObject*)super;
PyObject *module = ht->ht_module; PyObject *module = ht->ht_module;
@ -3818,7 +3806,7 @@ find_name_in_mro(PyTypeObject *type, PyObject *name, int *error)
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
base = PyTuple_GET_ITEM(mro, i); base = PyTuple_GET_ITEM(mro, i);
assert(PyType_Check(base)); assert(PyType_Check(base));
dict = ((PyTypeObject *)base)->tp_dict; dict = _PyType_CAST(base)->tp_dict;
assert(dict && PyDict_Check(dict)); assert(dict && PyDict_Check(dict));
res = _PyDict_GetItem_KnownHash(dict, name, hash); res = _PyDict_GetItem_KnownHash(dict, name, hash);
if (res != NULL) if (res != NULL)
@ -4780,7 +4768,6 @@ static int
object_set_class(PyObject *self, PyObject *value, void *closure) object_set_class(PyObject *self, PyObject *value, void *closure)
{ {
PyTypeObject *oldto = Py_TYPE(self); PyTypeObject *oldto = Py_TYPE(self);
PyTypeObject *newto;
if (value == NULL) { if (value == NULL) {
PyErr_SetString(PyExc_TypeError, PyErr_SetString(PyExc_TypeError,
@ -4793,12 +4780,13 @@ object_set_class(PyObject *self, PyObject *value, void *closure)
Py_TYPE(value)->tp_name); Py_TYPE(value)->tp_name);
return -1; return -1;
} }
PyTypeObject *newto = (PyTypeObject *)value;
if (PySys_Audit("object.__setattr__", "OsO", if (PySys_Audit("object.__setattr__", "OsO",
self, "__class__", value) < 0) { self, "__class__", value) < 0) {
return -1; return -1;
} }
newto = (PyTypeObject *)value;
/* In versions of CPython prior to 3.5, the code in /* In versions of CPython prior to 3.5, the code in
compatible_for_assignment was not set up to correctly check for memory compatible_for_assignment was not set up to correctly check for memory
layout / slot / etc. compatibility for non-HEAPTYPE classes, so we just layout / slot / etc. compatibility for non-HEAPTYPE classes, so we just
@ -6219,7 +6207,7 @@ type_ready_mro(PyTypeObject *type)
PyObject *mro = type->tp_mro; PyObject *mro = type->tp_mro;
Py_ssize_t n = PyTuple_GET_SIZE(mro); Py_ssize_t n = PyTuple_GET_SIZE(mro);
for (Py_ssize_t i = 0; i < n; i++) { for (Py_ssize_t i = 0; i < n; i++) {
PyTypeObject *base = (PyTypeObject *)PyTuple_GET_ITEM(mro, i); PyTypeObject *base = _PyType_CAST(PyTuple_GET_ITEM(mro, i));
if (PyType_Check(base) && (base->tp_flags & Py_TPFLAGS_HEAPTYPE)) { if (PyType_Check(base) && (base->tp_flags & Py_TPFLAGS_HEAPTYPE)) {
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"type '%.100s' is not dynamically allocated but " "type '%.100s' is not dynamically allocated but "
@ -6528,7 +6516,9 @@ add_all_subclasses(PyTypeObject *type, PyObject *bases)
PyObject *base = PyTuple_GET_ITEM(bases, i); PyObject *base = PyTuple_GET_ITEM(bases, i);
if (PyType_Check(base) && if (PyType_Check(base) &&
add_subclass((PyTypeObject*)base, type) < 0) add_subclass((PyTypeObject*)base, type) < 0)
{
res = -1; res = -1;
}
} }
} }
@ -6562,8 +6552,9 @@ remove_all_subclasses(PyTypeObject *type, PyObject *bases)
Py_ssize_t i; Py_ssize_t i;
for (i = 0; i < PyTuple_GET_SIZE(bases); i++) { for (i = 0; i < PyTuple_GET_SIZE(bases); i++) {
PyObject *base = PyTuple_GET_ITEM(bases, i); PyObject *base = PyTuple_GET_ITEM(bases, i);
if (PyType_Check(base)) if (PyType_Check(base)) {
remove_subclass((PyTypeObject*) base, type); remove_subclass((PyTypeObject*) base, type);
}
} }
} }
} }
@ -6857,7 +6848,7 @@ hackcheck(PyObject *self, setattrofunc func, const char *what)
PyTypeObject *defining_type = type; PyTypeObject *defining_type = type;
Py_ssize_t i; Py_ssize_t i;
for (i = PyTuple_GET_SIZE(mro) - 1; i >= 0; i--) { for (i = PyTuple_GET_SIZE(mro) - 1; i >= 0; i--) {
PyTypeObject *base = (PyTypeObject*) PyTuple_GET_ITEM(mro, i); PyTypeObject *base = _PyType_CAST(PyTuple_GET_ITEM(mro, i));
if (base->tp_setattro == slot_tp_setattro) { if (base->tp_setattro == slot_tp_setattro) {
/* Ignore Python classes: /* Ignore Python classes:
they never define their own C-level setattro. */ they never define their own C-level setattro. */
@ -7062,7 +7053,7 @@ wrap_init(PyObject *self, PyObject *args, void *wrapped, PyObject *kwds)
static PyObject * static PyObject *
tp_new_wrapper(PyObject *self, PyObject *args, PyObject *kwds) tp_new_wrapper(PyObject *self, PyObject *args, PyObject *kwds)
{ {
PyTypeObject *type, *subtype, *staticbase; PyTypeObject *staticbase;
PyObject *arg0, *res; PyObject *arg0, *res;
if (self == NULL || !PyType_Check(self)) { if (self == NULL || !PyType_Check(self)) {
@ -7070,7 +7061,7 @@ tp_new_wrapper(PyObject *self, PyObject *args, PyObject *kwds)
"__new__() called with non-type 'self'"); "__new__() called with non-type 'self'");
return NULL; return NULL;
} }
type = (PyTypeObject *)self; PyTypeObject *type = (PyTypeObject *)self;
if (!PyTuple_Check(args) || PyTuple_GET_SIZE(args) < 1) { if (!PyTuple_Check(args) || PyTuple_GET_SIZE(args) < 1) {
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
@ -7086,7 +7077,8 @@ tp_new_wrapper(PyObject *self, PyObject *args, PyObject *kwds)
Py_TYPE(arg0)->tp_name); Py_TYPE(arg0)->tp_name);
return NULL; return NULL;
} }
subtype = (PyTypeObject *)arg0; PyTypeObject *subtype = (PyTypeObject *)arg0;
if (!PyType_IsSubtype(subtype, type)) { if (!PyType_IsSubtype(subtype, type)) {
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"%s.__new__(%s): %s is not a subtype of %s", "%s.__new__(%s): %s is not a subtype of %s",
@ -8646,7 +8638,6 @@ static int
recurse_down_subclasses(PyTypeObject *type, PyObject *name, recurse_down_subclasses(PyTypeObject *type, PyObject *name,
update_callback callback, void *data) update_callback callback, void *data)
{ {
PyTypeObject *subclass;
PyObject *ref, *subclasses, *dict; PyObject *ref, *subclasses, *dict;
Py_ssize_t i; Py_ssize_t i;
@ -8657,11 +8648,13 @@ recurse_down_subclasses(PyTypeObject *type, PyObject *name,
i = 0; i = 0;
while (PyDict_Next(subclasses, &i, NULL, &ref)) { while (PyDict_Next(subclasses, &i, NULL, &ref)) {
assert(PyWeakref_CheckRef(ref)); assert(PyWeakref_CheckRef(ref));
subclass = (PyTypeObject *)PyWeakref_GET_OBJECT(ref); PyObject *obj = PyWeakref_GET_OBJECT(ref);
assert(subclass != NULL); assert(obj != NULL);
if ((PyObject *)subclass == Py_None) if (obj == Py_None) {
continue; continue;
assert(PyType_Check(subclass)); }
PyTypeObject *subclass = _PyType_CAST(obj);
/* Avoid recursing down into unaffected classes */ /* Avoid recursing down into unaffected classes */
dict = subclass->tp_dict; dict = subclass->tp_dict;
if (dict != NULL && PyDict_Check(dict)) { if (dict != NULL && PyDict_Check(dict)) {
@ -8838,28 +8831,24 @@ super_getattro(PyObject *self, PyObject *name)
replaced during PyDict_GetItemWithError(dict, name) */ replaced during PyDict_GetItemWithError(dict, name) */
Py_INCREF(mro); Py_INCREF(mro);
do { do {
PyObject *res, *tmp, *dict; PyObject *obj = PyTuple_GET_ITEM(mro, i);
descrgetfunc f; PyObject *dict = _PyType_CAST(obj)->tp_dict;
tmp = PyTuple_GET_ITEM(mro, i);
assert(PyType_Check(tmp));
dict = ((PyTypeObject *)tmp)->tp_dict;
assert(dict != NULL && PyDict_Check(dict)); assert(dict != NULL && PyDict_Check(dict));
res = PyDict_GetItemWithError(dict, name); PyObject *res = PyDict_GetItemWithError(dict, name);
if (res != NULL) { if (res != NULL) {
Py_INCREF(res); Py_INCREF(res);
f = Py_TYPE(res)->tp_descr_get; descrgetfunc f = Py_TYPE(res)->tp_descr_get;
if (f != NULL) { if (f != NULL) {
tmp = f(res, PyObject *res2;
res2 = f(res,
/* Only pass 'obj' param if this is instance-mode super /* Only pass 'obj' param if this is instance-mode super
(See SF ID #743627) */ (See SF ID #743627) */
(su->obj == (PyObject *)starttype) ? NULL : su->obj, (su->obj == (PyObject *)starttype) ? NULL : su->obj,
(PyObject *)starttype); (PyObject *)starttype);
Py_DECREF(res); Py_DECREF(res);
res = tmp; res = res2;
} }
Py_DECREF(mro); Py_DECREF(mro);
@ -8920,8 +8909,9 @@ supercheck(PyTypeObject *type, PyObject *obj)
{ {
int ok = PyType_IsSubtype( int ok = PyType_IsSubtype(
(PyTypeObject *)class_attr, type); (PyTypeObject *)class_attr, type);
if (ok) if (ok) {
return (PyTypeObject *)class_attr; return (PyTypeObject *)class_attr;
}
} }
Py_XDECREF(class_attr); Py_XDECREF(class_attr);
} }