Kaydet (Commit) da5eb5a3 authored tarafından Benjamin Peterson's avatar Benjamin Peterson

don't expand the operand to Py_XINCREF/XDECREF/CLEAR/DECREF multiple times (closes #17206)

A patch from Illia Polosukhin.
üst e7b47dda
...@@ -680,12 +680,6 @@ is not considered to be a reference to the type object, to save ...@@ -680,12 +680,6 @@ is not considered to be a reference to the type object, to save
complications in the deallocation function. (This is actually a complications in the deallocation function. (This is actually a
decision that's up to the implementer of each new type so if you want, decision that's up to the implementer of each new type so if you want,
you can count such references to the type object.) 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 /* First define a pile of simple helper macros, one set per special
...@@ -764,15 +758,16 @@ PyAPI_FUNC(void) _Py_Dealloc(PyObject *); ...@@ -764,15 +758,16 @@ PyAPI_FUNC(void) _Py_Dealloc(PyObject *);
#define Py_INCREF(op) ( \ #define Py_INCREF(op) ( \
_Py_INC_REFTOTAL _Py_REF_DEBUG_COMMA \ _Py_INC_REFTOTAL _Py_REF_DEBUG_COMMA \
((PyObject*)(op))->ob_refcnt++) ((PyObject *)(op))->ob_refcnt++)
#define Py_DECREF(op) \ #define Py_DECREF(op) \
do { \ do { \
PyObject *_py_decref_tmp = (PyObject *)(op); \
if (_Py_DEC_REFTOTAL _Py_REF_DEBUG_COMMA \ if (_Py_DEC_REFTOTAL _Py_REF_DEBUG_COMMA \
--((PyObject*)(op))->ob_refcnt != 0) \ --(_py_decref_tmp)->ob_refcnt != 0) \
_Py_CHECK_REFCNT(op) \ _Py_CHECK_REFCNT(_py_decref_tmp) \
else \ else \
_Py_Dealloc((PyObject *)(op)); \ _Py_Dealloc(_py_decref_tmp); \
} while (0) } while (0)
/* Safely decref `op` and set `op` to NULL, especially useful in tp_clear /* Safely decref `op` and set `op` to NULL, especially useful in tp_clear
...@@ -811,16 +806,27 @@ PyAPI_FUNC(void) _Py_Dealloc(PyObject *); ...@@ -811,16 +806,27 @@ PyAPI_FUNC(void) _Py_Dealloc(PyObject *);
*/ */
#define Py_CLEAR(op) \ #define Py_CLEAR(op) \
do { \ do { \
if (op) { \ PyObject *_py_tmp = (PyObject *)(op); \
PyObject *_py_tmp = (PyObject *)(op); \ if (_py_tmp != NULL) { \
(op) = NULL; \ (op) = NULL; \
Py_DECREF(_py_tmp); \ Py_DECREF(_py_tmp); \
} \ } \
} while (0) } while (0)
/* Macros to use in case the object pointer may be NULL: */ /* 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_XINCREF(op) \
#define Py_XDECREF(op) do { if ((op) == NULL) ; else Py_DECREF(op); } while (0) 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 These are provided as conveniences to Python runtime embedders, so that
......
...@@ -983,6 +983,7 @@ Oleg Plakhotnyuk ...@@ -983,6 +983,7 @@ Oleg Plakhotnyuk
Remi Pointel Remi Pointel
Ariel Poliak Ariel Poliak
Guilherme Polo Guilherme Polo
Illia Polosukhin
Michael Pomraning Michael Pomraning
Iustin Pop Iustin Pop
Claudiu Popa Claudiu Popa
......
...@@ -10,6 +10,10 @@ What's New in Python 3.4.0 Alpha 1? ...@@ -10,6 +10,10 @@ What's New in Python 3.4.0 Alpha 1?
Core and Builtins Core and Builtins
----------------- -----------------
- 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 #17937: Try harder to collect cyclic garbage at shutdown. - Issue #17937: Try harder to collect cyclic garbage at shutdown.
- Issue #12370: Prevent class bodies from interfering with the __class__ - Issue #12370: Prevent class bodies from interfering with the __class__
......
...@@ -2468,6 +2468,48 @@ test_pytime_object_to_timespec(PyObject *self, PyObject *args) ...@@ -2468,6 +2468,48 @@ test_pytime_object_to_timespec(PyObject *self, PyObject *args)
return Py_BuildValue("Nl", _PyLong_FromTime_t(sec), nsec); 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[] = { static PyMethodDef TestMethods[] = {
{"raise_exception", raise_exception, METH_VARARGS}, {"raise_exception", raise_exception, METH_VARARGS},
...@@ -2478,6 +2520,10 @@ static PyMethodDef TestMethods[] = { ...@@ -2478,6 +2520,10 @@ static PyMethodDef TestMethods[] = {
{"test_dict_iteration", (PyCFunction)test_dict_iteration,METH_NOARGS}, {"test_dict_iteration", (PyCFunction)test_dict_iteration,METH_NOARGS},
{"test_lazy_hash_inheritance", (PyCFunction)test_lazy_hash_inheritance,METH_NOARGS}, {"test_lazy_hash_inheritance", (PyCFunction)test_lazy_hash_inheritance,METH_NOARGS},
{"test_long_api", (PyCFunction)test_long_api, 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, {"test_long_and_overflow", (PyCFunction)test_long_and_overflow,
METH_NOARGS}, METH_NOARGS},
{"test_long_as_double", (PyCFunction)test_long_as_double,METH_NOARGS}, {"test_long_as_double", (PyCFunction)test_long_as_double,METH_NOARGS},
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment