@@ -2930,6 +2930,39 @@ Py_ReprLeave(PyObject *obj)
2930
2930
2931
2931
/* Trashcan support. */
2932
2932
2933
+ /* We need to store a pointer in the refcount field of
2934
+ * an object. It is important that we never store 0 (NULL).
2935
+ * It is also important to not make the object appear immortal,
2936
+ * or it might be untracked by the cycle GC. */
2937
+ uintptr_t
2938
+ pointer_to_safe_refcount (void * ptr )
2939
+ {
2940
+ uintptr_t full = (uintptr_t )ptr ;
2941
+ assert ((full & 3 ) == 0 );
2942
+ #if defined(Py_GIL_DISABLED )
2943
+ return full + 1 ;
2944
+ #else
2945
+ uint32_t refcnt = (uint32_t )full ;
2946
+ if (refcnt >= (uint32_t )_Py_IMMORTAL_MINIMUM_REFCNT ) {
2947
+ full = full - ((uintptr_t )_Py_IMMORTAL_MINIMUM_REFCNT ) + 1 ;
2948
+ }
2949
+ return full + 2 ;
2950
+ #endif
2951
+ }
2952
+
2953
+ void *
2954
+ safe_refcount_to_pointer (uintptr_t refcnt )
2955
+ {
2956
+ #if defined(Py_GIL_DISABLED )
2957
+ return (void * )(refcnt - 1 );
2958
+ #else
2959
+ if (refcnt & 1 ) {
2960
+ refcnt += _Py_IMMORTAL_MINIMUM_REFCNT - 1 ;
2961
+ }
2962
+ return (void * )(refcnt - 2 );
2963
+ #endif
2964
+ }
2965
+
2933
2966
/* Add op to the gcstate->trash_delete_later list. Called when the current
2934
2967
* call-stack depth gets large. op must be a currently untracked gc'ed
2935
2968
* object, with refcount 0. Py_DECREF must already have been called on it.
@@ -2941,11 +2974,10 @@ _PyTrash_thread_deposit_object(PyThreadState *tstate, PyObject *op)
2941
2974
#ifdef Py_GIL_DISABLED
2942
2975
op -> ob_tid = (uintptr_t )tstate -> delete_later ;
2943
2976
#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 ;
2977
+ /* Store the delete_later pointer in the refcnt field. */
2978
+ uintptr_t refcnt = pointer_to_safe_refcount (tstate -> delete_later );
2979
+ * ((uintptr_t * )op ) = refcnt ;
2980
+ assert (!_Py_IsImmortal (op ));
2949
2981
#endif
2950
2982
tstate -> delete_later = op ;
2951
2983
}
@@ -2967,7 +2999,7 @@ _PyTrash_thread_destroy_chain(PyThreadState *tstate)
2967
2999
/* Get the delete_later pointer from the refcnt field.
2968
3000
* See _PyTrash_thread_deposit_object(). */
2969
3001
uintptr_t refcnt = * ((uintptr_t * )op );
2970
- tstate -> delete_later = ( PyObject * )( refcnt - 1 );
3002
+ tstate -> delete_later = safe_refcount_to_pointer ( refcnt );
2971
3003
op -> ob_refcnt = 0 ;
2972
3004
#endif
2973
3005
0 commit comments