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
Better tp_version_tag overflow checks in specializer #89811
Unless I'm mistaken, the current code in Python/specialize.c doesn't check for valid tp_version_tag, so version tag could overflow and it wouldn't know any better.
Ideally, we should add more robust tests for when tp_version_tag overflows, but that's a project for another day.
Just want to report that I accidentally ran into this in the wild. I work on an instrumentation library that modifies builtin types like str and bytes, which involves a few calls to PyType_Modified. My tests call this function hundreds of thousands of times when enabling and disabling machinery.
Repeated calls to PyType_Modified eventually caused tp_version_tag for modified builtin types to reach _Py_MAX_GLOBAL_TYPE_VERSION_TAG, which in turn led to tp_version_tag == 0 on these types. Some of the recent LOAD_ATTR_* bytecode specializations rely on tp_version_tag to determine whether to continue with the specialization or fall back to the generic operation. However, with multiple types having tp_version_tag == 0, python was no longer able to correctly distinguish between different types, leading to a variety of strange (oddly hilarious) errors.
Here's a reproduction script:
importctypesPyType_Modified=ctypes.pythonapi.PyType_ModifiedPyType_Modified.argtypes= [ctypes.py_object]
# reach _Py_MAX_GLOBAL_TYPE_VERSION_TAGforiinrange(2**17):
PyType_Modified(list)
[].__add__# any attribute lookup forces a new tp_version_tag# newly modified types will be assigned tp_version_tag 0PyType_Modified(str)
PyType_Modified(bytes)
defget_capitalize(type_):
returntype_.capitalize# multiple calls with `str` leads to LOAD_ATTR specializationget_capitalize(str)
get_capitalize(str)
# specialized bytecode fails to differentiate `bytes` from `str`# TypeError: descriptor 'capitalize' for 'str' objects doesn't apply to a 'bytes' objectget_capitalize(bytes)(b"boom")
I verified that this fails in 3.12.1 and 3.13.0a2 and does not fail in 3.11.7 (source builds using pyenv on an M1 mac). I'll be able to work around my particular issue, but I felt responsible to report this as a data point. It's possible that other instrumentation tools will eventually encounter similar issues.
Thanks for all of the recent interpreter improvements - it's been exciting to see these changes. If you'd like me to try refreshing the stale PR here or help out in any other way, I'd be happy to give it a shot.
@lazorchakp thanks for the reproducer! I can help guide you on making a PR towards fixing this if you're interested. Honestly I did not expect this to appear in the wild, so I forgot about it.
The fix would still be the same - to check tp_version_tag == 0 after analyze_descriptor calls in specialize.c.
@Fidget-Spinner thanks for the quick response! I can definitely throw something together. This will be my first contribution to the project, so I'd really appreciate any guidance. I have a few conflicting priorities at the moment, but I'll work on getting a PR out and then hopefully you can catch anything I may have missed.
Sorry for the late reply. Do you need help or any guidance on this? If you need help I'll be happy to set up something (you can email me at my GH profile's email).
I'm marking this as a release blocker for 3.12 and 3.13. We should still backport this to 3.11, but the chances of this occuring in that version seems to be lower.
Peter, please don't feel rushed to do this and have a good holiday! If it helps, I think you can submit a draft PR first and we can try to help you from there.
cc @Yhg1s (sorry for the holiday ping, please ignore this until you get back)
This is marked as a release-blocker with the 3.11 tag. The issue is still open but I am not sure if this was expected to be backported to 3.11. It's there anything left for us to do here or can I proceed with the release?
Activity
Fidget-Spinner commentedon Oct 28, 2021
Unless I'm mistaken, the current code in Python/specialize.c doesn't check for valid tp_version_tag, so version tag could overflow and it wouldn't know any better.
Ideally, we should add more robust tests for when tp_version_tag overflows, but that's a project for another day.
lazorchakp commentedon Dec 12, 2023
Just want to report that I accidentally ran into this in the wild. I work on an instrumentation library that modifies builtin types like
strandbytes, which involves a few calls to PyType_Modified. My tests call this function hundreds of thousands of times when enabling and disabling machinery.Repeated calls to PyType_Modified eventually caused tp_version_tag for modified builtin types to reach
_Py_MAX_GLOBAL_TYPE_VERSION_TAG, which in turn led to tp_version_tag == 0 on these types. Some of the recent LOAD_ATTR_* bytecode specializations rely on tp_version_tag to determine whether to continue with the specialization or fall back to the generic operation. However, with multiple types having tp_version_tag == 0, python was no longer able to correctly distinguish between different types, leading to a variety of strange (oddly hilarious) errors.Here's a reproduction script:
I verified that this fails in 3.12.1 and 3.13.0a2 and does not fail in 3.11.7 (source builds using pyenv on an M1 mac). I'll be able to work around my particular issue, but I felt responsible to report this as a data point. It's possible that other instrumentation tools will eventually encounter similar issues.
Thanks for all of the recent interpreter improvements - it's been exciting to see these changes. If you'd like me to try refreshing the stale PR here or help out in any other way, I'd be happy to give it a shot.
Fidget-Spinner commentedon Dec 12, 2023
@lazorchakp thanks for the reproducer! I can help guide you on making a PR towards fixing this if you're interested. Honestly I did not expect this to appear in the wild, so I forgot about it.
The fix would still be the same - to check
tp_version_tag == 0afteranalyze_descriptorcalls inspecialize.c.lazorchakp commentedon Dec 12, 2023
@Fidget-Spinner thanks for the quick response! I can definitely throw something together. This will be my first contribution to the project, so I'd really appreciate any guidance. I have a few conflicting priorities at the moment, but I'll work on getting a PR out and then hopefully you can catch anything I may have missed.
Fidget-Spinner commentedon Dec 20, 2023
Sorry for the late reply. Do you need help or any guidance on this? If you need help I'll be happy to set up something (you can email me at my GH profile's email).
lazorchakp commentedon Dec 21, 2023
That would be great. I think I have a reasonable solution, but I'm unsure how to test it thoroughly - I'll reach out directly
Fidget-Spinner commentedon Dec 27, 2023
Another reproducer is at #113462.
I'm marking this as a release blocker for 3.12 and 3.13. We should still backport this to 3.11, but the chances of this occuring in that version seems to be lower.
Peter, please don't feel rushed to do this and have a good holiday! If it helps, I think you can submit a draft PR first and we can try to help you from there.
cc @Yhg1s (sorry for the holiday ping, please ignore this until you get back)
9 remaining items
bedevere-app commentedon Jan 17, 2024
GH-114216 is a backport of this pull request to the 3.12 branch.
Merge branch '3.12' into pythongh-89811-3.12-backport
[3.12] Check for valid tp_version_tag in specializer (gh-89811) (gh-1…
pythongh-89811: Check for valid tp_version_tag in specializer (python…
pablogsal commentedon Feb 5, 2024
This is marked as a release-blocker with the 3.11 tag. The issue is still open but I am not sure if this was expected to be backported to 3.11. It's there anything left for us to do here or can I proceed with the release?
lazorchakp commentedon Feb 5, 2024
@pablogsal This does need a backport to 3.11, but I'm currently working on it. Sorry for the delay - I'll have a PR up as soon as possible
pythongh-89811: Check for valid tp_version_tag in specializer (python…
bedevere-app commentedon Feb 5, 2024
GH-115045 is a backport of this pull request to the 3.12 branch.
bedevere-app commentedon Feb 5, 2024
GH-115045 is a backport of this pull request to the 3.11 branch.
[3.11] gh-89811: Check for valid tp_version_tag in specializer (GH-11…
pythongh-89811: Check for valid tp_version_tag in specializer (python…
pythongh-89811: Check for valid tp_version_tag in specializer (python…