LCOV - code coverage report
Current view: | top level - Objects - weakrefobject.c (source / functions) |  |  | Hit | Total | Coverage
Test: | CPython 3.12 LCOV report [commit 5e6661bce9] |  | Lines: | 188 | 409 | 46.0 %
Date: | 2023-03-20 08:15:36 |  | Functions: | 21 | 75 | 28.0 %
|  |  | Branches: | 86 | 670 | 12.8 %

               Branch data     Line data    Source code
           1                 :            : #include "Python.h"
           2                 :            : #include "pycore_object.h"        // _PyObject_GET_WEAKREFS_LISTPTR()
           3                 :            : #include "structmember.h"         // PyMemberDef
           4                 :            :
           5                 :            :
           6                 :            : #define GET_WEAKREFS_LISTPTR(o) \
           7                 :            :         ((PyWeakReference **) _PyObject_GET_WEAKREFS_LISTPTR(o))
           8                 :            :
           9                 :            :
          10                 :            : Py_ssize_t
          11                 :       1046 : _PyWeakref_GetWeakrefCount(PyWeakReference *head)
          12                 :            : {
          13                 :       1046 :     Py_ssize_t count = 0;
          14                 :            :
          15         [ +  + ]:       2092 :     while (head != NULL) {
          16                 :       1046 :         ++count;
          17                 :       1046 :         head = head->wr_next;
          18                 :            :     }
          19                 :       1046 :     return count;
          20                 :            : }
          21                 :            :
          22                 :            : static PyObject *weakref_vectorcall(PyWeakReference *self, PyObject *const *args, size_t nargsf, PyObject *kwnames);
          23                 :            :
          24                 :            : static void
          25                 :      17851 : init_weakref(PyWeakReference *self, PyObject *ob, PyObject *callback)
          26                 :            : {
          27                 :      17851 :     self->hash = -1;
          28                 :      17851 :     self->wr_object = ob;
          29                 :      17851 :     self->wr_prev = NULL;
          30                 :      17851 :     self->wr_next = NULL;
          31                 :      17851 :     self->wr_callback = Py_XNewRef(callback);
          32                 :      17851 :     self->vectorcall = (vectorcallfunc)weakref_vectorcall;
          33                 :      17851 : }
          34                 :            :
          35                 :            : static PyWeakReference *
          36                 :      16777 : new_weakref(PyObject *ob, PyObject *callback)
          37                 :            : {
          38                 :            :     PyWeakReference *result;
          39                 :            :
          40                 :      16777 :     result = PyObject_GC_New(PyWeakReference, &_PyWeakref_RefType);
          41         [ +  - ]:      16777 :     if (result) {
          42                 :      16777 :         init_weakref(result, ob, callback);
          43                 :      16777 :         PyObject_GC_Track(result);
          44                 :            :     }
          45                 :      16777 :     return result;
          46                 :            : }
          47                 :            :
          48                 :            :
          49                 :            : /* This function clears the passed-in reference and removes it from the
          50                 :            :  * list of weak references for the referent.  This is the only code that
          51                 :            :  * removes an item from the doubly-linked list of weak references for an
          52                 :            :  * object; it is also responsible for clearing the callback slot.
          53                 :            :  */
          54                 :            : static void
          55                 :      28643 : clear_weakref(PyWeakReference *self)
          56                 :            : {
          57                 :      28643 :     PyObject *callback = self->wr_callback;
          58                 :            :
          59         [ +  + ]:      28643 :     if (self->wr_object != Py_None) {
          60                 :      16972 :         PyWeakReference **list = GET_WEAKREFS_LISTPTR(self->wr_object);
          61                 :            :
          62         [ +  + ]:      16972 :         if (*list == self)
          63                 :            :             /* If 'self' is the end of the list (and thus self->wr_next == NULL)
          64                 :            :                then the weakref list itself (and thus the value of *list) will
          65                 :            :                end up being set to NULL. */
          66                 :      15433 :             *list = self->wr_next;
          67                 :      16972 :         self->wr_object = Py_None;
          68         [ +  + ]:      16972 :         if (self->wr_prev != NULL)
          69                 :       1539 :             self->wr_prev->wr_next = self->wr_next;
          70         [ +  + ]:      16972 :         if (self->wr_next != NULL)
          71                 :        309 :             self->wr_next->wr_prev = self->wr_prev;
          72                 :      16972 :         self->wr_prev = NULL;
          73                 :      16972 :         self->wr_next = NULL;
          74                 :            :     }
          75         [ +  + ]:      28643 :     if (callback != NULL) {
          76                 :       1613 :         Py_DECREF(callback);
          77                 :       1613 :         self->wr_callback = NULL;
          78                 :            :     }
          79                 :      28643 : }
          80                 :            :
          81                 :            : /* Cyclic gc uses this to *just* clear the passed-in reference, leaving
          82                 :            :  * the callback intact and uncalled.  It must be possible to call self's
          83                 :            :  * tp_dealloc() after calling this, so self has to be left in a sane enough
          84                 :            :  * state for that to work.  We expect tp_dealloc to decref the callback
          85                 :            :  * then.  The reason for not letting clear_weakref() decref the callback
          86                 :            :  * right now is that if the callback goes away, that may in turn trigger
          87                 :            :  * another callback (if a weak reference to the callback exists) -- running
          88                 :            :  * arbitrary Python code in the middle of gc is a disaster.  The convolution
          89                 :            :  * here allows gc to delay triggering such callbacks until the world is in
          90                 :            :  * a sane state again.
          91                 :            :  */
          92                 :            : void
          93                 :      10241 : _PyWeakref_ClearRef(PyWeakReference *self)
          94                 :            : {
          95                 :            :     PyObject *callback;
          96                 :            :
          97                 :            :     assert(self != NULL);
          98                 :            :     assert(PyWeakref_Check(self));
          99                 :            :     /* Preserve and restore the callback around clear_weakref. */
         100                 :      10241 :     callback = self->wr_callback;
         101                 :      10241 :     self->wr_callback = NULL;
         102                 :      10241 :     clear_weakref(self);
         103                 :      10241 :     self->wr_callback = callback;
         104                 :      10241 : }
         105                 :            :
         106                 :            : static void
         107                 :      16914 : weakref_dealloc(PyObject *self)
         108                 :            : {
         109                 :      16914 :     PyObject_GC_UnTrack(self);
         110                 :      16914 :     clear_weakref((PyWeakReference *) self);
         111                 :      16914 :     Py_TYPE(self)->tp_free(self);
         112                 :      16914 : }
         113                 :            :
         114                 :            :
         115                 :            : static int
         116                 :     159536 : gc_traverse(PyWeakReference *self, visitproc visit, void *arg)
         117                 :            : {
         118   [ +  +  -  + ]:     159536 :     Py_VISIT(self->wr_callback);
         119                 :     159536 :     return 0;
         120                 :            : }
         121                 :            :
         122                 :            :
         123                 :            : static int
         124                 :          0 : gc_clear(PyWeakReference *self)
         125                 :            : {
         126                 :          0 :     clear_weakref(self);
         127                 :          0 :     return 0;
         128                 :            : }
         129                 :            :
         130                 :            :
         131                 :            : static PyObject *
         132                 :        256 : weakref_vectorcall(PyWeakReference *self, PyObject *const *args,
         133                 :            :                    size_t nargsf, PyObject *kwnames)
         134                 :            : {
         135   [ -  +  -  - ]:        256 :     if (!_PyArg_NoKwnames("weakref", kwnames)) {
         136                 :          0 :         return NULL;
         137                 :            :     }
         138                 :        256 :     Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
         139   [ +  -  -  +  :        256 :     if (!_PyArg_CheckPositional("weakref", nargs, 0, 0)) {
                       -  - ]
         140                 :          0 :         return NULL;
         141                 :            :     }
         142                 :        256 :     return Py_NewRef(PyWeakref_GET_OBJECT(self));
         143                 :            : }
         144                 :            :
         145                 :            : static Py_hash_t
         146                 :     102006 : weakref_hash(PyWeakReference *self)
         147                 :            : {
         148         [ +  + ]:     102006 :     if (self->hash != -1)
         149                 :      99843 :         return self->hash;
         150                 :       2163 :     PyObject* obj = PyWeakref_GET_OBJECT(self);
         151         [ -  + ]:       2163 :     if (obj == Py_None) {
         152                 :          0 :         PyErr_SetString(PyExc_TypeError, "weak object has gone away");
         153                 :          0 :         return -1;
         154                 :            :     }
         155                 :       2163 :     Py_INCREF(obj);
         156                 :       2163 :     self->hash = PyObject_Hash(obj);
         157                 :       2163 :     Py_DECREF(obj);
         158                 :       2163 :     return self->hash;
         159                 :            : }
         160                 :            :
         161                 :            :
         162                 :            : static PyObject *
         163                 :          0 : weakref_repr(PyWeakReference *self)
         164                 :            : {
         165                 :            :     PyObject *name, *repr;
         166                 :          0 :     PyObject* obj = PyWeakref_GET_OBJECT(self);
         167                 :            :
         168         [ #  # ]:          0 :     if (obj == Py_None) {
         169                 :          0 :         return PyUnicode_FromFormat("<weakref at %p; dead>", self);
         170                 :            :     }
         171                 :            :
         172                 :          0 :     Py_INCREF(obj);
         173         [ #  # ]:          0 :     if (_PyObject_LookupAttr(obj, &_Py_ID(__name__), &name) < 0) {
         174                 :          0 :         Py_DECREF(obj);
         175                 :          0 :         return NULL;
         176                 :            :     }
         177   [ #  #  #  # ]:          0 :     if (name == NULL || !PyUnicode_Check(name)) {
         178                 :          0 :         repr = PyUnicode_FromFormat(
         179                 :            :             "<weakref at %p; to '%s' at %p>",
         180                 :            :             self,
         181                 :          0 :             Py_TYPE(PyWeakref_GET_OBJECT(self))->tp_name,
         182                 :            :             obj);
         183                 :            :     }
         184                 :            :     else {
         185                 :          0 :         repr = PyUnicode_FromFormat(
         186                 :            :             "<weakref at %p; to '%s' at %p (%U)>",
         187                 :            :             self,
         188                 :          0 :             Py_TYPE(PyWeakref_GET_OBJECT(self))->tp_name,
         189                 :            :             obj,
         190                 :            :             name);
         191                 :            :     }
         192                 :          0 :     Py_DECREF(obj);
         193                 :          0 :     Py_XDECREF(name);
         194                 :          0 :     return repr;
         195                 :            : }
         196                 :            :
         197                 :            : /* Weak references only support equality, not ordering. Two weak references
         198                 :            :    are equal if the underlying objects are equal. If the underlying object has
         199                 :            :    gone away, they are equal if they are identical. */
         200                 :            :
         201                 :            : static PyObject *
         202                 :      70251 : weakref_richcompare(PyWeakReference* self, PyWeakReference* other, int op)
         203                 :            : {
         204   [ -  +  -  -  :     140502 :     if ((op != Py_EQ && op != Py_NE) ||
                       -  + ]
         205   [ -  -  -  -  :     140502 :         !PyWeakref_Check(self) ||
                       -  + ]
         206   [ -  -  -  - ]:      70251 :         !PyWeakref_Check(other)) {
         207                 :          0 :         Py_RETURN_NOTIMPLEMENTED;
         208                 :            :     }
         209         [ +  - ]:      70251 :     if (PyWeakref_GET_OBJECT(self) == Py_None
         210         [ -  + ]:      70251 :         || PyWeakref_GET_OBJECT(other) == Py_None) {
         211                 :          0 :         int res = (self == other);
         212         [ #  # ]:          0 :         if (op == Py_NE)
         213                 :          0 :             res = !res;
         214         [ #  # ]:          0 :         if (res)
         215                 :          0 :             Py_RETURN_TRUE;
         216                 :            :         else
         217                 :          0 :             Py_RETURN_FALSE;
         218                 :            :     }
         219                 :      70251 :     PyObject* obj = PyWeakref_GET_OBJECT(self);
         220                 :      70251 :     PyObject* other_obj = PyWeakref_GET_OBJECT(other);
         221                 :      70251 :     Py_INCREF(obj);
         222                 :      70251 :     Py_INCREF(other_obj);
         223                 :      70251 :     PyObject* res = PyObject_RichCompare(obj, other_obj, op);
         224                 :      70251 :     Py_DECREF(obj);
         225                 :      70251 :     Py_DECREF(other_obj);
         226                 :      70251 :     return res;
         227                 :            : }
         228                 :            :
         229                 :            : /* Given the head of an object's list of weak references, extract the
         230                 :            :  * two callback-less refs (ref and proxy).  Used to determine if the
         231                 :            :  * shared references exist and to determine the back link for newly
         232                 :            :  * inserted references.
         233                 :            :  */
         234                 :            : static void
         235                 :     137243 : get_basic_refs(PyWeakReference *head,
         236                 :            :                PyWeakReference **refp, PyWeakReference **proxyp)
         237                 :            : {
         238                 :     137243 :     *refp = NULL;
         239                 :     137243 :     *proxyp = NULL;
         240                 :            :
         241   [ +  +  +  + ]:     137243 :     if (head != NULL && head->wr_callback == NULL) {
         242                 :            :         /* We need to be careful that the "basic refs" aren't
         243                 :            :            subclasses of the main types.  That complicates this a
         244                 :            :            little. */
         245         [ +  - ]:     104775 :         if (PyWeakref_CheckRefExact(head)) {
         246                 :     104775 :             *refp = head;
         247                 :     104775 :             head = head->wr_next;
         248                 :            :         }
         249         [ +  + ]:     104775 :         if (head != NULL
         250         [ -  + ]:     101111 :             && head->wr_callback == NULL
         251   [ #  #  #  # ]:          0 :             && PyWeakref_CheckProxy(head)) {
         252                 :          0 :             *proxyp = head;
         253                 :            :             /* head = head->wr_next; */
         254                 :            :         }
         255                 :            :     }
         256                 :     137243 : }
         257                 :            :
         258                 :            : /* Insert 'newref' in the list after 'prev'.  Both must be non-NULL. */
         259                 :            : static void
         260                 :       1609 : insert_after(PyWeakReference *newref, PyWeakReference *prev)
         261                 :            : {
         262                 :       1609 :     newref->wr_prev = prev;
         263                 :       1609 :     newref->wr_next = prev->wr_next;
         264         [ +  + ]:       1609 :     if (prev->wr_next != NULL)
         265                 :        638 :         prev->wr_next->wr_prev = newref;
         266                 :       1609 :     prev->wr_next = newref;
         267                 :       1609 : }
         268                 :            :
         269                 :            : /* Insert 'newref' at the head of the list; 'list' points to the variable
         270                 :            :  * that stores the head.
         271                 :            :  */
         272                 :            : static void
         273                 :      16242 : insert_head(PyWeakReference *newref, PyWeakReference **list)
         274                 :            : {
         275                 :      16242 :     PyWeakReference *next = *list;
         276                 :            :
         277                 :      16242 :     newref->wr_prev = NULL;
         278                 :      16242 :     newref->wr_next = next;
         279         [ +  + ]:      16242 :     if (next != NULL)
         280                 :          8 :         next->wr_prev = newref;
         281                 :      16242 :     *list = newref;
         282                 :      16242 : }
         283                 :            :
         284                 :            : static int
         285                 :       2160 : parse_weakref_init_args(const char *funcname, PyObject *args, PyObject *kwargs,
         286                 :            :                         PyObject **obp, PyObject **callbackp)
         287                 :            : {
         288                 :       2160 :     return PyArg_UnpackTuple(args, funcname, 1, 2, obp, callbackp);
         289                 :            : }
         290                 :            :
         291                 :            : static PyObject *
         292                 :       1080 : weakref___new__(PyTypeObject *type, PyObject *args, PyObject *kwargs)
         293                 :            : {
         294                 :       1080 :     PyWeakReference *self = NULL;
         295                 :       1080 :     PyObject *ob, *callback = NULL;
         296                 :            :
         297         [ +  - ]:       1080 :     if (parse_weakref_init_args("__new__", args, kwargs, &ob, &callback)) {
         298                 :            :         PyWeakReference *ref, *proxy;
         299                 :            :         PyWeakReference **list;
         300                 :            :
         301         [ -  + ]:       1080 :         if (!_PyType_SUPPORTS_WEAKREFS(Py_TYPE(ob))) {
         302                 :          0 :             PyErr_Format(PyExc_TypeError,
         303                 :            :                          "cannot create weak reference to '%s' object",
         304                 :          0 :                          Py_TYPE(ob)->tp_name);
         305                 :          6 :             return NULL;
         306                 :            :         }
         307         [ -  + ]:       1080 :         if (callback == Py_None)
         308                 :          0 :             callback = NULL;
         309                 :       1080 :         list = GET_WEAKREFS_LISTPTR(ob);
         310                 :       1080 :         get_basic_refs(*list, &ref, &proxy);
         311   [ +  +  +  - ]:       1080 :         if (callback == NULL && type == &_PyWeakref_RefType) {
         312         [ +  + ]:         22 :             if (ref != NULL) {
         313                 :            :                 /* We can re-use an existing reference. */
         314                 :          6 :                 return Py_NewRef(ref);
         315                 :            :             }
         316                 :            :         }
         317                 :            :         /* We have to create a new reference. */
         318                 :            :         /* Note: the tp_alloc() can trigger cyclic GC, so the weakref
         319                 :            :            list on ob can be mutated.  This means that the ref and
         320                 :            :            proxy pointers we got back earlier may have been collected,
         321                 :            :            so we need to compute these values again before we use
         322                 :            :            them. */
         323                 :       1074 :         self = (PyWeakReference *) (type->tp_alloc(type, 0));
         324         [ +  - ]:       1074 :         if (self != NULL) {
         325                 :       1074 :             init_weakref(self, ob, callback);
         326   [ +  +  +  - ]:       1074 :             if (callback == NULL && type == &_PyWeakref_RefType) {
         327                 :         16 :                 insert_head(self, list);
         328                 :            :             }
         329                 :            :             else {
         330                 :            :                 PyWeakReference *prev;
         331                 :            :
         332                 :       1058 :                 get_basic_refs(*list, &ref, &proxy);
         333         [ +  - ]:       1058 :                 prev = (proxy == NULL) ? ref : proxy;
         334         [ +  - ]:       1058 :                 if (prev == NULL)
         335                 :       1058 :                     insert_head(self, list);
         336                 :            :                 else
         337                 :          0 :                     insert_after(self, prev);
         338                 :            :             }
         339                 :            :         }
         340                 :            :     }
         341                 :       1074 :     return (PyObject *)self;
         342                 :            : }
         343                 :            :
         344                 :            : static int
         345                 :       1080 : weakref___init__(PyObject *self, PyObject *args, PyObject *kwargs)
         346                 :            : {
         347                 :            :     PyObject *tmp;
         348                 :            :
         349   [ -  +  -  - ]:       1080 :     if (!_PyArg_NoKeywords("ref", kwargs))
         350                 :          0 :         return -1;
         351                 :            :
         352         [ +  - ]:       1080 :     if (parse_weakref_init_args("__init__", args, kwargs, &tmp, &tmp))
         353                 :       1080 :         return 0;
         354                 :            :     else
         355                 :          0 :         return -1;
         356                 :            : }
         357                 :            :
         358                 :            :
         359                 :            : static PyMemberDef weakref_members[] = {
         360                 :            :     {"__callback__", T_OBJECT, offsetof(PyWeakReference, wr_callback), READONLY},
         361                 :            :     {NULL} /* Sentinel */
         362                 :            : };
         363                 :            :
         364                 :            : static PyMethodDef weakref_methods[] = {
         365                 :            :     {"__class_getitem__",    Py_GenericAlias,
         366                 :            :     METH_O|METH_CLASS,       PyDoc_STR("See PEP 585")},
         367                 :            :     {NULL} /* Sentinel */
         368                 :            : };
         369                 :            :
         370                 :            : PyTypeObject
         371                 :            : _PyWeakref_RefType = {
         372                 :            :     PyVarObject_HEAD_INIT(&PyType_Type, 0)
         373                 :            :     .tp_name = "weakref.ReferenceType",
         374                 :            :     .tp_basicsize = sizeof(PyWeakReference),
         375                 :            :     .tp_dealloc = weakref_dealloc,
         376                 :            :     .tp_vectorcall_offset = offsetof(PyWeakReference, vectorcall),
         377                 :            :     .tp_call = PyVectorcall_Call,
         378                 :            :     .tp_repr = (reprfunc)weakref_repr,
         379                 :            :     .tp_hash = (hashfunc)weakref_hash,
         380                 :            :     .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
         381                 :            :                 Py_TPFLAGS_HAVE_VECTORCALL | Py_TPFLAGS_BASETYPE,
         382                 :            :     .tp_traverse = (traverseproc)gc_traverse,
         383                 :            :     .tp_clear = (inquiry)gc_clear,
         384                 :            :     .tp_richcompare = (richcmpfunc)weakref_richcompare,
         385                 :            :     .tp_methods = weakref_methods,
         386                 :            :     .tp_members = weakref_members,
         387                 :            :     .tp_init = weakref___init__,
         388                 :            :     .tp_alloc = PyType_GenericAlloc,
         389                 :            :     .tp_new = weakref___new__,
         390                 :            :     .tp_free = PyObject_GC_Del,
         391                 :            : };
         392                 :            :
         393                 :            :
         394                 :            : static int
         395                 :          0 : proxy_checkref(PyWeakReference *proxy)
         396                 :            : {
         397         [ #  # ]:          0 :     if (PyWeakref_GET_OBJECT(proxy) == Py_None) {
         398                 :          0 :         PyErr_SetString(PyExc_ReferenceError,
         399                 :            :                         "weakly-referenced object no longer exists");
         400                 :          0 :         return 0;
         401                 :            :     }
         402                 :          0 :     return 1;
         403                 :            : }
         404                 :            :
         405                 :            :
         406                 :            : /* If a parameter is a proxy, check that it is still "live" and wrap it,
         407                 :            :  * replacing the original value with the raw object.  Raises ReferenceError
         408                 :            :  * if the param is a dead proxy.
         409                 :            :  */
         410                 :            : #define UNWRAP(o) \
         411                 :            :         if (PyWeakref_CheckProxy(o)) { \
         412                 :            :             if (!proxy_checkref((PyWeakReference *)o)) \
         413                 :            :                 return NULL; \
         414                 :            :             o = PyWeakref_GET_OBJECT(o); \
         415                 :            :         }
         416                 :            :
         417                 :            : #define WRAP_UNARY(method, generic) \
         418                 :            :     static PyObject * \
         419                 :            :     method(PyObject *proxy) { \
         420                 :            :         UNWRAP(proxy); \
         421                 :            :         Py_INCREF(proxy); \
         422                 :            :         PyObject* res = generic(proxy); \
         423                 :            :         Py_DECREF(proxy); \
         424                 :            :         return res; \
         425                 :            :     }
         426                 :            :
         427                 :            : #define WRAP_BINARY(method, generic) \
         428                 :            :     static PyObject * \
         429                 :            :     method(PyObject *x, PyObject *y) { \
         430                 :            :         UNWRAP(x); \
         431                 :            :         UNWRAP(y); \
         432                 :            :         Py_INCREF(x); \
         433                 :            :         Py_INCREF(y); \
         434                 :            :         PyObject* res = generic(x, y); \
         435                 :            :         Py_DECREF(x); \
         436                 :            :         Py_DECREF(y); \
         437                 :            :         return res; \
         438                 :            :     }
         439                 :            :
         440                 :            : /* Note that the third arg needs to be checked for NULL since the tp_call
         441                 :            :  * slot can receive NULL for this arg.
         442                 :            :  */
         443                 :            : #define WRAP_TERNARY(method, generic) \
         444                 :            :     static PyObject * \
         445                 :            :     method(PyObject *proxy, PyObject *v, PyObject *w) { \
         446                 :            :         UNWRAP(proxy); \
         447                 :            :         UNWRAP(v); \
         448                 :            :         if (w != NULL) \
         449                 :            :             UNWRAP(w); \
         450                 :            :         Py_INCREF(proxy); \
         451                 :            :         Py_INCREF(v); \
         452                 :            :         Py_XINCREF(w); \
         453                 :            :         PyObject* res = generic(proxy, v, w); \
         454                 :            :         Py_DECREF(proxy); \
         455                 :            :         Py_DECREF(v); \
         456                 :            :         Py_XDECREF(w); \
         457                 :            :         return res; \
         458                 :            :     }
         459                 :            :
         460                 :            : #define WRAP_METHOD(method, SPECIAL) \
         461                 :            :     static PyObject * \
         462                 :            :     method(PyObject *proxy, PyObject *Py_UNUSED(ignored)) { \
         463                 :            :             UNWRAP(proxy); \
         464                 :            :             Py_INCREF(proxy); \
         465                 :            :             PyObject* res = PyObject_CallMethodNoArgs(proxy, &_Py_ID(SPECIAL)); \
         466                 :            :             Py_DECREF(proxy); \
         467                 :            :             return res; \
         468                 :            :         }
         469                 :            :
         470                 :            :
         471                 :            : /* direct slots */
         472                 :            :
         473   [ #  #  #  #  :          0 : WRAP_BINARY(proxy_getattr, PyObject_GetAttr)
              #  #  #  #  #
                    #  #  # ]
         474   [ #  #  #  #  :          0 : WRAP_UNARY(proxy_str, PyObject_Str)
                       #  # ]
         475   [ #  #  #  #  :          0 : WRAP_TERNARY(proxy_call, PyObject_Call)
              #  #  #  #  #
              #  #  #  #  #
              #  #  #  #  #
                          # ]
         476                 :            :
         477                 :            : static PyObject *
         478                 :          0 : proxy_repr(PyWeakReference *proxy)
         479                 :            : {
         480                 :          0 :     return PyUnicode_FromFormat(
         481                 :            :         "<weakproxy at %p to %s at %p>",
         482                 :            :         proxy,
         483                 :          0 :         Py_TYPE(PyWeakref_GET_OBJECT(proxy))->tp_name,
         484                 :            :         PyWeakref_GET_OBJECT(proxy));
         485                 :            : }
         486                 :            :
         487                 :            :
         488                 :            : static int
         489                 :          0 : proxy_setattr(PyWeakReference *proxy, PyObject *name, PyObject *value)
         490                 :            : {
         491         [ #  # ]:          0 :     if (!proxy_checkref(proxy))
         492                 :          0 :         return -1;
         493                 :          0 :     PyObject *obj = PyWeakref_GET_OBJECT(proxy);
         494                 :          0 :     Py_INCREF(obj);
         495                 :          0 :     int res = PyObject_SetAttr(obj, name, value);
         496                 :          0 :     Py_DECREF(obj);
         497                 :          0 :     return res;
         498                 :            : }
         499                 :            :
         500                 :            : static PyObject *
         501                 :          0 : proxy_richcompare(PyObject *proxy, PyObject *v, int op)
         502                 :            : {
         503   [ #  #  #  #  :          0 :     UNWRAP(proxy);
                       #  # ]
         504   [ #  #  #  #  :          0 :     UNWRAP(v);
                       #  # ]
         505                 :          0 :     return PyObject_RichCompare(proxy, v, op);
         506                 :            : }
         507                 :            :
         508                 :            : /* number slots */
         509   [ #  #  #  #  :          0 : WRAP_BINARY(proxy_add, PyNumber_Add)
              #  #  #  #  #
                    #  #  # ]
         510   [ #  #  #  #  :          0 : WRAP_BINARY(proxy_sub, PyNumber_Subtract)
              #  #  #  #  #
                    #  #  # ]
         511   [ #  #  #  #  :          0 : WRAP_BINARY(proxy_mul, PyNumber_Multiply)
              #  #  #  #  #
                    #  #  # ]
         512   [ #  #  #  #  :          0 : WRAP_BINARY(proxy_floor_div, PyNumber_FloorDivide)
              #  #  #  #  #
                    #  #  # ]
         513   [ #  #  #  #  :          0 : WRAP_BINARY(proxy_true_div, PyNumber_TrueDivide)
              #  #  #  #  #
                    #  #  # ]
         514   [ #  #  #  #  :          0 : WRAP_BINARY(proxy_mod, PyNumber_Remainder)
              #  #  #  #  #
                    #  #  # ]
         515   [ #  #  #  #  :          0 : WRAP_BINARY(proxy_divmod, PyNumber_Divmod)
              #  #  #  #  #
                    #  #  # ]
         516   [ #  #  #  #  :          0 : WRAP_TERNARY(proxy_pow, PyNumber_Power)
              #  #  #  #  #
              #  #  #  #  #
              #  #  #  #  #
                          # ]
         517   [ #  #  #  #  :          0 : WRAP_UNARY(proxy_neg, PyNumber_Negative)
                       #  # ]
         518   [ #  #  #  #  :          0 : WRAP_UNARY(proxy_pos, PyNumber_Positive)
                       #  # ]
         519   [ #  #  #  #  :          0 : WRAP_UNARY(proxy_abs, PyNumber_Absolute)
                       #  # ]
         520   [ #  #  #  #  :          0 : WRAP_UNARY(proxy_invert, PyNumber_Invert)
                       #  # ]
         521   [ #  #  #  #  :          0 : WRAP_BINARY(proxy_lshift, PyNumber_Lshift)
              #  #  #  #  #
                    #  #  # ]
         522   [ #  #  #  #  :          0 : WRAP_BINARY(proxy_rshift, PyNumber_Rshift)
              #  #  #  #  #
                    #  #  # ]
         523   [ #  #  #  #  :          0 : WRAP_BINARY(proxy_and, PyNumber_And)
              #  #  #  #  #
                    #  #  # ]
         524   [ #  #  #  #  :          0 : WRAP_BINARY(proxy_xor, PyNumber_Xor)
              #  #  #  #  #
                    #  #  # ]
         525   [ #  #  #  #  :          0 : WRAP_BINARY(proxy_or, PyNumber_Or)
              #  #  #  #  #
                    #  #  # ]
         526   [ #  #  #  #  :          0 : WRAP_UNARY(proxy_int, PyNumber_Long)
                       #  # ]
         527   [ #  #  #  #  :          0 : WRAP_UNARY(proxy_float, PyNumber_Float)
                       #  # ]
         528   [ #  #  #  #  :          0 : WRAP_BINARY(proxy_iadd, PyNumber_InPlaceAdd)
              #  #  #  #  #
                    #  #  # ]
         529   [ #  #  #  #  :          0 : WRAP_BINARY(proxy_isub, PyNumber_InPlaceSubtract)
              #  #  #  #  #
                    #  #  # ]
         530   [ #  #  #  #  :          0 : WRAP_BINARY(proxy_imul, PyNumber_InPlaceMultiply)
              #  #  #  #  #
                    #  #  # ]
         531   [ #  #  #  #  :          0 : WRAP_BINARY(proxy_ifloor_div, PyNumber_InPlaceFloorDivide)
              #  #  #  #  #
                    #  #  # ]
         532   [ #  #  #  #  :          0 : WRAP_BINARY(proxy_itrue_div, PyNumber_InPlaceTrueDivide)
              #  #  #  #  #
                    #  #  # ]
         533   [ #  #  #  #  :          0 : WRAP_BINARY(proxy_imod, PyNumber_InPlaceRemainder)
              #  #  #  #  #
                    #  #  # ]
         534   [ #  #  #  #  :          0 : WRAP_TERNARY(proxy_ipow, PyNumber_InPlacePower)
              #  #  #  #  #
              #  #  #  #  #
              #  #  #  #  #
                          # ]
         535   [ #  #  #  #  :          0 : WRAP_BINARY(proxy_ilshift, PyNumber_InPlaceLshift)
              #  #  #  #  #
                    #  #  # ]
         536   [ #  #  #  #  :          0 : WRAP_BINARY(proxy_irshift, PyNumber_InPlaceRshift)
              #  #  #  #  #
                    #  #  # ]
         537   [ #  #  #  #  :          0 : WRAP_BINARY(proxy_iand, PyNumber_InPlaceAnd)
              #  #  #  #  #
                    #  #  # ]
         538   [ #  #  #  #  :          0 : WRAP_BINARY(proxy_ixor, PyNumber_InPlaceXor)
              #  #  #  #  #
                    #  #  # ]
         539   [ #  #  #  #  :          0 : WRAP_BINARY(proxy_ior, PyNumber_InPlaceOr)
              #  #  #  #  #
                    #  #  # ]
         540   [ #  #  #  #  :          0 : WRAP_UNARY(proxy_index, PyNumber_Index)
                       #  # ]
         541   [ #  #  #  #  :          0 : WRAP_BINARY(proxy_matmul, PyNumber_MatrixMultiply)
              #  #  #  #  #
                    #  #  # ]
         542   [ #  #  #  #  :          0 : WRAP_BINARY(proxy_imatmul, PyNumber_InPlaceMatrixMultiply)
              #  #  #  #  #
                    #  #  # ]
         543                 :            :
         544                 :            : static int
         545                 :          0 : proxy_bool(PyWeakReference *proxy)
         546                 :            : {
         547                 :          0 :     PyObject *o = PyWeakref_GET_OBJECT(proxy);
         548         [ #  # ]:          0 :     if (!proxy_checkref(proxy)) {
         549                 :          0 :         return -1;
         550                 :            :     }
         551                 :          0 :     Py_INCREF(o);
         552                 :          0 :     int res = PyObject_IsTrue(o);
         553                 :          0 :     Py_DECREF(o);
         554                 :          0 :     return res;
         555                 :            : }
         556                 :            :
         557                 :            : static void
         558                 :          0 : proxy_dealloc(PyWeakReference *self)
         559                 :            : {
         560                 :          0 :     PyObject_GC_UnTrack(self);
         561         [ #  # ]:          0 :     if (self->wr_callback != NULL)
         562                 :          0 :         PyObject_GC_UnTrack((PyObject *)self);
         563                 :          0 :     clear_weakref(self);
         564                 :          0 :     PyObject_GC_Del(self);
         565                 :          0 : }
         566                 :            :
         567                 :            : /* sequence slots */
         568                 :            :
         569                 :            : static int
         570                 :          0 : proxy_contains(PyWeakReference *proxy, PyObject *value)
         571                 :            : {
         572         [ #  # ]:          0 :     if (!proxy_checkref(proxy))
         573                 :          0 :         return -1;
         574                 :            :
         575                 :          0 :     PyObject *obj = PyWeakref_GET_OBJECT(proxy);
         576                 :          0 :     Py_INCREF(obj);
         577                 :          0 :     int res = PySequence_Contains(obj, value);
         578                 :          0 :     Py_DECREF(obj);
         579                 :          0 :     return res;
         580                 :            : }
         581                 :            :
         582                 :            : /* mapping slots */
         583                 :            :
         584                 :            : static Py_ssize_t
         585                 :          0 : proxy_length(PyWeakReference *proxy)
         586                 :            : {
         587         [ #  # ]:          0 :     if (!proxy_checkref(proxy))
         588                 :          0 :         return -1;
         589                 :            :
         590                 :          0 :     PyObject *obj = PyWeakref_GET_OBJECT(proxy);
         591                 :          0 :     Py_INCREF(obj);
         592                 :          0 :     Py_ssize_t res = PyObject_Length(obj);
         593                 :          0 :     Py_DECREF(obj);
         594                 :          0 :     return res;
         595                 :            : }
         596                 :            :
         597   [ #  #  #  #  :          0 : WRAP_BINARY(proxy_getitem, PyObject_GetItem)
              #  #  #  #  #
                    #  #  # ]
         598                 :            :
         599                 :            : static int
         600                 :          0 : proxy_setitem(PyWeakReference *proxy, PyObject *key, PyObject *value)
         601                 :            : {
         602         [ #  # ]:          0 :     if (!proxy_checkref(proxy))
         603                 :          0 :         return -1;
         604                 :            :
         605                 :          0 :     PyObject *obj = PyWeakref_GET_OBJECT(proxy);
         606                 :          0 :     Py_INCREF(obj);
         607                 :            :     int res;
         608         [ #  # ]:          0 :     if (value == NULL) {
         609                 :          0 :         res = PyObject_DelItem(obj, key);
         610                 :            :     } else {
         611                 :          0 :         res = PyObject_SetItem(obj, key, value);
         612                 :            :     }
         613                 :          0 :     Py_DECREF(obj);
         614                 :          0 :     return res;
         615                 :            : }
         616                 :            :
         617                 :            : /* iterator slots */
         618                 :            :
         619                 :            : static PyObject *
         620                 :          0 : proxy_iter(PyWeakReference *proxy)
         621                 :            : {
         622         [ #  # ]:          0 :     if (!proxy_checkref(proxy))
         623                 :          0 :         return NULL;
         624                 :          0 :     PyObject *obj = PyWeakref_GET_OBJECT(proxy);
         625                 :          0 :     Py_INCREF(obj);
         626                 :          0 :     PyObject* res = PyObject_GetIter(obj);
         627                 :          0 :     Py_DECREF(obj);
         628                 :          0 :     return res;
         629                 :            : }
         630                 :            :
         631                 :            : static PyObject *
         632                 :          0 : proxy_iternext(PyWeakReference *proxy)
         633                 :            : {
         634         [ #  # ]:          0 :     if (!proxy_checkref(proxy))
         635                 :          0 :         return NULL;
         636                 :            :
         637                 :          0 :     PyObject *obj = PyWeakref_GET_OBJECT(proxy);
         638         [ #  # ]:          0 :     if (!PyIter_Check(obj)) {
         639                 :          0 :         PyErr_Format(PyExc_TypeError,
         640                 :            :             "Weakref proxy referenced a non-iterator '%.200s' object",
         641                 :          0 :             Py_TYPE(obj)->tp_name);
         642                 :          0 :         return NULL;
         643                 :            :     }
         644                 :          0 :     Py_INCREF(obj);
         645                 :          0 :     PyObject* res = PyIter_Next(obj);
         646                 :          0 :     Py_DECREF(obj);
         647                 :          0 :     return res;
         648                 :            : }
         649                 :            :
         650                 :            :
         651   [ #  #  #  #  :          0 : WRAP_METHOD(proxy_bytes, __bytes__)
                       #  # ]
         652   [ #  #  #  #  :          0 : WRAP_METHOD(proxy_reversed, __reversed__)
                       #  # ]
         653                 :            :
         654                 :            :
         655                 :            : static PyMethodDef proxy_methods[] = {
         656                 :            :         {"__bytes__", proxy_bytes, METH_NOARGS},
         657                 :            :         {"__reversed__", proxy_reversed, METH_NOARGS},
         658                 :            :         {NULL, NULL}
         659                 :            : };
         660                 :            :
         661                 :            :
         662                 :            : static PyNumberMethods proxy_as_number = {
         663                 :            :     proxy_add,              /*nb_add*/
         664                 :            :     proxy_sub,              /*nb_subtract*/
         665                 :            :     proxy_mul,              /*nb_multiply*/
         666                 :            :     proxy_mod,              /*nb_remainder*/
         667                 :            :     proxy_divmod,           /*nb_divmod*/
         668                 :            :     proxy_pow,              /*nb_power*/
         669                 :            :     proxy_neg,              /*nb_negative*/
         670                 :            :     proxy_pos,              /*nb_positive*/
         671                 :            :     proxy_abs,              /*nb_absolute*/
         672                 :            :     (inquiry)proxy_bool,    /*nb_bool*/
         673                 :            :     proxy_invert,           /*nb_invert*/
         674                 :            :     proxy_lshift,           /*nb_lshift*/
         675                 :            :     proxy_rshift,           /*nb_rshift*/
         676                 :            :     proxy_and,              /*nb_and*/
         677                 :            :     proxy_xor,              /*nb_xor*/
         678                 :            :     proxy_or,               /*nb_or*/
         679                 :            :     proxy_int,              /*nb_int*/
         680                 :            :     0,                      /*nb_reserved*/
         681                 :            :     proxy_float,            /*nb_float*/
         682                 :            :     proxy_iadd,             /*nb_inplace_add*/
         683                 :            :     proxy_isub,             /*nb_inplace_subtract*/
         684                 :            :     proxy_imul,             /*nb_inplace_multiply*/
         685                 :            :     proxy_imod,             /*nb_inplace_remainder*/
         686                 :            :     proxy_ipow,             /*nb_inplace_power*/
         687                 :            :     proxy_ilshift,          /*nb_inplace_lshift*/
         688                 :            :     proxy_irshift,          /*nb_inplace_rshift*/
         689                 :            :     proxy_iand,             /*nb_inplace_and*/
         690                 :            :     proxy_ixor,             /*nb_inplace_xor*/
         691                 :            :     proxy_ior,              /*nb_inplace_or*/
         692                 :            :     proxy_floor_div,        /*nb_floor_divide*/
         693                 :            :     proxy_true_div,         /*nb_true_divide*/
         694                 :            :     proxy_ifloor_div,       /*nb_inplace_floor_divide*/
         695                 :            :     proxy_itrue_div,        /*nb_inplace_true_divide*/
         696                 :            :     proxy_index,            /*nb_index*/
         697                 :            :     proxy_matmul,           /*nb_matrix_multiply*/
         698                 :            :     proxy_imatmul,          /*nb_inplace_matrix_multiply*/
         699                 :            : };
         700                 :            :
         701                 :            : static PySequenceMethods proxy_as_sequence = {
         702                 :            :     (lenfunc)proxy_length,      /*sq_length*/
         703                 :            :     0,                          /*sq_concat*/
         704                 :            :     0,                          /*sq_repeat*/
         705                 :            :     0,                          /*sq_item*/
         706                 :            :     0,                          /*sq_slice*/
         707                 :            :     0,                          /*sq_ass_item*/
         708                 :            :     0,                           /*sq_ass_slice*/
         709                 :            :     (objobjproc)proxy_contains, /* sq_contains */
         710                 :            : };
         711                 :            :
         712                 :            : static PyMappingMethods proxy_as_mapping = {
         713                 :            :     (lenfunc)proxy_length,        /*mp_length*/
         714                 :            :     proxy_getitem,                /*mp_subscript*/
         715                 :            :     (objobjargproc)proxy_setitem, /*mp_ass_subscript*/
         716                 :            : };
         717                 :            :
         718                 :            :
         719                 :            : PyTypeObject
         720                 :            : _PyWeakref_ProxyType = {
         721                 :            :     PyVarObject_HEAD_INIT(&PyType_Type, 0)
         722                 :            :     "weakref.ProxyType",
         723                 :            :     sizeof(PyWeakReference),
         724                 :            :     0,
         725                 :            :     /* methods */
         726                 :            :     (destructor)proxy_dealloc,          /* tp_dealloc */
         727                 :            :     0,                                  /* tp_vectorcall_offset */
         728                 :            :     0,                                  /* tp_getattr */
         729                 :            :     0,                                  /* tp_setattr */
         730                 :            :     0,                                  /* tp_as_async */
         731                 :            :     (reprfunc)proxy_repr,               /* tp_repr */
         732                 :            :     &proxy_as_number,                   /* tp_as_number */
         733                 :            :     &proxy_as_sequence,                 /* tp_as_sequence */
         734                 :            :     &proxy_as_mapping,                  /* tp_as_mapping */
         735                 :            : // Notice that tp_hash is intentionally omitted as proxies are "mutable" (when the reference dies).
         736                 :            :     0,                                  /* tp_hash */
         737                 :            :     0,                                  /* tp_call */
         738                 :            :     proxy_str,                          /* tp_str */
         739                 :            :     proxy_getattr,                      /* tp_getattro */
         740                 :            :     (setattrofunc)proxy_setattr,        /* tp_setattro */
         741                 :            :     0,                                  /* tp_as_buffer */
         742                 :            :     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
         743                 :            :     0,                                  /* tp_doc */
         744                 :            :     (traverseproc)gc_traverse,          /* tp_traverse */
         745                 :            :     (inquiry)gc_clear,                  /* tp_clear */
         746                 :            :     proxy_richcompare,                  /* tp_richcompare */
         747                 :            :     0,                                  /* tp_weaklistoffset */
         748                 :            :     (getiterfunc)proxy_iter,            /* tp_iter */
         749                 :            :     (iternextfunc)proxy_iternext,       /* tp_iternext */
         750                 :            :         proxy_methods,                      /* tp_methods */
         751                 :            : };
         752                 :            :
         753                 :            :
         754                 :            : PyTypeObject
         755                 :            : _PyWeakref_CallableProxyType = {
         756                 :            :     PyVarObject_HEAD_INIT(&PyType_Type, 0)
         757                 :            :     "weakref.CallableProxyType",
         758                 :            :     sizeof(PyWeakReference),
         759                 :            :     0,
         760                 :            :     /* methods */
         761                 :            :     (destructor)proxy_dealloc,          /* tp_dealloc */
         762                 :            :     0,                                  /* tp_vectorcall_offset */
         763                 :            :     0,                                  /* tp_getattr */
         764                 :            :     0,                                  /* tp_setattr */
         765                 :            :     0,                                  /* tp_as_async */
         766                 :            :     (unaryfunc)proxy_repr,              /* tp_repr */
         767                 :            :     &proxy_as_number,                   /* tp_as_number */
         768                 :            :     &proxy_as_sequence,                 /* tp_as_sequence */
         769                 :            :     &proxy_as_mapping,                  /* tp_as_mapping */
         770                 :            :     0,                                  /* tp_hash */
         771                 :            :     proxy_call,                         /* tp_call */
         772                 :            :     proxy_str,                          /* tp_str */
         773                 :            :     proxy_getattr,                      /* tp_getattro */
         774                 :            :     (setattrofunc)proxy_setattr,        /* tp_setattro */
         775                 :            :     0,                                  /* tp_as_buffer */
         776                 :            :     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
         777                 :            :     0,                                  /* tp_doc */
         778                 :            :     (traverseproc)gc_traverse,          /* tp_traverse */
         779                 :            :     (inquiry)gc_clear,                  /* tp_clear */
         780                 :            :     proxy_richcompare,                  /* tp_richcompare */
         781                 :            :     0,                                  /* tp_weaklistoffset */
         782                 :            :     (getiterfunc)proxy_iter,            /* tp_iter */
         783                 :            :     (iternextfunc)proxy_iternext,       /* tp_iternext */
         784                 :            : };
         785                 :            :
         786                 :            :
         787                 :            :
         788                 :            : PyObject *
         789                 :     118328 : PyWeakref_NewRef(PyObject *ob, PyObject *callback)
         790                 :            : {
         791                 :     118328 :     PyWeakReference *result = NULL;
         792                 :            :     PyWeakReference **list;
         793                 :            :     PyWeakReference *ref, *proxy;
         794                 :            :
         795         [ -  + ]:     118328 :     if (!_PyType_SUPPORTS_WEAKREFS(Py_TYPE(ob))) {
         796                 :          0 :         PyErr_Format(PyExc_TypeError,
         797                 :            :                      "cannot create weak reference to '%s' object",
         798                 :          0 :                      Py_TYPE(ob)->tp_name);
         799                 :          0 :         return NULL;
         800                 :            :     }
         801                 :     118328 :     list = GET_WEAKREFS_LISTPTR(ob);
         802                 :     118328 :     get_basic_refs(*list, &ref, &proxy);
         803         [ -  + ]:     118328 :     if (callback == Py_None)
         804                 :          0 :         callback = NULL;
         805         [ +  + ]:     118328 :     if (callback == NULL)
         806                 :            :         /* return existing weak reference if it exists */
         807                 :     116718 :         result = ref;
         808         [ +  + ]:     118328 :     if (result != NULL)
         809                 :     101551 :         Py_INCREF(result);
         810                 :            :     else {
         811                 :            :         /* Note: new_weakref() can trigger cyclic GC, so the weakref
         812                 :            :            list on ob can be mutated.  This means that the ref and
         813                 :            :            proxy pointers we got back earlier may have been collected,
         814                 :            :            so we need to compute these values again before we use
         815                 :            :            them. */
         816                 :      16777 :         result = new_weakref(ob, callback);
         817         [ +  - ]:      16777 :         if (result != NULL) {
         818                 :      16777 :             get_basic_refs(*list, &ref, &proxy);
         819         [ +  + ]:      16777 :             if (callback == NULL) {
         820         [ +  - ]:      15167 :                 if (ref == NULL)
         821                 :      15167 :                     insert_head(result, list);
         822                 :            :                 else {
         823                 :            :                     /* Someone else added a ref without a callback
         824                 :            :                        during GC.  Return that one instead of this one
         825                 :            :                        to avoid violating the invariants of the list
         826                 :            :                        of weakrefs for ob. */
         827                 :          0 :                     Py_SETREF(result, (PyWeakReference*)Py_NewRef(ref));
         828                 :            :                 }
         829                 :            :             }
         830                 :            :             else {
         831                 :            :                 PyWeakReference *prev;
         832                 :            :
         833         [ +  - ]:       1610 :                 prev = (proxy == NULL) ? ref : proxy;
         834         [ +  + ]:       1610 :                 if (prev == NULL)
         835                 :          1 :                     insert_head(result, list);
         836                 :            :                 else
         837                 :       1609 :                     insert_after(result, prev);
         838                 :            :             }
         839                 :            :         }
         840                 :            :     }
         841                 :     118328 :     return (PyObject *) result;
         842                 :            : }
         843                 :            :
         844                 :            :
         845                 :            : PyObject *
         846                 :          0 : PyWeakref_NewProxy(PyObject *ob, PyObject *callback)
         847                 :            : {
         848                 :          0 :     PyWeakReference *result = NULL;
         849                 :            :     PyWeakReference **list;
         850                 :            :     PyWeakReference *ref, *proxy;
         851                 :            :
         852         [ #  # ]:          0 :     if (!_PyType_SUPPORTS_WEAKREFS(Py_TYPE(ob))) {
         853                 :          0 :         PyErr_Format(PyExc_TypeError,
         854                 :            :                      "cannot create weak reference to '%s' object",
         855                 :          0 :                      Py_TYPE(ob)->tp_name);
         856                 :          0 :         return NULL;
         857                 :            :     }
         858                 :          0 :     list = GET_WEAKREFS_LISTPTR(ob);
         859                 :          0 :     get_basic_refs(*list, &ref, &proxy);
         860         [ #  # ]:          0 :     if (callback == Py_None)
         861                 :          0 :         callback = NULL;
         862         [ #  # ]:          0 :     if (callback == NULL)
         863                 :            :         /* attempt to return an existing weak reference if it exists */
         864                 :          0 :         result = proxy;
         865         [ #  # ]:          0 :     if (result != NULL)
         866                 :          0 :         Py_INCREF(result);
         867                 :            :     else {
         868                 :            :         /* Note: new_weakref() can trigger cyclic GC, so the weakref
         869                 :            :            list on ob can be mutated.  This means that the ref and
         870                 :            :            proxy pointers we got back earlier may have been collected,
         871                 :            :            so we need to compute these values again before we use
         872                 :            :            them. */
         873                 :          0 :         result = new_weakref(ob, callback);
         874         [ #  # ]:          0 :         if (result != NULL) {
         875                 :            :             PyWeakReference *prev;
         876                 :            :
         877         [ #  # ]:          0 :             if (PyCallable_Check(ob)) {
         878                 :          0 :                 Py_SET_TYPE(result, &_PyWeakref_CallableProxyType);
         879                 :            :             }
         880                 :            :             else {
         881                 :          0 :                 Py_SET_TYPE(result, &_PyWeakref_ProxyType);
         882                 :            :             }
         883                 :          0 :             get_basic_refs(*list, &ref, &proxy);
         884         [ #  # ]:          0 :             if (callback == NULL) {
         885         [ #  # ]:          0 :                 if (proxy != NULL) {
         886                 :            :                     /* Someone else added a proxy without a callback
         887                 :            :                        during GC.  Return that one instead of this one
         888                 :            :                        to avoid violating the invariants of the list
         889                 :            :                        of weakrefs for ob. */
         890                 :          0 :                     Py_SETREF(result, (PyWeakReference*)Py_NewRef(proxy));
         891                 :          0 :                     goto skip_insert;
         892                 :            :                 }
         893                 :          0 :                 prev = ref;
         894                 :            :             }
         895                 :            :             else
         896         [ #  # ]:          0 :                 prev = (proxy == NULL) ? ref : proxy;
         897                 :            :
         898         [ #  # ]:          0 :             if (prev == NULL)
         899                 :          0 :                 insert_head(result, list);
         900                 :            :             else
         901                 :          0 :                 insert_after(result, prev);
         902                 :          0 :         skip_insert:
         903                 :            :             ;
         904                 :            :         }
         905                 :            :     }
         906                 :          0 :     return (PyObject *) result;
         907                 :            : }
         908                 :            :
         909                 :            :
         910                 :            : PyObject *
         911                 :        590 : PyWeakref_GetObject(PyObject *ref)
         912                 :            : {
         913   [ +  -  -  +  :        590 :     if (ref == NULL || !PyWeakref_Check(ref)) {
                 -  -  -  - ]
         914                 :          0 :         PyErr_BadInternalCall();
         915                 :          0 :         return NULL;
         916                 :            :     }
         917                 :        590 :     return PyWeakref_GET_OBJECT(ref);
         918                 :            : }
         919                 :            :
         920                 :            : /* Note that there's an inlined copy-paste of handle_callback() in gcmodule.c's
         921                 :            :  * handle_weakrefs().
         922                 :            :  */
         923                 :            : static void
         924                 :       1046 : handle_callback(PyWeakReference *ref, PyObject *callback)
         925                 :            : {
         926                 :       1046 :     PyObject *cbresult = PyObject_CallOneArg(callback, (PyObject *)ref);
         927                 :            :
         928         [ -  + ]:       1046 :     if (cbresult == NULL)
         929                 :          0 :         PyErr_WriteUnraisable(callback);
         930                 :            :     else
         931                 :       1046 :         Py_DECREF(cbresult);
         932                 :       1046 : }
         933                 :            :
         934                 :            : /* This function is called by the tp_dealloc handler to clear weak references.
         935                 :            :  *
         936                 :            :  * This iterates through the weak references for 'object' and calls callbacks
         937                 :            :  * for those references which have one.  It returns when all callbacks have
         938                 :            :  * been attempted.
         939                 :            :  */
         940                 :            : void
         941                 :     553176 : PyObject_ClearWeakRefs(PyObject *object)
         942                 :            : {
         943                 :            :     PyWeakReference **list;
         944                 :            :
         945         [ +  - ]:     553176 :     if (object == NULL
         946         [ +  - ]:     553176 :         || !_PyType_SUPPORTS_WEAKREFS(Py_TYPE(object))
         947         [ -  + ]:     553176 :         || Py_REFCNT(object) != 0)
         948                 :            :     {
         949                 :          0 :         PyErr_BadInternalCall();
         950                 :          0 :         return;
         951                 :            :     }
         952                 :     553176 :     list = GET_WEAKREFS_LISTPTR(object);
         953                 :            :     /* Remove the callback-less basic and proxy references */
         954   [ +  +  +  + ]:     553176 :     if (*list != NULL && (*list)->wr_callback == NULL) {
         955                 :        384 :         clear_weakref(*list);
         956   [ -  +  -  - ]:        384 :         if (*list != NULL && (*list)->wr_callback == NULL)
         957                 :          0 :             clear_weakref(*list);
         958                 :            :     }
         959         [ +  + ]:     553176 :     if (*list != NULL) {
         960                 :       1046 :         PyWeakReference *current = *list;
         961                 :       1046 :         Py_ssize_t count = _PyWeakref_GetWeakrefCount(current);
         962                 :       1046 :         PyObject *exc = PyErr_GetRaisedException();
         963                 :            :
         964         [ +  - ]:       1046 :         if (count == 1) {
         965                 :       1046 :             PyObject *callback = current->wr_callback;
         966                 :            :
         967                 :       1046 :             current->wr_callback = NULL;
         968                 :       1046 :             clear_weakref(current);
         969         [ +  - ]:       1046 :             if (callback != NULL) {
         970         [ +  - ]:       1046 :                 if (Py_REFCNT((PyObject *)current) > 0) {
         971                 :       1046 :                     handle_callback(current, callback);
         972                 :            :                 }
         973                 :       1046 :                 Py_DECREF(callback);
         974                 :            :             }
         975                 :            :         }
         976                 :            :         else {
         977                 :            :             PyObject *tuple;
         978                 :          0 :             Py_ssize_t i = 0;
         979                 :            :
         980                 :          0 :             tuple = PyTuple_New(count * 2);
         981         [ #  # ]:          0 :             if (tuple == NULL) {
         982                 :          0 :                 _PyErr_ChainExceptions1(exc);
         983                 :          0 :                 return;
         984                 :            :             }
         985                 :            :
         986         [ #  # ]:          0 :             for (i = 0; i < count; ++i) {
         987                 :          0 :                 PyWeakReference *next = current->wr_next;
         988                 :            :
         989         [ #  # ]:          0 :                 if (Py_REFCNT((PyObject *)current) > 0) {
         990                 :          0 :                     PyTuple_SET_ITEM(tuple, i * 2, Py_NewRef(current));
         991                 :          0 :                     PyTuple_SET_ITEM(tuple, i * 2 + 1, current->wr_callback);
         992                 :            :                 }
         993                 :            :                 else {
         994                 :          0 :                     Py_DECREF(current->wr_callback);
         995                 :            :                 }
         996                 :          0 :                 current->wr_callback = NULL;
         997                 :          0 :                 clear_weakref(current);
         998                 :          0 :                 current = next;
         999                 :            :             }
        1000         [ #  # ]:          0 :             for (i = 0; i < count; ++i) {
        1001                 :          0 :                 PyObject *callback = PyTuple_GET_ITEM(tuple, i * 2 + 1);
        1002                 :            :
        1003                 :            :                 /* The tuple may have slots left to NULL */
        1004         [ #  # ]:          0 :                 if (callback != NULL) {
        1005                 :          0 :                     PyObject *item = PyTuple_GET_ITEM(tuple, i * 2);
        1006                 :          0 :                     handle_callback((PyWeakReference *)item, callback);
        1007                 :            :                 }
        1008                 :            :             }
        1009                 :          0 :             Py_DECREF(tuple);
        1010                 :            :         }
        1011                 :            :         assert(!PyErr_Occurred());
        1012                 :       1046 :         PyErr_SetRaisedException(exc);
        1013                 :            :     }
        1014                 :            : }
        1015                 :            :
        1016                 :            : /* This function is called by _PyStaticType_Dealloc() to clear weak references.
        1017                 :            :  *
        1018                 :            :  * This is called at the end of runtime finalization, so we can just
        1019                 :            :  * wipe out the type's weaklist.  We don't bother with callbacks
        1020                 :            :  * or anything else.
        1021                 :            :  */
        1022                 :            : void
        1023                 :       4625 : _PyStaticType_ClearWeakRefs(PyTypeObject *type)
        1024                 :            : {
        1025                 :       4625 :     static_builtin_state *state = _PyStaticType_GetState(type);
        1026                 :       4625 :     PyObject **list = _PyStaticType_GET_WEAKREFS_LISTPTR(state);
        1027         [ +  + ]:       4683 :     while (*list != NULL) {
        1028                 :            :         /* Note that clear_weakref() pops the first ref off the type's
        1029                 :            :            weaklist before clearing its wr_object and wr_callback.
        1030                 :            :            That is how we're able to loop over the list. */
        1031                 :         58 :         clear_weakref((PyWeakReference *)*list);
        1032                 :            :     }
        1033                 :       4625 : }

Generated by: LCOV version 1.14