@@ -530,24 +530,39 @@ proxy_check_ref(PyObject *obj)
530530 return true;
531531}
532532
533-
534- /* If a parameter is a proxy, check that it is still "live" and wrap it,
535- * replacing the original value with the raw object. Raises ReferenceError
536- * if the param is a dead proxy.
533+ /*
534+ * Unwrap a proxy into a strong reference.
535+ * - If `o` is a live proxy: replaces `o` with the underlying object
536+ * (already Py_INCREF'd by _PyWeakref_GET_REF), sets *did_incref = 1.
537+ * - If `o` is a dead proxy: sets ReferenceError, sets `o` = NULL,
538+ * sets *did_incref = 0.
539+ * - If `o` is not a proxy: Py_INCREF's it, sets *did_incref = 1.
540+ * Returns 1 on success, 0 on dead proxy (caller must goto error).
537541 */
538- #define UNWRAP (o ) \
539- if (PyWeakref_CheckProxy(o)) { \
540- o = _PyWeakref_GET_REF(o); \
541- proxy_check_ref(o); \
542- } \
543- else { \
544- Py_INCREF(o); \
542+ static inline int
543+ _proxy_unwrap (PyObject * * op , int * did_incref )
544+ {
545+ if (PyWeakref_CheckProxy (* op )) {
546+ * op = _PyWeakref_GET_REF (* op );
547+ if (!proxy_check_ref (* op )) {
548+ * did_incref = 0 ;
549+ return 0 ;
545550 }
551+ /* _PyWeakref_GET_REF already returned a strong ref */
552+ }
553+ else {
554+ Py_INCREF (* op );
555+ }
556+ * did_incref = 1 ;
557+ return 1 ;
558+ }
546559
547560#define WRAP_UNARY (method , generic ) \
548561 static PyObject * \
549562 method(PyObject *proxy) { \
550- UNWRAP(proxy); \
563+ int proxy_incref = 0; \
564+ if (!_proxy_unwrap(&proxy, &proxy_incref)) \
565+ return NULL; \
551566 PyObject* res = generic(proxy); \
552567 Py_DECREF(proxy); \
553568 return res; \
@@ -556,18 +571,19 @@ proxy_check_ref(PyObject *obj)
556571#define WRAP_BINARY (method , generic ) \
557572 static PyObject * \
558573 method(PyObject *x, PyObject *y) { \
559- UNWRAP(x); \
560- if (x == NULL) \
561- return NULL; \
562- UNWRAP(y); \
563- if (y == NULL) { \
564- Py_XDECREF(x); \
565- return NULL; \
574+ int x_incref = 0, y_incref = 0; \
575+ if (!_proxy_unwrap(&x, &x_incref)) goto clean_up; \
576+ if (!_proxy_unwrap(&y, &y_incref)) goto clean_up; \
577+ { \
578+ PyObject* res = generic(x, y); \
579+ Py_DECREF(x); \
580+ Py_DECREF(y); \
581+ return res; \
566582 } \
567- PyObject* res = generic(x, y); \
568- Py_DECREF(x); \
569- Py_DECREF(y); \
570- return res ; \
583+ clean_up: \
584+ if (x_incref) Py_DECREF(x); \
585+ if (y_incref) Py_DECREF(y); \
586+ return NULL ; \
571587 }
572588
573589/* Note that the third arg needs to be checked for NULL since the tp_call
@@ -576,40 +592,36 @@ proxy_check_ref(PyObject *obj)
576592#define WRAP_TERNARY (method , generic ) \
577593 static PyObject * \
578594 method(PyObject *proxy, PyObject *v, PyObject *w) { \
579- UNWRAP(proxy); \
580- if (proxy == NULL) \
581- return NULL; \
582- UNWRAP(v); \
583- if (v == NULL) { \
584- Py_XDECREF(proxy); \
585- return NULL; \
586- } \
595+ int proxy_incref = 0, v_incref = 0, w_incref = 0; \
596+ if (!_proxy_unwrap(&proxy, &proxy_incref)) goto clean_up; \
597+ if (!_proxy_unwrap(&v, &v_incref)) goto clean_up; \
587598 if (w != NULL) { \
588- UNWRAP(w); \
589- if (w == NULL) { \
590- Py_XDECREF(proxy); \
591- Py_XDECREF(v); \
592- return NULL; \
593- } \
599+ if (!_proxy_unwrap(&w, &w_incref)) goto clean_up; \
594600 } \
595- PyObject* res = generic(proxy, v, w); \
596- Py_DECREF(proxy); \
597- Py_DECREF(v); \
598- Py_XDECREF(w); \
599- return res; \
601+ { \
602+ PyObject* res = generic(proxy, v, w); \
603+ Py_DECREF(proxy); \
604+ Py_DECREF(v); \
605+ Py_XDECREF(w); \
606+ return res; \
607+ } \
608+ clean_up: \
609+ if (proxy_incref) Py_DECREF(proxy); \
610+ if (v_incref) Py_DECREF(v); \
611+ if (w_incref) Py_DECREF(w); \
612+ return NULL; \
600613 }
601614
602615#define WRAP_METHOD (method , SPECIAL ) \
603616 static PyObject * \
604617 method(PyObject *proxy, PyObject *Py_UNUSED(ignored)) { \
605- UNWRAP(proxy); \
606- if (proxy == NULL) \
607- return NULL; \
608- PyObject* res = PyObject_CallMethodNoArgs(proxy, &_Py_ID(SPECIAL)); \
609- Py_DECREF(proxy); \
610- return res; \
611- }
612-
618+ int proxy_incref = 0; \
619+ if (!_proxy_unwrap(&proxy, &proxy_incref)) \
620+ return NULL; \
621+ PyObject* res = PyObject_CallMethodNoArgs(proxy, &_Py_ID(SPECIAL)); \
622+ Py_DECREF(proxy); \
623+ return res; \
624+ }
613625
614626/* direct slots */
615627
@@ -652,18 +664,19 @@ proxy_setattr(PyObject *proxy, PyObject *name, PyObject *value)
652664static PyObject *
653665proxy_richcompare (PyObject * proxy , PyObject * v , int op )
654666{
655- UNWRAP (proxy );
656- if (proxy == NULL )
657- return NULL ;
658- UNWRAP (v );
659- if (v == NULL ) {
660- Py_XDECREF (proxy );
661- return NULL ;
667+ int proxy_incref = 0 , v_incref = 0 ;
668+ if (!_proxy_unwrap (& proxy , & proxy_incref )) goto clean_up ;
669+ if (!_proxy_unwrap (& v , & v_incref )) goto clean_up ;
670+ {
671+ PyObject * res = PyObject_RichCompare (proxy , v , op );
672+ Py_DECREF (proxy );
673+ Py_DECREF (v );
674+ return res ;
662675 }
663- PyObject * res = PyObject_RichCompare ( proxy , v , op );
664- Py_DECREF (proxy );
665- Py_DECREF (v );
666- return res ;
676+ clean_up :
677+ if ( proxy_incref ) Py_DECREF (proxy );
678+ if ( v_incref ) Py_DECREF (v );
679+ return NULL ;
667680}
668681
669682/* number slots */
0 commit comments