-
-
Notifications
You must be signed in to change notification settings - Fork 32.7k
Open
Labels
type-crashA hard crash of the interpreter, possibly with a core dumpA hard crash of the interpreter, possibly with a core dump
Description
Crash report
What happened?
Over at Eventlet an interesting crash has been discovered: eventlet/eventlet#864
I managed to narrow it down to something like this
# crash.py
import gc
class Cls:
var = []
for ref in gc.get_referrers(Cls.var):
del ref['var']
# Depending on the environment only a subset of these calls is needed
# to trigger the segfault:
gc.collect()
print(Cls.var)
gc.collect()
print(Cls.var)
It crashes with all currently supported Python versions (3.8-3.12) and with the current main
branch:
% python3 crash.py
[]
zsh: segmentation fault python3 crash.py
I'm not familiar with this code but I think the problem is caused by the type cache being unaware of the class' dictionary being modified. If I disable the type cache lookup in _PyType_Lookup
like so
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index ea29a38d74ae..c6e65593b454 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -4759,13 +4759,13 @@ _PyType_Lookup(PyTypeObject *type, PyObject *name)
unsigned int h = MCACHE_HASH_METHOD(type, name);
struct type_cache *cache = get_type_cache();
struct type_cache_entry *entry = &cache->hashtable[h];
- if (entry->version == type->tp_version_tag &&
- entry->name == name) {
- assert(_PyType_HasFeature(type, Py_TPFLAGS_VALID_VERSION_TAG));
- OBJECT_STAT_INC_COND(type_cache_hits, !is_dunder_name(name));
- OBJECT_STAT_INC_COND(type_cache_dunder_hits, is_dunder_name(name));
- return entry->value;
- }
+ // if (entry->version == type->tp_version_tag &&
+ // entry->name == name) {
+ // assert(_PyType_HasFeature(type, Py_TPFLAGS_VALID_VERSION_TAG));
+ // OBJECT_STAT_INC_COND(type_cache_hits, !is_dunder_name(name));
+ // OBJECT_STAT_INC_COND(type_cache_dunder_hits, is_dunder_name(name));
+ // return entry->value;
+ // }
OBJECT_STAT_INC_COND(type_cache_misses, !is_dunder_name(name));
OBJECT_STAT_INC_COND(type_cache_dunder_misses, is_dunder_name(name));
the issue goes away:
% ~/projects/cpython/python.exe crash.py
Traceback (most recent call last):
File "/Users/user/crash.py", line 12, in <module>
print(Cls.var)
^^^^^^^
AttributeError: type object 'Cls' has no attribute 'var'
I don't feel confident enough to produce a good fix for this at this stage.
CPython versions tested on:
3.8, 3.9, 3.10, 3.11, 3.12, CPython main branch
Operating systems tested on:
Linux, macOS
Output from running 'python -VV' on the command line:
No response
Metadata
Metadata
Assignees
Labels
type-crashA hard crash of the interpreter, possibly with a core dumpA hard crash of the interpreter, possibly with a core dump