diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index 9dfc8c62ba..8aaebd6e0b 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -55,6 +55,10 @@ _PyObject_InitVar(PyVarObject *op, PyTypeObject *typeobj, Py_ssize_t size) } +#ifdef Py_DEBUG +extern int _PyGC_VisitAfterTrack(PyObject *op, void *parent_raw); +#endif + /* Tell the GC to track this object. * * The object must not be tracked by the GC. @@ -92,6 +96,13 @@ static inline void _PyObject_GC_TRACK( _PyGCHead_SET_PREV(gc, last); _PyGCHead_SET_NEXT(gc, generation0); generation0->_gc_prev = (uintptr_t)gc; + +#ifdef Py_DEBUG + /* Check that the object is valid: validate objects traversed + by tp_traverse() */ + traverseproc traverse = Py_TYPE(op)->tp_traverse; + (void)traverse(op, _PyGC_VisitAfterTrack, op); +#endif } /* Tell the GC to stop tracking this object. diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index e5e5aa3287..3ce5ccf7b0 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -2179,8 +2179,8 @@ _PyGC_Dump(PyGC_Head *g) #ifdef Py_DEBUG -static int -visit_validate(PyObject *op, void *parent_raw) +int +_PyGC_VisitAfterTrack(PyObject *op, void *parent_raw) { PyObject *parent = _PyObject_CAST(parent_raw); if (_PyObject_IsFreed(op)) { @@ -2205,13 +2205,6 @@ PyObject_GC_Track(void *op_raw) "by the garbage collector"); } _PyObject_GC_TRACK(op); - -#ifdef Py_DEBUG - /* Check that the object is valid: validate objects traversed - by tp_traverse() */ - traverseproc traverse = Py_TYPE(op)->tp_traverse; - (void)traverse(op, visit_validate, op); -#endif } void diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 3a1dbc994b..5bc132d826 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -3103,6 +3103,13 @@ static int dict_traverse(PyObject *op, visitproc visit, void *arg) { PyDictObject *mp = (PyDictObject *)op; + if (mp->ma_keys == NULL) { + // In debug mode, _PyObject_GC_TRACK() called by PyType_GenericAlloc() + // visits the instance. But PyDictObject members are not initialized + // yet. + return 0; + } + PyDictKeysObject *keys = mp->ma_keys; PyDictKeyEntry *entries = DK_ENTRIES(keys); Py_ssize_t i, n = keys->dk_nentries; diff --git a/Objects/genobject.c b/Objects/genobject.c index db00d19a34..da51fd7080 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -842,20 +842,28 @@ gen_new_with_qualname(PyTypeObject *type, PyFrameObject *f, else gen->gi_qualname = gen->gi_name; Py_INCREF(gen->gi_qualname); - _PyObject_GC_TRACK(gen); return (PyObject *)gen; } PyObject * PyGen_NewWithQualName(PyFrameObject *f, PyObject *name, PyObject *qualname) { - return gen_new_with_qualname(&PyGen_Type, f, name, qualname); + PyObject *gen = gen_new_with_qualname(&PyGen_Type, f, name, qualname); + if (gen != NULL) { + _PyObject_GC_TRACK(gen); + } + return gen; + } PyObject * PyGen_New(PyFrameObject *f) { - return gen_new_with_qualname(&PyGen_Type, f, NULL, NULL); + PyObject *gen = gen_new_with_qualname(&PyGen_Type, f, NULL, NULL); + if (gen != NULL) { + _PyObject_GC_TRACK(gen); + } + return gen; } /* Coroutine Object */ @@ -1186,25 +1194,25 @@ compute_cr_origin(int origin_depth) PyObject * PyCoro_New(PyFrameObject *f, PyObject *name, PyObject *qualname) { - PyObject *coro = gen_new_with_qualname(&PyCoro_Type, f, name, qualname); - if (!coro) { - return NULL; - } - PyThreadState *tstate = _PyThreadState_GET(); int origin_depth = tstate->coroutine_origin_tracking_depth; - + PyObject *cr_origin; if (origin_depth == 0) { - ((PyCoroObject *)coro)->cr_origin = NULL; + cr_origin = NULL; } else { - PyObject *cr_origin = compute_cr_origin(origin_depth); - ((PyCoroObject *)coro)->cr_origin = cr_origin; + cr_origin = compute_cr_origin(origin_depth); if (!cr_origin) { - Py_DECREF(coro); return NULL; } } + PyObject *coro = gen_new_with_qualname(&PyCoro_Type, f, name, qualname); + if (!coro) { + Py_DECREF(cr_origin); + return NULL; + } + ((PyCoroObject *)coro)->cr_origin = cr_origin; + _PyObject_GC_TRACK(coro); return coro; } @@ -1469,6 +1477,7 @@ PyAsyncGen_New(PyFrameObject *f, PyObject *name, PyObject *qualname) o->ag_closed = 0; o->ag_hooks_inited = 0; o->ag_running_async = 0; + _PyObject_GC_TRACK(o); return (PyObject*)o; } diff --git a/Objects/setobject.c b/Objects/setobject.c index caff85c9e3..ad5d45425b 100644 --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -657,11 +657,17 @@ Raises KeyError if the set is empty."); static int set_traverse(PySetObject *so, visitproc visit, void *arg) { + if (so->table == NULL) { + // traverse called just after a set object was created, before + // it has been initialized. + return 0; + } + Py_ssize_t pos = 0; setentry *entry; - - while (set_next(so, &pos, &entry)) + while (set_next(so, &pos, &entry)) { Py_VISIT(entry->key); + } return 0; } diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 3c766e9230..a2c2feb26e 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -1065,6 +1065,11 @@ static PyGetSetDef type_getsets[] = { static PyObject * type_repr(PyTypeObject *type) { + if (type->tp_name == NULL) { + // type_repr() called before the type is fully initialized + return PyUnicode_FromString(""); + } + PyObject *mod, *name, *rtn; mod = type_module(type, NULL); @@ -1157,8 +1162,9 @@ type_call(PyTypeObject *type, PyObject *args, PyObject *kwds) return obj; } -PyObject * -PyType_GenericAlloc(PyTypeObject *type, Py_ssize_t nitems) +// Similar to PyType_GenericAlloc(), but don't track the object in the GC +static PyObject * +type_alloc(PyTypeObject *type, Py_ssize_t nitems) { PyObject *obj; const size_t size = _PyObject_VAR_SIZE(type, nitems+1); @@ -1183,9 +1189,17 @@ PyType_GenericAlloc(PyTypeObject *type, Py_ssize_t nitems) else { _PyObject_InitVar((PyVarObject *)obj, type, nitems); } + return obj; +} - if (_PyType_IS_GC(type)) { - _PyObject_GC_TRACK(obj); +PyObject * +PyType_GenericAlloc(PyTypeObject *type, Py_ssize_t nitems) +{ + PyObject *obj = type_alloc(type, nitems); + if (obj != NULL) { + if (_PyType_IS_GC(type)) { + _PyObject_GC_TRACK(obj); + } } return obj; } @@ -2753,7 +2767,7 @@ type_new_alloc(type_new_ctx *ctx) type->tp_dealloc = subtype_dealloc; /* Always override allocation strategy to use regular heap */ - type->tp_alloc = PyType_GenericAlloc; + type->tp_alloc = type_alloc; type->tp_free = PyObject_GC_Del; type->tp_traverse = subtype_traverse; @@ -3194,6 +3208,11 @@ type_new_impl(type_new_ctx *ctx) goto error; } + assert(type->tp_alloc != PyType_GenericAlloc); + if (_PyType_IS_GC(Py_TYPE(type))) { + _PyObject_GC_TRACK(type); + } + assert(_PyType_CheckConsistency(type)); return (PyObject *)type; @@ -3308,6 +3327,10 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) } if (res == 1) { assert(type != NULL); + if (_PyType_IS_GC(Py_TYPE(type)) && !_PyObject_GC_IS_TRACKED(type)) { + _PyObject_GC_TRACK(type); + } + assert( ((PyTypeObject*)type)->tp_alloc != PyType_GenericAlloc); return type; } assert(ctx.base != NULL); @@ -3398,7 +3421,7 @@ PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases) } } - res = (PyHeapTypeObject*)PyType_GenericAlloc(&PyType_Type, nmembers); + res = (PyHeapTypeObject*)type_alloc(&PyType_Type, nmembers); if (res == NULL) return NULL; res_start = (char*)res; @@ -3417,6 +3440,11 @@ PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases) s++; type = &res->ht_type; + + /* Always override allocation strategy to use regular heap */ + type->tp_alloc = type_alloc; + type->tp_free = PyObject_GC_Del; + /* The flags must be initialized early, before the GC traverses us */ type->tp_flags = spec->flags | Py_TPFLAGS_HEAPTYPE; res->ht_name = PyUnicode_FromString(s); @@ -3543,6 +3571,10 @@ PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases) type->tp_dealloc = subtype_dealloc; } + /* Always override allocation strategy to use regular heap */ + type->tp_alloc = type_alloc; + type->tp_free = PyObject_GC_Del; + if (vectorcalloffset) { type->tp_vectorcall_offset = vectorcalloffset; } @@ -3600,6 +3632,11 @@ PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases) } } + if (_PyType_IS_GC(Py_TYPE(type))) { + _PyObject_GC_TRACK(type); + } + assert(type->tp_alloc != PyType_GenericAlloc); + assert(_PyType_CheckConsistency(type)); return (PyObject*)res; @@ -4345,7 +4382,7 @@ PyTypeObject PyType_Type = { 0, /* tp_descr_set */ offsetof(PyTypeObject, tp_dict), /* tp_dictoffset */ type_init, /* tp_init */ - 0, /* tp_alloc */ + type_alloc, /* tp_alloc */ type_new, /* tp_new */ PyObject_GC_Del, /* tp_free */ (inquiry)type_is_gc, /* tp_is_gc */