| #ifndef Py_INTERNAL_WEAKREF_H |
| #define Py_INTERNAL_WEAKREF_H |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| #ifndef Py_BUILD_CORE |
| # error "this header requires Py_BUILD_CORE define" |
| #endif |
| |
| static inline PyObject* _PyWeakref_GET_REF(PyObject *ref_obj) { |
| assert(PyWeakref_Check(ref_obj)); |
| PyWeakReference *ref = _Py_CAST(PyWeakReference*, ref_obj); |
| PyObject *obj = ref->wr_object; |
| |
| if (obj == Py_None) { |
| // clear_weakref() was called |
| return NULL; |
| } |
| |
| // Explanation for the Py_REFCNT() check: when a weakref's target is part |
| // of a long chain of deallocations which triggers the trashcan mechanism, |
| // clearing the weakrefs can be delayed long after the target's refcount |
| // has dropped to zero. In the meantime, code accessing the weakref will |
| // be able to "see" the target object even though it is supposed to be |
| // unreachable. See issue gh-60806. |
| Py_ssize_t refcnt = Py_REFCNT(obj); |
| if (refcnt == 0) { |
| return NULL; |
| } |
| |
| assert(refcnt > 0); |
| return Py_NewRef(obj); |
| } |
| |
| static inline int _PyWeakref_IS_DEAD(PyObject *ref_obj) { |
| assert(PyWeakref_Check(ref_obj)); |
| PyWeakReference *ref = _Py_CAST(PyWeakReference*, ref_obj); |
| PyObject *obj = ref->wr_object; |
| if (obj == Py_None) { |
| // clear_weakref() was called |
| return 1; |
| } |
| |
| // See _PyWeakref_GET_REF() for the rationale of this test |
| return (Py_REFCNT(obj) == 0); |
| } |
| |
| extern Py_ssize_t _PyWeakref_GetWeakrefCount(PyWeakReference *head); |
| |
| extern void _PyWeakref_ClearRef(PyWeakReference *self); |
| |
| #ifdef __cplusplus |
| } |
| #endif |
| #endif /* !Py_INTERNAL_WEAKREF_H */ |
| |