Skip to content

Commit 850aa2d

Browse files
committed
fix: harden diagnostics memory parsing
1 parent d161d45 commit 850aa2d

2 files changed

Lines changed: 40 additions & 5 deletions

File tree

pilot/core/diagnostics.py

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -215,14 +215,31 @@ def _pid_alive(self, path: Path) -> bool:
215215
return False
216216

217217
def _linux_memory(self) -> dict[str, int]:
218-
path = Path("/proc/meminfo")
218+
path = self._meminfo_path()
219219
if not path.exists():
220220
return {}
221-
fields = {}
222-
for line in path.read_text().splitlines():
221+
fields: dict[str, int] = {}
222+
try:
223+
lines = path.read_text().splitlines()
224+
except OSError:
225+
return {}
226+
for line in lines:
227+
if ":" not in line:
228+
continue
223229
key, value = line.split(":", 1)
224-
fields[key] = int(value.strip().split()[0])
225-
return {"available": fields.get("MemAvailable", 0)}
230+
parts = value.strip().split()
231+
if not parts:
232+
continue
233+
try:
234+
fields[key] = int(parts[0])
235+
except ValueError:
236+
continue
237+
if "MemAvailable" not in fields:
238+
return {}
239+
return {"available": fields["MemAvailable"]}
240+
241+
def _meminfo_path(self) -> Path:
242+
return Path("/proc/meminfo")
226243

227244
def _tcp_open(self, host: str, port: int) -> bool:
228245
try:

tests/test_diagnostics.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,24 @@ def test_diagnostics_cpu_load_warns_under_pressure(tmp_path: Path, monkeypatch)
130130
assert check.status == "warn"
131131

132132

133+
def test_diagnostics_memory_parser_ignores_malformed_lines(tmp_path: Path, monkeypatch) -> None:
134+
bench = make_initialized_bench(tmp_path)
135+
meminfo = tmp_path / "meminfo"
136+
meminfo.write_text("broken\nMemTotal:\nMemFree: nope kB\nMemAvailable: 2048 kB\n")
137+
monkeypatch.setattr(DiagnosticRunner, "_meminfo_path", lambda self: meminfo)
138+
139+
assert DiagnosticRunner(bench)._linux_memory() == {"available": 2048}
140+
141+
142+
def test_diagnostics_memory_parser_skips_without_available_memory(tmp_path: Path, monkeypatch) -> None:
143+
bench = make_initialized_bench(tmp_path)
144+
meminfo = tmp_path / "meminfo"
145+
meminfo.write_text("MemTotal: 4096 kB\n")
146+
monkeypatch.setattr(DiagnosticRunner, "_meminfo_path", lambda self: meminfo)
147+
148+
assert DiagnosticRunner(bench)._memory_check().status == "skip"
149+
150+
133151
def test_diagnostic_report_json(tmp_path: Path) -> None:
134152
bench = make_initialized_bench(tmp_path)
135153
check = DiagnosticRunner(bench)._path_check("bench", "bench.toml", bench.path / "bench.toml", "")

0 commit comments

Comments
 (0)