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 : }
|