summaryrefslogtreecommitdiffstats
path: root/Include/object.h
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@python.org>2022-11-09 13:06:36 (GMT)
committerGitHub <noreply@github.com>2022-11-09 13:06:36 (GMT)
commitc03e05c2e72f3ea5e797389e7d1042eef85ad37a (patch)
tree3a30ddb1b3b35a9b2ea7d233f242c72e74e71e71 /Include/object.h
parent0124b5dd28eff7bb80eb7244e97e402a036db13b (diff)
downloadcpython-c03e05c2e72f3ea5e797389e7d1042eef85ad37a.zip
cpython-c03e05c2e72f3ea5e797389e7d1042eef85ad37a.tar.gz
cpython-c03e05c2e72f3ea5e797389e7d1042eef85ad37a.tar.bz2
gh-98724: Fix Py_CLEAR() macro side effects (#99100)
The Py_CLEAR(), Py_SETREF() and Py_XSETREF() macros now only evaluate their argument once. If an argument has side effects, these side effects are no longer duplicated. Add test_py_clear() and test_py_setref() unit tests to _testcapi.
Diffstat (limited to 'Include/object.h')
-rw-r--r--Include/object.h19
1 files changed, 12 insertions, 7 deletions
diff --git a/Include/object.h b/Include/object.h
index 75624fe..a2ed0bd 100644
--- a/Include/object.h
+++ b/Include/object.h
@@ -598,16 +598,21 @@ static inline void Py_DECREF(PyObject *op)
* one of those can't cause problems -- but in part that relies on that
* Python integers aren't currently weakly referencable. Best practice is
* to use Py_CLEAR() even if you can't think of a reason for why you need to.
+ *
+ * gh-98724: Use the _py_tmp_ptr variable to evaluate the macro argument
+ * exactly once, to prevent the duplication of side effects in this macro.
*/
-#define Py_CLEAR(op) \
- do { \
- PyObject *_py_tmp = _PyObject_CAST(op); \
- if (_py_tmp != NULL) { \
- (op) = NULL; \
- Py_DECREF(_py_tmp); \
- } \
+#define Py_CLEAR(op) \
+ do { \
+ PyObject **_py_tmp_ptr = _Py_CAST(PyObject**, &(op)); \
+ if (*_py_tmp_ptr != NULL) { \
+ PyObject* _py_tmp = (*_py_tmp_ptr); \
+ *_py_tmp_ptr = NULL; \
+ Py_DECREF(_py_tmp); \
+ } \
} while (0)
+
/* Function to use in case the object pointer can be NULL: */
static inline void Py_XINCREF(PyObject *op)
{