11use crate :: model:: {
22 Argument , Arguments , Attribute , Class , Function , Module , VariableLengthArgument ,
33} ;
4- use anyhow:: { bail, ensure, Context , Result } ;
4+ use anyhow:: { anyhow, bail, ensure, Context , Result } ;
5+ use goblin:: elf:: section_header:: SHN_XINDEX ;
56use goblin:: elf:: Elf ;
67use goblin:: mach:: load_command:: CommandVariant ;
78use goblin:: mach:: symbols:: { NO_SECT , N_SECT } ;
@@ -11,8 +12,8 @@ use goblin::Object;
1112use serde:: Deserialize ;
1213use std:: cmp:: Ordering ;
1314use std:: collections:: HashMap ;
14- use std:: fs;
1515use std:: path:: Path ;
16+ use std:: { fs, str} ;
1617
1718/// Introspect a cdylib built with PyO3 and returns the definition of a Python module.
1819///
@@ -268,13 +269,12 @@ fn find_introspection_chunks_in_elf(elf: &Elf<'_>, library_content: &[u8]) -> Re
268269 let mut chunks = Vec :: new ( ) ;
269270 for sym in & elf. syms {
270271 if is_introspection_symbol ( elf. strtab . get_at ( sym. st_name ) . unwrap_or_default ( ) ) {
272+ ensure ! ( u32 :: try_from( sym. st_shndx) ? != SHN_XINDEX , "Section names length is greater than SHN_LORESERVE in ELF, this is not supported by PyO3 yet" ) ;
271273 let section_header = & elf. section_headers [ sym. st_shndx ] ;
272274 let data_offset = sym. st_value + section_header. sh_offset - section_header. sh_addr ;
273- chunks. push ( read_symbol_value_with_ptr_and_len (
275+ chunks. push ( deserialize_chunk (
274276 & library_content[ usize:: try_from ( data_offset) . context ( "File offset overflow" ) ?..] ,
275- 0 ,
276- library_content,
277- elf. is_64 ,
277+ elf. little_endian ,
278278 ) ?) ;
279279 }
280280 }
@@ -311,73 +311,47 @@ fn find_introspection_chunks_in_macho(
311311 {
312312 let section = & sections[ nlist. n_sect - 1 ] ; // Sections are counted from 1
313313 let data_offset = nlist. n_value + u64:: from ( section. offset ) - section. addr ;
314- chunks. push ( read_symbol_value_with_ptr_and_len (
314+ chunks. push ( deserialize_chunk (
315315 & library_content[ usize:: try_from ( data_offset) . context ( "File offset overflow" ) ?..] ,
316- 0 ,
317- library_content,
318- macho. is_64 ,
316+ macho. little_endian ,
319317 ) ?) ;
320318 }
321319 }
322320 Ok ( chunks)
323321}
324322
325323fn find_introspection_chunks_in_pe ( pe : & PE < ' _ > , library_content : & [ u8 ] ) -> Result < Vec < Chunk > > {
326- let rdata_data_section = pe
327- . sections
328- . iter ( )
329- . find ( |section| section. name ( ) . unwrap_or_default ( ) == ".rdata" )
330- . context ( "No .rdata section found" ) ?;
331- let rdata_shift = usize:: try_from ( pe. image_base ) . context ( "image_base overflow" ) ?
332- + usize:: try_from ( rdata_data_section. virtual_address )
333- . context ( ".rdata virtual_address overflow" ) ?
334- - usize:: try_from ( rdata_data_section. pointer_to_raw_data )
335- . context ( ".rdata pointer_to_raw_data overflow" ) ?;
336-
337324 let mut chunks = Vec :: new ( ) ;
338325 for export in & pe. exports {
339326 if is_introspection_symbol ( export. name . unwrap_or_default ( ) ) {
340- chunks. push ( read_symbol_value_with_ptr_and_len (
327+ chunks. push ( deserialize_chunk (
341328 & library_content[ export. offset . context ( "No symbol offset" ) ?..] ,
342- rdata_shift,
343- library_content,
344- pe. is_64 ,
329+ true ,
345330 ) ?) ;
346331 }
347332 }
348333 Ok ( chunks)
349334}
350335
351- fn read_symbol_value_with_ptr_and_len (
352- value_slice : & [ u8 ] ,
353- shift : usize ,
354- full_library_content : & [ u8 ] ,
355- is_64 : bool ,
336+ fn deserialize_chunk (
337+ content_with_chunk_at_the_beginning : & [ u8 ] ,
338+ is_little_endian : bool ,
356339) -> Result < Chunk > {
357- let ( ptr, len) = if is_64 {
358- let ( ptr, len) = value_slice[ ..16 ] . split_at ( 8 ) ;
359- let ptr = usize:: try_from ( u64:: from_le_bytes (
360- ptr. try_into ( ) . context ( "Too short symbol value" ) ?,
361- ) )
362- . context ( "Pointer overflow" ) ?;
363- let len = usize:: try_from ( u64:: from_le_bytes (
364- len. try_into ( ) . context ( "Too short symbol value" ) ?,
365- ) )
366- . context ( "Length overflow" ) ?;
367- ( ptr, len)
340+ let length = content_with_chunk_at_the_beginning
341+ . split_at ( 4 )
342+ . 0
343+ . try_into ( )
344+ . context ( "The introspection chunk must contain a length" ) ?;
345+ let length = if is_little_endian {
346+ u32:: from_le_bytes ( length)
368347 } else {
369- let ( ptr, len) = value_slice[ ..8 ] . split_at ( 4 ) ;
370- let ptr = usize:: try_from ( u32:: from_le_bytes (
371- ptr. try_into ( ) . context ( "Too short symbol value" ) ?,
372- ) )
373- . context ( "Pointer overflow" ) ?;
374- let len = usize:: try_from ( u32:: from_le_bytes (
375- len. try_into ( ) . context ( "Too short symbol value" ) ?,
376- ) )
377- . context ( "Length overflow" ) ?;
378- ( ptr, len)
348+ u32:: from_be_bytes ( length)
379349 } ;
380- let chunk = & full_library_content[ ptr - shift..ptr - shift + len] ;
350+ let chunk = content_with_chunk_at_the_beginning
351+ . get ( 4 ..4 + length as usize )
352+ . ok_or_else ( || {
353+ anyhow ! ( "The introspection chunk length {length} is greater that the binary size" )
354+ } ) ?;
381355 serde_json:: from_slice ( chunk) . with_context ( || {
382356 format ! (
383357 "Failed to parse introspection chunk: '{}'" ,
@@ -389,7 +363,7 @@ fn read_symbol_value_with_ptr_and_len(
389363fn is_introspection_symbol ( name : & str ) -> bool {
390364 name. strip_prefix ( '_' )
391365 . unwrap_or ( name)
392- . starts_with ( "PYO3_INTROSPECTION_0_ " )
366+ . starts_with ( "PYO3_INTROSPECTION_1_ " )
393367}
394368
395369#[ derive( Deserialize ) ]
0 commit comments