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 627612 : _PyWeakref_GetWeakrefCount(PyWeakReference *head)
12 : {
13 627612 : Py_ssize_t count = 0;
14 :
15 1315520 : while (head != NULL) {
16 687910 : ++count;
17 687910 : head = head->wr_next;
18 : }
19 627612 : return count;
20 : }
21 :
22 : static PyObject *weakref_vectorcall(PyWeakReference *self, PyObject *const *args, size_t nargsf, PyObject *kwnames);
23 :
24 : static void
25 3913850 : init_weakref(PyWeakReference *self, PyObject *ob, PyObject *callback)
26 : {
27 3913850 : self->hash = -1;
28 3913850 : self->wr_object = ob;
29 3913850 : self->wr_prev = NULL;
30 3913850 : self->wr_next = NULL;
31 3913850 : self->wr_callback = Py_XNewRef(callback);
32 3913850 : self->vectorcall = (vectorcallfunc)weakref_vectorcall;
33 3913850 : }
34 :
35 : static PyWeakReference *
36 2719910 : new_weakref(PyObject *ob, PyObject *callback)
37 : {
38 : PyWeakReference *result;
39 :
40 2719910 : result = PyObject_GC_New(PyWeakReference, &_PyWeakref_RefType);
41 2719910 : if (result) {
42 2719910 : init_weakref(result, ob, callback);
43 2719910 : PyObject_GC_Track(result);
44 : }
45 2719910 : 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 6455540 : clear_weakref(PyWeakReference *self)
56 : {
57 6455540 : PyObject *callback = self->wr_callback;
58 :
59 6455540 : if (self->wr_object != Py_None) {
60 3787620 : PyWeakReference **list = GET_WEAKREFS_LISTPTR(self->wr_object);
61 :
62 3787620 : 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 3574630 : *list = self->wr_next;
67 3787620 : self->wr_object = Py_None;
68 3787620 : if (self->wr_prev != NULL)
69 212994 : self->wr_prev->wr_next = self->wr_next;
70 3787620 : if (self->wr_next != NULL)
71 257253 : self->wr_next->wr_prev = self->wr_prev;
72 3787620 : self->wr_prev = NULL;
73 3787620 : self->wr_next = NULL;
74 : }
75 6455540 : if (callback != NULL) {
76 703769 : Py_DECREF(callback);
77 703769 : self->wr_callback = NULL;
78 : }
79 6455540 : }
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 1872750 : _PyWeakref_ClearRef(PyWeakReference *self)
94 : {
95 : PyObject *callback;
96 :
97 1872750 : assert(self != NULL);
98 1872750 : assert(PyWeakref_Check(self));
99 : /* Preserve and restore the callback around clear_weakref. */
100 1872750 : callback = self->wr_callback;
101 1872750 : self->wr_callback = NULL;
102 1872750 : clear_weakref(self);
103 1872750 : self->wr_callback = callback;
104 1872750 : }
105 :
106 : static void
107 3780240 : weakref_dealloc(PyObject *self)
108 : {
109 3780240 : PyObject_GC_UnTrack(self);
110 3780240 : clear_weakref((PyWeakReference *) self);
111 3780240 : Py_TYPE(self)->tp_free(self);
112 3780240 : }
113 :
114 :
115 : static int
116 68166200 : gc_traverse(PyWeakReference *self, visitproc visit, void *arg)
117 : {
118 68166200 : Py_VISIT(self->wr_callback);
119 68166200 : return 0;
120 : }
121 :
122 :
123 : static int
124 25 : gc_clear(PyWeakReference *self)
125 : {
126 25 : clear_weakref(self);
127 25 : return 0;
128 : }
129 :
130 :
131 : static PyObject *
132 975194 : weakref_vectorcall(PyWeakReference *self, PyObject *const *args,
133 : size_t nargsf, PyObject *kwnames)
134 : {
135 975194 : if (!_PyArg_NoKwnames("weakref", kwnames)) {
136 0 : return NULL;
137 : }
138 975194 : Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
139 975194 : if (!_PyArg_CheckPositional("weakref", nargs, 0, 0)) {
140 0 : return NULL;
141 : }
142 975194 : return Py_NewRef(PyWeakref_GET_OBJECT(self));
143 : }
144 :
145 : static Py_hash_t
146 1585490 : weakref_hash(PyWeakReference *self)
147 : {
148 1585490 : if (self->hash != -1)
149 1020420 : return self->hash;
150 565067 : PyObject* obj = PyWeakref_GET_OBJECT(self);
151 565067 : if (obj == Py_None) {
152 2 : PyErr_SetString(PyExc_TypeError, "weak object has gone away");
153 2 : return -1;
154 : }
155 565065 : Py_INCREF(obj);
156 565065 : self->hash = PyObject_Hash(obj);
157 565065 : Py_DECREF(obj);
158 565065 : return self->hash;
159 : }
160 :
161 :
162 : static PyObject *
163 9 : weakref_repr(PyWeakReference *self)
164 : {
165 : PyObject *name, *repr;
166 9 : PyObject* obj = PyWeakref_GET_OBJECT(self);
167 :
168 9 : if (obj == Py_None) {
169 2 : return PyUnicode_FromFormat("<weakref at %p; dead>", self);
170 : }
171 :
172 7 : Py_INCREF(obj);
173 7 : if (_PyObject_LookupAttr(obj, &_Py_ID(__name__), &name) < 0) {
174 0 : Py_DECREF(obj);
175 0 : return NULL;
176 : }
177 7 : if (name == NULL || !PyUnicode_Check(name)) {
178 7 : repr = PyUnicode_FromFormat(
179 : "<weakref at %p; to '%s' at %p>",
180 : self,
181 7 : 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 7 : Py_DECREF(obj);
193 7 : Py_XDECREF(name);
194 7 : 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 549567 : weakref_richcompare(PyWeakReference* self, PyWeakReference* other, int op)
203 : {
204 1099120 : if ((op != Py_EQ && op != Py_NE) ||
205 1099100 : !PyWeakref_Check(self) ||
206 549555 : !PyWeakref_Check(other)) {
207 20 : Py_RETURN_NOTIMPLEMENTED;
208 : }
209 549547 : if (PyWeakref_GET_OBJECT(self) == Py_None
210 549536 : || PyWeakref_GET_OBJECT(other) == Py_None) {
211 345 : int res = (self == other);
212 345 : if (op == Py_NE)
213 3 : res = !res;
214 345 : if (res)
215 3 : Py_RETURN_TRUE;
216 : else
217 342 : Py_RETURN_FALSE;
218 : }
219 549202 : PyObject* obj = PyWeakref_GET_OBJECT(self);
220 549202 : PyObject* other_obj = PyWeakref_GET_OBJECT(other);
221 549202 : Py_INCREF(obj);
222 549202 : Py_INCREF(other_obj);
223 549202 : PyObject* res = PyObject_RichCompare(obj, other_obj, op);
224 549202 : Py_DECREF(obj);
225 549202 : Py_DECREF(other_obj);
226 549202 : 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 8948820 : get_basic_refs(PyWeakReference *head,
236 : PyWeakReference **refp, PyWeakReference **proxyp)
237 : {
238 8948820 : *refp = NULL;
239 8948820 : *proxyp = NULL;
240 :
241 8948820 : 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 1603760 : if (PyWeakref_CheckRefExact(head)) {
246 1603760 : *refp = head;
247 1603760 : head = head->wr_next;
248 : }
249 1603760 : if (head != NULL
250 1038680 : && head->wr_callback == NULL
251 14 : && PyWeakref_CheckProxy(head)) {
252 11 : *proxyp = head;
253 : /* head = head->wr_next; */
254 : }
255 : }
256 8948820 : }
257 :
258 : /* Insert 'newref' in the list after 'prev'. Both must be non-NULL. */
259 : static void
260 227256 : insert_after(PyWeakReference *newref, PyWeakReference *prev)
261 : {
262 227256 : newref->wr_prev = prev;
263 227256 : newref->wr_next = prev->wr_next;
264 227256 : if (prev->wr_next != NULL)
265 108269 : prev->wr_next->wr_prev = newref;
266 227256 : prev->wr_next = newref;
267 227256 : }
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 3686590 : insert_head(PyWeakReference *newref, PyWeakReference **list)
274 : {
275 3686590 : PyWeakReference *next = *list;
276 :
277 3686590 : newref->wr_prev = NULL;
278 3686590 : newref->wr_next = next;
279 3686590 : if (next != NULL)
280 189301 : next->wr_prev = newref;
281 3686590 : *list = newref;
282 3686590 : }
283 :
284 : static int
285 2413120 : parse_weakref_init_args(const char *funcname, PyObject *args, PyObject *kwargs,
286 : PyObject **obp, PyObject **callbackp)
287 : {
288 2413120 : return PyArg_UnpackTuple(args, funcname, 1, 2, obp, callbackp);
289 : }
290 :
291 : static PyObject *
292 1206570 : weakref___new__(PyTypeObject *type, PyObject *args, PyObject *kwargs)
293 : {
294 1206570 : PyWeakReference *self = NULL;
295 1206570 : PyObject *ob, *callback = NULL;
296 :
297 1206570 : if (parse_weakref_init_args("__new__", args, kwargs, &ob, &callback)) {
298 : PyWeakReference *ref, *proxy;
299 : PyWeakReference **list;
300 :
301 1206570 : if (!_PyType_SUPPORTS_WEAKREFS(Py_TYPE(ob))) {
302 18 : PyErr_Format(PyExc_TypeError,
303 : "cannot create weak reference to '%s' object",
304 18 : Py_TYPE(ob)->tp_name);
305 12634 : return NULL;
306 : }
307 1206550 : if (callback == Py_None)
308 5 : callback = NULL;
309 1206550 : list = GET_WEAKREFS_LISTPTR(ob);
310 1206550 : get_basic_refs(*list, &ref, &proxy);
311 1206550 : if (callback == NULL && type == &_PyWeakref_RefType) {
312 40744 : if (ref != NULL) {
313 : /* We can re-use an existing reference. */
314 12616 : Py_INCREF(ref);
315 12616 : return (PyObject *)ref;
316 : }
317 : }
318 : /* We have to create a new reference. */
319 : /* Note: the tp_alloc() can trigger cyclic GC, so the weakref
320 : list on ob can be mutated. This means that the ref and
321 : proxy pointers we got back earlier may have been collected,
322 : so we need to compute these values again before we use
323 : them. */
324 1193930 : self = (PyWeakReference *) (type->tp_alloc(type, 0));
325 1193930 : if (self != NULL) {
326 1193930 : init_weakref(self, ob, callback);
327 1193930 : if (callback == NULL && type == &_PyWeakref_RefType) {
328 28128 : insert_head(self, list);
329 : }
330 : else {
331 : PyWeakReference *prev;
332 :
333 1165810 : get_basic_refs(*list, &ref, &proxy);
334 1165810 : prev = (proxy == NULL) ? ref : proxy;
335 1165810 : if (prev == NULL)
336 1164840 : insert_head(self, list);
337 : else
338 963 : insert_after(self, prev);
339 : }
340 : }
341 : }
342 1193930 : return (PyObject *)self;
343 : }
344 :
345 : static int
346 1206550 : weakref___init__(PyObject *self, PyObject *args, PyObject *kwargs)
347 : {
348 : PyObject *tmp;
349 :
350 1206550 : if (!_PyArg_NoKeywords("ref", kwargs))
351 1 : return -1;
352 :
353 1206550 : if (parse_weakref_init_args("__init__", args, kwargs, &tmp, &tmp))
354 1206550 : return 0;
355 : else
356 1 : return -1;
357 : }
358 :
359 :
360 : static PyMemberDef weakref_members[] = {
361 : {"__callback__", T_OBJECT, offsetof(PyWeakReference, wr_callback), READONLY},
362 : {NULL} /* Sentinel */
363 : };
364 :
365 : static PyMethodDef weakref_methods[] = {
366 : {"__class_getitem__", Py_GenericAlias,
367 : METH_O|METH_CLASS, PyDoc_STR("See PEP 585")},
368 : {NULL} /* Sentinel */
369 : };
370 :
371 : PyTypeObject
372 : _PyWeakref_RefType = {
373 : PyVarObject_HEAD_INIT(&PyType_Type, 0)
374 : .tp_name = "weakref.ReferenceType",
375 : .tp_basicsize = sizeof(PyWeakReference),
376 : .tp_dealloc = weakref_dealloc,
377 : .tp_vectorcall_offset = offsetof(PyWeakReference, vectorcall),
378 : .tp_call = PyVectorcall_Call,
379 : .tp_repr = (reprfunc)weakref_repr,
380 : .tp_hash = (hashfunc)weakref_hash,
381 : .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
382 : Py_TPFLAGS_HAVE_VECTORCALL | Py_TPFLAGS_BASETYPE,
383 : .tp_traverse = (traverseproc)gc_traverse,
384 : .tp_clear = (inquiry)gc_clear,
385 : .tp_richcompare = (richcmpfunc)weakref_richcompare,
386 : .tp_methods = weakref_methods,
387 : .tp_members = weakref_members,
388 : .tp_init = weakref___init__,
389 : .tp_alloc = PyType_GenericAlloc,
390 : .tp_new = weakref___new__,
391 : .tp_free = PyObject_GC_Del,
392 : };
393 :
394 :
395 : static int
396 19338 : proxy_checkref(PyWeakReference *proxy)
397 : {
398 19338 : if (PyWeakref_GET_OBJECT(proxy) == Py_None) {
399 29 : PyErr_SetString(PyExc_ReferenceError,
400 : "weakly-referenced object no longer exists");
401 29 : return 0;
402 : }
403 19309 : return 1;
404 : }
405 :
406 :
407 : /* If a parameter is a proxy, check that it is still "live" and wrap it,
408 : * replacing the original value with the raw object. Raises ReferenceError
409 : * if the param is a dead proxy.
410 : */
411 : #define UNWRAP(o) \
412 : if (PyWeakref_CheckProxy(o)) { \
413 : if (!proxy_checkref((PyWeakReference *)o)) \
414 : return NULL; \
415 : o = PyWeakref_GET_OBJECT(o); \
416 : }
417 :
418 : #define WRAP_UNARY(method, generic) \
419 : static PyObject * \
420 : method(PyObject *proxy) { \
421 : UNWRAP(proxy); \
422 : Py_INCREF(proxy); \
423 : PyObject* res = generic(proxy); \
424 : Py_DECREF(proxy); \
425 : return res; \
426 : }
427 :
428 : #define WRAP_BINARY(method, generic) \
429 : static PyObject * \
430 : method(PyObject *x, PyObject *y) { \
431 : UNWRAP(x); \
432 : UNWRAP(y); \
433 : Py_INCREF(x); \
434 : Py_INCREF(y); \
435 : PyObject* res = generic(x, y); \
436 : Py_DECREF(x); \
437 : Py_DECREF(y); \
438 : return res; \
439 : }
440 :
441 : /* Note that the third arg needs to be checked for NULL since the tp_call
442 : * slot can receive NULL for this arg.
443 : */
444 : #define WRAP_TERNARY(method, generic) \
445 : static PyObject * \
446 : method(PyObject *proxy, PyObject *v, PyObject *w) { \
447 : UNWRAP(proxy); \
448 : UNWRAP(v); \
449 : if (w != NULL) \
450 : UNWRAP(w); \
451 : Py_INCREF(proxy); \
452 : Py_INCREF(v); \
453 : Py_XINCREF(w); \
454 : PyObject* res = generic(proxy, v, w); \
455 : Py_DECREF(proxy); \
456 : Py_DECREF(v); \
457 : Py_XDECREF(w); \
458 : return res; \
459 : }
460 :
461 : #define WRAP_METHOD(method, SPECIAL) \
462 : static PyObject * \
463 : method(PyObject *proxy, PyObject *Py_UNUSED(ignored)) { \
464 : UNWRAP(proxy); \
465 : Py_INCREF(proxy); \
466 : PyObject* res = PyObject_CallMethodNoArgs(proxy, &_Py_ID(SPECIAL)); \
467 : Py_DECREF(proxy); \
468 : return res; \
469 : }
470 :
471 :
472 : /* direct slots */
473 :
474 5734 : WRAP_BINARY(proxy_getattr, PyObject_GetAttr)
475 8 : WRAP_UNARY(proxy_str, PyObject_Str)
476 4 : WRAP_TERNARY(proxy_call, PyObject_Call)
477 :
478 : static PyObject *
479 0 : proxy_repr(PyWeakReference *proxy)
480 : {
481 0 : return PyUnicode_FromFormat(
482 : "<weakproxy at %p to %s at %p>",
483 : proxy,
484 0 : Py_TYPE(PyWeakref_GET_OBJECT(proxy))->tp_name,
485 : PyWeakref_GET_OBJECT(proxy));
486 : }
487 :
488 :
489 : static int
490 13543 : proxy_setattr(PyWeakReference *proxy, PyObject *name, PyObject *value)
491 : {
492 13543 : if (!proxy_checkref(proxy))
493 0 : return -1;
494 13543 : PyObject *obj = PyWeakref_GET_OBJECT(proxy);
495 13543 : Py_INCREF(obj);
496 13543 : int res = PyObject_SetAttr(obj, name, value);
497 13543 : Py_DECREF(obj);
498 13543 : return res;
499 : }
500 :
501 : static PyObject *
502 1 : proxy_richcompare(PyObject *proxy, PyObject *v, int op)
503 : {
504 1 : UNWRAP(proxy);
505 1 : UNWRAP(v);
506 1 : return PyObject_RichCompare(proxy, v, op);
507 : }
508 :
509 : /* number slots */
510 2 : WRAP_BINARY(proxy_add, PyNumber_Add)
511 0 : WRAP_BINARY(proxy_sub, PyNumber_Subtract)
512 0 : WRAP_BINARY(proxy_mul, PyNumber_Multiply)
513 1 : WRAP_BINARY(proxy_floor_div, PyNumber_FloorDivide)
514 0 : WRAP_BINARY(proxy_true_div, PyNumber_TrueDivide)
515 0 : WRAP_BINARY(proxy_mod, PyNumber_Remainder)
516 0 : WRAP_BINARY(proxy_divmod, PyNumber_Divmod)
517 0 : WRAP_TERNARY(proxy_pow, PyNumber_Power)
518 0 : WRAP_UNARY(proxy_neg, PyNumber_Negative)
519 0 : WRAP_UNARY(proxy_pos, PyNumber_Positive)
520 0 : WRAP_UNARY(proxy_abs, PyNumber_Absolute)
521 0 : WRAP_UNARY(proxy_invert, PyNumber_Invert)
522 0 : WRAP_BINARY(proxy_lshift, PyNumber_Lshift)
523 0 : WRAP_BINARY(proxy_rshift, PyNumber_Rshift)
524 0 : WRAP_BINARY(proxy_and, PyNumber_And)
525 0 : WRAP_BINARY(proxy_xor, PyNumber_Xor)
526 0 : WRAP_BINARY(proxy_or, PyNumber_Or)
527 0 : WRAP_UNARY(proxy_int, PyNumber_Long)
528 0 : WRAP_UNARY(proxy_float, PyNumber_Float)
529 0 : WRAP_BINARY(proxy_iadd, PyNumber_InPlaceAdd)
530 0 : WRAP_BINARY(proxy_isub, PyNumber_InPlaceSubtract)
531 0 : WRAP_BINARY(proxy_imul, PyNumber_InPlaceMultiply)
532 1 : WRAP_BINARY(proxy_ifloor_div, PyNumber_InPlaceFloorDivide)
533 0 : WRAP_BINARY(proxy_itrue_div, PyNumber_InPlaceTrueDivide)
534 0 : WRAP_BINARY(proxy_imod, PyNumber_InPlaceRemainder)
535 0 : WRAP_TERNARY(proxy_ipow, PyNumber_InPlacePower)
536 0 : WRAP_BINARY(proxy_ilshift, PyNumber_InPlaceLshift)
537 0 : WRAP_BINARY(proxy_irshift, PyNumber_InPlaceRshift)
538 0 : WRAP_BINARY(proxy_iand, PyNumber_InPlaceAnd)
539 0 : WRAP_BINARY(proxy_ixor, PyNumber_InPlaceXor)
540 0 : WRAP_BINARY(proxy_ior, PyNumber_InPlaceOr)
541 1 : WRAP_UNARY(proxy_index, PyNumber_Index)
542 2 : WRAP_BINARY(proxy_matmul, PyNumber_MatrixMultiply)
543 1 : WRAP_BINARY(proxy_imatmul, PyNumber_InPlaceMatrixMultiply)
544 :
545 : static int
546 4 : proxy_bool(PyWeakReference *proxy)
547 : {
548 4 : PyObject *o = PyWeakref_GET_OBJECT(proxy);
549 4 : if (!proxy_checkref(proxy)) {
550 1 : return -1;
551 : }
552 3 : Py_INCREF(o);
553 3 : int res = PyObject_IsTrue(o);
554 3 : Py_DECREF(o);
555 3 : return res;
556 : }
557 :
558 : static void
559 6983 : proxy_dealloc(PyWeakReference *self)
560 : {
561 6983 : if (self->wr_callback != NULL)
562 125 : PyObject_GC_UnTrack((PyObject *)self);
563 6983 : clear_weakref(self);
564 6983 : PyObject_GC_Del(self);
565 6983 : }
566 :
567 : /* sequence slots */
568 :
569 : static int
570 2 : proxy_contains(PyWeakReference *proxy, PyObject *value)
571 : {
572 2 : if (!proxy_checkref(proxy))
573 0 : return -1;
574 :
575 2 : PyObject *obj = PyWeakref_GET_OBJECT(proxy);
576 2 : Py_INCREF(obj);
577 2 : int res = PySequence_Contains(obj, value);
578 2 : Py_DECREF(obj);
579 2 : return res;
580 : }
581 :
582 : /* mapping slots */
583 :
584 : static Py_ssize_t
585 16 : proxy_length(PyWeakReference *proxy)
586 : {
587 16 : if (!proxy_checkref(proxy))
588 13 : return -1;
589 :
590 3 : PyObject *obj = PyWeakref_GET_OBJECT(proxy);
591 3 : Py_INCREF(obj);
592 3 : Py_ssize_t res = PyObject_Length(obj);
593 3 : Py_DECREF(obj);
594 3 : return res;
595 : }
596 :
597 5 : WRAP_BINARY(proxy_getitem, PyObject_GetItem)
598 :
599 : static int
600 3 : proxy_setitem(PyWeakReference *proxy, PyObject *key, PyObject *value)
601 : {
602 3 : if (!proxy_checkref(proxy))
603 0 : return -1;
604 :
605 3 : PyObject *obj = PyWeakref_GET_OBJECT(proxy);
606 3 : Py_INCREF(obj);
607 : int res;
608 3 : if (value == NULL) {
609 1 : res = PyObject_DelItem(obj, key);
610 : } else {
611 2 : res = PyObject_SetItem(obj, key, value);
612 : }
613 3 : Py_DECREF(obj);
614 3 : return res;
615 : }
616 :
617 : /* iterator slots */
618 :
619 : static PyObject *
620 2 : proxy_iter(PyWeakReference *proxy)
621 : {
622 2 : if (!proxy_checkref(proxy))
623 0 : return NULL;
624 2 : PyObject *obj = PyWeakref_GET_OBJECT(proxy);
625 2 : Py_INCREF(obj);
626 2 : PyObject* res = PyObject_GetIter(obj);
627 2 : Py_DECREF(obj);
628 2 : return res;
629 : }
630 :
631 : static PyObject *
632 5 : proxy_iternext(PyWeakReference *proxy)
633 : {
634 5 : if (!proxy_checkref(proxy))
635 0 : return NULL;
636 :
637 5 : PyObject *obj = PyWeakref_GET_OBJECT(proxy);
638 5 : if (!PyIter_Check(obj)) {
639 1 : PyErr_Format(PyExc_TypeError,
640 : "Weakref proxy referenced a non-iterator '%.200s' object",
641 1 : Py_TYPE(obj)->tp_name);
642 1 : return NULL;
643 : }
644 4 : Py_INCREF(obj);
645 4 : PyObject* res = PyIter_Next(obj);
646 4 : Py_DECREF(obj);
647 4 : return res;
648 : }
649 :
650 :
651 1 : WRAP_METHOD(proxy_bytes, __bytes__)
652 1 : 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 3849550 : PyWeakref_NewRef(PyObject *ob, PyObject *callback)
790 : {
791 3849550 : PyWeakReference *result = NULL;
792 : PyWeakReference **list;
793 : PyWeakReference *ref, *proxy;
794 :
795 3849550 : 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 3849550 : list = GET_WEAKREFS_LISTPTR(ob);
802 3849550 : get_basic_refs(*list, &ref, &proxy);
803 3849550 : if (callback == Py_None)
804 0 : callback = NULL;
805 3849550 : if (callback == NULL)
806 : /* return existing weak reference if it exists */
807 3621400 : result = ref;
808 3849550 : if (result != NULL)
809 1136630 : 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 2712920 : result = new_weakref(ob, callback);
817 2712920 : if (result != NULL) {
818 2712920 : get_basic_refs(*list, &ref, &proxy);
819 2712920 : if (callback == NULL) {
820 2484770 : if (ref == NULL)
821 2484770 : 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_DECREF(result);
828 0 : Py_INCREF(ref);
829 0 : result = ref;
830 : }
831 : }
832 : else {
833 : PyWeakReference *prev;
834 :
835 228153 : prev = (proxy == NULL) ? ref : proxy;
836 228153 : if (prev == NULL)
837 1997 : insert_head(result, list);
838 : else
839 226156 : insert_after(result, prev);
840 : }
841 : }
842 : }
843 3849550 : return (PyObject *) result;
844 : }
845 :
846 :
847 : PyObject *
848 6994 : PyWeakref_NewProxy(PyObject *ob, PyObject *callback)
849 : {
850 6994 : PyWeakReference *result = NULL;
851 : PyWeakReference **list;
852 : PyWeakReference *ref, *proxy;
853 :
854 6994 : if (!_PyType_SUPPORTS_WEAKREFS(Py_TYPE(ob))) {
855 0 : PyErr_Format(PyExc_TypeError,
856 : "cannot create weak reference to '%s' object",
857 0 : Py_TYPE(ob)->tp_name);
858 0 : return NULL;
859 : }
860 6994 : list = GET_WEAKREFS_LISTPTR(ob);
861 6994 : get_basic_refs(*list, &ref, &proxy);
862 6994 : if (callback == Py_None)
863 4 : callback = NULL;
864 6994 : if (callback == NULL)
865 : /* attempt to return an existing weak reference if it exists */
866 6861 : result = proxy;
867 6994 : if (result != NULL)
868 5 : Py_INCREF(result);
869 : else {
870 : /* Note: new_weakref() can trigger cyclic GC, so the weakref
871 : list on ob can be mutated. This means that the ref and
872 : proxy pointers we got back earlier may have been collected,
873 : so we need to compute these values again before we use
874 : them. */
875 6989 : result = new_weakref(ob, callback);
876 6989 : if (result != NULL) {
877 : PyWeakReference *prev;
878 :
879 6989 : if (PyCallable_Check(ob)) {
880 138 : Py_SET_TYPE(result, &_PyWeakref_CallableProxyType);
881 : }
882 : else {
883 6851 : Py_SET_TYPE(result, &_PyWeakref_ProxyType);
884 : }
885 6989 : get_basic_refs(*list, &ref, &proxy);
886 6989 : if (callback == NULL) {
887 6856 : if (proxy != NULL) {
888 : /* Someone else added a proxy without a callback
889 : during GC. Return that one instead of this one
890 : to avoid violating the invariants of the list
891 : of weakrefs for ob. */
892 0 : Py_DECREF(result);
893 0 : result = proxy;
894 0 : Py_INCREF(result);
895 0 : goto skip_insert;
896 : }
897 6856 : prev = ref;
898 : }
899 : else
900 133 : prev = (proxy == NULL) ? ref : proxy;
901 :
902 6989 : if (prev == NULL)
903 6852 : insert_head(result, list);
904 : else
905 137 : insert_after(result, prev);
906 0 : skip_insert:
907 : ;
908 : }
909 : }
910 6994 : return (PyObject *) result;
911 : }
912 :
913 :
914 : PyObject *
915 99268 : PyWeakref_GetObject(PyObject *ref)
916 : {
917 99268 : if (ref == NULL || !PyWeakref_Check(ref)) {
918 0 : PyErr_BadInternalCall();
919 0 : return NULL;
920 : }
921 99268 : return PyWeakref_GET_OBJECT(ref);
922 : }
923 :
924 : /* Note that there's an inlined copy-paste of handle_callback() in gcmodule.c's
925 : * handle_weakrefs().
926 : */
927 : static void
928 687863 : handle_callback(PyWeakReference *ref, PyObject *callback)
929 : {
930 687863 : PyObject *cbresult = PyObject_CallOneArg(callback, (PyObject *)ref);
931 :
932 687863 : if (cbresult == NULL)
933 14 : PyErr_WriteUnraisable(callback);
934 : else
935 687849 : Py_DECREF(cbresult);
936 687863 : }
937 :
938 : /* This function is called by the tp_dealloc handler to clear weak references.
939 : *
940 : * This iterates through the weak references for 'object' and calls callbacks
941 : * for those references which have one. It returns when all callbacks have
942 : * been attempted.
943 : */
944 : void
945 20099900 : PyObject_ClearWeakRefs(PyObject *object)
946 : {
947 : PyWeakReference **list;
948 :
949 20099900 : if (object == NULL
950 20099900 : || !_PyType_SUPPORTS_WEAKREFS(Py_TYPE(object))
951 20099900 : || Py_REFCNT(object) != 0)
952 : {
953 0 : PyErr_BadInternalCall();
954 0 : return;
955 : }
956 20099900 : list = GET_WEAKREFS_LISTPTR(object);
957 : /* Remove the callback-less basic and proxy references */
958 20099900 : if (*list != NULL && (*list)->wr_callback == NULL) {
959 107675 : clear_weakref(*list);
960 107675 : if (*list != NULL && (*list)->wr_callback == NULL)
961 4 : clear_weakref(*list);
962 : }
963 20099900 : if (*list != NULL) {
964 627579 : PyWeakReference *current = *list;
965 627579 : Py_ssize_t count = _PyWeakref_GetWeakrefCount(current);
966 : PyObject *err_type, *err_value, *err_tb;
967 :
968 627579 : PyErr_Fetch(&err_type, &err_value, &err_tb);
969 627579 : if (count == 1) {
970 567353 : PyObject *callback = current->wr_callback;
971 :
972 567353 : current->wr_callback = NULL;
973 567353 : clear_weakref(current);
974 567353 : if (callback != NULL) {
975 567352 : if (Py_REFCNT((PyObject *)current) > 0) {
976 567351 : handle_callback(current, callback);
977 : }
978 567352 : Py_DECREF(callback);
979 : }
980 : }
981 : else {
982 : PyObject *tuple;
983 60226 : Py_ssize_t i = 0;
984 :
985 60226 : tuple = PyTuple_New(count * 2);
986 60226 : if (tuple == NULL) {
987 0 : _PyErr_ChainExceptions(err_type, err_value, err_tb);
988 0 : return;
989 : }
990 :
991 180740 : for (i = 0; i < count; ++i) {
992 120514 : PyWeakReference *next = current->wr_next;
993 :
994 120514 : if (Py_REFCNT((PyObject *)current) > 0) {
995 120512 : Py_INCREF(current);
996 120512 : PyTuple_SET_ITEM(tuple, i * 2, (PyObject *) current);
997 120512 : PyTuple_SET_ITEM(tuple, i * 2 + 1, current->wr_callback);
998 : }
999 : else {
1000 2 : Py_DECREF(current->wr_callback);
1001 : }
1002 120514 : current->wr_callback = NULL;
1003 120514 : clear_weakref(current);
1004 120514 : current = next;
1005 : }
1006 180740 : for (i = 0; i < count; ++i) {
1007 120514 : PyObject *callback = PyTuple_GET_ITEM(tuple, i * 2 + 1);
1008 :
1009 : /* The tuple may have slots left to NULL */
1010 120514 : if (callback != NULL) {
1011 120512 : PyObject *item = PyTuple_GET_ITEM(tuple, i * 2);
1012 120512 : handle_callback((PyWeakReference *)item, callback);
1013 : }
1014 : }
1015 60226 : Py_DECREF(tuple);
1016 : }
1017 627579 : assert(!PyErr_Occurred());
1018 627579 : PyErr_Restore(err_type, err_value, err_tb);
1019 : }
1020 : }
|