-
-
Notifications
You must be signed in to change notification settings - Fork 31.7k
GH-99293: Fix stale method caches and assertion errors in SWIG-generated modules #99294
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
modules. Extension modules generated by SWIG up to version 4.1.0 clear the Py_TPFLAGS_VALID_VERSION_TAG bit from tp_flags when modifying the type, as they should, but do not update tp_version_tag as typeobject.c expects. (For example, merely one of many instances I've found: https://github.com/OSGeo/gdal/blob/6bd07b20b3e55c2fc94da611244a615a4fd2991f/swig/python/extensions/osr_wrap.cpp#L2296) In release builds this means a potentially stale cached entry is used, and in debug builds (or release builds that happen to enable assertions, which as it turns out is actually a good idea) it triggers an assertion error. SWIG 4.1.0 avoids this problem by using PyType_Modified(), but there are a lot of older versions of SWIG and of checked-in generated extension modules around.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. However, let's wait a bit for others to review.
#if MCACHE_STATS | ||
cache->hits++; | ||
#endif | ||
assert(_PyType_HasFeature(type, Py_TPFLAGS_VALID_VERSION_TAG)); | ||
return entry->value; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For other reviewers wondering what happens down this code path if Py_TPFLAGS_VALID_VERSION_TAG
is not set:
- A normal lookup happens where we walk the MRO.
- We assign a new version tag to the type. This sets
Py_TPFLAGS_VALID_VERSION_TAG
.
So this should be safe.
@@ -0,0 +1 @@ | |||
Fix an issue where extension modules could inadvertently trigger an assertion error in typeobject.c by clearing the Py_TPFLAGS_VALID_VERSION_TAG tp_flag without clearing the tp_version_tag field. (Extension modules should use PyType_Modified() instead, however.) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just noticed Py_TPFLAGS_VALID_VERSION_TAG
isn't actually documented.
Fix an issue where extension modules could inadvertently trigger an assertion error in typeobject.c by clearing the Py_TPFLAGS_VALID_VERSION_TAG tp_flag without clearing the tp_version_tag field. (Extension modules should use PyType_Modified() instead, however.) | |
Fix an issue where extension modules could inadvertently trigger an assertion error in ``typeobject.c`` by clearing the ``Py_TPFLAGS_VALID_VERSION_TAG`` :c:member:`~PyTypeObject.tp_flags` without clearing the :c:member:`~PyTypeObject.tp_version_tag` field. (Extension modules should use :c:func:`PyType_Modified` instead, however.) |
Copying a comment I made elsewhere: The code will One fix is to add a guard to all specialised |
Extension modules generated by SWIG up to version 4.1.0 clear the Py_TPFLAGS_VALID_VERSION_TAG bit from tp_flags when modifying the type, as they should, but do not update tp_version_tag as typeobject.c expects. (For example, merely one of many instances I've found: https://github.com/OSGeo/gdal/blob/6bd07b20b3e55c2fc94da611244a615a4fd2991f/swig/python/extensions/osr_wrap.cpp#L2296)
In release builds this means a potentially stale cached entry is used, and in debug builds (or release builds that happen to enable assertions, which as it turns out is actually a good idea) it triggers an assertion error.
SWIG 4.1.0 avoids this problem by using PyType_Modified(), but there are a lot of older versions of SWIG and of checked-in generated extension modules around.