diff -r 42bf74b90626 Include/object.h --- a/Include/object.h Wed Mar 20 14:26:33 2013 -0700 +++ b/Include/object.h Tue Apr 02 22:02:00 2013 -0700 @@ -680,12 +680,6 @@ complications in the deallocation function. (This is actually a decision that's up to the implementer of each new type so if you want, you can count such references to the type object.) - -*** WARNING*** The Py_DECREF macro must have a side-effect-free argument -since it may evaluate its argument multiple times. (The alternative -would be to mace it a proper function or assign it to a global temporary -variable first, both of which are slower; and in a multi-threaded -environment the global variable trick is not safe.) */ /* First define a pile of simple helper macros, one set per special @@ -768,11 +762,12 @@ #define Py_DECREF(op) \ do { \ + PyObject* _py_decref_tmp = (PyObject*)(op); \ if (_Py_DEC_REFTOTAL _Py_REF_DEBUG_COMMA \ - --((PyObject*)(op))->ob_refcnt != 0) \ - _Py_CHECK_REFCNT(op) \ + --(_py_decref_tmp)->ob_refcnt != 0) \ + _Py_CHECK_REFCNT(_py_decref_tmp) \ else \ - _Py_Dealloc((PyObject *)(op)); \ + _Py_Dealloc(_py_decref_tmp); \ } while (0) /* Safely decref `op` and set `op` to NULL, especially useful in tp_clear @@ -811,16 +806,27 @@ */ #define Py_CLEAR(op) \ do { \ - if (op) { \ - PyObject *_py_tmp = (PyObject *)(op); \ + PyObject *_py_tmp = (PyObject *)(op); \ + if (_py_tmp != NULL) { \ (op) = NULL; \ Py_DECREF(_py_tmp); \ } \ } while (0) /* Macros to use in case the object pointer may be NULL: */ -#define Py_XINCREF(op) do { if ((op) == NULL) ; else Py_INCREF(op); } while (0) -#define Py_XDECREF(op) do { if ((op) == NULL) ; else Py_DECREF(op); } while (0) +#define Py_XINCREF(op) \ + do { \ + PyObject* _py_xincref_tmp=(PyObject*)(op); \ + if (_py_xincref_tmp != NULL) \ + Py_INCREF(_py_xincref_tmp); \ + } while (0) + +#define Py_XDECREF(op) \ + do { \ + PyObject* _py_xdecref_tmp=(PyObject*)(op); \ + if (_py_xdecref_tmp != NULL) \ + Py_DECREF(_py_xdecref_tmp); \ + } while (0) /* These are provided as conveniences to Python runtime embedders, so that diff -r 42bf74b90626 Misc/ACKS --- a/Misc/ACKS Wed Mar 20 14:26:33 2013 -0700 +++ b/Misc/ACKS Tue Apr 02 22:02:00 2013 -0700 @@ -964,6 +964,7 @@ Remi Pointel Ariel Poliak Guilherme Polo +Illia Polosukhin Michael Pomraning Iustin Pop Claudiu Popa diff -r 42bf74b90626 Misc/NEWS --- a/Misc/NEWS Wed Mar 20 14:26:33 2013 -0700 +++ b/Misc/NEWS Tue Apr 02 22:02:00 2013 -0700 @@ -19,6 +19,10 @@ and kwarg and kwargannotation. Change the column offset of ast.Attribute to be at the attribute name. +- Issue #17206: Py_CLEAR(), Py_DECREF(), Py_XINCREF() and Py_XDECREF() now + expands their arguments once instead of multiple times. + Patch written by Illia Polosukhin. + - Issue #17434: Properly raise a SyntaxError when a string occurs between future imports. diff -r 42bf74b90626 Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c Wed Mar 20 14:26:33 2013 -0700 +++ b/Modules/_testcapimodule.c Tue Apr 02 22:02:00 2013 -0700 @@ -2468,6 +2468,48 @@ return Py_BuildValue("Nl", _PyLong_FromTime_t(sec), nsec); } +static PyObject* +_test_incref(PyObject* ob) +{ + Py_INCREF(ob); + return ob; +} + +static PyObject* +test_xincref_doesnt_leak(PyObject* ob) +{ + PyObject *obj = PyLong_FromLong(0); + Py_XINCREF(_test_incref(obj)); + Py_DECREF(obj); + Py_DECREF(obj); + Py_DECREF(obj); + Py_RETURN_NONE; +} + +static PyObject* +test_incref_doesnt_leak(PyObject* ob) +{ + PyObject *obj = PyLong_FromLong(0); + Py_INCREF(_test_incref(obj)); + Py_DECREF(obj); + Py_DECREF(obj); + Py_DECREF(obj); + Py_RETURN_NONE; +} + +static PyObject* +test_xdecref_doesnt_leak(PyObject* ob) +{ + Py_XDECREF(PyLong_FromLong(0)); + Py_RETURN_NONE; +} + +static PyObject* +test_decref_doesnt_leak(PyObject* ob) +{ + Py_DECREF(PyLong_FromLong(0)); + Py_RETURN_NONE; +} static PyMethodDef TestMethods[] = { {"raise_exception", raise_exception, METH_VARARGS}, @@ -2478,6 +2520,10 @@ {"test_dict_iteration", (PyCFunction)test_dict_iteration,METH_NOARGS}, {"test_lazy_hash_inheritance", (PyCFunction)test_lazy_hash_inheritance,METH_NOARGS}, {"test_long_api", (PyCFunction)test_long_api, METH_NOARGS}, + {"test_xincref_doesnt_leak", (PyCFunction)test_xincref_doesnt_leak, METH_NOARGS}, + {"test_incref_doesnt_leak", (PyCFunction)test_incref_doesnt_leak, METH_NOARGS}, + {"test_xdecref_doesnt_leak", (PyCFunction)test_xdecref_doesnt_leak, METH_NOARGS}, + {"test_decref_doesnt_leak", (PyCFunction)test_decref_doesnt_leak, METH_NOARGS}, {"test_long_and_overflow", (PyCFunction)test_long_and_overflow, METH_NOARGS}, {"test_long_as_double", (PyCFunction)test_long_as_double,METH_NOARGS},