Skip to content

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

Open
anujbharambe wants to merge 4 commits intopython:mainfrom
anujbharambe:fix-type-watcher-dealloc
Open

gh-149216: Notify type watchers on heap type deallocation#149236
anujbharambe wants to merge 4 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 #32513994 | 📁 Comparing 3195afb against main (f2c7c0d)

  🔍 Preview build  

41 files changed · ± 41 modified

± Modified

Comment thread Objects/typeobject.c Outdated
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
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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PyType_Watch does not report deallocations

3 participants