@@ -2930,6 +2930,33 @@ Py_ReprLeave(PyObject *obj)
29302930
29312931/* Trashcan support. */
29322932
2933+ #ifndef Py_GIL_DISABLED
2934+ /* We need to store a pointer in the refcount field of
2935+ * an object. It is important that we never store 0 (NULL).
2936+ * It is also important to not make the object appear immortal,
2937+ * or it might be untracked by the cycle GC. */
2938+ static uintptr_t
2939+ pointer_to_safe_refcount (void * ptr )
2940+ {
2941+ uintptr_t full = (uintptr_t )ptr ;
2942+ assert ((full & 3 ) == 0 );
2943+ uint32_t refcnt = (uint32_t )full ;
2944+ if (refcnt >= (uint32_t )_Py_IMMORTAL_MINIMUM_REFCNT ) {
2945+ full = full - ((uintptr_t )_Py_IMMORTAL_MINIMUM_REFCNT ) + 1 ;
2946+ }
2947+ return full + 2 ;
2948+ }
2949+
2950+ static void *
2951+ safe_refcount_to_pointer (uintptr_t refcnt )
2952+ {
2953+ if (refcnt & 1 ) {
2954+ refcnt += _Py_IMMORTAL_MINIMUM_REFCNT - 1 ;
2955+ }
2956+ return (void * )(refcnt - 2 );
2957+ }
2958+ #endif
2959+
29332960/* Add op to the gcstate->trash_delete_later list. Called when the current
29342961 * call-stack depth gets large. op must be a currently untracked gc'ed
29352962 * object, with refcount 0. Py_DECREF must already have been called on it.
@@ -2941,11 +2968,10 @@ _PyTrash_thread_deposit_object(PyThreadState *tstate, PyObject *op)
29412968#ifdef Py_GIL_DISABLED
29422969 op -> ob_tid = (uintptr_t )tstate -> delete_later ;
29432970#else
2944- /* Store the delete_later pointer in the refcnt field.
2945- * As this object may still be tracked by the GC,
2946- * it is important that we never store 0 (NULL). */
2947- uintptr_t refcnt = (uintptr_t )tstate -> delete_later ;
2948- * ((uintptr_t * )op ) = refcnt + 1 ;
2971+ /* Store the delete_later pointer in the refcnt field. */
2972+ uintptr_t refcnt = pointer_to_safe_refcount (tstate -> delete_later );
2973+ * ((uintptr_t * )op ) = refcnt ;
2974+ assert (!_Py_IsImmortal (op ));
29492975#endif
29502976 tstate -> delete_later = op ;
29512977}
@@ -2967,7 +2993,7 @@ _PyTrash_thread_destroy_chain(PyThreadState *tstate)
29672993 /* Get the delete_later pointer from the refcnt field.
29682994 * See _PyTrash_thread_deposit_object(). */
29692995 uintptr_t refcnt = * ((uintptr_t * )op );
2970- tstate -> delete_later = ( PyObject * )( refcnt - 1 );
2996+ tstate -> delete_later = safe_refcount_to_pointer ( refcnt );
29712997 op -> ob_refcnt = 0 ;
29722998#endif
29732999
0 commit comments