@@ -1143,18 +1143,24 @@ struct _mem_work_chunk {
11431143    struct  _mem_work_item  array [WORK_ITEMS_PER_CHUNK ];
11441144};
11451145
1146+ static  int 
1147+ work_item_should_decref (uintptr_t  ptr )
1148+ {
1149+     return  ptr  &  0x01 ;
1150+ }
1151+ 
11461152static  void 
11471153free_work_item (uintptr_t  ptr , delayed_dealloc_cb  cb , void  * state )
11481154{
1149-     if  (ptr   &   0x01 ) {
1155+     if  (work_item_should_decref ( ptr ) ) {
11501156        PyObject  * obj  =  (PyObject  * )(ptr  -  1 );
11511157#ifdef  Py_GIL_DISABLED 
11521158        if  (cb  ==  NULL ) {
11531159            assert (!_PyInterpreterState_GET ()-> stoptheworld .world_stopped );
11541160            Py_DECREF (obj );
11551161            return ;
11561162        }
1157- 
1163+          assert ( _PyInterpreterState_GET () -> stoptheworld . world_stopped ); 
11581164        Py_ssize_t  refcount  =  _Py_ExplicitMergeRefcount (obj , -1 );
11591165        if  (refcount  ==  0 ) {
11601166            cb (obj , state );
@@ -1180,7 +1186,7 @@ free_delayed(uintptr_t ptr)
11801186    {
11811187        // Free immediately during interpreter shutdown or if the world is 
11821188        // stopped. 
1183-         assert (!interp -> stoptheworld .world_stopped  ||  !(ptr   &   0x01 ));
1189+         assert (!interp -> stoptheworld .world_stopped  ||  !work_item_should_decref (ptr ));
11841190        free_work_item (ptr , NULL , NULL );
11851191        return ;
11861192    }
@@ -1207,10 +1213,22 @@ free_delayed(uintptr_t ptr)
12071213
12081214    if  (buf  ==  NULL ) {
12091215        // failed to allocate a buffer, free immediately 
1216+         PyObject  * to_dealloc  =  NULL ;
12101217        _PyEval_StopTheWorld (tstate -> base .interp );
1211-         // TODO: Fix me 
1212-         free_work_item (ptr , NULL , NULL );
1218+         if  (work_item_should_decref (ptr )) {
1219+             PyObject  * obj  =  (PyObject  * )(ptr  -  1 );
1220+             Py_ssize_t  refcount  =  _Py_ExplicitMergeRefcount (obj , -1 );
1221+             if  (refcount  ==  0 ) {
1222+                 to_dealloc  =  obj ;
1223+             }
1224+         }
1225+         else  {
1226+             PyMem_Free ((void  * )ptr );
1227+         }
12131228        _PyEval_StartTheWorld (tstate -> base .interp );
1229+         if  (to_dealloc  !=  NULL ) {
1230+             _Py_Dealloc (to_dealloc );
1231+         }
12141232        return ;
12151233    }
12161234
@@ -1257,14 +1275,16 @@ process_queue(struct llist_node *head, struct _qsbr_thread_state *qsbr,
12571275    while  (!llist_empty (head )) {
12581276        struct  _mem_work_chunk  * buf  =  work_queue_first (head );
12591277
1260-         while  (buf -> rd_idx  <  buf -> wr_idx ) {
1278+         if  (buf -> rd_idx  <  buf -> wr_idx ) {
12611279            struct  _mem_work_item  * item  =  & buf -> array [buf -> rd_idx ];
12621280            if  (!_Py_qsbr_poll (qsbr , item -> qsbr_goal )) {
12631281                return ;
12641282            }
12651283
1266-             free_work_item (item -> ptr , cb , state );
12671284            buf -> rd_idx ++ ;
1285+             // NB: free_work_item may re-enter or execute arbitrary code 
1286+             free_work_item (item -> ptr , cb , state );
1287+             continue ;
12681288        }
12691289
12701290        assert (buf -> rd_idx  ==  buf -> wr_idx );
@@ -1360,12 +1380,14 @@ _PyMem_FiniDelayed(PyInterpreterState *interp)
13601380    while  (!llist_empty (head )) {
13611381        struct  _mem_work_chunk  * buf  =  work_queue_first (head );
13621382
1363-         while  (buf -> rd_idx  <  buf -> wr_idx ) {
1383+         if  (buf -> rd_idx  <  buf -> wr_idx ) {
13641384            // Free the remaining items immediately. There should be no other 
13651385            // threads accessing the memory at this point during shutdown. 
13661386            struct  _mem_work_item  * item  =  & buf -> array [buf -> rd_idx ];
1367-             free_work_item (item -> ptr , NULL , NULL );
13681387            buf -> rd_idx ++ ;
1388+             // NB: free_work_item may re-enter or execute arbitrary code 
1389+             free_work_item (item -> ptr , NULL , NULL );
1390+             continue ;
13691391        }
13701392
13711393        llist_remove (& buf -> node );
0 commit comments