@@ -1070,7 +1070,7 @@ _PyMem_Strdup(const char *str)
10701070
10711071// A pointer to be freed once the QSBR read sequence reaches qsbr_goal.
10721072struct _mem_work_item {
1073- void * ptr ;
1073+ uintptr_t ptr ; // lowest bit tagged 1 for objects freed with PyObject_Free
10741074 uint64_t qsbr_goal ;
10751075};
10761076
@@ -1084,16 +1084,27 @@ struct _mem_work_chunk {
10841084 struct _mem_work_item array [WORK_ITEMS_PER_CHUNK ];
10851085};
10861086
1087- void
1088- _PyMem_FreeDelayed (void * ptr )
1087+ static void
1088+ free_work_item (uintptr_t ptr )
1089+ {
1090+ if (ptr & 0x01 ) {
1091+ PyObject_Free ((char * )(ptr - 1 ));
1092+ }
1093+ else {
1094+ PyMem_Free ((void * )ptr );
1095+ }
1096+ }
1097+
1098+ static void
1099+ free_delayed (uintptr_t ptr )
10891100{
10901101#ifndef Py_GIL_DISABLED
1091- PyMem_Free (ptr );
1102+ free_work_item (ptr );
10921103#else
10931104 if (_PyRuntime .stoptheworld .world_stopped ) {
10941105 // Free immediately if the world is stopped, including during
10951106 // interpreter shutdown.
1096- PyMem_Free (ptr );
1107+ free_work_item (ptr );
10971108 return ;
10981109 }
10991110
@@ -1120,7 +1131,7 @@ _PyMem_FreeDelayed(void *ptr)
11201131 if (buf == NULL ) {
11211132 // failed to allocate a buffer, free immediately
11221133 _PyEval_StopTheWorld (tstate -> base .interp );
1123- PyMem_Free (ptr );
1134+ free_work_item (ptr );
11241135 _PyEval_StartTheWorld (tstate -> base .interp );
11251136 return ;
11261137 }
@@ -1137,6 +1148,20 @@ _PyMem_FreeDelayed(void *ptr)
11371148#endif
11381149}
11391150
1151+ void
1152+ _PyMem_FreeDelayed (void * ptr )
1153+ {
1154+ assert (!((uintptr_t )ptr & 0x01 ));
1155+ free_delayed ((uintptr_t )ptr );
1156+ }
1157+
1158+ void
1159+ _PyObject_FreeDelayed (void * ptr )
1160+ {
1161+ assert (!((uintptr_t )ptr & 0x01 ));
1162+ free_delayed (((uintptr_t )ptr )|0x01 );
1163+ }
1164+
11401165static struct _mem_work_chunk *
11411166work_queue_first (struct llist_node * head )
11421167{
@@ -1156,7 +1181,7 @@ process_queue(struct llist_node *head, struct _qsbr_thread_state *qsbr,
11561181 return ;
11571182 }
11581183
1159- PyMem_Free (item -> ptr );
1184+ free_work_item (item -> ptr );
11601185 buf -> rd_idx ++ ;
11611186 }
11621187
@@ -1243,7 +1268,7 @@ _PyMem_FiniDelayed(PyInterpreterState *interp)
12431268 // Free the remaining items immediately. There should be no other
12441269 // threads accessing the memory at this point during shutdown.
12451270 struct _mem_work_item * item = & buf -> array [buf -> rd_idx ];
1246- PyMem_Free (item -> ptr );
1271+ free_work_item (item -> ptr );
12471272 buf -> rd_idx ++ ;
12481273 }
12491274
0 commit comments