aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/tools/python3/src/Objects/object.c
diff options
context:
space:
mode:
authorshadchin <shadchin@yandex-team.com>2024-02-12 07:53:52 +0300
committershadchin <shadchin@yandex-team.com>2024-02-12 08:07:36 +0300
commitce1b7ca3171f9158180640c6a02a74b4afffedea (patch)
treee47c1e8391b1b0128262c1e9b1e6ed4c8fff2348 /contrib/tools/python3/src/Objects/object.c
parent57350d96f030db90f220ce50ee591d5c5d403df7 (diff)
downloadydb-ce1b7ca3171f9158180640c6a02a74b4afffedea.tar.gz
Update Python from 3.11.8 to 3.12.2
Diffstat (limited to 'contrib/tools/python3/src/Objects/object.c')
-rw-r--r--contrib/tools/python3/src/Objects/object.c749
1 files changed, 492 insertions, 257 deletions
diff --git a/contrib/tools/python3/src/Objects/object.c b/contrib/tools/python3/src/Objects/object.c
index c4f2786c50..aac707d6a2 100644
--- a/contrib/tools/python3/src/Objects/object.c
+++ b/contrib/tools/python3/src/Objects/object.c
@@ -14,9 +14,10 @@
#include "pycore_pymem.h" // _PyMem_IsPtrFreed()
#include "pycore_pystate.h" // _PyThreadState_GET()
#include "pycore_symtable.h" // PySTEntry_Type
-#include "pycore_typeobject.h" // _PyTypes_InitSlotDefs()
+#include "pycore_typevarobject.h" // _PyTypeAlias_Type, _Py_initialize_generic
+#include "pycore_typeobject.h" // _PyBufferWrapper_Type
#include "pycore_unionobject.h" // _PyUnion_Type
-#include "pycore_interpreteridobject.h" // _PyInterpreterID_Type
+#include "interpreteridobject.h" // _PyInterpreterID_Type
#ifdef Py_LIMITED_API
// Prevent recursive call _Py_IncRef() <=> Py_INCREF()
@@ -55,19 +56,100 @@ _PyObject_CheckConsistency(PyObject *op, int check_content)
#ifdef Py_REF_DEBUG
+/* We keep the legacy symbol around for backward compatibility. */
Py_ssize_t _Py_RefTotal;
-Py_ssize_t
-_Py_GetRefTotal(void)
+static inline Py_ssize_t
+get_legacy_reftotal(void)
{
return _Py_RefTotal;
}
+#endif
+
+#ifdef Py_REF_DEBUG
+
+# define REFTOTAL(interp) \
+ interp->object_state.reftotal
+
+static inline void
+reftotal_increment(PyInterpreterState *interp)
+{
+ REFTOTAL(interp)++;
+}
+
+static inline void
+reftotal_decrement(PyInterpreterState *interp)
+{
+ REFTOTAL(interp)--;
+}
+
+static inline void
+reftotal_add(PyInterpreterState *interp, Py_ssize_t n)
+{
+ REFTOTAL(interp) += n;
+}
+
+static inline Py_ssize_t get_global_reftotal(_PyRuntimeState *);
+
+/* We preserve the number of refs leaked during runtime finalization,
+ so they can be reported if the runtime is initialized again. */
+// XXX We don't lose any information by dropping this,
+// so we should consider doing so.
+static Py_ssize_t last_final_reftotal = 0;
+
+void
+_Py_FinalizeRefTotal(_PyRuntimeState *runtime)
+{
+ last_final_reftotal = get_global_reftotal(runtime);
+ runtime->object_state.interpreter_leaks = 0;
+}
+
+void
+_PyInterpreterState_FinalizeRefTotal(PyInterpreterState *interp)
+{
+ interp->runtime->object_state.interpreter_leaks += REFTOTAL(interp);
+ REFTOTAL(interp) = 0;
+}
+
+static inline Py_ssize_t
+get_reftotal(PyInterpreterState *interp)
+{
+ /* For a single interpreter, we ignore the legacy _Py_RefTotal,
+ since we can't determine which interpreter updated it. */
+ return REFTOTAL(interp);
+}
+
+static inline Py_ssize_t
+get_global_reftotal(_PyRuntimeState *runtime)
+{
+ Py_ssize_t total = 0;
+
+ /* Add up the total from each interpreter. */
+ HEAD_LOCK(&_PyRuntime);
+ PyInterpreterState *interp = PyInterpreterState_Head();
+ for (; interp != NULL; interp = PyInterpreterState_Next(interp)) {
+ total += REFTOTAL(interp);
+ }
+ HEAD_UNLOCK(&_PyRuntime);
+
+ /* Add in the updated value from the legacy _Py_RefTotal. */
+ total += get_legacy_reftotal();
+ total += last_final_reftotal;
+ total += runtime->object_state.interpreter_leaks;
+
+ return total;
+}
+
+#undef REFTOTAL
void
_PyDebug_PrintTotalRefs(void) {
+ _PyRuntimeState *runtime = &_PyRuntime;
fprintf(stderr,
"[%zd refs, %zd blocks]\n",
- _Py_GetRefTotal(), _Py_GetAllocatedBlocks());
+ get_global_reftotal(runtime), _Py_GetGlobalAllocatedBlocks());
+ /* It may be helpful to also print the "legacy" reftotal separately.
+ Likewise for the total for each interpreter. */
}
#endif /* Py_REF_DEBUG */
@@ -76,11 +158,16 @@ _PyDebug_PrintTotalRefs(void) {
Do not call them otherwise, they do not initialize the object! */
#ifdef Py_TRACE_REFS
-/* Head of circular doubly-linked list of all objects. These are linked
- * together via the _ob_prev and _ob_next members of a PyObject, which
- * exist only in a Py_TRACE_REFS build.
- */
-static PyObject refchain = {&refchain, &refchain};
+
+#define REFCHAIN(interp) &interp->object_state.refchain
+
+static inline void
+init_refchain(PyInterpreterState *interp)
+{
+ PyObject *refchain = REFCHAIN(interp);
+ refchain->_ob_prev = refchain;
+ refchain->_ob_next = refchain;
+}
/* Insert op at the front of the list of all objects. If force is true,
* op is added even if _ob_prev and _ob_next are non-NULL already. If
@@ -105,10 +192,11 @@ _Py_AddToAllObjects(PyObject *op, int force)
}
#endif
if (force || op->_ob_prev == NULL) {
- op->_ob_next = refchain._ob_next;
- op->_ob_prev = &refchain;
- refchain._ob_next->_ob_prev = op;
- refchain._ob_next = op;
+ PyObject *refchain = REFCHAIN(_PyInterpreterState_GET());
+ op->_ob_next = refchain->_ob_next;
+ op->_ob_prev = refchain;
+ refchain->_ob_next->_ob_prev = op;
+ refchain->_ob_next = op;
}
}
#endif /* Py_TRACE_REFS */
@@ -122,6 +210,58 @@ _Py_NegativeRefcount(const char *filename, int lineno, PyObject *op)
filename, lineno, __func__);
}
+/* This is used strictly by Py_INCREF(). */
+void
+_Py_INCREF_IncRefTotal(void)
+{
+ reftotal_increment(_PyInterpreterState_GET());
+}
+
+/* This is used strictly by Py_DECREF(). */
+void
+_Py_DECREF_DecRefTotal(void)
+{
+ reftotal_decrement(_PyInterpreterState_GET());
+}
+
+void
+_Py_IncRefTotal(PyInterpreterState *interp)
+{
+ reftotal_increment(interp);
+}
+
+void
+_Py_DecRefTotal(PyInterpreterState *interp)
+{
+ reftotal_decrement(interp);
+}
+
+void
+_Py_AddRefTotal(PyInterpreterState *interp, Py_ssize_t n)
+{
+ reftotal_add(interp, n);
+}
+
+/* This includes the legacy total
+ and any carried over from the last runtime init/fini cycle. */
+Py_ssize_t
+_Py_GetGlobalRefTotal(void)
+{
+ return get_global_reftotal(&_PyRuntime);
+}
+
+Py_ssize_t
+_Py_GetLegacyRefTotal(void)
+{
+ return get_legacy_reftotal();
+}
+
+Py_ssize_t
+_PyInterpreterState_GetRefTotal(PyInterpreterState *interp)
+{
+ return get_reftotal(interp);
+}
+
#endif /* Py_REF_DEBUG */
void
@@ -148,6 +288,9 @@ _Py_DecRef(PyObject *o)
Py_DECREF(o);
}
+
+/**************************************/
+
PyObject *
PyObject_Init(PyObject *op, PyTypeObject *tp)
{
@@ -239,17 +382,12 @@ PyObject_CallFinalizerFromDealloc(PyObject *self)
/* tp_finalize resurrected it! Make it look like the original Py_DECREF
* never happened. */
Py_ssize_t refcnt = Py_REFCNT(self);
- _Py_NewReference(self);
+ _Py_NewReferenceNoTotal(self);
Py_SET_REFCNT(self, refcnt);
_PyObject_ASSERT(self,
(!_PyType_IS_GC(Py_TYPE(self))
|| _PyObject_GC_IS_TRACKED(self)));
- /* If Py_REF_DEBUG macro is defined, _Py_NewReference() increased
- _Py_RefTotal, so we need to undo that. */
-#ifdef Py_REF_DEBUG
- _Py_RefTotal--;
-#endif
return -1;
}
@@ -273,11 +411,8 @@ PyObject_Print(PyObject *op, FILE *fp, int flags)
}
else {
if (Py_REFCNT(op) <= 0) {
- /* XXX(twouters) cast refcount to long until %zd is
- universally available */
Py_BEGIN_ALLOW_THREADS
- fprintf(fp, "<refcnt %ld at %p>",
- (long)Py_REFCNT(op), (void *)op);
+ fprintf(fp, "<refcnt %zd at %p>", Py_REFCNT(op), (void *)op);
Py_END_ALLOW_THREADS
}
else {
@@ -286,31 +421,22 @@ PyObject_Print(PyObject *op, FILE *fp, int flags)
s = PyObject_Str(op);
else
s = PyObject_Repr(op);
- if (s == NULL)
+ if (s == NULL) {
ret = -1;
- else if (PyBytes_Check(s)) {
- fwrite(PyBytes_AS_STRING(s), 1,
- PyBytes_GET_SIZE(s), fp);
}
- else if (PyUnicode_Check(s)) {
- PyObject *t;
- t = PyUnicode_AsEncodedString(s, "utf-8", "backslashreplace");
+ else {
+ assert(PyUnicode_Check(s));
+ const char *t;
+ Py_ssize_t len;
+ t = PyUnicode_AsUTF8AndSize(s, &len);
if (t == NULL) {
ret = -1;
}
else {
- fwrite(PyBytes_AS_STRING(t), 1,
- PyBytes_GET_SIZE(t), fp);
- Py_DECREF(t);
+ fwrite(t, 1, len, fp);
}
+ Py_DECREF(s);
}
- else {
- PyErr_Format(PyExc_TypeError,
- "str() or repr() returned '%.100s'",
- Py_TYPE(s)->tp_name);
- ret = -1;
- }
- Py_XDECREF(s);
}
}
if (ret == 0) {
@@ -370,9 +496,7 @@ _PyObject_Dump(PyObject* op)
/* first, write fields which are the least likely to crash */
fprintf(stderr, "object address : %p\n", (void *)op);
- /* XXX(twouters) cast refcount to long until %zd is
- universally available */
- fprintf(stderr, "object refcount : %ld\n", (long)Py_REFCNT(op));
+ fprintf(stderr, "object refcount : %zd\n", Py_REFCNT(op));
fflush(stderr);
PyTypeObject *type = Py_TYPE(op);
@@ -385,13 +509,12 @@ _PyObject_Dump(PyObject* op)
fflush(stderr);
PyGILState_STATE gil = PyGILState_Ensure();
- PyObject *error_type, *error_value, *error_traceback;
- PyErr_Fetch(&error_type, &error_value, &error_traceback);
+ PyObject *exc = PyErr_GetRaisedException();
(void)PyObject_Print(op, stderr, 0);
fflush(stderr);
- PyErr_Restore(error_type, error_value, error_traceback);
+ PyErr_SetRaisedException(exc);
PyGILState_Release(gil);
fprintf(stderr, "\n");
@@ -470,8 +593,7 @@ PyObject_Str(PyObject *v)
if (PyUnicode_READY(v) < 0)
return NULL;
#endif
- Py_INCREF(v);
- return v;
+ return Py_NewRef(v);
}
if (Py_TYPE(v)->tp_str == NULL)
return PyObject_Repr(v);
@@ -547,8 +669,7 @@ PyObject_Bytes(PyObject *v)
return PyBytes_FromString("<NULL>");
if (PyBytes_CheckExact(v)) {
- Py_INCREF(v);
- return v;
+ return Py_NewRef(v);
}
func = _PyObject_LookupSpecial(v, &_Py_ID(__bytes__));
@@ -704,8 +825,7 @@ do_richcompare(PyThreadState *tstate, PyObject *v, PyObject *w, int op)
Py_TYPE(w)->tp_name);
return NULL;
}
- Py_INCREF(res);
- return res;
+ return Py_NewRef(res);
}
/* Perform a rich comparison with object result. This wraps do_richcompare()
@@ -778,7 +898,7 @@ PyObject_Hash(PyObject *v)
* an explicit call to PyType_Ready, we implicitly call
* PyType_Ready here and then check the tp_hash slot again
*/
- if (tp->tp_dict == NULL) {
+ if (!_PyType_IsReady(tp)) {
if (PyType_Ready(tp) < 0)
return -1;
if (tp->tp_hash != NULL)
@@ -806,13 +926,24 @@ PyObject_GetAttrString(PyObject *v, const char *name)
int
PyObject_HasAttrString(PyObject *v, const char *name)
{
- PyObject *res = PyObject_GetAttrString(v, name);
- if (res != NULL) {
- Py_DECREF(res);
- return 1;
+ if (Py_TYPE(v)->tp_getattr != NULL) {
+ PyObject *res = (*Py_TYPE(v)->tp_getattr)(v, (char*)name);
+ if (res != NULL) {
+ Py_DECREF(res);
+ return 1;
+ }
+ PyErr_Clear();
+ return 0;
}
- PyErr_Clear();
- return 0;
+
+ PyObject *attr_name = PyUnicode_FromString(name);
+ if (attr_name == NULL) {
+ PyErr_Clear();
+ return 0;
+ }
+ int ok = PyObject_HasAttr(v, attr_name);
+ Py_DECREF(attr_name);
+ return ok;
}
int
@@ -878,25 +1009,22 @@ set_attribute_error_context(PyObject* v, PyObject* name)
return 0;
}
// Intercept AttributeError exceptions and augment them to offer suggestions later.
- PyObject *type, *value, *traceback;
- PyErr_Fetch(&type, &value, &traceback);
- PyErr_NormalizeException(&type, &value, &traceback);
- // Check if the normalized exception is indeed an AttributeError
- if (!PyErr_GivenExceptionMatches(value, PyExc_AttributeError)) {
+ PyObject *exc = PyErr_GetRaisedException();
+ if (!PyErr_GivenExceptionMatches(exc, PyExc_AttributeError)) {
goto restore;
}
- PyAttributeErrorObject* the_exc = (PyAttributeErrorObject*) value;
+ PyAttributeErrorObject* the_exc = (PyAttributeErrorObject*) exc;
// Check if this exception was already augmented
if (the_exc->name || the_exc->obj) {
goto restore;
}
// Augment the exception with the name and object
- if (PyObject_SetAttr(value, &_Py_ID(name), name) ||
- PyObject_SetAttr(value, &_Py_ID(obj), v)) {
+ if (PyObject_SetAttr(exc, &_Py_ID(name), name) ||
+ PyObject_SetAttr(exc, &_Py_ID(obj), v)) {
return 1;
}
restore:
- PyErr_Restore(type, value, traceback);
+ PyErr_SetRaisedException(exc);
return 0;
}
@@ -924,7 +1052,7 @@ PyObject_GetAttr(PyObject *v, PyObject *name)
}
else {
PyErr_Format(PyExc_AttributeError,
- "'%.50s' object has no attribute '%U'",
+ "'%.100s' object has no attribute '%U'",
tp->tp_name, name);
}
@@ -957,7 +1085,26 @@ _PyObject_LookupAttr(PyObject *v, PyObject *name, PyObject **result)
}
return 0;
}
- if (tp->tp_getattro != NULL) {
+ if (tp->tp_getattro == (getattrofunc)_Py_type_getattro) {
+ int supress_missing_attribute_exception = 0;
+ *result = _Py_type_getattro_impl((PyTypeObject*)v, name, &supress_missing_attribute_exception);
+ if (supress_missing_attribute_exception) {
+ // return 0 without having to clear the exception
+ return 0;
+ }
+ }
+ else if (tp->tp_getattro == (getattrofunc)_Py_module_getattro) {
+ // optimization: suppress attribute error from module getattro method
+ *result = _Py_module_getattro_impl((PyModuleObject*)v, name, 1);
+ if (*result != NULL) {
+ return 1;
+ }
+ if (PyErr_Occurred()) {
+ return -1;
+ }
+ return 0;
+ }
+ else if (tp->tp_getattro != NULL) {
*result = (*tp->tp_getattro)(v, name);
}
else if (tp->tp_getattr != NULL) {
@@ -1059,18 +1206,19 @@ PyObject_SetAttr(PyObject *v, PyObject *name, PyObject *value)
}
PyObject **
-_PyObject_DictPointer(PyObject *obj)
+_PyObject_ComputedDictPointer(PyObject *obj)
{
- Py_ssize_t dictoffset;
PyTypeObject *tp = Py_TYPE(obj);
+ assert((tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0);
- if (tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
- return _PyObject_ManagedDictPointer(obj);
- }
- dictoffset = tp->tp_dictoffset;
- if (dictoffset == 0)
+ Py_ssize_t dictoffset = tp->tp_dictoffset;
+ if (dictoffset == 0) {
return NULL;
+ }
+
if (dictoffset < 0) {
+ assert(dictoffset != -1);
+
Py_ssize_t tsize = Py_SIZE(obj);
if (tsize < 0) {
tsize = -tsize;
@@ -1096,29 +1244,24 @@ PyObject **
_PyObject_GetDictPtr(PyObject *obj)
{
if ((Py_TYPE(obj)->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0) {
- return _PyObject_DictPointer(obj);
+ return _PyObject_ComputedDictPointer(obj);
}
- PyObject **dict_ptr = _PyObject_ManagedDictPointer(obj);
- PyDictValues **values_ptr = _PyObject_ValuesPointer(obj);
- if (*values_ptr == NULL) {
- return dict_ptr;
- }
- assert(*dict_ptr == NULL);
- PyObject *dict = _PyObject_MakeDictFromInstanceAttributes(obj, *values_ptr);
- if (dict == NULL) {
- PyErr_Clear();
- return NULL;
+ PyDictOrValues *dorv_ptr = _PyObject_DictOrValuesPointer(obj);
+ if (_PyDictOrValues_IsValues(*dorv_ptr)) {
+ PyObject *dict = _PyObject_MakeDictFromInstanceAttributes(obj, _PyDictOrValues_GetValues(*dorv_ptr));
+ if (dict == NULL) {
+ PyErr_Clear();
+ return NULL;
+ }
+ dorv_ptr->dict = dict;
}
- *values_ptr = NULL;
- *dict_ptr = dict;
- return dict_ptr;
+ return &dorv_ptr->dict;
}
PyObject *
PyObject_SelfIter(PyObject *obj)
{
- Py_INCREF(obj);
- return obj;
+ return Py_NewRef(obj);
}
/* Helper used when the __next__ method is removed from a type:
@@ -1180,36 +1323,46 @@ _PyObject_GetMethod(PyObject *obj, PyObject *name, PyObject **method)
}
}
}
- PyDictValues *values;
- if ((tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) &&
- (values = *_PyObject_ValuesPointer(obj)))
- {
- assert(*_PyObject_DictPointer(obj) == NULL);
- PyObject *attr = _PyObject_GetInstanceAttribute(obj, values, name);
- if (attr != NULL) {
- *method = attr;
- Py_XDECREF(descr);
- return 0;
- }
- }
- else {
- PyObject **dictptr = _PyObject_DictPointer(obj);
- PyObject *dict;
- if (dictptr != NULL && (dict = *dictptr) != NULL) {
- Py_INCREF(dict);
- PyObject *attr = PyDict_GetItemWithError(dict, name);
+ PyObject *dict;
+ if ((tp->tp_flags & Py_TPFLAGS_MANAGED_DICT)) {
+ PyDictOrValues* dorv_ptr = _PyObject_DictOrValuesPointer(obj);
+ if (_PyDictOrValues_IsValues(*dorv_ptr)) {
+ PyDictValues *values = _PyDictOrValues_GetValues(*dorv_ptr);
+ PyObject *attr = _PyObject_GetInstanceAttribute(obj, values, name);
if (attr != NULL) {
- *method = Py_NewRef(attr);
- Py_DECREF(dict);
+ *method = attr;
Py_XDECREF(descr);
return 0;
}
+ dict = NULL;
+ }
+ else {
+ dict = dorv_ptr->dict;
+ }
+ }
+ else {
+ PyObject **dictptr = _PyObject_ComputedDictPointer(obj);
+ if (dictptr != NULL) {
+ dict = *dictptr;
+ }
+ else {
+ dict = NULL;
+ }
+ }
+ if (dict != NULL) {
+ Py_INCREF(dict);
+ PyObject *attr = PyDict_GetItemWithError(dict, name);
+ if (attr != NULL) {
+ *method = Py_NewRef(attr);
Py_DECREF(dict);
+ Py_XDECREF(descr);
+ return 0;
+ }
+ Py_DECREF(dict);
- if (PyErr_Occurred()) {
- Py_XDECREF(descr);
- return 0;
- }
+ if (PyErr_Occurred()) {
+ Py_XDECREF(descr);
+ return 0;
}
}
@@ -1230,7 +1383,7 @@ _PyObject_GetMethod(PyObject *obj, PyObject *name, PyObject **method)
}
PyErr_Format(PyExc_AttributeError,
- "'%.50s' object has no attribute '%U'",
+ "'%.100s' object has no attribute '%U'",
tp->tp_name, name);
set_attribute_error_context(obj, name);
@@ -1253,7 +1406,6 @@ _PyObject_GenericGetAttrWithDict(PyObject *obj, PyObject *name,
PyObject *descr = NULL;
PyObject *res = NULL;
descrgetfunc f;
- PyObject **dictptr;
if (!PyUnicode_Check(name)){
PyErr_Format(PyExc_TypeError,
@@ -1263,7 +1415,7 @@ _PyObject_GenericGetAttrWithDict(PyObject *obj, PyObject *name,
}
Py_INCREF(name);
- if (tp->tp_dict == NULL) {
+ if (!_PyType_IsReady(tp)) {
if (PyType_Ready(tp) < 0)
goto done;
}
@@ -1284,30 +1436,31 @@ _PyObject_GenericGetAttrWithDict(PyObject *obj, PyObject *name,
}
}
if (dict == NULL) {
- if ((tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) &&
- *_PyObject_ValuesPointer(obj))
- {
- PyDictValues **values_ptr = _PyObject_ValuesPointer(obj);
- if (PyUnicode_CheckExact(name)) {
- assert(*_PyObject_DictPointer(obj) == NULL);
- res = _PyObject_GetInstanceAttribute(obj, *values_ptr, name);
- if (res != NULL) {
- goto done;
+ if ((tp->tp_flags & Py_TPFLAGS_MANAGED_DICT)) {
+ PyDictOrValues* dorv_ptr = _PyObject_DictOrValuesPointer(obj);
+ if (_PyDictOrValues_IsValues(*dorv_ptr)) {
+ PyDictValues *values = _PyDictOrValues_GetValues(*dorv_ptr);
+ if (PyUnicode_CheckExact(name)) {
+ res = _PyObject_GetInstanceAttribute(obj, values, name);
+ if (res != NULL) {
+ goto done;
+ }
+ }
+ else {
+ dict = _PyObject_MakeDictFromInstanceAttributes(obj, values);
+ if (dict == NULL) {
+ res = NULL;
+ goto done;
+ }
+ dorv_ptr->dict = dict;
}
}
else {
- dictptr = _PyObject_DictPointer(obj);
- assert(dictptr != NULL && *dictptr == NULL);
- *dictptr = dict = _PyObject_MakeDictFromInstanceAttributes(obj, *values_ptr);
- if (dict == NULL) {
- res = NULL;
- goto done;
- }
- *values_ptr = NULL;
+ dict = _PyDictOrValues_GetDict(*dorv_ptr);
}
}
else {
- dictptr = _PyObject_DictPointer(obj);
+ PyObject **dictptr = _PyObject_ComputedDictPointer(obj);
if (dictptr) {
dict = *dictptr;
}
@@ -1351,7 +1504,7 @@ _PyObject_GenericGetAttrWithDict(PyObject *obj, PyObject *name,
if (!suppress) {
PyErr_Format(PyExc_AttributeError,
- "'%.50s' object has no attribute '%U'",
+ "'%.100s' object has no attribute '%U'",
tp->tp_name, name);
set_attribute_error_context(obj, name);
@@ -1384,8 +1537,9 @@ _PyObject_GenericSetAttrWithDict(PyObject *obj, PyObject *name,
return -1;
}
- if (tp->tp_dict == NULL && PyType_Ready(tp) < 0)
+ if (!_PyType_IsReady(tp) && PyType_Ready(tp) < 0) {
return -1;
+ }
Py_INCREF(name);
Py_INCREF(tp);
@@ -1401,27 +1555,34 @@ _PyObject_GenericSetAttrWithDict(PyObject *obj, PyObject *name,
}
if (dict == NULL) {
- if ((tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) && *_PyObject_ValuesPointer(obj)) {
- res = _PyObject_StoreInstanceAttribute(obj, *_PyObject_ValuesPointer(obj), name, value);
+ PyObject **dictptr;
+ if ((tp->tp_flags & Py_TPFLAGS_MANAGED_DICT)) {
+ PyDictOrValues *dorv_ptr = _PyObject_DictOrValuesPointer(obj);
+ if (_PyDictOrValues_IsValues(*dorv_ptr)) {
+ res = _PyObject_StoreInstanceAttribute(
+ obj, _PyDictOrValues_GetValues(*dorv_ptr), name, value);
+ goto error_check;
+ }
+ dictptr = &dorv_ptr->dict;
}
else {
- PyObject **dictptr = _PyObject_DictPointer(obj);
- if (dictptr == NULL) {
- if (descr == NULL) {
- PyErr_Format(PyExc_AttributeError,
- "'%.100s' object has no attribute '%U'",
- tp->tp_name, name);
- }
- else {
- PyErr_Format(PyExc_AttributeError,
- "'%.50s' object attribute '%U' is read-only",
- tp->tp_name, name);
- }
- goto done;
+ dictptr = _PyObject_ComputedDictPointer(obj);
+ }
+ if (dictptr == NULL) {
+ if (descr == NULL) {
+ PyErr_Format(PyExc_AttributeError,
+ "'%.100s' object has no attribute '%U'",
+ tp->tp_name, name);
}
else {
- res = _PyObjectDict_SetItem(tp, dictptr, name, value);
+ PyErr_Format(PyExc_AttributeError,
+ "'%.100s' object attribute '%U' is read-only",
+ tp->tp_name, name);
}
+ goto done;
+ }
+ else {
+ res = _PyObjectDict_SetItem(tp, dictptr, name, value);
}
}
else {
@@ -1432,6 +1593,7 @@ _PyObject_GenericSetAttrWithDict(PyObject *obj, PyObject *name,
res = PyDict_SetItem(dict, name, value);
Py_DECREF(dict);
}
+ error_check:
if (res < 0 && PyErr_ExceptionMatches(PyExc_KeyError)) {
if (PyType_IsSubtype(tp, &PyType_Type)) {
PyErr_Format(PyExc_AttributeError,
@@ -1463,7 +1625,7 @@ PyObject_GenericSetDict(PyObject *obj, PyObject *value, void *context)
PyObject **dictptr = _PyObject_GetDictPtr(obj);
if (dictptr == NULL) {
if (_PyType_HasFeature(Py_TYPE(obj), Py_TPFLAGS_MANAGED_DICT) &&
- *_PyObject_ValuesPointer(obj) != NULL)
+ _PyDictOrValues_IsValues(*_PyObject_DictOrValuesPointer(obj)))
{
/* Was unable to convert to dict */
PyErr_NoMemory();
@@ -1484,8 +1646,7 @@ PyObject_GenericSetDict(PyObject *obj, PyObject *value, void *context)
"not a '%.200s'", Py_TYPE(value)->tp_name);
return -1;
}
- Py_INCREF(value);
- Py_XSETREF(*dictptr, value);
+ Py_XSETREF(*dictptr, Py_NewRef(value));
return 0;
}
@@ -1549,13 +1710,15 @@ _dir_locals(void)
PyObject *names;
PyObject *locals;
- locals = PyEval_GetLocals();
+ locals = _PyEval_GetFrameLocals();
if (locals == NULL)
return NULL;
names = PyMapping_Keys(locals);
- if (!names)
+ Py_DECREF(locals);
+ if (!names) {
return NULL;
+ }
if (!PyList_Check(names)) {
PyErr_Format(PyExc_TypeError,
"dir(): expected keys() of locals to be a list, "
@@ -1567,7 +1730,6 @@ _dir_locals(void)
Py_DECREF(names);
return NULL;
}
- /* the locals don't need to be DECREF'd */
return names;
}
@@ -1624,10 +1786,14 @@ none_repr(PyObject *op)
return PyUnicode_FromString("None");
}
-static void _Py_NO_RETURN
-none_dealloc(PyObject* Py_UNUSED(ignore))
+static void
+none_dealloc(PyObject* none)
{
- _Py_FatalRefcountError("deallocating None");
+ /* This should never get called, but we also don't want to SEGV if
+ * we accidentally decref None out of existence. Instead,
+ * since None is an immortal object, re-set the reference count.
+ */
+ _Py_SetImmortal(none);
}
static PyObject *
@@ -1646,6 +1812,11 @@ none_bool(PyObject *v)
return 0;
}
+static Py_hash_t none_hash(PyObject *v)
+{
+ return 0xFCA86420;
+}
+
static PyNumberMethods none_as_number = {
0, /* nb_add */
0, /* nb_subtract */
@@ -1688,7 +1859,7 @@ PyTypeObject _PyNone_Type = {
"NoneType",
0,
0,
- none_dealloc, /*tp_dealloc*/ /*never called*/
+ none_dealloc, /*tp_dealloc*/
0, /*tp_vectorcall_offset*/
0, /*tp_getattr*/
0, /*tp_setattr*/
@@ -1697,7 +1868,7 @@ PyTypeObject _PyNone_Type = {
&none_as_number, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
- 0, /*tp_hash */
+ (hashfunc)none_hash,/*tp_hash */
0, /*tp_call */
0, /*tp_str */
0, /*tp_getattro */
@@ -1707,7 +1878,7 @@ PyTypeObject _PyNone_Type = {
0, /*tp_doc */
0, /*tp_traverse */
0, /*tp_clear */
- 0, /*tp_richcompare */
+ _Py_BaseObject_RichCompare, /*tp_richcompare */
0, /*tp_weaklistoffset */
0, /*tp_iter */
0, /*tp_iternext */
@@ -1725,8 +1896,9 @@ PyTypeObject _PyNone_Type = {
};
PyObject _Py_NoneStruct = {
- _PyObject_EXTRA_INIT
- 1, &_PyNone_Type
+ _PyObject_EXTRA_INIT
+ { _Py_IMMORTAL_REFCNT },
+ &_PyNone_Type
};
/* NotImplemented is an object that can be used to signal that an
@@ -1759,13 +1931,14 @@ notimplemented_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
Py_RETURN_NOTIMPLEMENTED;
}
-static void _Py_NO_RETURN
-notimplemented_dealloc(PyObject* ignore)
+static void
+notimplemented_dealloc(PyObject *notimplemented)
{
/* This should never get called, but we also don't want to SEGV if
- * we accidentally decref NotImplemented out of existence.
+ * we accidentally decref NotImplemented out of existence. Instead,
+ * since Notimplemented is an immortal object, re-set the reference count.
*/
- Py_FatalError("deallocating NotImplemented");
+ _Py_SetImmortal(notimplemented);
}
static int
@@ -1827,31 +2000,27 @@ PyTypeObject _PyNotImplemented_Type = {
PyObject _Py_NotImplementedStruct = {
_PyObject_EXTRA_INIT
- 1, &_PyNotImplemented_Type
+ { _Py_IMMORTAL_REFCNT },
+ &_PyNotImplemented_Type
};
-PyStatus
-_PyTypes_InitState(PyInterpreterState *interp)
+
+void
+_PyObject_InitState(PyInterpreterState *interp)
{
+#ifdef Py_TRACE_REFS
if (!_Py_IsMainInterpreter(interp)) {
- return _PyStatus_OK();
- }
-
- PyStatus status = _PyTypes_InitSlotDefs();
- if (_PyStatus_EXCEPTION(status)) {
- return status;
+ init_refchain(interp);
}
-
- return _PyStatus_OK();
+#endif
}
-
-#ifdef MS_WINDOWS
-extern PyTypeObject PyHKEY_Type;
-#endif
extern PyTypeObject _Py_GenericAliasIterType;
extern PyTypeObject _PyMemoryIter_Type;
+extern PyTypeObject _PyLineIterator;
+extern PyTypeObject _PyPositionsIterator;
+extern PyTypeObject _PyLegacyEventHandler_Type;
static PyTypeObject* static_types[] = {
// The two most important base types: must be initialized first and
@@ -1897,9 +2066,6 @@ static PyTypeObject* static_types[] = {
&PyFunction_Type,
&PyGen_Type,
&PyGetSetDescr_Type,
-#ifdef MS_WINDOWS
- &PyHKEY_Type,
-#endif
&PyInstanceMethod_Type,
&PyListIter_Type,
&PyListRevIter_Type,
@@ -1939,6 +2105,7 @@ static PyTypeObject* static_types[] = {
&_PyAsyncGenASend_Type,
&_PyAsyncGenAThrow_Type,
&_PyAsyncGenWrappedValue_Type,
+ &_PyBufferWrapper_Type,
&_PyContextTokenMissing_Type,
&_PyCoroWrapper_Type,
&_Py_GenericAliasIterType,
@@ -1949,18 +2116,22 @@ static PyTypeObject* static_types[] = {
&_PyHamt_BitmapNode_Type,
&_PyHamt_CollisionNode_Type,
&_PyHamt_Type,
+ &_PyLegacyEventHandler_Type,
&_PyInterpreterID_Type,
+ &_PyLineIterator,
&_PyManagedBuffer_Type,
&_PyMemoryIter_Type,
&_PyMethodWrapper_Type,
&_PyNamespace_Type,
&_PyNone_Type,
&_PyNotImplemented_Type,
+ &_PyPositionsIterator,
&_PyUnicodeASCIIIter_Type,
&_PyUnion_Type,
&_PyWeakref_CallableProxyType,
&_PyWeakref_ProxyType,
&_PyWeakref_RefType,
+ &_PyTypeAlias_Type,
// subclasses: _PyTypes_FiniTypes() deallocates them before their base
// class
@@ -1976,15 +2147,11 @@ static PyTypeObject* static_types[] = {
PyStatus
_PyTypes_InitTypes(PyInterpreterState *interp)
{
- if (!_Py_IsMainInterpreter(interp)) {
- return _PyStatus_OK();
- }
-
// All other static types (unless initialized elsewhere)
for (size_t i=0; i < Py_ARRAY_LENGTH(static_types); i++) {
PyTypeObject *type = static_types[i];
- if (PyType_Ready(type) < 0) {
- return _PyStatus_ERR("Can't initialize types");
+ if (_PyStaticType_InitBuiltin(interp, type) < 0) {
+ return _PyStatus_ERR("Can't initialize builtin type");
}
if (type == &PyType_Type) {
// Sanitify checks of the two most important types
@@ -1993,6 +2160,11 @@ _PyTypes_InitTypes(PyInterpreterState *interp)
}
}
+ // Must be after static types are initialized
+ if (_Py_initialize_generic(interp) < 0) {
+ return _PyStatus_ERR("Can't initialize generic types");
+ }
+
return _PyStatus_OK();
}
@@ -2006,34 +2178,43 @@ _PyTypes_InitTypes(PyInterpreterState *interp)
void
_PyTypes_FiniTypes(PyInterpreterState *interp)
{
- if (!_Py_IsMainInterpreter(interp)) {
- return;
- }
-
// Deallocate types in the reverse order to deallocate subclasses before
// their base classes.
for (Py_ssize_t i=Py_ARRAY_LENGTH(static_types)-1; i>=0; i--) {
PyTypeObject *type = static_types[i];
- _PyStaticType_Dealloc(type);
+ _PyStaticType_Dealloc(interp, type);
}
}
-void
-_Py_NewReference(PyObject *op)
+static inline void
+new_reference(PyObject *op)
{
- if (_Py_tracemalloc_config.tracing) {
+ if (_PyRuntime.tracemalloc.config.tracing) {
_PyTraceMalloc_NewReference(op);
}
-#ifdef Py_REF_DEBUG
- _Py_RefTotal++;
-#endif
- Py_SET_REFCNT(op, 1);
+ // Skip the immortal object check in Py_SET_REFCNT; always set refcnt to 1
+ op->ob_refcnt = 1;
#ifdef Py_TRACE_REFS
_Py_AddToAllObjects(op, 1);
#endif
}
+void
+_Py_NewReference(PyObject *op)
+{
+#ifdef Py_REF_DEBUG
+ reftotal_increment(_PyInterpreterState_GET());
+#endif
+ new_reference(op);
+}
+
+void
+_Py_NewReferenceNoTotal(PyObject *op)
+{
+ new_reference(op);
+}
+
#ifdef Py_TRACE_REFS
void
@@ -2043,7 +2224,8 @@ _Py_ForgetReference(PyObject *op)
_PyObject_ASSERT_FAILED_MSG(op, "negative refcnt");
}
- if (op == &refchain ||
+ PyObject *refchain = REFCHAIN(_PyInterpreterState_GET());
+ if (op == refchain ||
op->_ob_prev->_ob_next != op || op->_ob_next->_ob_prev != op)
{
_PyObject_ASSERT_FAILED_MSG(op, "invalid object chain");
@@ -2051,12 +2233,12 @@ _Py_ForgetReference(PyObject *op)
#ifdef SLOW_UNREF_CHECK
PyObject *p;
- for (p = refchain._ob_next; p != &refchain; p = p->_ob_next) {
+ for (p = refchain->_ob_next; p != refchain; p = p->_ob_next) {
if (p == op) {
break;
}
}
- if (p == &refchain) {
+ if (p == refchain) {
/* Not found */
_PyObject_ASSERT_FAILED_MSG(op,
"object not found in the objects list");
@@ -2072,11 +2254,15 @@ _Py_ForgetReference(PyObject *op)
* interpreter must be in a healthy state.
*/
void
-_Py_PrintReferences(FILE *fp)
+_Py_PrintReferences(PyInterpreterState *interp, FILE *fp)
{
PyObject *op;
+ if (interp == NULL) {
+ interp = _PyInterpreterState_Main();
+ }
fprintf(fp, "Remaining objects:\n");
- for (op = refchain._ob_next; op != &refchain; op = op->_ob_next) {
+ PyObject *refchain = REFCHAIN(interp);
+ for (op = refchain->_ob_next; op != refchain; op = op->_ob_next) {
fprintf(fp, "%p [%zd] ", (void *)op, Py_REFCNT(op));
if (PyObject_Print(op, fp, 0) != 0) {
PyErr_Clear();
@@ -2088,34 +2274,42 @@ _Py_PrintReferences(FILE *fp)
/* Print the addresses of all live objects. Unlike _Py_PrintReferences, this
* doesn't make any calls to the Python C API, so is always safe to call.
*/
+// XXX This function is not safe to use if the interpreter has been
+// freed or is in an unhealthy state (e.g. late in finalization).
+// The call in Py_FinalizeEx() is okay since the main interpreter
+// is statically allocated.
void
-_Py_PrintReferenceAddresses(FILE *fp)
+_Py_PrintReferenceAddresses(PyInterpreterState *interp, FILE *fp)
{
PyObject *op;
+ PyObject *refchain = REFCHAIN(interp);
fprintf(fp, "Remaining object addresses:\n");
- for (op = refchain._ob_next; op != &refchain; op = op->_ob_next)
+ for (op = refchain->_ob_next; op != refchain; op = op->_ob_next)
fprintf(fp, "%p [%zd] %s\n", (void *)op,
Py_REFCNT(op), Py_TYPE(op)->tp_name);
}
+/* The implementation of sys.getobjects(). */
PyObject *
_Py_GetObjects(PyObject *self, PyObject *args)
{
int i, n;
PyObject *t = NULL;
PyObject *res, *op;
+ PyInterpreterState *interp = _PyInterpreterState_GET();
if (!PyArg_ParseTuple(args, "i|O", &n, &t))
return NULL;
- op = refchain._ob_next;
+ PyObject *refchain = REFCHAIN(interp);
+ op = refchain->_ob_next;
res = PyList_New(0);
if (res == NULL)
return NULL;
- for (i = 0; (n == 0 || i < n) && op != &refchain; i++) {
+ for (i = 0; (n == 0 || i < n) && op != refchain; i++) {
while (op == self || op == args || op == res || op == t ||
(t != NULL && !Py_IS_TYPE(op, (PyTypeObject *) t))) {
op = op->_ob_next;
- if (op == &refchain)
+ if (op == refchain)
return res;
}
if (PyList_Append(res, op) < 0) {
@@ -2127,7 +2321,9 @@ _Py_GetObjects(PyObject *self, PyObject *args)
return res;
}
-#endif
+#undef REFCHAIN
+
+#endif /* Py_TRACE_REFS */
/* Hack to force loading of abstract.o */
@@ -2195,9 +2391,8 @@ Py_ReprLeave(PyObject *obj)
PyObject *dict;
PyObject *list;
Py_ssize_t i;
- PyObject *error_type, *error_value, *error_traceback;
- PyErr_Fetch(&error_type, &error_value, &error_traceback);
+ PyObject *exc = PyErr_GetRaisedException();
dict = PyThreadState_GetDict();
if (dict == NULL)
@@ -2218,7 +2413,7 @@ Py_ReprLeave(PyObject *obj)
finally:
/* ignore exceptions because there is no way to report them. */
- PyErr_Restore(error_type, error_value, error_traceback);
+ PyErr_SetRaisedException(exc);
}
/* Trashcan support. */
@@ -2230,22 +2425,20 @@ finally:
* object, with refcount 0. Py_DECREF must already have been called on it.
*/
static void
-_PyTrash_thread_deposit_object(PyObject *op)
+_PyTrash_thread_deposit_object(struct _py_trashcan *trash, PyObject *op)
{
- PyThreadState *tstate = _PyThreadState_GET();
_PyObject_ASSERT(op, _PyObject_IS_GC(op));
_PyObject_ASSERT(op, !_PyObject_GC_IS_TRACKED(op));
_PyObject_ASSERT(op, Py_REFCNT(op) == 0);
- _PyGCHead_SET_PREV(_Py_AS_GC(op), tstate->trash_delete_later);
- tstate->trash_delete_later = op;
+ _PyGCHead_SET_PREV(_Py_AS_GC(op), (PyGC_Head*)trash->delete_later);
+ trash->delete_later = op;
}
/* Deallocate all the objects in the gcstate->trash_delete_later list.
* Called when the call-stack unwinds again. */
static void
-_PyTrash_thread_destroy_chain(void)
+_PyTrash_thread_destroy_chain(struct _py_trashcan *trash)
{
- PyThreadState *tstate = _PyThreadState_GET();
/* We need to increase trash_delete_nesting here, otherwise,
_PyTrash_thread_destroy_chain will be called recursively
and then possibly crash. An example that may crash without
@@ -2257,13 +2450,13 @@ _PyTrash_thread_destroy_chain(void)
tups = [(tup,) for tup in tups]
del tups
*/
- assert(tstate->trash_delete_nesting == 0);
- ++tstate->trash_delete_nesting;
- while (tstate->trash_delete_later) {
- PyObject *op = tstate->trash_delete_later;
+ assert(trash->delete_nesting == 0);
+ ++trash->delete_nesting;
+ while (trash->delete_later) {
+ PyObject *op = trash->delete_later;
destructor dealloc = Py_TYPE(op)->tp_dealloc;
- tstate->trash_delete_later =
+ trash->delete_later =
(PyObject*) _PyGCHead_PREV(_Py_AS_GC(op));
/* Call the deallocator directly. This used to try to
@@ -2274,22 +2467,64 @@ _PyTrash_thread_destroy_chain(void)
*/
_PyObject_ASSERT(op, Py_REFCNT(op) == 0);
(*dealloc)(op);
- assert(tstate->trash_delete_nesting == 1);
+ assert(trash->delete_nesting == 1);
+ }
+ --trash->delete_nesting;
+}
+
+
+static struct _py_trashcan *
+_PyTrash_get_state(PyThreadState *tstate)
+{
+ if (tstate != NULL) {
+ return &tstate->trash;
+ }
+ // The current thread must be finalizing.
+ // Fall back to using thread-local state.
+ // XXX Use thread-local variable syntax?
+ assert(PyThread_tss_is_created(&_PyRuntime.trashTSSkey));
+ struct _py_trashcan *trash =
+ (struct _py_trashcan *)PyThread_tss_get(&_PyRuntime.trashTSSkey);
+ if (trash == NULL) {
+ trash = PyMem_RawMalloc(sizeof(struct _py_trashcan));
+ if (trash == NULL) {
+ Py_FatalError("Out of memory");
+ }
+ PyThread_tss_set(&_PyRuntime.trashTSSkey, (void *)trash);
+ }
+ return trash;
+}
+
+static void
+_PyTrash_clear_state(PyThreadState *tstate)
+{
+ if (tstate != NULL) {
+ assert(tstate->trash.delete_later == NULL);
+ return;
+ }
+ if (PyThread_tss_is_created(&_PyRuntime.trashTSSkey)) {
+ struct _py_trashcan *trash =
+ (struct _py_trashcan *)PyThread_tss_get(&_PyRuntime.trashTSSkey);
+ if (trash != NULL) {
+ PyThread_tss_set(&_PyRuntime.trashTSSkey, (void *)NULL);
+ PyMem_RawFree(trash);
+ }
}
- --tstate->trash_delete_nesting;
}
int
_PyTrash_begin(PyThreadState *tstate, PyObject *op)
{
- if (tstate->trash_delete_nesting >= _PyTrash_UNWIND_LEVEL) {
+ // XXX Make sure the GIL is held.
+ struct _py_trashcan *trash = _PyTrash_get_state(tstate);
+ if (trash->delete_nesting >= _PyTrash_UNWIND_LEVEL) {
/* Store the object (to be deallocated later) and jump past
* Py_TRASHCAN_END, skipping the body of the deallocator */
- _PyTrash_thread_deposit_object(op);
+ _PyTrash_thread_deposit_object(trash, op);
return 1;
}
- ++tstate->trash_delete_nesting;
+ ++trash->delete_nesting;
return 0;
}
@@ -2297,9 +2532,14 @@ _PyTrash_begin(PyThreadState *tstate, PyObject *op)
void
_PyTrash_end(PyThreadState *tstate)
{
- --tstate->trash_delete_nesting;
- if (tstate->trash_delete_later && tstate->trash_delete_nesting <= 0) {
- _PyTrash_thread_destroy_chain();
+ // XXX Make sure the GIL is held.
+ struct _py_trashcan *trash = _PyTrash_get_state(tstate);
+ --trash->delete_nesting;
+ if (trash->delete_nesting <= 0) {
+ if (trash->delete_later != NULL) {
+ _PyTrash_thread_destroy_chain(trash);
+ }
+ _PyTrash_clear_state(tstate);
}
}
@@ -2347,14 +2587,9 @@ _PyObject_AssertFailed(PyObject *obj, const char *expr, const char *msg,
/* Display the traceback where the object has been allocated.
Do it before dumping repr(obj), since repr() is more likely
to crash than dumping the traceback. */
- void *ptr;
PyTypeObject *type = Py_TYPE(obj);
- if (_PyType_IS_GC(type)) {
- ptr = (void *)((char *)obj - sizeof(PyGC_Head));
- }
- else {
- ptr = (void *)obj;
- }
+ const size_t presize = _PyType_PreHeaderSize(type);
+ void *ptr = (void *)((char *)obj - presize);
_PyMem_DumpTraceback(fileno(stderr), ptr);
/* This might succeed or fail, but we're about to abort, so at least
@@ -2376,10 +2611,10 @@ _Py_Dealloc(PyObject *op)
destructor dealloc = type->tp_dealloc;
#ifdef Py_DEBUG
PyThreadState *tstate = _PyThreadState_GET();
- PyObject *old_exc_type = tstate->curexc_type;
+ PyObject *old_exc = tstate != NULL ? tstate->current_exception : NULL;
// Keep the old exception type alive to prevent undefined behavior
// on (tstate->curexc_type != old_exc_type) below
- Py_XINCREF(old_exc_type);
+ Py_XINCREF(old_exc);
// Make sure that type->tp_name remains valid
Py_INCREF(type);
#endif
@@ -2392,12 +2627,12 @@ _Py_Dealloc(PyObject *op)
#ifdef Py_DEBUG
// gh-89373: The tp_dealloc function must leave the current exception
// unchanged.
- if (tstate->curexc_type != old_exc_type) {
+ if (tstate != NULL && tstate->current_exception != old_exc) {
const char *err;
- if (old_exc_type == NULL) {
+ if (old_exc == NULL) {
err = "Deallocator of type '%s' raised an exception";
}
- else if (tstate->curexc_type == NULL) {
+ else if (tstate->current_exception == NULL) {
err = "Deallocator of type '%s' cleared the current exception";
}
else {
@@ -2408,7 +2643,7 @@ _Py_Dealloc(PyObject *op)
}
_Py_FatalErrorFormat(__func__, err, type->tp_name);
}
- Py_XDECREF(old_exc_type);
+ Py_XDECREF(old_exc);
Py_DECREF(type);
#endif
}