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