@@ -9902,6 +9902,17 @@ gc_is_moveable_obj(rb_objspace_t *objspace, VALUE obj)
99029902 return FALSE;
99039903}
99049904
9905+ /* Used in places that could malloc, which can cause the GC to run. We need to
9906+ * temporarily disable the GC to allow the malloc to happen. */
9907+ #define COULD_MALLOC_REGION_START () \
9908+ GC_ASSERT(during_gc); \
9909+ VALUE _already_disabled = rb_gc_disable_no_rest(); \
9910+ during_gc = false;
9911+
9912+ #define COULD_MALLOC_REGION_END () \
9913+ during_gc = true; \
9914+ if (_already_disabled == Qfalse) rb_objspace_gc_enable(objspace);
9915+
99059916static VALUE
99069917gc_move (rb_objspace_t * objspace , VALUE scan , VALUE free , size_t src_slot_size , size_t slot_size )
99079918{
@@ -9930,11 +9941,12 @@ gc_move(rb_objspace_t *objspace, VALUE scan, VALUE free, size_t src_slot_size, s
99309941 CLEAR_IN_BITMAP (GET_HEAP_MARKING_BITS ((VALUE )src ), (VALUE )src );
99319942
99329943 if (FL_TEST ((VALUE )src , FL_EXIVAR )) {
9933- /* Same deal as below. Generic ivars are held in st tables.
9934- * Resizing the table could cause a GC to happen and we can't allow it */
9935- VALUE already_disabled = rb_gc_disable_no_rest ();
9936- rb_mv_generic_ivar ((VALUE )src , (VALUE )dest );
9937- if (already_disabled == Qfalse ) rb_objspace_gc_enable (objspace );
9944+ /* Resizing the st table could cause a malloc */
9945+ COULD_MALLOC_REGION_START ();
9946+ {
9947+ rb_mv_generic_ivar ((VALUE )src , (VALUE )dest );
9948+ }
9949+ COULD_MALLOC_REGION_END ();
99389950 }
99399951
99409952 st_data_t srcid = (st_data_t )src , id ;
@@ -9943,13 +9955,13 @@ gc_move(rb_objspace_t *objspace, VALUE scan, VALUE free, size_t src_slot_size, s
99439955 * the object to object id mapping. */
99449956 if (st_lookup (objspace -> obj_to_id_tbl , srcid , & id )) {
99459957 gc_report (4 , objspace , "Moving object with seen id: %p -> %p\n" , (void * )src , (void * )dest );
9946- /* inserting in the st table can cause the GC to run. We need to
9947- * prevent re-entry in to the GC since `gc_move` is running in the GC,
9948- * so temporarily disable the GC around the st table mutation */
9949- VALUE already_disabled = rb_gc_disable_no_rest ( );
9950- st_delete (objspace -> obj_to_id_tbl , & srcid , 0 );
9951- st_insert ( objspace -> obj_to_id_tbl , ( st_data_t ) dest , id );
9952- if ( already_disabled == Qfalse ) rb_objspace_gc_enable ( objspace );
9958+ /* Resizing the st table could cause a malloc */
9959+ COULD_MALLOC_REGION_START ();
9960+ {
9961+ st_delete ( objspace -> obj_to_id_tbl , & srcid , 0 );
9962+ st_insert (objspace -> obj_to_id_tbl , ( st_data_t ) dest , id );
9963+ }
9964+ COULD_MALLOC_REGION_END ( );
99539965 }
99549966
99559967 /* Move the object */
@@ -12192,9 +12204,26 @@ objspace_malloc_prepare(rb_objspace_t *objspace, size_t size)
1219212204 return size ;
1219312205}
1219412206
12207+ static bool
12208+ malloc_during_gc_p (rb_objspace_t * objspace )
12209+ {
12210+ /* malloc is not allowed during GC when we're not using multiple ractors
12211+ * (since ractors can run while another thread is sweeping) and when we
12212+ * have the GVL (since if we don't have the GVL, we'll try to acquire the
12213+ * GVL which will block and ensure the other thread finishes GC). */
12214+ return during_gc && !rb_multi_ractor_p () && ruby_thread_has_gvl_p ();
12215+ }
12216+
1219512217static inline void *
1219612218objspace_malloc_fixup (rb_objspace_t * objspace , void * mem , size_t size )
1219712219{
12220+ if (UNLIKELY (malloc_during_gc_p (objspace ))) {
12221+ rb_warn ("malloc during GC detected, this could cause crashes if it triggers another GC" );
12222+ #if RGENGC_CHECK_MODE
12223+ rb_bug ("Cannot malloc during GC" );
12224+ #endif
12225+ }
12226+
1219812227 size = objspace_malloc_size (objspace , mem , size );
1219912228 objspace_malloc_increase (objspace , mem , size , 0 , MEMOP_TYPE_MALLOC );
1220012229
@@ -12273,6 +12302,13 @@ xmalloc2_size(const size_t count, const size_t elsize)
1227312302static void *
1227412303objspace_xrealloc (rb_objspace_t * objspace , void * ptr , size_t new_size , size_t old_size )
1227512304{
12305+ if (UNLIKELY (malloc_during_gc_p (objspace ))) {
12306+ rb_warn ("realloc during GC detected, this could cause crashes if it triggers another GC" );
12307+ #if RGENGC_CHECK_MODE
12308+ rb_bug ("Cannot realloc during GC" );
12309+ #endif
12310+ }
12311+
1227612312 void * mem ;
1227712313
1227812314 if (!ptr ) return objspace_xmalloc0 (objspace , new_size );
0 commit comments