Skip to content

Comments

refactor(proc-cap): centralize procfs start_time parsing#59

Merged
heidi-dang merged 1 commit intomainfrom
fix/proc-starttime-helper
Feb 19, 2026
Merged

refactor(proc-cap): centralize procfs start_time parsing#59
heidi-dang merged 1 commit intomainfrom
fix/proc-starttime-helper

Conversation

@heidi-dang
Copy link
Owner

Refactor only: deduplicates /proc//stat start_time parsing used by the leader start-time guard.

  • Adds read_proc_start_time_ticks(pid) + parse_start_time_from_stat_line() helper
  • Replaces duplicated parsing at spawn + enforcement
  • Adds unit test for comm with spaces

No behavioral change intended:

  • parse failure => no start_time => fallback to observed-PGID behavior
  • mismatch => skip enforcement (existing semantics)

Verification:

  • Release build
  • ctest
  • IT_ProcCap_KillsProcessGroup repeated 20x

@gemini-code-assist
Copy link

Summary of Changes

Hello @heidi-dang, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request refactors the process start time parsing logic within the proc-cap module. It centralizes the extraction of start_time from /proc/<pid>/stat into new utility functions, eliminating duplicated code and enhancing maintainability. The change also strengthens the mechanism for detecting PID reuse by storing the leader's start time at spawn and validating it during process group enforcement, without altering existing behavioral semantics.

Highlights

  • Centralized procfs parsing: The logic for parsing start_time from /proc/<pid>/stat has been extracted into dedicated helper functions, read_proc_start_time_ticks() and parse_start_time_from_stat_line().
  • Deduplicated code: The previously duplicated start_time parsing logic, used both at process spawn and during enforcement, has been replaced with calls to the new helper functions.
  • PID reuse protection: A new leader_start_time field was added to the Job struct to store the leader process's start time at spawn, enabling validation against PID reuse during process group enforcement.
  • Unit testing: A new unit test was added to specifically verify the parse_start_time_from_stat_line() helper's ability to correctly handle process command names (comm) that contain spaces.
  • No behavioral change: The refactoring is intended to be purely internal, with no changes to the external behavior of the process capping mechanism. Existing semantics for parse failures and mismatches are preserved.
Changelog
  • include/heidi-kernel/job.h
    • Added leader_start_time field to the Job struct to store the boot-time ticks of the leader process at spawn.
  • src/job/CMakeLists.txt
    • Included procfs_starttime.cpp in the heidi-kernel-job library build.
  • src/job/job.cpp
    • Added an include for procfs_starttime.h.
    • Modified RealProcessSpawner::spawn_process to capture and store the leader_start_time using the new helper function.
    • Introduced logic in JobRunner::enforce_job_process_cap to validate the current process group leader's start_time against the stored leader_start_time to detect PID reuse.
  • src/job/procfs_starttime.cpp
    • Implemented read_proc_start_time_ticks to read /proc/<pid>/stat and extract the start_time.
    • Implemented parse_start_time_from_stat_line to parse the start_time (field 22) from a given /proc/<pid>/stat line, handling comm fields with spaces.
  • src/job/procfs_starttime.h
    • Declared read_proc_start_time_ticks and parse_start_time_from_stat_line functions.
  • tests/test_job.cpp
    • Included procfs_starttime.h for testing.
    • Added a TEST(ParseStartTime, HandlesCommWithSpaces) to verify the parsing of start_time when the command name contains spaces.
Activity
  • The author performed verification steps including a release build, running ctest, and repeating the IT_ProcCap_KillsProcessGroup integration test 20 times.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors the procfs start_time parsing into a centralized helper function, which is a good improvement for code deduplication and testability. The overall logic for using the leader's start time to guard against PID reuse is sound. However, I've identified a critical issue in the new unit test that needs to be addressed, as it currently uses an incorrect test case. Additionally, I've suggested a couple of medium-severity improvements in the new parsing logic to align it better with modern C++ practices for resource management and efficiency.

Comment on lines +200 to +201
std::string line =
"1234 (my weird comm) R 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 999999 0 0";

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The test string for ParseStartTime appears to be incorrect. The starttime field in /proc/<pid>/stat is the 22nd field. In your parser, this corresponds to the 20th token after the closing parenthesis of the command name. The current test string has 999999 as the 21st token, which means the parser will actually read the 20th token (19) and the test will fail.

To fix this, 999999 should be the 20th token after (my weird comm). This involves removing the 19 token from the test string.

Suggested change
std::string line =
"1234 (my weird comm) R 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 999999 0 0";
std::string line =
"1234 (my weird comm) R 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 999999 0 0";

Comment on lines +11 to +29
std::optional<uint64_t> read_proc_start_time_ticks(pid_t pid) {
char stat_path[256];
snprintf(stat_path, sizeof(stat_path), "/proc/%d/stat", pid);
FILE* stat_file = fopen(stat_path, "r");
if (!stat_file)
return std::nullopt;

char buf[4096];
std::optional<uint64_t> result = std::nullopt;
if (!fgets(buf, sizeof(buf), stat_file)) {
fclose(stat_file);
return std::nullopt;
}
// Delegate to the parsing helper so tests can directly exercise it.
result = parse_start_time_from_stat_line(buf);

fclose(stat_file);
return result;
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The implementation of read_proc_start_time_ticks uses C-style file I/O (fopen, fgets, fclose). While correct in this simple case, using C++ streams and RAII (Resource Acquisition Is Initialization) is more idiomatic and generally safer, as it automatically handles resource cleanup, even in the presence of exceptions.

Consider refactoring to use std::ifstream, which would also simplify the code.

std::optional<uint64_t> read_proc_start_time_ticks(pid_t pid) {
  // Note: this change requires including <fstream> and <string>,
  // and removing <cstdio>.
  std::ifstream stat_file("/proc/" + std::to_string(pid) + "/stat");
  if (!stat_file) {
    return std::nullopt;
  }

  std::string line;
  if (!std::getline(stat_file, line)) {
    return std::nullopt;
  }
  return parse_start_time_from_stat_line(line.c_str());
}

Comment on lines +53 to +62
// parse token [t, s)
char tmp[64] = {0};
int len = (int)(s - t);
if (len > 0 && len < (int)sizeof(tmp)) {
memcpy(tmp, t, len);
tmp[len] = '\0';
uint64_t v = strtoull(tmp, nullptr, 10);
return v;
}
return std::nullopt;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The parsing logic currently copies the token for starttime into a temporary buffer before converting it to a uint64_t. This copy is unnecessary and can be avoided by parsing the number directly from the original buffer slice. Using strtoull with its endptr argument allows for in-place parsing and validation, which is more efficient.

      // parse token [t, s)
      char* end_ptr;
      uint64_t v = strtoull(t, &end_ptr, 10);
      if (end_ptr == s) {
        return v;
      }
      return std::nullopt;

@heidi-dang heidi-dang merged commit bd1c8cb into main Feb 19, 2026
4 checks passed
@heidi-dang heidi-dang deleted the fix/proc-starttime-helper branch February 19, 2026 09:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant