@@ -85,16 +85,37 @@ impl FromStr for MapsEntry {
8585 // e.g.: "ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall]"
8686 // e.g.: "7f5985f46000-7f5985f48000 rw-p 00039000 103:06 76021795 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2"
8787 // e.g.: "35b1a21000-35b1a22000 rw-p 00000000 00:00 0"
88+ //
89+ // Note that paths may contain spaces, so we can't use `str::split` for parsing (until
90+ // Split::remainder is stabilized #77998).
8891 fn from_str ( s : & str ) -> Result < Self , Self :: Err > {
89- let mut parts = s
90- . split ( ' ' ) // space-separated fields
91- . filter ( |s| s. len ( ) > 0 ) ; // multiple spaces implies empty strings that need to be skipped.
92- let range_str = parts. next ( ) . ok_or ( "Couldn't find address" ) ?;
93- let perms_str = parts. next ( ) . ok_or ( "Couldn't find permissions" ) ?;
94- let offset_str = parts. next ( ) . ok_or ( "Couldn't find offset" ) ?;
95- let dev_str = parts. next ( ) . ok_or ( "Couldn't find dev" ) ?;
96- let inode_str = parts. next ( ) . ok_or ( "Couldn't find inode" ) ?;
97- let pathname_str = parts. next ( ) . unwrap_or ( "" ) ; // pathname may be omitted.
92+ let ( range_str, s) = s. trim_start ( ) . split_once ( ' ' ) . unwrap_or ( ( s, "" ) ) ;
93+ if range_str. is_empty ( ) {
94+ return Err ( "Couldn't find address" ) ;
95+ }
96+
97+ let ( perms_str, s) = s. trim_start ( ) . split_once ( ' ' ) . unwrap_or ( ( s, "" ) ) ;
98+ if perms_str. is_empty ( ) {
99+ return Err ( "Couldn't find permissions" ) ;
100+ }
101+
102+ let ( offset_str, s) = s. trim_start ( ) . split_once ( ' ' ) . unwrap_or ( ( s, "" ) ) ;
103+ if offset_str. is_empty ( ) {
104+ return Err ( "Couldn't find offset" ) ;
105+ }
106+
107+ let ( dev_str, s) = s. trim_start ( ) . split_once ( ' ' ) . unwrap_or ( ( s, "" ) ) ;
108+ if dev_str. is_empty ( ) {
109+ return Err ( "Couldn't find dev" ) ;
110+ }
111+
112+ let ( inode_str, s) = s. trim_start ( ) . split_once ( ' ' ) . unwrap_or ( ( s, "" ) ) ;
113+ if inode_str. is_empty ( ) {
114+ return Err ( "Couldn't find inode" ) ;
115+ }
116+
117+ // Pathname may be omitted in which case it will be empty
118+ let pathname_str = s. trim_start ( ) ;
98119
99120 let hex = |s| usize:: from_str_radix ( s, 16 ) . map_err ( |_| "Couldn't parse hex number" ) ;
100121 let address = if let Some ( ( start, limit) ) = range_str. split_once ( '-' ) {
@@ -229,4 +250,46 @@ fn check_maps_entry_parsing_32bit() {
229250 pathname: Default :: default ( ) ,
230251 }
231252 ) ;
253+ assert_eq ! (
254+ "b7c79000-b7e02000 r--p 00000000 08:01 60662705 \
255+ /executable/path/with some spaces"
256+ . parse:: <MapsEntry >( )
257+ . unwrap( ) ,
258+ MapsEntry {
259+ address: ( 0xb7c79000 , 0xb7e02000 ) ,
260+ perms: [ 'r' , '-' , '-' , 'p' ] ,
261+ offset: 0x00000000 ,
262+ dev: ( 0x08 , 0x01 ) ,
263+ inode: 0x60662705 ,
264+ pathname: "/executable/path/with some spaces" . into( ) ,
265+ }
266+ ) ;
267+ assert_eq ! (
268+ "b7c79000-b7e02000 r--p 00000000 08:01 60662705 \
269+ /executable/path/with multiple-continuous spaces "
270+ . parse:: <MapsEntry >( )
271+ . unwrap( ) ,
272+ MapsEntry {
273+ address: ( 0xb7c79000 , 0xb7e02000 ) ,
274+ perms: [ 'r' , '-' , '-' , 'p' ] ,
275+ offset: 0x00000000 ,
276+ dev: ( 0x08 , 0x01 ) ,
277+ inode: 0x60662705 ,
278+ pathname: "/executable/path/with multiple-continuous spaces " . into( ) ,
279+ }
280+ ) ;
281+ assert_eq ! (
282+ " b7c79000-b7e02000 r--p 00000000 08:01 60662705 \
283+ /executable/path/starts-with-spaces"
284+ . parse:: <MapsEntry >( )
285+ . unwrap( ) ,
286+ MapsEntry {
287+ address: ( 0xb7c79000 , 0xb7e02000 ) ,
288+ perms: [ 'r' , '-' , '-' , 'p' ] ,
289+ offset: 0x00000000 ,
290+ dev: ( 0x08 , 0x01 ) ,
291+ inode: 0x60662705 ,
292+ pathname: "/executable/path/starts-with-spaces" . into( ) ,
293+ }
294+ ) ;
232295}
0 commit comments