@@ -637,6 +637,75 @@ static inline void Py_DECREF(PyObject *op)
637637#endif
638638
639639
640+ #if !defined(Py_LIMITED_API ) || Py_LIMITED_API + 0 >= 0x030C0000
641+
642+ /* Safely decref `dst` and set `dst` to `src`.
643+ *
644+ * As in case of Py_CLEAR "the obvious" code can be deadly:
645+ *
646+ * Py_DECREF(dst);
647+ * dst = src;
648+ *
649+ * The safe way is:
650+ *
651+ * Py_SETREF(dst, src);
652+ *
653+ * That arranges to set `dst` to `src` _before_ decref'ing, so that any code
654+ * triggered as a side-effect of `dst` getting torn down no longer believes
655+ * `dst` points to a valid object.
656+ *
657+ * Temporary variables are used to only evalutate macro arguments once and so
658+ * avoid the duplication of side effects. _Py_TYPEOF() or memcpy() is used to
659+ * avoid a miscompilation caused by type punning. See Py_CLEAR() comment for
660+ * implementation details about type punning.
661+ *
662+ * The memcpy() implementation does not emit a compiler warning if 'src' has
663+ * not the same type than 'src': any pointer type is accepted for 'src'.
664+ */
665+ #ifdef _Py_TYPEOF
666+ #define Py_SETREF (dst , src ) \
667+ do { \
668+ _Py_TYPEOF(dst)* _tmp_dst_ptr = &(dst); \
669+ _Py_TYPEOF(dst) _tmp_old_dst = (*_tmp_dst_ptr); \
670+ *_tmp_dst_ptr = (src); \
671+ Py_DECREF(_tmp_old_dst); \
672+ } while (0)
673+ #else
674+ #define Py_SETREF (dst , src ) \
675+ do { \
676+ PyObject **_tmp_dst_ptr = _Py_CAST(PyObject**, &(dst)); \
677+ PyObject *_tmp_old_dst = (*_tmp_dst_ptr); \
678+ PyObject *_tmp_src = _PyObject_CAST(src); \
679+ memcpy(_tmp_dst_ptr, &_tmp_src, sizeof(PyObject*)); \
680+ Py_DECREF(_tmp_old_dst); \
681+ } while (0)
682+ #endif
683+
684+ /* Py_XSETREF() is a variant of Py_SETREF() that uses Py_XDECREF() instead of
685+ * Py_DECREF().
686+ */
687+ #ifdef _Py_TYPEOF
688+ #define Py_XSETREF (dst , src ) \
689+ do { \
690+ _Py_TYPEOF(dst)* _tmp_dst_ptr = &(dst); \
691+ _Py_TYPEOF(dst) _tmp_old_dst = (*_tmp_dst_ptr); \
692+ *_tmp_dst_ptr = (src); \
693+ Py_XDECREF(_tmp_old_dst); \
694+ } while (0)
695+ #else
696+ #define Py_XSETREF (dst , src ) \
697+ do { \
698+ PyObject **_tmp_dst_ptr = _Py_CAST(PyObject**, &(dst)); \
699+ PyObject *_tmp_old_dst = (*_tmp_dst_ptr); \
700+ PyObject *_tmp_src = _PyObject_CAST(src); \
701+ memcpy(_tmp_dst_ptr, &_tmp_src, sizeof(PyObject*)); \
702+ Py_XDECREF(_tmp_old_dst); \
703+ } while (0)
704+ #endif
705+
706+ #endif // Py_LIMITED_API
707+
708+
640709/* Function to use in case the object pointer can be NULL: */
641710static inline void Py_XINCREF (PyObject * op )
642711{
0 commit comments