| #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 |
| |
| #include "pycore_critical_section.h" // Py_BEGIN_CRITICAL_SECTION() |
| #include "pycore_object.h" // _Py_REF_IS_MERGED() |
| |
| static inline int _is_dead(PyObject *obj) |
| { |
| // 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. |
| #if defined(Py_GIL_DISABLED) |
| Py_ssize_t shared = _Py_atomic_load_ssize_relaxed(&obj->ob_ref_shared); |
| return shared == _Py_REF_SHARED(0, _Py_REF_MERGED); |
| #else |
| return (Py_REFCNT(obj) == 0); |
| #endif |
| } |
| |
| static inline PyObject* _PyWeakref_GET_REF(PyObject *ref_obj) |
| { |
| assert(PyWeakref_Check(ref_obj)); |
| PyObject *ret = NULL; |
| Py_BEGIN_CRITICAL_SECTION(ref_obj); |
| PyWeakReference *ref = _Py_CAST(PyWeakReference*, ref_obj); |
| PyObject *obj = ref->wr_object; |
| |
| if (obj == Py_None) { |
| // clear_weakref() was called |
| goto end; |
| } |
| |
| if (_is_dead(obj)) { |
| goto end; |
| } |
| #if !defined(Py_GIL_DISABLED) |
| assert(Py_REFCNT(obj) > 0); |
| #endif |
| ret = Py_NewRef(obj); |
| end: |
| Py_END_CRITICAL_SECTION(); |
| return ret; |
| } |
| |
| static inline int _PyWeakref_IS_DEAD(PyObject *ref_obj) |
| { |
| assert(PyWeakref_Check(ref_obj)); |
| int ret = 0; |
| Py_BEGIN_CRITICAL_SECTION(ref_obj); |
| PyWeakReference *ref = _Py_CAST(PyWeakReference*, ref_obj); |
| PyObject *obj = ref->wr_object; |
| if (obj == Py_None) { |
| // clear_weakref() was called |
| ret = 1; |
| } |
| else { |
| // See _PyWeakref_GET_REF() for the rationale of this test |
| ret = _is_dead(obj); |
| } |
| Py_END_CRITICAL_SECTION(); |
| return ret; |
| } |
| |
| extern Py_ssize_t _PyWeakref_GetWeakrefCount(PyWeakReference *head); |
| |
| extern void _PyWeakref_ClearRef(PyWeakReference *self); |
| |
| #ifdef __cplusplus |
| } |
| #endif |
| #endif /* !Py_INTERNAL_WEAKREF_H */ |
| |