Skip to content

Commit a706ecb

Browse files
authored
Merge pull request #257 from cakebaker/pmap_error_handling_for_parser
pmap: remove `expect()`s from parser & return `Result`
2 parents de17adb + 0a754bc commit a706ecb

File tree

2 files changed

+45
-18
lines changed

2 files changed

+45
-18
lines changed

src/uu/pmap/src/maps_format_parser.rs

Lines changed: 44 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
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)]
810
pub 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"));

src/uu/pmap/src/pmap.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ fn parse_maps(pid: &str) -> Result<u64, Error> {
8080
let mut total = 0;
8181

8282
for line in contents.lines() {
83-
let map_line = parse_map_line(line);
83+
let map_line = parse_map_line(line)?;
8484
println!(
8585
"{} {:>6}K {} {}",
8686
map_line.address, map_line.size_in_kb, map_line.perms, map_line.mapping

0 commit comments

Comments
 (0)