Skip to content

Commit ddad602

Browse files
committed
Fix weakref proxy ref leak
1 parent ec5f154 commit ddad602

1 file changed

Lines changed: 53 additions & 19 deletions

File tree

Objects/weakrefobject.c

Lines changed: 53 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -541,23 +541,28 @@ proxy_check_ref(PyObject *obj)
541541

542542
/* If a parameter is a proxy, check that it is still "live" and wrap it,
543543
* replacing the original value with the raw object. Raises ReferenceError
544-
* if the param is a dead proxy.
544+
* if the param is a dead proxy. Returns a new reference.
545545
*/
546-
#define UNWRAP(o) \
547-
if (PyWeakref_CheckProxy(o)) { \
548-
o = _PyWeakref_GET_REF(o); \
549-
if (!proxy_check_ref(o)) { \
550-
return NULL; \
551-
} \
552-
} \
553-
else { \
554-
Py_INCREF(o); \
546+
static inline PyObject *
547+
proxy_unwrap(PyObject *obj)
548+
{
549+
if (PyWeakref_CheckProxy(obj)) {
550+
obj = _PyWeakref_GET_REF(obj);
551+
if (!proxy_check_ref(obj)) {
552+
return NULL;
555553
}
554+
return obj;
555+
}
556+
return Py_NewRef(obj);
557+
}
556558

557559
#define WRAP_UNARY(method, generic) \
558560
static PyObject * \
559561
method(PyObject *proxy) { \
560-
UNWRAP(proxy); \
562+
proxy = proxy_unwrap(proxy); \
563+
if (proxy == NULL) { \
564+
return NULL; \
565+
} \
561566
PyObject* res = generic(proxy); \
562567
Py_DECREF(proxy); \
563568
return res; \
@@ -566,8 +571,15 @@ proxy_check_ref(PyObject *obj)
566571
#define WRAP_BINARY(method, generic) \
567572
static PyObject * \
568573
method(PyObject *x, PyObject *y) { \
569-
UNWRAP(x); \
570-
UNWRAP(y); \
574+
x = proxy_unwrap(x); \
575+
if (x == NULL) { \
576+
return NULL; \
577+
} \
578+
y = proxy_unwrap(y); \
579+
if (y == NULL) { \
580+
Py_DECREF(x); \
581+
return NULL; \
582+
} \
571583
PyObject* res = generic(x, y); \
572584
Py_DECREF(x); \
573585
Py_DECREF(y); \
@@ -580,10 +592,22 @@ proxy_check_ref(PyObject *obj)
580592
#define WRAP_TERNARY(method, generic) \
581593
static PyObject * \
582594
method(PyObject *proxy, PyObject *v, PyObject *w) { \
583-
UNWRAP(proxy); \
584-
UNWRAP(v); \
595+
proxy = proxy_unwrap(proxy); \
596+
if (proxy == NULL) { \
597+
return NULL; \
598+
} \
599+
v = proxy_unwrap(v); \
600+
if (v == NULL) { \
601+
Py_DECREF(proxy); \
602+
return NULL; \
603+
} \
585604
if (w != NULL) { \
586-
UNWRAP(w); \
605+
w = proxy_unwrap(w); \
606+
if (w == NULL) { \
607+
Py_DECREF(proxy); \
608+
Py_DECREF(v); \
609+
return NULL; \
610+
} \
587611
} \
588612
PyObject* res = generic(proxy, v, w); \
589613
Py_DECREF(proxy); \
@@ -595,7 +619,10 @@ proxy_check_ref(PyObject *obj)
595619
#define WRAP_METHOD(method, SPECIAL) \
596620
static PyObject * \
597621
method(PyObject *proxy, PyObject *Py_UNUSED(ignored)) { \
598-
UNWRAP(proxy); \
622+
proxy = proxy_unwrap(proxy); \
623+
if (proxy == NULL) { \
624+
return NULL; \
625+
} \
599626
PyObject* res = PyObject_CallMethodNoArgs(proxy, &_Py_ID(SPECIAL)); \
600627
Py_DECREF(proxy); \
601628
return res; \
@@ -643,8 +670,15 @@ proxy_setattr(PyObject *proxy, PyObject *name, PyObject *value)
643670
static PyObject *
644671
proxy_richcompare(PyObject *proxy, PyObject *v, int op)
645672
{
646-
UNWRAP(proxy);
647-
UNWRAP(v);
673+
proxy = proxy_unwrap(proxy);
674+
if (proxy == NULL) {
675+
return NULL;
676+
}
677+
v = proxy_unwrap(v);
678+
if (v == NULL) {
679+
Py_DECREF(proxy);
680+
return NULL;
681+
}
648682
PyObject* res = PyObject_RichCompare(proxy, v, op);
649683
Py_DECREF(proxy);
650684
Py_DECREF(v);

0 commit comments

Comments
 (0)