@@ -530,42 +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.
537- */
538- #define UNWRAP (o ) \
539- if (PyWeakref_CheckProxy(o)) { \
540- o = _PyWeakref_GET_REF(o); \
541- if (!proxy_check_ref(o)) { \
542- return NULL; \
543- } \
544- } \
545- else { \
546- Py_INCREF(o); \
547- }
548-
549- /* Like UNWRAP, but executes `cleanup` before returning NULL.
550- * Use when a prior UNWRAP has already incremented a refcount that
551- * must be released if this unwrap fails.
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).
552541 */
553- #define UNWRAP_OR (o , cleanup ) \
554- if (PyWeakref_CheckProxy(o)) { \
555- o = _PyWeakref_GET_REF(o); \
556- if (!proxy_check_ref(o)) { \
557- cleanup; \
558- return NULL; \
559- } \
560- } \
561- else { \
562- 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 ;
563550 }
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+ }
564559
565560#define WRAP_UNARY (method , generic ) \
566561 static PyObject * \
567562 method(PyObject *proxy) { \
568- UNWRAP(proxy); \
563+ int proxy_incref = 0; \
564+ if (!_proxy_unwrap(&proxy, &proxy_incref)) \
565+ return NULL; \
569566 PyObject* res = generic(proxy); \
570567 Py_DECREF(proxy); \
571568 return res; \
@@ -574,12 +571,19 @@ proxy_check_ref(PyObject *obj)
574571#define WRAP_BINARY (method , generic ) \
575572 static PyObject * \
576573 method(PyObject *x, PyObject *y) { \
577- UNWRAP(x); \
578- UNWRAP_OR(y, Py_DECREF(x)); \
579- PyObject* res = generic(x, y); \
580- Py_DECREF(x); \
581- Py_DECREF(y); \
582- return res; \
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; \
582+ } \
583+ clean_up: \
584+ if (x_incref) Py_DECREF(x); \
585+ if (y_incref) Py_DECREF(y); \
586+ return NULL; \
583587 }
584588
585589/* Note that the third arg needs to be checked for NULL since the tp_call
@@ -588,27 +592,36 @@ proxy_check_ref(PyObject *obj)
588592#define WRAP_TERNARY (method , generic ) \
589593 static PyObject * \
590594 method(PyObject *proxy, PyObject *v, PyObject *w) { \
591- UNWRAP(proxy); \
592- UNWRAP_OR(v, Py_DECREF(proxy)); \
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; \
593598 if (w != NULL) { \
594- UNWRAP_OR( w, Py_DECREF(proxy); Py_DECREF(v)) ; \
599+ if (!_proxy_unwrap(& w, &w_incref)) goto clean_up ; \
595600 } \
596- PyObject* res = generic(proxy, v, w); \
597- Py_DECREF(proxy); \
598- Py_DECREF(v); \
599- Py_XDECREF(w); \
600- 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; \
601613 }
602614
603615#define WRAP_METHOD (method , SPECIAL ) \
604616 static PyObject * \
605617 method(PyObject *proxy, PyObject *Py_UNUSED(ignored)) { \
606- UNWRAP(proxy); \
607- PyObject* res = PyObject_CallMethodNoArgs(proxy, &_Py_ID(SPECIAL)); \
608- Py_DECREF(proxy); \
609- return res; \
610- }
611-
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+ }
612625
613626/* direct slots */
614627
@@ -651,12 +664,19 @@ proxy_setattr(PyObject *proxy, PyObject *name, PyObject *value)
651664static PyObject *
652665proxy_richcompare (PyObject * proxy , PyObject * v , int op )
653666{
654- UNWRAP (proxy );
655- UNWRAP_OR (v , Py_DECREF (proxy ));
656- PyObject * res = PyObject_RichCompare (proxy , v , op );
657- Py_DECREF (proxy );
658- Py_DECREF (v );
659- return res ;
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 ;
675+ }
676+ clean_up :
677+ if (proxy_incref ) Py_DECREF (proxy );
678+ if (v_incref ) Py_DECREF (v );
679+ return NULL ;
660680}
661681
662682/* number slots */
0 commit comments