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