Skip to content

Commit b729d77

Browse files
authored
Fix bug in smaps parsing logic related to pathnames containing whitespace (#1237)
* Adds failing test for smaps pathnames with whitespace * Adds fix for pathnames containing whitespace * Adds changelog entry
1 parent b7b446f commit b729d77

File tree

2 files changed

+43
-5
lines changed

2 files changed

+43
-5
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1212
- Introduced the ability for users to configure lading's sample rate,
1313
configuration option `sample_period_milliseconds` in `lading.yaml`.
1414
- Users can now configure expvar scraping on https endpoints, skipping certificate validation.
15+
- `smaps` parsing logic correctly collects memory region pathnames that contain whitespace
1516
- Fixes issue when parsing `NaN` values from a prometheus endpoint
1617

1718
## [0.25.4]

lading/src/observer/linux/procfs/memory/smaps.rs

+42-5
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,11 @@ impl Region {
6767
let mut offset: Option<u64> = None;
6868
let mut dev: Option<String> = None;
6969
let mut inode: Option<u64> = None;
70-
let mut pathname: Option<String> = None;
70+
let pathname: Option<String> = None;
71+
let mut pathname_tokens = vec![];
7172

7273
let mut chars = metadata_line.char_indices().peekable();
74+
let mut entered_pathname = false;
7375

7476
loop {
7577
let token = next_token(metadata_line, &mut chars);
@@ -93,14 +95,15 @@ impl Region {
9395
dev = Some(token.to_string());
9496
} else if inode.is_none() {
9597
inode = Some(token.parse::<u64>()?);
96-
} else if pathname.is_none() {
97-
pathname = Some(token.to_string());
98+
} else if pathname.is_none() || entered_pathname {
99+
entered_pathname = true;
100+
pathname_tokens.push(token);
98101
} else {
99102
break;
100103
}
101104
}
102105

103-
pathname
106+
pathname_tokens.join(" ")
104107
};
105108

106109
let mut size: Option<u64> = None;
@@ -216,7 +219,7 @@ impl Region {
216219
};
217220

218221
Ok(Region {
219-
pathname: pathname.unwrap_or_default(),
222+
pathname,
220223
size,
221224
pss,
222225
swap,
@@ -731,4 +734,38 @@ VmFlags: rd ex mr mw me de sd";
731734

732735
let _region = Region::from_str(region).expect("Parsing failed");
733736
}
737+
738+
#[test]
739+
fn test_pathnames_with_whitespace() {
740+
let region =
741+
"7514356d1000-7514356d3000 rw-p 00000000 00:00 0 [anon: glibc: loader malloc]
742+
Size: 8 kB
743+
KernelPageSize: 4 kB
744+
MMUPageSize: 4 kB
745+
Rss: 8 kB
746+
Pss: 8 kB
747+
Pss_Dirty: 8 kB
748+
Shared_Clean: 0 kB
749+
Shared_Dirty: 0 kB
750+
Private_Clean: 0 kB
751+
Private_Dirty: 8 kB
752+
Referenced: 8 kB
753+
Anonymous: 8 kB
754+
KSM: 0 kB
755+
LazyFree: 0 kB
756+
AnonHugePages: 0 kB
757+
ShmemPmdMapped: 0 kB
758+
FilePmdMapped: 0 kB
759+
Shared_Hugetlb: 0 kB
760+
Private_Hugetlb: 0 kB
761+
Swap: 0 kB
762+
SwapPss: 0 kB
763+
Locked: 0 kB
764+
THPeligible: 0
765+
ProtectionKey: 0
766+
VmFlags: rd wr mr mw me ac sd";
767+
let parsed_region = Region::from_str(region).expect("Parsing failed");
768+
769+
assert_eq!(parsed_region.pathname, ("[anon: glibc: loader malloc]"));
770+
}
734771
}

0 commit comments

Comments
 (0)