Skip to content

GH-99293: Fix stale method caches and assertion errors in SWIG-generated modules - #99294

Closed
Yhg1s wants to merge 2 commits into
python:mainfrom
Yhg1s:fix_assertion_errors
Closed

GH-99293: Fix stale method caches and assertion errors in SWIG-generated modules#99294
Yhg1s wants to merge 2 commits into
python:mainfrom
Yhg1s:fix_assertion_errors

Conversation

@Yhg1s

@Yhg1s Yhg1s commented Nov 9, 2022

Copy link
Copy Markdown
Member

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.

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.

@Fidget-Spinner Fidget-Spinner left a comment

Copy link
Copy Markdown
Member

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.

Comment thread Objects/typeobject.c
assert(_PyType_HasFeature(type, Py_TPFLAGS_VALID_VERSION_TAG));
return entry->value;
}

@Fidget-Spinner Fidget-Spinner Nov 9, 2022

Copy link
Copy Markdown
Member

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:

  1. A normal lookup happens where we walk the MRO.
  2. 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.)

Copy link
Copy Markdown
Member

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.

Suggested change
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.)

@Fidget-Spinner

Fidget-Spinner commented Nov 9, 2022

Copy link
Copy Markdown
Member

Copying a comment I made elsewhere:

The code will crash return incorrect cached methods and values on 3.11 when running specialised instructions. Those only use tp_version_tag as a guard and don't check Py_TPFLAGS_VALID_VERSION_TAG for speed reasons.

One fix is to add a guard to all specialised LOAD_METHOD/ATTR instructions to check for the flag (this will slow down all those instructions a little). Another fix is to ask everyone to regenerate their code with a newer SWIG for Python 3.11.0.

@hugovk hugovk removed the needs backport to 3.10 only security fixes label Apr 7, 2023
@serhiy-storchaka serhiy-storchaka added needs backport to 3.12 only security fixes needs backport to 3.13 bugs and security fixes and removed needs backport to 3.11 only security fixes labels May 9, 2024
@hugovk hugovk removed the needs backport to 3.12 only security fixes label Apr 25, 2025
@serhiy-storchaka serhiy-storchaka added the needs backport to 3.14 bugs and security fixes label May 8, 2025
@github-actions

Copy link
Copy Markdown

This PR is stale because it has been open for 30 days with no activity.

@github-actions github-actions Bot added the stale Stale PR or inactive for long period of time. label Apr 11, 2026
@serhiy-storchaka serhiy-storchaka added the needs backport to 3.15 pre-release feature fixes, bugs and security fixes label May 30, 2026
@github-actions github-actions Bot removed the stale Stale PR or inactive for long period of time. label Jun 5, 2026
@Yhg1s Yhg1s closed this Aug 13, 2026
@Yhg1s
Yhg1s deleted the fix_assertion_errors branch August 13, 2026 12:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

DO-NOT-MERGE needs backport to 3.13 bugs and security fixes needs backport to 3.14 bugs and security fixes needs backport to 3.15 pre-release feature fixes, bugs and security fixes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants