You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Segfault on cls.__dict__['__new__'].__annotations__ #125017
The following is a reproducer of (another) segfault discovered when trying to test Python 3.14 in CI for Sphinx:
classSpam:
def__new__(cls, x, y):
passif__name__=='__main__':
assertSpam.__new__.__annotations__== {}
obj=Spam.__dict__['__new__']
assertisinstance(obj, staticmethod)
getattr(obj, '__annotations__', None) # segfault heretry:
obj.__annotations__# and here (absent the above)exceptAttributeError:
passprint('no segfault!')
Whilst checking __annotations__ directly is somewhat convoluted, it was originally triggered by inspect.isasyncgenfunction(), which calls inspect._signature_is_functionlike() via _has_code_flag().
A similar error occurs with __class_getitem__ and __init_subclass__, but not with user-defined methdods declared with either classmethod or staticmethod. As the reproducer demonstrates, the segfault only happens with the descriptor object from __dict__ -- cls.__new__.__annotations__ is fine.
d28afd3fa064db10a2eb2a65bba33e8ea77a8fcf is the first bad commit
commit d28afd3fa064db10a2eb2a65bba33e8ea77a8fcf
Author: Jelle Zijlstra <jelle.zijlstra@gmail.com>
Date: Fri May 31 14:05:51 2024 -0700
gh-119180: Lazily wrap annotations on classmethod and staticmethod (#119864)
A
CPython versions tested on:
CPython main branch
Operating systems tested on:
Linux
Output from running 'python -VV' on the command line:
Python 3.14.0a0 (bisect/bad:d28afd3fa06, Oct 6 2024, 01:35:23) [GCC 13.2.0]
@JelleZijlstra I took a quick glance at the implementation and PR, and I think this is a matter of forgetting to initialize sm_dict and cm_dict in constructors. IIRC, if tp_dictoffset is used, the dictionary won't get created until someone tries to access __dict__, so here it ends up being NULL, and thus segfaulting.
Thanks @ZeroIntensity, I agree that's the right diagnosis. Found a related crash too:
Python 3.14.0a1+ (heads/main-dirty:a5a7f5e16d8, Oct 16 2024, 22:38:43) [Clang 15.0.0 (clang-1500.3.9.4)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> @classmethod
... def f(): pass
...
>>> del f.__annotations__
Assertion failed: (!_PyErr_Occurred(tstate)), function _PyEval_EvalFrameDefault, file generated_cases.c.h, line 5059.
Abort trap: 6
Activity
ZeroIntensity commentedon Oct 6, 2024
@JelleZijlstra I took a quick glance at the implementation and PR, and I think this is a matter of forgetting to initialize
sm_dictandcm_dictin constructors. IIRC, iftp_dictoffsetis used, the dictionary won't get created until someone tries to access__dict__, so here it ends up being NULL, and thus segfaulting.JelleZijlstra commentedon Oct 17, 2024
Thanks @ZeroIntensity, I agree that's the right diagnosis. Found a related crash too:
pythongh-125017: Fix crash on premature access to classmethod/staticm…
gh-125017: Fix crash on premature access to classmethod/staticmethod …
pythongh-125017: Fix refleak from pythonGH-125636
gh-125017: Fix refleak from GH-125636 (GH-125664)
pythongh-125017: Fix crash on premature access to classmethod/staticm…
pythongh-125017: Fix refleak from pythonGH-125636 (pythonGH-125664)