33// For the full copyright and license information, please view the LICENSE
44// file that was distributed with this source code.
55
6+ use std:: io:: { Error , ErrorKind } ;
7+
68// Represents a parsed single line from /proc/<PID>/maps.
79#[ derive( Debug , PartialEq ) ]
810pub struct MapLine {
@@ -12,39 +14,48 @@ pub struct MapLine {
1214 pub mapping : String ,
1315}
1416
15- // Parses a single line from /proc/<PID>/maps. It assumes the format of `line` is correct (see
16- // https://www.kernel.org/doc/html/latest/filesystems/proc.html for details).
17- pub fn parse_map_line ( line : & str ) -> MapLine {
18- let ( memory_range, rest) = line. split_once ( ' ' ) . expect ( "line should contain ' '" ) ;
19- let ( address, size_in_kb) = parse_address ( memory_range) ;
20-
21- let ( perms, rest) = rest. split_once ( ' ' ) . expect ( "line should contain 2nd ' '" ) ;
17+ // Parses a single line from /proc/<PID>/maps. See
18+ // https://www.kernel.org/doc/html/latest/filesystems/proc.html for details about the expected
19+ // format.
20+ //
21+ // # Errors
22+ //
23+ // Will return an `Error` if the format is incorrect.
24+ pub fn parse_map_line ( line : & str ) -> Result < MapLine , Error > {
25+ let ( memory_range, rest) = line
26+ . split_once ( ' ' )
27+ . ok_or_else ( || Error :: from ( ErrorKind :: InvalidData ) ) ?;
28+ let ( address, size_in_kb) = parse_address ( memory_range) ?;
29+
30+ let ( perms, rest) = rest
31+ . split_once ( ' ' )
32+ . ok_or_else ( || Error :: from ( ErrorKind :: InvalidData ) ) ?;
2233 let perms = parse_perms ( perms) ;
2334
2435 let mapping: String = rest. splitn ( 4 , ' ' ) . skip ( 3 ) . collect ( ) ;
2536 let mapping = mapping. trim_ascii_start ( ) ;
2637 let mapping = parse_mapping ( mapping) ;
2738
28- MapLine {
39+ Ok ( MapLine {
2940 address,
3041 size_in_kb,
3142 perms,
3243 mapping,
33- }
44+ } )
3445}
3546
3647// Returns the start address and the size of the provided memory range. The start address is always
3748// 16-digits and padded with 0, if necessary. The size is in KB.
38- fn parse_address ( memory_range : & str ) -> ( String , u64 ) {
49+ fn parse_address ( memory_range : & str ) -> Result < ( String , u64 ) , Error > {
3950 let ( start, end) = memory_range
4051 . split_once ( '-' )
41- . expect ( "memory range should contain '-'" ) ;
52+ . ok_or_else ( || Error :: from ( ErrorKind :: InvalidData ) ) ? ;
4253
43- let low = u64:: from_str_radix ( start, 16 ) . expect ( "should be a hex value" ) ;
44- let high = u64:: from_str_radix ( end, 16 ) . expect ( "should be a hex value" ) ;
54+ let low = u64:: from_str_radix ( start, 16 ) . map_err ( |_| Error :: from ( ErrorKind :: InvalidData ) ) ? ;
55+ let high = u64:: from_str_radix ( end, 16 ) . map_err ( |_| Error :: from ( ErrorKind :: InvalidData ) ) ? ;
4556 let size_in_kb = ( high - low) / 1024 ;
4657
47- ( format ! ( "{start:0>16}" ) , size_in_kb)
58+ Ok ( ( format ! ( "{start:0>16}" ) , size_in_kb) )
4859}
4960
5061// Turns a 4-char perms string from /proc/<PID>/maps into a 5-char perms string. The first three
@@ -118,21 +129,37 @@ mod test {
118129 ] ;
119130
120131 for ( expected_map_line, line) in data {
121- assert_eq ! ( expected_map_line, parse_map_line( line) ) ;
132+ assert_eq ! ( expected_map_line, parse_map_line( line) . unwrap ( ) ) ;
122133 }
123134 }
124135
136+ #[ test]
137+ fn test_parse_map_line_with_invalid_format ( ) {
138+ assert ! ( parse_map_line( "invalid_format" ) . is_err( ) ) ;
139+ }
140+
125141 #[ test]
126142 fn test_parse_address ( ) {
127- let ( start, size) = parse_address ( "ffffffffff600000-ffffffffff601000" ) ;
143+ let ( start, size) = parse_address ( "ffffffffff600000-ffffffffff601000" ) . unwrap ( ) ;
128144 assert_eq ! ( start, "ffffffffff600000" ) ;
129145 assert_eq ! ( size, 4 ) ;
130146
131- let ( start, size) = parse_address ( "7ffc4f0c2000-7ffc4f0e3000" ) ;
147+ let ( start, size) = parse_address ( "7ffc4f0c2000-7ffc4f0e3000" ) . unwrap ( ) ;
132148 assert_eq ! ( start, "00007ffc4f0c2000" ) ;
133149 assert_eq ! ( size, 132 ) ;
134150 }
135151
152+ #[ test]
153+ fn test_parse_address_with_missing_hyphen ( ) {
154+ assert ! ( parse_address( "ffffffffff600000" ) . is_err( ) ) ;
155+ }
156+
157+ #[ test]
158+ fn test_parse_address_with_non_hex_values ( ) {
159+ assert ! ( parse_address( "zfffffffff600000-ffffffffff601000" ) . is_err( ) ) ;
160+ assert ! ( parse_address( "ffffffffff600000-zfffffffff601000" ) . is_err( ) ) ;
161+ }
162+
136163 #[ test]
137164 fn test_parse_perms ( ) {
138165 assert_eq ! ( "-----" , parse_perms( "---p" ) ) ;
0 commit comments