mirror of https://github.com/python/cpython.git
don't expand the operand to Py_XINCREF/XDECREF/CLEAR/DECREF multiple times (closes #17206)
A patch from Illia Polosukhin.
This commit is contained in:
parent
e7b47dda64
commit
da5eb5a31c
|
@ -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 *);
|
||||||
|
|
||||||
#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 *);
|
||||||
*/
|
*/
|
||||||
#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
|
||||||
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?
|
||||||
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)
|
||||||
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[] = {
|
||||||
{"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},
|
||||||
|
|
Loading…
Reference in New Issue