fix: harden Linux procfs reads and ancestry traversal#180
Conversation
Retry getline when interrupted by signals to avoid transient read failures while scanning procfs/sysfs files. Also guard ancestry traversal against invalid self-parent links, preventing pathological infinite loops in racey process snapshots.
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
There was a problem hiding this comment.
Pull request overview
This PR improves robustness of Linux /proc/sysfs interactions by hardening single-line file reads against signal interruptions and making process ancestry traversal more defensive against inconsistent /proc snapshots.
Changes:
- Retry
getline()onEINTRinread_line_from_file()to reduce transient/proc/sysfs read failures. - Add a guard in Linux
is_child_of()to avoid endless loops when a process reports an invalid/self parent link.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| src/util.c | Retries getline() on EINTR while reading first-line procfs/sysfs files. |
| src/process_iterator_linux.c | Adds defensive PPID validation during parent-chain traversal to prevent pathological loops. |
| * procfs/sysfs files. | ||
| */ | ||
| do { | ||
| errno = 0; | ||
| read_result = getline(&line, &line_size, input_file); |
There was a problem hiding this comment.
The EINTR retry loop should clear the stream error indicator before retrying. After a stdio call like getline() fails, the FILE error flag can remain set (sticky) and a subsequent getline() may immediately fail again unless clearerr(input_file) is called when errno==EINTR. Without clearing, this change may still return NULL on an interrupted read.
| * procfs/sysfs files. | |
| */ | |
| do { | |
| errno = 0; | |
| read_result = getline(&line, &line_size, input_file); | |
| * procfs/sysfs files. Because stdio stream error indicators are sticky, | |
| * clear the stream state before retrying after EINTR. | |
| */ | |
| do { | |
| errno = 0; | |
| read_result = getline(&line, &line_size, input_file); | |
| if (read_result < 0 && errno == EINTR) { | |
| clearerr(input_file); | |
| } |
|
@copilot apply changes based on the comments in this thread |
Agent-Logs-Url: https://github.com/HiGarfield/cpulimit/sessions/01e75fcb-6a9e-4d3d-9d1f-68295f249101 Co-authored-by: HiGarfield <32226909+HiGarfield@users.noreply.github.com>
Done in b1281ac. Added |
Motivation
/procor sysfs reads are interrupted by signals and prevent pathological infinite loops when traversing parent chains from inconsistent/procsnapshots.Description
getline()onEINTRinread_line_from_file()to tolerate signal-interrupted reads and return the file contents only on real failures (file:src/util.c).next_ppidcheck inis_child_of()to reject invalid or self-parent links (next_ppid <= 0 || next_ppid == child_pid) and return non-descendant immediately to prevent endless loops (file:src/process_iterator_linux.c).Testing
cmake --build build --target formatsuccessfully.cmakeandcmake --build ... --target allwith no build errors.checktarget (cppcheck + clang-tidy) and found no report files with errors; the check target completed successfully.cmake --build build --target valgrind) and all unit/integration tests and valgrind runs passed with no leaks or errors.Codex Task