@@ -2692,27 +2692,27 @@ Py_ReprLeave(PyObject *obj)
26922692 * call-stack depth gets large. op must be a currently untracked gc'ed
26932693 * object, with refcount 0. Py_DECREF must already have been called on it.
26942694 */
2695- static void
2696- _PyTrash_thread_deposit_object ( struct _py_trashcan * trash , PyObject * op )
2695+ void
2696+ PyTrash_thread_deposit_object ( PyThreadState * tstate , PyObject * op )
26972697{
26982698 _PyObject_ASSERT (op , _PyObject_IS_GC (op ));
26992699 _PyObject_ASSERT (op , !_PyObject_GC_IS_TRACKED (op ));
27002700 _PyObject_ASSERT (op , Py_REFCNT (op ) == 0 );
27012701#ifdef Py_GIL_DISABLED
27022702 _PyObject_ASSERT (op , op -> ob_tid == 0 );
2703- op -> ob_tid = (uintptr_t )trash -> delete_later ;
2703+ op -> ob_tid = (uintptr_t )tstate -> delete_later ;
27042704#else
2705- _PyGCHead_SET_PREV (_Py_AS_GC (op ), (PyGC_Head * )trash -> delete_later );
2705+ _PyGCHead_SET_PREV (_Py_AS_GC (op ), (PyGC_Head * )tstate -> delete_later );
27062706#endif
2707- trash -> delete_later = op ;
2707+ tstate -> delete_later = op ;
27082708}
27092709
27102710/* Deallocate all the objects in the gcstate->trash_delete_later list.
27112711 * Called when the call-stack unwinds again. */
2712- static void
2713- _PyTrash_thread_destroy_chain ( struct _py_trashcan * trash )
2712+ void
2713+ PyTrash_thread_destroy_chain ( PyThreadState * tstate )
27142714{
2715- /* We need to increase trash_delete_nesting here, otherwise,
2715+ /* We need to increase c_recursion_remaining here, otherwise,
27162716 _PyTrash_thread_destroy_chain will be called recursively
27172717 and then possibly crash. An example that may crash without
27182718 increase:
@@ -2723,17 +2723,17 @@ _PyTrash_thread_destroy_chain(struct _py_trashcan *trash)
27232723 tups = [(tup,) for tup in tups]
27242724 del tups
27252725 */
2726- assert (trash -> delete_nesting == 0 );
2727- ++ trash -> delete_nesting ;
2728- while (trash -> delete_later ) {
2729- PyObject * op = trash -> delete_later ;
2726+ assert (tstate -> c_recursion_remaining > 50 );
2727+ tstate -> c_recursion_remaining -- ;
2728+ while (tstate -> delete_later ) {
2729+ PyObject * op = tstate -> delete_later ;
27302730 destructor dealloc = Py_TYPE (op )-> tp_dealloc ;
27312731
27322732#ifdef Py_GIL_DISABLED
2733- trash -> delete_later = (PyObject * ) op -> ob_tid ;
2733+ tstate -> delete_later = (PyObject * ) op -> ob_tid ;
27342734 op -> ob_tid = 0 ;
27352735#else
2736- trash -> delete_later = (PyObject * ) _PyGCHead_PREV (_Py_AS_GC (op ));
2736+ tstate -> delete_later = (PyObject * ) _PyGCHead_PREV (_Py_AS_GC (op ));
27372737#endif
27382738
27392739 /* Call the deallocator directly. This used to try to
@@ -2744,92 +2744,10 @@ _PyTrash_thread_destroy_chain(struct _py_trashcan *trash)
27442744 */
27452745 _PyObject_ASSERT (op , Py_REFCNT (op ) == 0 );
27462746 (* dealloc )(op );
2747- assert (trash -> delete_nesting == 1 );
2748- }
2749- -- trash -> delete_nesting ;
2750- }
2751-
2752-
2753- static struct _py_trashcan *
2754- _PyTrash_get_state (PyThreadState * tstate )
2755- {
2756- if (tstate != NULL ) {
2757- return & tstate -> trash ;
2758- }
2759- // The current thread must be finalizing.
2760- // Fall back to using thread-local state.
2761- // XXX Use thread-local variable syntax?
2762- assert (PyThread_tss_is_created (& _PyRuntime .trashTSSkey ));
2763- struct _py_trashcan * trash =
2764- (struct _py_trashcan * )PyThread_tss_get (& _PyRuntime .trashTSSkey );
2765- if (trash == NULL ) {
2766- trash = PyMem_RawMalloc (sizeof (struct _py_trashcan ));
2767- if (trash == NULL ) {
2768- Py_FatalError ("Out of memory" );
2769- }
2770- PyThread_tss_set (& _PyRuntime .trashTSSkey , (void * )trash );
2771- }
2772- return trash ;
2773- }
2774-
2775- static void
2776- _PyTrash_clear_state (PyThreadState * tstate )
2777- {
2778- if (tstate != NULL ) {
2779- assert (tstate -> trash .delete_later == NULL );
2780- return ;
2781- }
2782- if (PyThread_tss_is_created (& _PyRuntime .trashTSSkey )) {
2783- struct _py_trashcan * trash =
2784- (struct _py_trashcan * )PyThread_tss_get (& _PyRuntime .trashTSSkey );
2785- if (trash != NULL ) {
2786- PyThread_tss_set (& _PyRuntime .trashTSSkey , (void * )NULL );
2787- PyMem_RawFree (trash );
2788- }
27892747 }
2748+ tstate -> c_recursion_remaining ++ ;
27902749}
27912750
2792-
2793- int
2794- _PyTrash_begin (PyThreadState * tstate , PyObject * op )
2795- {
2796- // XXX Make sure the GIL is held.
2797- struct _py_trashcan * trash = _PyTrash_get_state (tstate );
2798- if (trash -> delete_nesting >= _PyTrash_UNWIND_LEVEL ) {
2799- /* Store the object (to be deallocated later) and jump past
2800- * Py_TRASHCAN_END, skipping the body of the deallocator */
2801- _PyTrash_thread_deposit_object (trash , op );
2802- return 1 ;
2803- }
2804- ++ trash -> delete_nesting ;
2805- return 0 ;
2806- }
2807-
2808-
2809- void
2810- _PyTrash_end (PyThreadState * tstate )
2811- {
2812- // XXX Make sure the GIL is held.
2813- struct _py_trashcan * trash = _PyTrash_get_state (tstate );
2814- -- trash -> delete_nesting ;
2815- if (trash -> delete_nesting <= 0 ) {
2816- if (trash -> delete_later != NULL ) {
2817- _PyTrash_thread_destroy_chain (trash );
2818- }
2819- _PyTrash_clear_state (tstate );
2820- }
2821- }
2822-
2823-
2824- /* bpo-40170: It's only be used in Py_TRASHCAN_BEGIN macro to hide
2825- implementation details. */
2826- int
2827- _PyTrash_cond (PyObject * op , destructor dealloc )
2828- {
2829- return Py_TYPE (op )-> tp_dealloc == dealloc ;
2830- }
2831-
2832-
28332751void _Py_NO_RETURN
28342752_PyObject_AssertFailed (PyObject * obj , const char * expr , const char * msg ,
28352753 const char * file , int line , const char * function )
0 commit comments