Skip to content

Commit d008d39

Browse files
Correctly handle spaces in /proc/pid/maps pathnames (#553)
Prior to this change, pathnames were parsed from `/proc/pid/maps` using `s.split(' ')`. This is incorrect, because pathnames may contain spaces. In practice, on the relevant operating systems, this resulted in truncation of pathnames containing spaces. This lead to a failure resolve any symbols or offsets, which in turn causes the stack trace to be printed containing only `<unknown>`s to the end user. This PR corrects the parsing code, resolving the issue.
2 parents 40410b7 + aa3186a commit d008d39

File tree

1 file changed

+72
-9
lines changed

1 file changed

+72
-9
lines changed

src/symbolize/gimli/parse_running_mmaps_unix.rs

Lines changed: 72 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)