@@ -2763,24 +2763,27 @@ rb_gc_impl_define_finalizer(void *objspace_ptr, VALUE obj, VALUE block)
27632763
27642764 RBASIC (obj )-> flags |= FL_FINALIZE ;
27652765
2766- int lev = RB_GC_VM_LOCK ();
2766+ unsigned int lev = RB_GC_VM_LOCK ();
27672767
27682768 if (st_lookup (finalizer_table , obj , & data )) {
27692769 table = (VALUE )data ;
2770+ VALUE dup_table = rb_ary_dup (table );
27702771
2772+ RB_GC_VM_UNLOCK (lev );
27712773 /* avoid duplicate block, table is usually small */
27722774 {
27732775 long len = RARRAY_LEN (table );
27742776 long i ;
27752777
27762778 for (i = 0 ; i < len ; i ++ ) {
2777- VALUE recv = RARRAY_AREF (table , i );
2778- if (rb_equal (recv , block )) {
2779- RB_GC_VM_UNLOCK (lev );
2779+ VALUE recv = RARRAY_AREF (dup_table , i );
2780+ if (rb_equal (recv , block )) { // can't be called with VM lock held
27802781 return recv ;
27812782 }
27822783 }
27832784 }
2785+ lev = RB_GC_VM_LOCK ();
2786+ RB_GC_GUARD (dup_table );
27842787
27852788 rb_ary_push (table , block );
27862789 }
@@ -2841,8 +2844,8 @@ get_final(long i, void *data)
28412844 return RARRAY_AREF (table , i + 1 );
28422845}
28432846
2844- static void
2845- run_final (rb_objspace_t * objspace , VALUE zombie )
2847+ static unsigned int
2848+ run_final (rb_objspace_t * objspace , VALUE zombie , unsigned int lev )
28462849{
28472850 if (RZOMBIE (zombie )-> dfree ) {
28482851 RZOMBIE (zombie )-> dfree (RZOMBIE (zombie )-> data );
@@ -2853,7 +2856,9 @@ run_final(rb_objspace_t *objspace, VALUE zombie)
28532856 FL_UNSET (zombie , FL_FINALIZE );
28542857 st_data_t table ;
28552858 if (st_delete (finalizer_table , & key , & table )) {
2859+ RB_GC_VM_UNLOCK (lev );
28562860 rb_gc_run_obj_finalizer (RARRAY_AREF (table , 0 ), RARRAY_LEN (table ) - 1 , get_final , (void * )table );
2861+ lev = RB_GC_VM_LOCK ();
28572862 }
28582863 else {
28592864 rb_bug ("FL_FINALIZE flag is set, but finalizers are not found" );
@@ -2862,6 +2867,7 @@ run_final(rb_objspace_t *objspace, VALUE zombie)
28622867 else {
28632868 GC_ASSERT (!st_lookup (finalizer_table , key , NULL ));
28642869 }
2870+ return lev ;
28652871}
28662872
28672873static void
@@ -2874,9 +2880,9 @@ finalize_list(rb_objspace_t *objspace, VALUE zombie)
28742880 next_zombie = RZOMBIE (zombie )-> next ;
28752881 page = GET_HEAP_PAGE (zombie );
28762882
2877- int lev = RB_GC_VM_LOCK ();
2883+ unsigned int lev = RB_GC_VM_LOCK ();
28782884
2879- run_final (objspace , zombie );
2885+ lev = run_final (objspace , zombie , lev );
28802886 {
28812887 GC_ASSERT (BUILTIN_TYPE (zombie ) == T_ZOMBIE );
28822888 GC_ASSERT (page -> heap -> final_slots_count > 0 );
0 commit comments