Skip to content

Commit bc67f18

Browse files
authored
bpo-46417: Add _PyType_CAST() macro (pythonGH-30760)
In debug mode, the macro makes sure that its argument is a type using an assertion.
1 parent 60705cf commit bc67f18

File tree

3 files changed

+50
-58
lines changed

3 files changed

+50
-58
lines changed

Include/object.h

+2
Original file line numberDiff line numberDiff line change
@@ -755,6 +755,8 @@ static inline int _PyType_Check(PyObject *op) {
755755
}
756756
#define PyType_Check(op) _PyType_Check(_PyObject_CAST(op))
757757

758+
#define _PyType_CAST(op) (assert(PyType_Check(op)), (PyTypeObject*)(op))
759+
758760
static inline int _PyType_CheckExact(PyObject *op) {
759761
return Py_IS_TYPE(op, &PyType_Type);
760762
}

Include/py_curses.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ typedef struct {
7777

7878
static void **PyCurses_API;
7979

80-
#define PyCursesWindow_Type (*(PyTypeObject *) PyCurses_API[0])
80+
#define PyCursesWindow_Type (*_PyType_CAST(PyCurses_API[0]))
8181
#define PyCursesSetupTermCalled {if (! ((int (*)(void))PyCurses_API[1]) () ) return NULL;}
8282
#define PyCursesInitialised {if (! ((int (*)(void))PyCurses_API[2]) () ) return NULL;}
8383
#define PyCursesInitialisedColor {if (! ((int (*)(void))PyCurses_API[3]) () ) return NULL;}

Objects/typeobject.c

+47-57
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ PyType_Modified(PyTypeObject *type)
342342
assert(PyWeakref_CheckRef(ref));
343343
ref = PyWeakref_GET_OBJECT(ref);
344344
if (ref != Py_None) {
345-
PyType_Modified((PyTypeObject *)ref);
345+
PyType_Modified(_PyType_CAST(ref));
346346
}
347347
}
348348
}
@@ -387,10 +387,7 @@ type_mro_modified(PyTypeObject *type, PyObject *bases) {
387387
n = PyTuple_GET_SIZE(bases);
388388
for (i = 0; i < n; i++) {
389389
PyObject *b = PyTuple_GET_ITEM(bases, i);
390-
PyTypeObject *cls;
391-
392-
assert(PyType_Check(b));
393-
cls = (PyTypeObject *)b;
390+
PyTypeObject *cls = _PyType_CAST(b);
394391

395392
if (!PyType_IsSubtype(type, cls)) {
396393
goto clear;
@@ -431,8 +428,7 @@ assign_version_tag(struct type_cache *cache, PyTypeObject *type)
431428
n = PyTuple_GET_SIZE(bases);
432429
for (i = 0; i < n; i++) {
433430
PyObject *b = PyTuple_GET_ITEM(bases, i);
434-
assert(PyType_Check(b));
435-
if (!assign_version_tag(cache, (PyTypeObject *)b))
431+
if (!assign_version_tag(cache, _PyType_CAST(b)))
436432
return 0;
437433
}
438434
type->tp_flags |= Py_TPFLAGS_VALID_VERSION_TAG;
@@ -736,8 +732,7 @@ mro_hierarchy(PyTypeObject *type, PyObject *temp)
736732
return -1;
737733
n = PyList_GET_SIZE(subclasses);
738734
for (i = 0; i < n; i++) {
739-
PyTypeObject *subclass;
740-
subclass = (PyTypeObject *)PyList_GET_ITEM(subclasses, i);
735+
PyTypeObject *subclass = _PyType_CAST(PyList_GET_ITEM(subclasses, i));
741736
res = mro_hierarchy(subclass, temp);
742737
if (res < 0)
743738
break;
@@ -771,18 +766,15 @@ type_set_bases(PyTypeObject *type, PyObject *new_bases, void *context)
771766
return -1;
772767
}
773768
for (i = 0; i < PyTuple_GET_SIZE(new_bases); i++) {
774-
PyObject *ob;
775-
PyTypeObject *base;
776-
777-
ob = PyTuple_GET_ITEM(new_bases, i);
769+
PyObject *ob = PyTuple_GET_ITEM(new_bases, i);
778770
if (!PyType_Check(ob)) {
779771
PyErr_Format(PyExc_TypeError,
780772
"%s.__bases__ must be tuple of classes, not '%s'",
781773
type->tp_name, Py_TYPE(ob)->tp_name);
782774
return -1;
783775
}
776+
PyTypeObject *base = (PyTypeObject*)ob;
784777

785-
base = (PyTypeObject*)ob;
786778
if (PyType_IsSubtype(base, type) ||
787779
/* In case of reentering here again through a custom mro()
788780
the above check is not enough since it relies on
@@ -1947,7 +1939,7 @@ mro_implementation(PyTypeObject *type)
19471939
assert(PyTuple_Check(bases));
19481940
n = PyTuple_GET_SIZE(bases);
19491941
for (i = 0; i < n; i++) {
1950-
PyTypeObject *base = (PyTypeObject *)PyTuple_GET_ITEM(bases, i);
1942+
PyTypeObject *base = _PyType_CAST(PyTuple_GET_ITEM(bases, i));
19511943
if (base->tp_mro == NULL) {
19521944
PyErr_Format(PyExc_TypeError,
19531945
"Cannot extend an incomplete type '%.100s'",
@@ -1961,7 +1953,7 @@ mro_implementation(PyTypeObject *type)
19611953
/* Fast path: if there is a single base, constructing the MRO
19621954
* is trivial.
19631955
*/
1964-
PyTypeObject *base = (PyTypeObject *)PyTuple_GET_ITEM(bases, 0);
1956+
PyTypeObject *base = _PyType_CAST(PyTuple_GET_ITEM(bases, 0));
19651957
Py_ssize_t k = PyTuple_GET_SIZE(base->tp_mro);
19661958
result = PyTuple_New(k + 1);
19671959
if (result == NULL) {
@@ -1998,7 +1990,7 @@ mro_implementation(PyTypeObject *type)
19981990
}
19991991

20001992
for (i = 0; i < n; i++) {
2001-
PyTypeObject *base = (PyTypeObject *)PyTuple_GET_ITEM(bases, i);
1993+
PyTypeObject *base = _PyType_CAST(PyTuple_GET_ITEM(bases, i));
20021994
to_merge[i] = base->tp_mro;
20031995
}
20041996
to_merge[n] = bases;
@@ -2047,19 +2039,16 @@ mro_check(PyTypeObject *type, PyObject *mro)
20472039

20482040
n = PyTuple_GET_SIZE(mro);
20492041
for (i = 0; i < n; i++) {
2050-
PyTypeObject *base;
2051-
PyObject *tmp;
2052-
2053-
tmp = PyTuple_GET_ITEM(mro, i);
2054-
if (!PyType_Check(tmp)) {
2042+
PyObject *obj = PyTuple_GET_ITEM(mro, i);
2043+
if (!PyType_Check(obj)) {
20552044
PyErr_Format(
20562045
PyExc_TypeError,
20572046
"mro() returned a non-class ('%.500s')",
2058-
Py_TYPE(tmp)->tp_name);
2047+
Py_TYPE(obj)->tp_name);
20592048
return -1;
20602049
}
2050+
PyTypeObject *base = (PyTypeObject*)obj;
20612051

2062-
base = (PyTypeObject*)tmp;
20632052
if (!PyType_IsSubtype(solid, solid_base(base))) {
20642053
PyErr_Format(
20652054
PyExc_TypeError,
@@ -2196,23 +2185,23 @@ static PyTypeObject *
21962185
best_base(PyObject *bases)
21972186
{
21982187
Py_ssize_t i, n;
2199-
PyTypeObject *base, *winner, *candidate, *base_i;
2200-
PyObject *base_proto;
2188+
PyTypeObject *base, *winner, *candidate;
22012189

22022190
assert(PyTuple_Check(bases));
22032191
n = PyTuple_GET_SIZE(bases);
22042192
assert(n > 0);
22052193
base = NULL;
22062194
winner = NULL;
22072195
for (i = 0; i < n; i++) {
2208-
base_proto = PyTuple_GET_ITEM(bases, i);
2196+
PyObject *base_proto = PyTuple_GET_ITEM(bases, i);
22092197
if (!PyType_Check(base_proto)) {
22102198
PyErr_SetString(
22112199
PyExc_TypeError,
22122200
"bases must be types");
22132201
return NULL;
22142202
}
2215-
base_i = (PyTypeObject *)base_proto;
2203+
PyTypeObject *base_i = (PyTypeObject *)base_proto;
2204+
22162205
if (!_PyType_IsReady(base_i)) {
22172206
if (PyType_Ready(base_i) < 0)
22182207
return NULL;
@@ -2663,9 +2652,8 @@ type_new_slots_bases(type_new_ctx *ctx)
26632652
/* Skip primary base */
26642653
continue;
26652654
}
2655+
PyTypeObject *type = _PyType_CAST(base);
26662656

2667-
assert(PyType_Check(base));
2668-
PyTypeObject *type = (PyTypeObject *)base;
26692657
if (ctx->may_add_dict && ctx->add_dict == 0 &&
26702658
type->tp_dictoffset != 0)
26712659
{
@@ -3754,7 +3742,7 @@ _PyType_GetModuleByDef(PyTypeObject *type, struct PyModuleDef *def)
37543742
// by PyType_FromModuleAndSpec() or on its subclasses.
37553743
// type_ready_mro() ensures that a static type cannot inherit from a
37563744
// heap type.
3757-
assert(_PyType_HasFeature((PyTypeObject *)type, Py_TPFLAGS_HEAPTYPE));
3745+
assert(_PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE));
37583746

37593747
PyHeapTypeObject *ht = (PyHeapTypeObject*)super;
37603748
PyObject *module = ht->ht_module;
@@ -3818,7 +3806,7 @@ find_name_in_mro(PyTypeObject *type, PyObject *name, int *error)
38183806
for (i = 0; i < n; i++) {
38193807
base = PyTuple_GET_ITEM(mro, i);
38203808
assert(PyType_Check(base));
3821-
dict = ((PyTypeObject *)base)->tp_dict;
3809+
dict = _PyType_CAST(base)->tp_dict;
38223810
assert(dict && PyDict_Check(dict));
38233811
res = _PyDict_GetItem_KnownHash(dict, name, hash);
38243812
if (res != NULL)
@@ -4780,7 +4768,6 @@ static int
47804768
object_set_class(PyObject *self, PyObject *value, void *closure)
47814769
{
47824770
PyTypeObject *oldto = Py_TYPE(self);
4783-
PyTypeObject *newto;
47844771

47854772
if (value == NULL) {
47864773
PyErr_SetString(PyExc_TypeError,
@@ -4793,12 +4780,13 @@ object_set_class(PyObject *self, PyObject *value, void *closure)
47934780
Py_TYPE(value)->tp_name);
47944781
return -1;
47954782
}
4783+
PyTypeObject *newto = (PyTypeObject *)value;
4784+
47964785
if (PySys_Audit("object.__setattr__", "OsO",
47974786
self, "__class__", value) < 0) {
47984787
return -1;
47994788
}
48004789

4801-
newto = (PyTypeObject *)value;
48024790
/* In versions of CPython prior to 3.5, the code in
48034791
compatible_for_assignment was not set up to correctly check for memory
48044792
layout / slot / etc. compatibility for non-HEAPTYPE classes, so we just
@@ -6219,7 +6207,7 @@ type_ready_mro(PyTypeObject *type)
62196207
PyObject *mro = type->tp_mro;
62206208
Py_ssize_t n = PyTuple_GET_SIZE(mro);
62216209
for (Py_ssize_t i = 0; i < n; i++) {
6222-
PyTypeObject *base = (PyTypeObject *)PyTuple_GET_ITEM(mro, i);
6210+
PyTypeObject *base = _PyType_CAST(PyTuple_GET_ITEM(mro, i));
62236211
if (PyType_Check(base) && (base->tp_flags & Py_TPFLAGS_HEAPTYPE)) {
62246212
PyErr_Format(PyExc_TypeError,
62256213
"type '%.100s' is not dynamically allocated but "
@@ -6528,7 +6516,9 @@ add_all_subclasses(PyTypeObject *type, PyObject *bases)
65286516
PyObject *base = PyTuple_GET_ITEM(bases, i);
65296517
if (PyType_Check(base) &&
65306518
add_subclass((PyTypeObject*)base, type) < 0)
6519+
{
65316520
res = -1;
6521+
}
65326522
}
65336523
}
65346524

@@ -6562,8 +6552,9 @@ remove_all_subclasses(PyTypeObject *type, PyObject *bases)
65626552
Py_ssize_t i;
65636553
for (i = 0; i < PyTuple_GET_SIZE(bases); i++) {
65646554
PyObject *base = PyTuple_GET_ITEM(bases, i);
6565-
if (PyType_Check(base))
6555+
if (PyType_Check(base)) {
65666556
remove_subclass((PyTypeObject*) base, type);
6557+
}
65676558
}
65686559
}
65696560
}
@@ -6857,7 +6848,7 @@ hackcheck(PyObject *self, setattrofunc func, const char *what)
68576848
PyTypeObject *defining_type = type;
68586849
Py_ssize_t i;
68596850
for (i = PyTuple_GET_SIZE(mro) - 1; i >= 0; i--) {
6860-
PyTypeObject *base = (PyTypeObject*) PyTuple_GET_ITEM(mro, i);
6851+
PyTypeObject *base = _PyType_CAST(PyTuple_GET_ITEM(mro, i));
68616852
if (base->tp_setattro == slot_tp_setattro) {
68626853
/* Ignore Python classes:
68636854
they never define their own C-level setattro. */
@@ -7062,15 +7053,15 @@ wrap_init(PyObject *self, PyObject *args, void *wrapped, PyObject *kwds)
70627053
static PyObject *
70637054
tp_new_wrapper(PyObject *self, PyObject *args, PyObject *kwds)
70647055
{
7065-
PyTypeObject *type, *subtype, *staticbase;
7056+
PyTypeObject *staticbase;
70667057
PyObject *arg0, *res;
70677058

70687059
if (self == NULL || !PyType_Check(self)) {
70697060
PyErr_Format(PyExc_SystemError,
70707061
"__new__() called with non-type 'self'");
70717062
return NULL;
70727063
}
7073-
type = (PyTypeObject *)self;
7064+
PyTypeObject *type = (PyTypeObject *)self;
70747065

70757066
if (!PyTuple_Check(args) || PyTuple_GET_SIZE(args) < 1) {
70767067
PyErr_Format(PyExc_TypeError,
@@ -7086,7 +7077,8 @@ tp_new_wrapper(PyObject *self, PyObject *args, PyObject *kwds)
70867077
Py_TYPE(arg0)->tp_name);
70877078
return NULL;
70887079
}
7089-
subtype = (PyTypeObject *)arg0;
7080+
PyTypeObject *subtype = (PyTypeObject *)arg0;
7081+
70907082
if (!PyType_IsSubtype(subtype, type)) {
70917083
PyErr_Format(PyExc_TypeError,
70927084
"%s.__new__(%s): %s is not a subtype of %s",
@@ -8646,7 +8638,6 @@ static int
86468638
recurse_down_subclasses(PyTypeObject *type, PyObject *name,
86478639
update_callback callback, void *data)
86488640
{
8649-
PyTypeObject *subclass;
86508641
PyObject *ref, *subclasses, *dict;
86518642
Py_ssize_t i;
86528643

@@ -8657,11 +8648,13 @@ recurse_down_subclasses(PyTypeObject *type, PyObject *name,
86578648
i = 0;
86588649
while (PyDict_Next(subclasses, &i, NULL, &ref)) {
86598650
assert(PyWeakref_CheckRef(ref));
8660-
subclass = (PyTypeObject *)PyWeakref_GET_OBJECT(ref);
8661-
assert(subclass != NULL);
8662-
if ((PyObject *)subclass == Py_None)
8651+
PyObject *obj = PyWeakref_GET_OBJECT(ref);
8652+
assert(obj != NULL);
8653+
if (obj == Py_None) {
86638654
continue;
8664-
assert(PyType_Check(subclass));
8655+
}
8656+
PyTypeObject *subclass = _PyType_CAST(obj);
8657+
86658658
/* Avoid recursing down into unaffected classes */
86668659
dict = subclass->tp_dict;
86678660
if (dict != NULL && PyDict_Check(dict)) {
@@ -8838,28 +8831,24 @@ super_getattro(PyObject *self, PyObject *name)
88388831
replaced during PyDict_GetItemWithError(dict, name) */
88398832
Py_INCREF(mro);
88408833
do {
8841-
PyObject *res, *tmp, *dict;
8842-
descrgetfunc f;
8843-
8844-
tmp = PyTuple_GET_ITEM(mro, i);
8845-
assert(PyType_Check(tmp));
8846-
8847-
dict = ((PyTypeObject *)tmp)->tp_dict;
8834+
PyObject *obj = PyTuple_GET_ITEM(mro, i);
8835+
PyObject *dict = _PyType_CAST(obj)->tp_dict;
88488836
assert(dict != NULL && PyDict_Check(dict));
88498837

8850-
res = PyDict_GetItemWithError(dict, name);
8838+
PyObject *res = PyDict_GetItemWithError(dict, name);
88518839
if (res != NULL) {
88528840
Py_INCREF(res);
88538841

8854-
f = Py_TYPE(res)->tp_descr_get;
8842+
descrgetfunc f = Py_TYPE(res)->tp_descr_get;
88558843
if (f != NULL) {
8856-
tmp = f(res,
8844+
PyObject *res2;
8845+
res2 = f(res,
88578846
/* Only pass 'obj' param if this is instance-mode super
88588847
(See SF ID #743627) */
88598848
(su->obj == (PyObject *)starttype) ? NULL : su->obj,
88608849
(PyObject *)starttype);
88618850
Py_DECREF(res);
8862-
res = tmp;
8851+
res = res2;
88638852
}
88648853

88658854
Py_DECREF(mro);
@@ -8920,8 +8909,9 @@ supercheck(PyTypeObject *type, PyObject *obj)
89208909
{
89218910
int ok = PyType_IsSubtype(
89228911
(PyTypeObject *)class_attr, type);
8923-
if (ok)
8912+
if (ok) {
89248913
return (PyTypeObject *)class_attr;
8914+
}
89258915
}
89268916
Py_XDECREF(class_attr);
89278917
}

0 commit comments

Comments
 (0)