From 2f2e9f9539c7631a2f060c99fbe86297cfd31629 Mon Sep 17 00:00:00 2001 From: Mason Remaley Date: Sun, 23 Jul 2023 18:52:30 -0700 Subject: [PATCH 1/8] Corrects /proc/pid/maps parser to correctly handle spaces in pathnames --- .../gimli/parse_running_mmaps_unix.rs | 53 +++++++++++++++---- 1 file changed, 44 insertions(+), 9 deletions(-) diff --git a/src/symbolize/gimli/parse_running_mmaps_unix.rs b/src/symbolize/gimli/parse_running_mmaps_unix.rs index deeeb2971..5b342d237 100644 --- a/src/symbolize/gimli/parse_running_mmaps_unix.rs +++ b/src/symbolize/gimli/parse_running_mmaps_unix.rs @@ -85,16 +85,37 @@ impl FromStr for MapsEntry { // e.g.: "ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall]" // e.g.: "7f5985f46000-7f5985f48000 rw-p 00039000 103:06 76021795 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2" // e.g.: "35b1a21000-35b1a22000 rw-p 00000000 00:00 0" + // + // Note that paths may contain spaces, so we can't use `str::split` for parsing (until + // Split::remainder is stabalized #77998). fn from_str(s: &str) -> Result { - let mut parts = s - .split(' ') // space-separated fields - .filter(|s| s.len() > 0); // multiple spaces implies empty strings that need to be skipped. - let range_str = parts.next().ok_or("Couldn't find address")?; - let perms_str = parts.next().ok_or("Couldn't find permissions")?; - let offset_str = parts.next().ok_or("Couldn't find offset")?; - let dev_str = parts.next().ok_or("Couldn't find dev")?; - let inode_str = parts.next().ok_or("Couldn't find inode")?; - let pathname_str = parts.next().unwrap_or(""); // pathname may be omitted. + let (range_str, s) = s.trim().split_once(' ').unwrap_or((s, "")); + if range_str.is_empty() { + return Err("Couldn't find address"); + } + + let (perms_str, s) = s.trim().split_once(' ').unwrap_or((s, "")); + if range_str.is_empty() { + return Err("Couldn't find permissions"); + } + + let (offset_str, s) = s.trim().split_once(' ').unwrap_or((s, "")); + if range_str.is_empty() { + return Err("Couldn't find offset"); + } + + let (dev_str, s) = s.trim().split_once(' ').unwrap_or((s, "")); + if range_str.is_empty() { + return Err("Couldn't find dev"); + } + + let (inode_str, s) = s.trim().split_once(' ').unwrap_or((s, "")); + if range_str.is_empty() { + return Err("Couldn't find inode"); + } + + // Pathname may be omitted in which case it will be empty + let pathname_str = s.trim(); let hex = |s| usize::from_str_radix(s, 16).map_err(|_| "Couldn't parse hex number"); let address = if let Some((start, limit)) = range_str.split_once('-') { @@ -229,4 +250,18 @@ fn check_maps_entry_parsing_32bit() { pathname: Default::default(), } ); + assert_eq!( + "b7c79000-b7e02000 r--p 00000000 08:01 60662705 \ + /executable/path/with some spaces" + .parse::() + .unwrap(), + MapsEntry { + address: (0xb7c79000, 0xb7e02000), + perms: ['r', '-', '-', 'p'], + offset: 0x00000000, + dev: (0x08, 0x01), + inode: 0x60662705, + pathname: "/executable/path/with some spaces".into(), + } + ); } From 047c2b316fdb2e3aa01943896d905b117f77f3f9 Mon Sep 17 00:00:00 2001 From: Mason Remaley Date: Mon, 24 Jul 2023 13:30:24 -0700 Subject: [PATCH 2/8] Fixes copy paste error --- src/symbolize/gimli/parse_running_mmaps_unix.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/symbolize/gimli/parse_running_mmaps_unix.rs b/src/symbolize/gimli/parse_running_mmaps_unix.rs index 5b342d237..4fbd980ff 100644 --- a/src/symbolize/gimli/parse_running_mmaps_unix.rs +++ b/src/symbolize/gimli/parse_running_mmaps_unix.rs @@ -95,22 +95,22 @@ impl FromStr for MapsEntry { } let (perms_str, s) = s.trim().split_once(' ').unwrap_or((s, "")); - if range_str.is_empty() { + if perms_str.is_empty() { return Err("Couldn't find permissions"); } let (offset_str, s) = s.trim().split_once(' ').unwrap_or((s, "")); - if range_str.is_empty() { + if offset_str.is_empty() { return Err("Couldn't find offset"); } let (dev_str, s) = s.trim().split_once(' ').unwrap_or((s, "")); - if range_str.is_empty() { + if dev_str.is_empty() { return Err("Couldn't find dev"); } let (inode_str, s) = s.trim().split_once(' ').unwrap_or((s, "")); - if range_str.is_empty() { + if inode_str.is_empty() { return Err("Couldn't find inode"); } From c017a001e33790fbbbd3744d70caacaf4121536e Mon Sep 17 00:00:00 2001 From: Mason Remaley Date: Mon, 24 Jul 2023 13:31:57 -0700 Subject: [PATCH 3/8] Adds test for multiple continuous spaces --- src/symbolize/gimli/parse_running_mmaps_unix.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/symbolize/gimli/parse_running_mmaps_unix.rs b/src/symbolize/gimli/parse_running_mmaps_unix.rs index 4fbd980ff..a1e4e780b 100644 --- a/src/symbolize/gimli/parse_running_mmaps_unix.rs +++ b/src/symbolize/gimli/parse_running_mmaps_unix.rs @@ -264,4 +264,18 @@ fn check_maps_entry_parsing_32bit() { pathname: "/executable/path/with some spaces".into(), } ); + assert_eq!( + "b7c79000-b7e02000 r--p 00000000 08:01 60662705 \ + /executable/path/with multiple-continues spaces " + .parse::() + .unwrap(), + MapsEntry { + address: (0xb7c79000, 0xb7e02000), + perms: ['r', '-', '-', 'p'], + offset: 0x00000000, + dev: (0x08, 0x01), + inode: 0x60662705, + pathname: "/executable/path/with multiple-continues spaces".into(), + } + ); } From ce72d89eb85eacfb1e8cdb47fcc37c211ae78dbc Mon Sep 17 00:00:00 2001 From: Mason Remaley Date: Mon, 24 Jul 2023 13:37:19 -0700 Subject: [PATCH 4/8] Replaces most trims with trim_start --- .../gimli/parse_running_mmaps_unix.rs | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/symbolize/gimli/parse_running_mmaps_unix.rs b/src/symbolize/gimli/parse_running_mmaps_unix.rs index a1e4e780b..f3460ad75 100644 --- a/src/symbolize/gimli/parse_running_mmaps_unix.rs +++ b/src/symbolize/gimli/parse_running_mmaps_unix.rs @@ -89,27 +89,27 @@ impl FromStr for MapsEntry { // Note that paths may contain spaces, so we can't use `str::split` for parsing (until // Split::remainder is stabalized #77998). fn from_str(s: &str) -> Result { - let (range_str, s) = s.trim().split_once(' ').unwrap_or((s, "")); + let (range_str, s) = s.trim_start().split_once(' ').unwrap_or((s, "")); if range_str.is_empty() { return Err("Couldn't find address"); } - let (perms_str, s) = s.trim().split_once(' ').unwrap_or((s, "")); + let (perms_str, s) = s.trim_start().split_once(' ').unwrap_or((s, "")); if perms_str.is_empty() { return Err("Couldn't find permissions"); } - let (offset_str, s) = s.trim().split_once(' ').unwrap_or((s, "")); + let (offset_str, s) = s.trim_start().split_once(' ').unwrap_or((s, "")); if offset_str.is_empty() { return Err("Couldn't find offset"); } - let (dev_str, s) = s.trim().split_once(' ').unwrap_or((s, "")); + let (dev_str, s) = s.trim_start().split_once(' ').unwrap_or((s, "")); if dev_str.is_empty() { return Err("Couldn't find dev"); } - let (inode_str, s) = s.trim().split_once(' ').unwrap_or((s, "")); + let (inode_str, s) = s.trim_start().split_once(' ').unwrap_or((s, "")); if inode_str.is_empty() { return Err("Couldn't find inode"); } @@ -278,4 +278,18 @@ fn check_maps_entry_parsing_32bit() { pathname: "/executable/path/with multiple-continues spaces".into(), } ); + assert_eq!( + " b7c79000-b7e02000 r--p 00000000 08:01 60662705 \ + /executable/path/starts-with-spaces" + .parse::() + .unwrap(), + MapsEntry { + address: (0xb7c79000, 0xb7e02000), + perms: ['r', '-', '-', 'p'], + offset: 0x00000000, + dev: (0x08, 0x01), + inode: 0x60662705, + pathname: "/executable/path/starts-with-spaces".into(), + } + ); } From aeb25db61227c22540b4b4263a6602b518796753 Mon Sep 17 00:00:00 2001 From: Mason Remaley Date: Mon, 24 Jul 2023 13:48:00 -0700 Subject: [PATCH 5/8] Allows for paths with trailing spaces --- src/symbolize/gimli/parse_running_mmaps_unix.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/symbolize/gimli/parse_running_mmaps_unix.rs b/src/symbolize/gimli/parse_running_mmaps_unix.rs index f3460ad75..a7121f142 100644 --- a/src/symbolize/gimli/parse_running_mmaps_unix.rs +++ b/src/symbolize/gimli/parse_running_mmaps_unix.rs @@ -115,7 +115,7 @@ impl FromStr for MapsEntry { } // Pathname may be omitted in which case it will be empty - let pathname_str = s.trim(); + let pathname_str = s.trim_start(); let hex = |s| usize::from_str_radix(s, 16).map_err(|_| "Couldn't parse hex number"); let address = if let Some((start, limit)) = range_str.split_once('-') { @@ -275,7 +275,7 @@ fn check_maps_entry_parsing_32bit() { offset: 0x00000000, dev: (0x08, 0x01), inode: 0x60662705, - pathname: "/executable/path/with multiple-continues spaces".into(), + pathname: "/executable/path/with multiple-continues spaces ".into(), } ); assert_eq!( From edad5f0eb7516b62816ade3f70bcbab93354ed13 Mon Sep 17 00:00:00 2001 From: Mason Remaley Date: Sun, 30 Jul 2023 16:04:13 -0400 Subject: [PATCH 6/8] Update src/symbolize/gimli/parse_running_mmaps_unix.rs Co-authored-by: Jubilee <46493976+workingjubilee@users.noreply.github.com> --- src/symbolize/gimli/parse_running_mmaps_unix.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/symbolize/gimli/parse_running_mmaps_unix.rs b/src/symbolize/gimli/parse_running_mmaps_unix.rs index a7121f142..a009b92f8 100644 --- a/src/symbolize/gimli/parse_running_mmaps_unix.rs +++ b/src/symbolize/gimli/parse_running_mmaps_unix.rs @@ -266,7 +266,7 @@ fn check_maps_entry_parsing_32bit() { ); assert_eq!( "b7c79000-b7e02000 r--p 00000000 08:01 60662705 \ - /executable/path/with multiple-continues spaces " + /executable/path/with multiple-continuous spaces " .parse::() .unwrap(), MapsEntry { From 45aa13b4b31331da5d493d72e43a78deaa78aaf1 Mon Sep 17 00:00:00 2001 From: Mason Remaley Date: Sun, 30 Jul 2023 16:04:47 -0400 Subject: [PATCH 7/8] Update src/symbolize/gimli/parse_running_mmaps_unix.rs Co-authored-by: Jubilee <46493976+workingjubilee@users.noreply.github.com> --- src/symbolize/gimli/parse_running_mmaps_unix.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/symbolize/gimli/parse_running_mmaps_unix.rs b/src/symbolize/gimli/parse_running_mmaps_unix.rs index a009b92f8..acf91e0a8 100644 --- a/src/symbolize/gimli/parse_running_mmaps_unix.rs +++ b/src/symbolize/gimli/parse_running_mmaps_unix.rs @@ -275,7 +275,7 @@ fn check_maps_entry_parsing_32bit() { offset: 0x00000000, dev: (0x08, 0x01), inode: 0x60662705, - pathname: "/executable/path/with multiple-continues spaces ".into(), + pathname: "/executable/path/with multiple-continuous spaces ".into(), } ); assert_eq!( From aa3186abab63415edebe3f1f7061ab8bce0a6f14 Mon Sep 17 00:00:00 2001 From: Mason Remaley Date: Sun, 30 Jul 2023 16:04:55 -0400 Subject: [PATCH 8/8] Update src/symbolize/gimli/parse_running_mmaps_unix.rs Co-authored-by: Jubilee <46493976+workingjubilee@users.noreply.github.com> --- src/symbolize/gimli/parse_running_mmaps_unix.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/symbolize/gimli/parse_running_mmaps_unix.rs b/src/symbolize/gimli/parse_running_mmaps_unix.rs index acf91e0a8..5d4b34675 100644 --- a/src/symbolize/gimli/parse_running_mmaps_unix.rs +++ b/src/symbolize/gimli/parse_running_mmaps_unix.rs @@ -87,7 +87,7 @@ impl FromStr for MapsEntry { // e.g.: "35b1a21000-35b1a22000 rw-p 00000000 00:00 0" // // Note that paths may contain spaces, so we can't use `str::split` for parsing (until - // Split::remainder is stabalized #77998). + // Split::remainder is stabilized #77998). fn from_str(s: &str) -> Result { let (range_str, s) = s.trim_start().split_once(' ').unwrap_or((s, "")); if range_str.is_empty() {