@@ -161,6 +161,11 @@ impl Reader {
161161
162162 /// Fetches the i-th sequence name.
163163 pub fn seq_name ( & self , i : i32 ) -> Result < String , FaidxError > {
164+ // faidx_iseq does no bounds checking (it indexes directly into an
165+ // array), so we must validate the index before calling it.
166+ if i < 0 || ( i as u64 ) >= self . n_seqs ( ) {
167+ return Err ( FaidxError :: InvalidSequenceName { index : i } ) ;
168+ }
164169 let ptr = unsafe { htslib:: faidx_iseq ( self . inner , i) } ;
165170 if ptr. is_null ( ) {
166171 return Err ( FaidxError :: InvalidSequenceName { index : i } ) ;
@@ -324,6 +329,40 @@ mod tests {
324329 assert_eq ! ( n, "chr2" ) ;
325330 }
326331
332+ #[ test]
333+ fn faidx_seq_name_all_valid_indices ( ) {
334+ let r = open_reader ( ) ;
335+ assert_eq ! ( r. seq_name( 0 ) . unwrap( ) , "chr1" ) ;
336+ assert_eq ! ( r. seq_name( 1 ) . unwrap( ) , "chr2" ) ;
337+ assert_eq ! ( r. seq_name( 2 ) . unwrap( ) , "chr3" ) ;
338+ }
339+
340+ #[ test]
341+ fn faidx_seq_name_boundary ( ) {
342+ // n_seqs() == 3, so index 2 is the last valid and 3 is the first invalid.
343+ // faidx_iseq does no bounds checking in C, so calling it with an
344+ // out-of-bounds index would segfault without our Rust-side guard.
345+ let r = open_reader ( ) ;
346+ assert ! ( r. seq_name( 2 ) . is_ok( ) ) ;
347+ assert ! ( matches!(
348+ r. seq_name( 3 ) ,
349+ Err ( FaidxError :: InvalidSequenceName { index: 3 } )
350+ ) ) ;
351+ }
352+
353+ #[ test]
354+ fn faidx_seq_name_i32_extremes ( ) {
355+ let r = open_reader ( ) ;
356+ assert ! ( matches!(
357+ r. seq_name( i32 :: MAX ) ,
358+ Err ( FaidxError :: InvalidSequenceName { index: i32 :: MAX } )
359+ ) ) ;
360+ assert ! ( matches!(
361+ r. seq_name( i32 :: MIN ) ,
362+ Err ( FaidxError :: InvalidSequenceName { index: i32 :: MIN } )
363+ ) ) ;
364+ }
365+
327366 #[ test]
328367 fn faidx_get_seq_len ( ) {
329368 let r = open_reader ( ) ;
0 commit comments