3333/* Progress callback frequency */
3434#define PROGRESS_CALLBACK_INTERVAL 1000
3535
36+ /* Cap per-batch RLE samples to bound the timestamp list (gh-151378) */
37+ #define MAX_RLE_BATCH_SAMPLES 8192
38+
3639/* ============================================================================
3740 * BINARY READER IMPLEMENTATION
3841 * ============================================================================ */
@@ -1083,21 +1086,6 @@ emit_sample(RemoteDebuggingState *state, PyObject *collector,
10831086 return 0 ;
10841087}
10851088
1086- /* Helper to trim timestamp list and emit batch. Returns 0 on success, -1 on error. */
1087- static int
1088- emit_batch (RemoteDebuggingState * state , PyObject * collector ,
1089- uint64_t thread_id , uint32_t interpreter_id , uint8_t status ,
1090- const uint32_t * frame_indices , size_t stack_depth ,
1091- BinaryReader * reader , PyObject * timestamps_list , Py_ssize_t actual_size )
1092- {
1093- /* Trim list to actual size */
1094- if (PyList_SetSlice (timestamps_list , actual_size , PyList_GET_SIZE (timestamps_list ), NULL ) < 0 ) {
1095- return -1 ;
1096- }
1097- return emit_sample (state , collector , thread_id , interpreter_id , status ,
1098- frame_indices , stack_depth , reader , timestamps_list );
1099- }
1100-
11011089/* Helper to invoke progress callback, returns -1 on error */
11021090static inline int
11031091invoke_progress_callback (PyObject * callback , Py_ssize_t current , uint64_t total )
@@ -1226,17 +1214,18 @@ binary_reader_replay(BinaryReader *reader, PyObject *collector, PyObject *progre
12261214 ts -> prev_timestamp += delta ;
12271215
12281216 /* Start new batch on first sample or status change */
1229- if (i == 0 || status != batch_status ) {
1217+ if (i == 0 || status != batch_status
1218+ || batch_idx >= MAX_RLE_BATCH_SAMPLES ) {
12301219 if (timestamps_list ) {
1231- int rc = emit_batch (state , collector , thread_id , interpreter_id ,
1232- batch_status , ts -> current_stack , ts -> current_stack_depth ,
1233- reader , timestamps_list , batch_idx );
1220+ int rc = emit_sample (state , collector , thread_id , interpreter_id ,
1221+ batch_status , ts -> current_stack , ts -> current_stack_depth ,
1222+ reader , timestamps_list );
12341223 Py_DECREF (timestamps_list );
12351224 if (rc < 0 ) {
12361225 return -1 ;
12371226 }
12381227 }
1239- timestamps_list = PyList_New (count - i );
1228+ timestamps_list = PyList_New (0 );
12401229 if (!timestamps_list ) {
12411230 return -1 ;
12421231 }
@@ -1249,14 +1238,20 @@ binary_reader_replay(BinaryReader *reader, PyObject *collector, PyObject *progre
12491238 Py_DECREF (timestamps_list );
12501239 return -1 ;
12511240 }
1252- PyList_SET_ITEM (timestamps_list , batch_idx ++ , ts_obj );
1241+ int append_rc = PyList_Append (timestamps_list , ts_obj );
1242+ Py_DECREF (ts_obj );
1243+ if (append_rc < 0 ) {
1244+ Py_DECREF (timestamps_list );
1245+ return -1 ;
1246+ }
1247+ batch_idx ++ ;
12531248 }
12541249
12551250 /* Emit final batch */
12561251 if (timestamps_list ) {
1257- int rc = emit_batch (state , collector , thread_id , interpreter_id ,
1258- batch_status , ts -> current_stack , ts -> current_stack_depth ,
1259- reader , timestamps_list , batch_idx );
1252+ int rc = emit_sample (state , collector , thread_id , interpreter_id ,
1253+ batch_status , ts -> current_stack , ts -> current_stack_depth ,
1254+ reader , timestamps_list );
12601255 Py_DECREF (timestamps_list );
12611256 if (rc < 0 ) {
12621257 return -1 ;
0 commit comments