@@ -2930,6 +2930,33 @@ Py_ReprLeave(PyObject *obj)
2930
2930
2931
2931
/* Trashcan support. */
2932
2932
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
+
2933
2960
/* Add op to the gcstate->trash_delete_later list. Called when the current
2934
2961
* call-stack depth gets large. op must be a currently untracked gc'ed
2935
2962
* 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)
2941
2968
#ifdef Py_GIL_DISABLED
2942
2969
op -> ob_tid = (uintptr_t )tstate -> delete_later ;
2943
2970
#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 ));
2949
2975
#endif
2950
2976
tstate -> delete_later = op ;
2951
2977
}
@@ -2967,7 +2993,7 @@ _PyTrash_thread_destroy_chain(PyThreadState *tstate)
2967
2993
/* Get the delete_later pointer from the refcnt field.
2968
2994
* See _PyTrash_thread_deposit_object(). */
2969
2995
uintptr_t refcnt = * ((uintptr_t * )op );
2970
- tstate -> delete_later = ( PyObject * )( refcnt - 1 );
2996
+ tstate -> delete_later = safe_refcount_to_pointer ( refcnt );
2971
2997
op -> ob_refcnt = 0 ;
2972
2998
#endif
2973
2999
0 commit comments