bpo-40217: Ensure Py_VISIT(Py_TYPE(self)) is always called for PyTyp… · python/cpython@1cf15af (original) (raw)
`@@ -1039,42 +1039,6 @@ type_call(PyTypeObject *type, PyObject *args, PyObject *kwds)
`
1039
1039
`return obj;
`
1040
1040
`}
`
1041
1041
``
1042
``
`-
PyObject *
`
1043
``
`-
PyType_FromSpec_Alloc(PyTypeObject *type, Py_ssize_t nitems)
`
1044
``
`-
{
`
1045
``
`-
PyObject *obj;
`
1046
``
`-
const size_t size = _Py_SIZE_ROUND_UP(
`
1047
``
`-
_PyObject_VAR_SIZE(type, nitems+1) + sizeof(traverseproc),
`
1048
``
`-
SIZEOF_VOID_P);
`
1049
``
`-
/* note that we need to add one, for the sentinel and space for the
`
1050
``
`-
provided tp-traverse: See bpo-40217 for more details */
`
1051
``
-
1052
``
`-
if (PyType_IS_GC(type)) {
`
1053
``
`-
obj = _PyObject_GC_Malloc(size);
`
1054
``
`-
}
`
1055
``
`-
else {
`
1056
``
`-
obj = (PyObject *)PyObject_MALLOC(size);
`
1057
``
`-
}
`
1058
``
-
1059
``
`-
if (obj == NULL) {
`
1060
``
`-
return PyErr_NoMemory();
`
1061
``
`-
}
`
1062
``
-
1063
``
`-
memset(obj, '\0', size);
`
1064
``
-
1065
``
`-
if (type->tp_itemsize == 0) {
`
1066
``
`-
(void)PyObject_INIT(obj, type);
`
1067
``
`-
}
`
1068
``
`-
else {
`
1069
``
`-
(void) PyObject_INIT_VAR((PyVarObject *)obj, type, nitems);
`
1070
``
`-
}
`
1071
``
-
1072
``
`-
if (PyType_IS_GC(type)) {
`
1073
``
`-
_PyObject_GC_TRACK(obj);
`
1074
``
`-
}
`
1075
``
`-
return obj;
`
1076
``
`-
}
`
1077
``
-
1078
1042
`PyObject *
`
1079
1043
`PyType_GenericAlloc(PyTypeObject *type, Py_ssize_t nitems)
`
1080
1044
`{
`
`@@ -1164,11 +1128,16 @@ subtype_traverse(PyObject *self, visitproc visit, void *arg)
`
1164
1128
`Py_VISIT(*dictptr);
`
1165
1129
` }
`
1166
1130
``
1167
``
`-
if (type->tp_flags & Py_TPFLAGS_HEAPTYPE)
`
``
1131
`+
if (type->tp_flags & Py_TPFLAGS_HEAPTYPE
`
``
1132
`+
&& (!basetraverse || !(base->tp_flags & Py_TPFLAGS_HEAPTYPE))) {
`
1168
1133
`/* For a heaptype, the instances count as references
`
1169
1134
` to the type. Traverse the type so the collector
`
1170
``
`-
can find cycles involving this link. */
`
``
1135
`+
can find cycles involving this link.
`
``
1136
`+
Skip this visit if basetraverse belongs to a heap type: in that
`
``
1137
`+
case, basetraverse will visit the type when we call it later.
`
``
1138
`+
*/
`
1171
1139
`Py_VISIT(type);
`
``
1140
`+
}
`
1172
1141
``
1173
1142
`if (basetraverse)
`
1174
1143
`return basetraverse(self, visit, arg);
`
`@@ -2910,36 +2879,6 @@ static const short slotoffsets[] = {
`
2910
2879
`#include "typeslots.inc"
`
2911
2880
`};
`
2912
2881
``
2913
``
`-
static int
`
2914
``
`-
PyType_FromSpec_tp_traverse(PyObject *self, visitproc visit, void *arg)
`
2915
``
`-
{
`
2916
``
`-
PyTypeObject *parent = Py_TYPE(self);
`
2917
``
-
2918
``
`-
// Only a instance of a type that is directly created by
`
2919
``
`-
// PyType_FromSpec (not subclasses) must visit its parent.
`
2920
``
`-
if (parent->tp_traverse == PyType_FromSpec_tp_traverse) {
`
2921
``
`-
Py_VISIT(parent);
`
2922
``
`-
}
`
2923
``
-
2924
``
`-
// Search for the original type that was created using PyType_FromSpec
`
2925
``
`-
PyTypeObject *base;
`
2926
``
`-
base = parent;
`
2927
``
`-
while (base->tp_traverse != PyType_FromSpec_tp_traverse) {
`
2928
``
`-
base = base->tp_base;
`
2929
``
`-
assert(base);
`
2930
``
`-
}
`
2931
``
-
2932
``
`-
// Extract the user defined traverse function that we placed at the end
`
2933
``
`-
// of the type and call it.
`
2934
``
`-
size_t size = Py_SIZE(base);
`
2935
``
`-
size_t _offset = _PyObject_VAR_SIZE(&PyType_Type, size+1);
`
2936
``
`-
traverseproc fun = (traverseproc)((char*)base + _offset);
`
2937
``
`-
if (fun == NULL) {
`
2938
``
`-
return 0;
`
2939
``
`-
}
`
2940
``
`-
return fun(self, visit, arg);
`
2941
``
`-
}
`
2942
``
-
2943
2882
`PyObject *
`
2944
2883
`PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases)
`
2945
2884
`{
`
`@@ -2985,7 +2924,7 @@ PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases)
`
2985
2924
` }
`
2986
2925
` }
`
2987
2926
``
2988
``
`-
res = (PyHeapTypeObject*)PyType_FromSpec_Alloc(&PyType_Type, nmembers);
`
``
2927
`+
res = (PyHeapTypeObject*)PyType_GenericAlloc(&PyType_Type, nmembers);
`
2989
2928
`if (res == NULL)
`
2990
2929
`return NULL;
`
2991
2930
`res_start = (char*)res;
`
`@@ -3093,30 +3032,6 @@ PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases)
`
3093
3032
`memcpy(PyHeapType_GET_MEMBERS(res), slot->pfunc, len);
`
3094
3033
`type->tp_members = PyHeapType_GET_MEMBERS(res);
`
3095
3034
` }
`
3096
``
`-
else if (slot->slot == Py_tp_traverse) {
`
3097
``
-
3098
``
`-
/* Types created by PyType_FromSpec own a strong reference to their
`
3099
``
`-
- type, but this was added in Python 3.8. The tp_traverse function
`
3100
``
`-
- needs to call Py_VISIT on the type but all existing traverse
`
3101
``
`-
- functions cannot be updated (especially the ones from existing user
`
3102
``
`-
- functions) so we need to provide a tp_traverse that manually calls
`
3103
``
`-
- Py_VISIT(Py_TYPE(self)) and then call the provided tp_traverse. In
`
3104
``
`-
- this way, user functions do not need to be updated, preserve
`
3105
``
`-
- backwards compatibility.
`
3106
``
`-
`
3107
``
`-
- We store the user-provided traverse function at the end of the type
`
3108
``
`-
- (we have allocated space for it) so we can call it from our
`
3109
``
`-
- PyType_FromSpec_tp_traverse wrapper.
`
3110
``
`-
`
3111
``
`-
- Check bpo-40217 for more information and rationale about this issue.
`
3112
``
`-
`
3113
``
`-
- */
`
3114
``
-
3115
``
`-
type->tp_traverse = PyType_FromSpec_tp_traverse;
`
3116
``
`-
size_t _offset = _PyObject_VAR_SIZE(&PyType_Type, nmembers+1);
`
3117
``
`-
traverseproc user_traverse = (traverseproc)((char*)type + _offset);
`
3118
``
`-
*user_traverse = slot->pfunc;
`
3119
``
`-
}
`
3120
3035
`else {
`
3121
3036
`/* Copy other slots directly */
`
3122
3037
`(void*)(res_start + slotoffsets[slot->slot]) = slot->pfunc;
`