Skip to content

Add PyWeakref_IsDead() to test if a weak reference is dead #128008

Description

@colesbury

Feature or enhancement

// Returns 1 if the pointed to object is dead, 0 if it's alive, and -1 with an error set if `ref` is not a weak reference.
int PyWeakref_IsDead(PyObject *ref);

C API Working Group Issue

Motivation

Prior to Python 3.13, you could check if a weak reference is dead via PyWeakref_GetObject(ref) == Py_None, but that function is now deprecated. You might try writing an "is dead" check using PyWeakref_GetRef. For example:

int is_dead(PyObject *ref) {
    PyObject *tmp;
    if (PyWeakref_GetRef(&ref, &tmp) < 0) {
        return -1;
    }
    else if (tmp == NULL) {
        return 1;
    }
    Py_DECREF(tmp);
    return 0;
}

In addition to not being ergonomic, the problem with this code is that the Py_DECREF(tmp) may introduce a side effect from a calling a destructor, at least in the free threading build where some other thread may concurrently drop the last reference. Our internal _PyWeakref_IS_DEAD implementation avoids this problem, but it's not possible to reimplement that code using our existing public APIs.

This can be a problem when you need to check if a weak reference is dead within a lock, such as when cleaning up dictionaries or lists of weak references -- you don't want to execute arbitrary code via a destructor while holding the lock.

I've run into this in two C API extensions this week that are not currently thread-safe with free threading:

  • CFFI uses a dictionary that maps a string keys to unowned references. I'm working on update it to use PyWeakReference, but the "is dead" clean-up checks are more difficult due to the above issues.
  • Pandas cleans up a list of weak references. (The code is not currently thread-safe, and probably needs a lock.)

Linked PRs

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions