@@ -35,31 +35,50 @@ fn infer_current_exe(base_addr: usize) -> OsString {
3535    env:: current_exe ( ) . map ( |e| e. into ( ) ) . unwrap_or_default ( ) 
3636} 
3737
38- // `info` should be a valid pointers. 
39- // `vec` should be a valid pointer to a `std::Vec`. 
38+ /// # Safety 
39+ /// `info` must be a valid pointer. 
40+ /// `vec` must be a valid pointer to `Vec<Library>` 
41+ #[ forbid( unsafe_op_in_unsafe_fn) ]  
4042unsafe  extern  "C"  fn  callback ( 
4143    info :  * mut  libc:: dl_phdr_info , 
4244    _size :  libc:: size_t , 
4345    vec :  * mut  libc:: c_void , 
4446)  -> libc:: c_int  { 
45-     let  info = & * info; 
46-     let  libs = & mut  * vec. cast :: < Vec < Library > > ( ) ; 
47-     let  is_main_prog = info. dlpi_name . is_null ( )  || * info. dlpi_name  == 0 ; 
48-     let  name = if  is_main_prog { 
49-         // The man page for dl_iterate_phdr says that the first object visited by 
50-         // callback is the main program; so the first time we encounter a 
51-         // nameless entry, we can assume its the main program and try to infer its path. 
52-         // After that, we cannot continue that assumption, and we use an empty string. 
53-         if  libs. is_empty ( )  { 
54-             infer_current_exe ( info. dlpi_addr  as  usize ) 
55-         }  else  { 
47+     // SAFETY: We are guaranteed these fields: 
48+     let  dlpi_addr = unsafe  {  ( * info) . dlpi_addr  } ; 
49+     let  dlpi_name = unsafe  {  ( * info) . dlpi_name  } ; 
50+     let  dlpi_phdr = unsafe  {  ( * info) . dlpi_phdr  } ; 
51+     let  dlpi_phnum = unsafe  {  ( * info) . dlpi_phnum  } ; 
52+     // SAFETY: We assured this. 
53+     let  libs = unsafe  {  & mut  * vec. cast :: < Vec < Library > > ( )  } ; 
54+     // most implementations give us the main program first 
55+     let  is_main = libs. is_empty ( ) ; 
56+     // we may be statically linked, which means we are main and mostly one big blob of code 
57+     let  is_static = dlpi_addr == 0 ; 
58+     // sometimes we get a null or 0-len CStr, based on libc's whims, but these mean the same thing 
59+     let  no_given_name = dlpi_name. is_null ( ) 
60+         // SAFETY: we just checked for null 
61+         || unsafe  {  * dlpi_name == 0  } ; 
62+     let  name = if  is_static { 
63+         // don't try to look up our name from /proc/self/maps, it'll get silly 
64+         env:: current_exe ( ) . unwrap_or_default ( ) . into_os_string ( ) 
65+     }  else  if  is_main && no_given_name { 
66+         infer_current_exe ( dlpi_addr as  usize ) 
67+     }  else  { 
68+         // this fallback works even if we are main, because some platforms give the name anyways 
69+         if  dlpi_name. is_null ( )  { 
5670            OsString :: new ( ) 
71+         }  else  { 
72+             // SAFETY: we just checked for nullness 
73+             OsStr :: from_bytes ( unsafe  {  CStr :: from_ptr ( dlpi_name)  } . to_bytes ( ) ) . to_owned ( ) 
5774        } 
75+     } ; 
76+     let  headers = if  dlpi_phdr. is_null ( )  || dlpi_phnum == 0  { 
77+         & [ ] 
5878    }  else  { 
59-         let  bytes =  CStr :: from_ptr ( info . dlpi_name ) . to_bytes ( ) ; 
60-         OsStr :: from_bytes ( bytes ) . to_owned ( ) 
79+         // SAFETY: We just checked for nullness or 0-len slices 
80+         unsafe   {  slice :: from_raw_parts ( dlpi_phdr ,  dlpi_phnum  as   usize )   } 
6181    } ; 
62-     let  headers = slice:: from_raw_parts ( info. dlpi_phdr ,  info. dlpi_phnum  as  usize ) ; 
6382    libs. push ( Library  { 
6483        name, 
6584        segments :  headers
@@ -69,7 +88,7 @@ unsafe extern "C" fn callback(
6988                stated_virtual_memory_address :  ( * header) . p_vaddr  as  usize , 
7089            } ) 
7190            . collect ( ) , 
72-         bias :  info . dlpi_addr  as  usize , 
91+         bias :  dlpi_addr as  usize , 
7392    } ) ; 
7493    0 
7594} 
0 commit comments