@@ -331,36 +331,14 @@ pub unsafe extern "C" fn PyBuffer_FillInfo(
331331
332332#[ unsafe( no_mangle) ]
333333pub unsafe extern "C" fn PyBuffer_SizeFromFormat ( format : * const c_char ) -> isize {
334- if format. is_null ( ) {
335- return -1 ;
336- }
337334 with_vm ( |vm| {
338335 let fmt = unsafe { format. try_as_str ( vm) } ?;
339- // Basic format string size parsing following struct module rules
340- let mut size: isize = 0 ;
341- let mut count: isize = 0 ;
342- for ch in fmt. chars ( ) {
343- match ch {
344- '@' | '=' | '<' | '>' | '!' | ' ' => continue ,
345- '0' ..='9' => {
346- let digit = ( ch as u8 - b'0' ) as isize ;
347- count = count * 10 + digit;
348- }
349- _ => {
350- let item_count = if count == 0 { 1 } else { count } ;
351- count = 0 ;
352- let elem_size = match ch {
353- 'x' | 'c' | 'b' | 'B' | '?' => 1 ,
354- 'h' | 'H' | 'e' => 2 ,
355- 'i' | 'I' | 'l' | 'L' | 'f' => 4 ,
356- 'q' | 'Q' | 'd' => 8 ,
357- 'P' => core:: mem:: size_of :: < * mut c_void > ( ) as isize ,
358- _ => return Err ( vm. new_value_error ( format ! ( "unknown format code: {ch}" ) ) ) ,
359- } ;
360- size += item_count * elem_size;
361- }
362- }
363- }
336+ let struct_mod = vm. import ( "struct" , 0 ) ?;
337+ let calcsize = struct_mod. get_attr ( "calcsize" , vm) ?;
338+ let res = calcsize. call ( ( fmt, ) , vm) ?;
339+ let size: isize = res. try_index ( vm) ?. as_bigint ( ) . try_into ( ) . map_err ( |_| {
340+ vm. new_overflow_error ( "struct.calcsize result too large for isize" . to_owned ( ) )
341+ } ) ?;
364342 Ok ( size)
365343 } )
366344}
@@ -423,6 +401,9 @@ mod tests {
423401
424402 let size_double = unsafe { PyBuffer_SizeFromFormat ( c"d" . as_ptr ( ) ) } ;
425403 assert_eq ! ( size_double, 8 ) ;
404+
405+ let null_size = unsafe { PyBuffer_SizeFromFormat ( core:: ptr:: null ( ) ) } ;
406+ assert_eq ! ( null_size, -1 ) ;
426407 } ) ;
427408 }
428409
0 commit comments