@@ -571,15 +571,16 @@ reader_get_or_create_thread_state(BinaryReader *reader, uint64_t thread_id,
571571 return NULL ;
572572 }
573573 } else if (reader -> thread_state_count >= reader -> thread_state_capacity ) {
574- reader -> thread_states = grow_array (reader -> thread_states ,
575- & reader -> thread_state_capacity ,
576- sizeof (ReaderThreadState ));
577- if (!reader -> thread_states ) {
574+ ReaderThreadState * new_states = grow_array (reader -> thread_states ,
575+ & reader -> thread_state_capacity ,
576+ sizeof (ReaderThreadState ));
577+ if (!new_states ) {
578578 return NULL ;
579579 }
580+ reader -> thread_states = new_states ;
580581 }
581582
582- ReaderThreadState * ts = & reader -> thread_states [reader -> thread_state_count ++ ];
583+ ReaderThreadState * ts = & reader -> thread_states [reader -> thread_state_count ];
583584 memset (ts , 0 , sizeof (ReaderThreadState ));
584585 ts -> thread_id = thread_id ;
585586 ts -> interpreter_id = interpreter_id ;
@@ -590,6 +591,9 @@ reader_get_or_create_thread_state(BinaryReader *reader, uint64_t thread_id,
590591 PyErr_NoMemory ();
591592 return NULL ;
592593 }
594+ // Increment count only after successful allocation to avoid
595+ // leaving a half-initialized entry visible to future lookups
596+ reader -> thread_state_count ++ ;
593597 return ts ;
594598}
595599
@@ -604,7 +608,11 @@ static inline int
604608decode_stack_full (ReaderThreadState * ts , const uint8_t * data ,
605609 size_t * offset , size_t max_size )
606610{
611+ size_t prev_offset = * offset ;
607612 uint32_t depth = decode_varint_u32 (data , offset , max_size );
613+ if (* offset == prev_offset ) {
614+ return -1 ;
615+ }
608616
609617 /* Validate depth against capacity to prevent buffer overflow */
610618 if (depth > ts -> current_stack_capacity ) {
@@ -615,7 +623,11 @@ decode_stack_full(ReaderThreadState *ts, const uint8_t *data,
615623
616624 ts -> current_stack_depth = depth ;
617625 for (uint32_t i = 0 ; i < depth ; i ++ ) {
626+ size_t prev_offset = * offset ;
618627 ts -> current_stack [i ] = decode_varint_u32 (data , offset , max_size );
628+ if (* offset == prev_offset ) {
629+ return -1 ;
630+ }
619631 }
620632 return 0 ;
621633}
@@ -627,8 +639,16 @@ static inline int
627639decode_stack_suffix (ReaderThreadState * ts , const uint8_t * data ,
628640 size_t * offset , size_t max_size )
629641{
642+ size_t prev_offset = * offset ;
630643 uint32_t shared = decode_varint_u32 (data , offset , max_size );
644+ if (* offset == prev_offset ) {
645+ return -1 ;
646+ }
647+ prev_offset = * offset ;
631648 uint32_t new_count = decode_varint_u32 (data , offset , max_size );
649+ if (* offset == prev_offset ) {
650+ return -1 ;
651+ }
632652
633653 /* Validate shared doesn't exceed current stack depth */
634654 if (shared > ts -> current_stack_depth ) {
@@ -664,7 +684,11 @@ decode_stack_suffix(ReaderThreadState *ts, const uint8_t *data,
664684 }
665685
666686 for (uint32_t i = 0 ; i < new_count ; i ++ ) {
687+ size_t prev_offset = * offset ;
667688 ts -> current_stack [i ] = decode_varint_u32 (data , offset , max_size );
689+ if (* offset == prev_offset ) {
690+ return -1 ;
691+ }
668692 }
669693 ts -> current_stack_depth = final_depth ;
670694 return 0 ;
@@ -677,8 +701,16 @@ static inline int
677701decode_stack_pop_push (ReaderThreadState * ts , const uint8_t * data ,
678702 size_t * offset , size_t max_size )
679703{
704+ size_t prev_offset = * offset ;
680705 uint32_t pop = decode_varint_u32 (data , offset , max_size );
706+ if (* offset == prev_offset ) {
707+ return -1 ;
708+ }
709+ prev_offset = * offset ;
681710 uint32_t push = decode_varint_u32 (data , offset , max_size );
711+ if (* offset == prev_offset ) {
712+ return -1 ;
713+ }
682714 size_t keep = (ts -> current_stack_depth > pop ) ? ts -> current_stack_depth - pop : 0 ;
683715
684716 /* Validate final depth doesn't exceed capacity */
@@ -699,7 +731,12 @@ decode_stack_pop_push(ReaderThreadState *ts, const uint8_t *data,
699731 }
700732
701733 for (uint32_t i = 0 ; i < push ; i ++ ) {
734+ size_t prev_offset = * offset ;
702735 ts -> current_stack [i ] = decode_varint_u32 (data , offset , max_size );
736+ /* If offset didn't advance, varint decoding failed */
737+ if (* offset == prev_offset ) {
738+ return -1 ;
739+ }
703740 }
704741 ts -> current_stack_depth = final_depth ;
705742 return 0 ;
@@ -1222,6 +1259,9 @@ binary_reader_close(BinaryReader *reader)
12221259 reader -> mapped_data = NULL ; /* Prevent use-after-free */
12231260 reader -> mapped_size = 0 ;
12241261 }
1262+ /* Clear sample_data which may point into the now-unmapped region */
1263+ reader -> sample_data = NULL ;
1264+ reader -> sample_data_size = 0 ;
12251265 if (reader -> fd >= 0 ) {
12261266 close (reader -> fd );
12271267 reader -> fd = -1 ; /* Mark as closed */
0 commit comments