Skip to content

gh-149216: Notify type watchers on heap type deallocation#149236

Merged
markshannon merged 7 commits intopython:mainfrom
anujbharambe:fix-type-watcher-dealloc
May 5, 2026
Merged

gh-149216: Notify type watchers on heap type deallocation#149236
markshannon merged 7 commits intopython:mainfrom
anujbharambe:fix-type-watcher-dealloc

Conversation

@anujbharambe
Copy link
Copy Markdown
Contributor

@anujbharambe anujbharambe commented May 1, 2026

Summary

  • Notify type watcher callbacks from type_dealloc() before teardown, using the _PyObject_ResurrectStart/_PyObject_ResurrectEnd resurrection pattern (same as dict_dealloc())
  • Add a new test callback kind (NAME=3) in _testcapi/watchers.c that records the type's name as a string (avoids resurrecting the type during dealloc testing)
  • Add test_watch_type_dealloc and test_watch_type_dealloc_error tests
  • Document that PyType_WatchCallback may be called during deallocation

Fixes #149216

CC: @markshannon

When a watched heap type is deallocated, type watcher callbacks were
never invoked. The JIT optimizer relies on type watchers plus pointer
comparisons on watched types; if a type is freed and a new type is
allocated at the same address, stale JIT code could crash.

Call the registered watcher callbacks from type_dealloc(), using the
same _PyObject_ResurrectStart/_PyObject_ResurrectEnd pattern that
dict_dealloc() already uses. The notification happens before any
teardown, so callbacks can safely inspect the type object.
@read-the-docs-community
Copy link
Copy Markdown

read-the-docs-community Bot commented May 1, 2026

Documentation build overview

📚 cpython-previews | 🛠️ Build #32539179 | 📁 Comparing 13c5f96 against main (f2c7c0d)

  🔍 Preview build  

54 files changed · + 1 added · ± 53 modified

+ Added

± Modified

Comment thread Objects/typeobject.c
i++;
bits >>= 1;
}
if (_PyObject_ResurrectEnd(self)) {
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.

Suggested change
if (_PyObject_ResurrectEnd(self)) {
assert(Py_REFCNT(self) == 0);

Watchers aren't allowed to make changes like this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, replaced with the assert. Thanks for the review.

@anujbharambe anujbharambe requested a review from markshannon May 1, 2026 18:19
Comment thread Objects/typeobject.c Outdated
i++;
bits >>= 1;
}
assert(Py_REFCNT(self) == 0);
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.

Sorry to keep changing my mind, but now I think about this, it might not be safe to pass type to the watcher with refcount == 0.

The docs say very little about what a watcher can or cannot do.

So I think we need to increase the refcount to 1 before calling the watchers, then reduce it by one (not using Py_DECREF to avoid recursion), then finally check if it has been resurrected, as you did before.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverted the changes.

Copy link
Copy Markdown
Member

@markshannon markshannon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, thanks

@markshannon markshannon merged commit f6d16a0 into python:main May 5, 2026
102 of 106 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PyType_Watch does not report deallocations

3 participants