Skip to content

lpt: fix misprint fgets buffer size in cgroup parsing - #2059

Open
GermanAizek wants to merge 1 commit into
htop-dev:mainfrom
GermanAizek:fix-fgets-size
Open

lpt: fix misprint fgets buffer size in cgroup parsing#2059
GermanAizek wants to merge 1 commit into
htop-dev:mainfrom
GermanAizek:fix-fgets-size

Conversation

@GermanAizek

@GermanAizek GermanAizek commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

https://github.com/htop-dev/htop/blob/main/linux/LinuxProcessTable.c#L935-L941

LinuxProcessTable_readCGroupFile() declares an inner buffer of PROC_LINE_LENGTH + 1 bytes but passes PROC_LINE_LENGTH to fgets(), telling it that the buffer is one byte smaller than it actually is

LinuxProcessTable_readCGroupFile() declares an inner buffer of
PROC_LINE_LENGTH + 1 bytes but passes PROC_LINE_LENGTH to fgets(),
telling it that the buffer is one byte smaller than it actually is
@coderabbitai coderabbitai Bot added the bug 🐛 Something isn't working label Aug 5, 2026
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 6ed88fe8-875a-4bb2-a504-bb0697af7d75

📥 Commits

Reviewing files that changed from the base of the PR and between 443a414 and 3f486d8.

📒 Files selected for processing (1)
  • linux/LinuxProcessTable.c

📝 Walkthrough

Walkthrough

LinuxProcessTable_readCGroupFile now passes the full buffer capacity to fgets instead of PROC_LINE_LENGTH.

Suggested labels: bug :bug:

Suggested reviewers: benbe

Poem

A buffer stood ready, with space to spare,
fgets now reads its capacity with care.
One extra byte joins the line,
Null termination remains fine.
The cgroup parser moves on.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@GermanAizek

Copy link
Copy Markdown
Contributor Author

Wtf CI / build-solaris-latest-gcc Cancelled after 20m

@GermanAizek

Copy link
Copy Markdown
Contributor Author

Wtf CI / build-solaris-latest-gcc Cancelled after 20m

Download: 2220/3041 items 910.2/1252.2MB 72% complete (809k/s)
Download: 2220/3041 items 912.1/1252.2MB 72% complete (668k/s)
Download: 2220/3041 items 914.4/1252.2MB 73% complete (464k/s)
Download: 2220/3041 items 916.4/1252.2MB 73% complete (436k/s)
Download: 2220/3041 items 919.8/1252.2MB 73% complete (563k/s)
Download: 2220/3041 items 921.8/1252.2MB 73% complete (553k/s)
Download: 2220/3041 items 924.4/1252.2MB 73% complete (460k/s)
Download: 2220/3041 items 927.9/1252.2MB 74% complete (608k/s)
Download: 2220/3041 items 929.6/1252.2MB 74% complete (567k/s)
Error: The operation was canceled.

@ravi-arnan ravi-arnan left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Correct, and safe either way: buffer is PROC_LINE_LENGTH + 1 bytes, so
sizeof(buffer) is within bounds and the old form simply left the last byte
unused. No overflow before or after.

Since I had a Linux box to hand I checked when the extra byte can actually be
observed, which turns out to be narrower than it looks.

It only matters for a /proc/<pid>/cgroup line of 4096 bytes or more. Those are
constructible: a delegated user cgroup plus 21 nested 200-character components
gives a 4099-byte line. It has to be built with relative chdir because the
absolute path is past PATH_MAX, but the kernel prints the full line regardless:

$ python3 -c "..."   # chdir down 21 levels under user@1000.service, write pid
line bytes: 4099

On that process, both main and this branch abort before the byte matters:

main    exit=134   FATAL PROGRAM ERROR / signal 6
pr2059  exit=134   same

That is #1913, the CGROUP column width crash that #2051 fixes, not anything
introduced here. Rebuilding this branch with #2051's buffer fix on top, and
rebuilding the same tree with only that fix and the fgets line reverted, both
run clean and render the same 255 characters, since the column truncates there
anyway:

with fgets(buffer, PROC_LINE_LENGTH)  longest rendered cgroup run = 255
with fgets(buffer, sizeof(buffer))    longest rendered cgroup run = 255

So this is hygiene rather than a user-visible fix, and it can only ever be
exercised behind #2051. That is not an argument against merging it, just a note
in case the commit message wants to be accurate about impact.

One adjacent thing this exposed, clearly out of scope for a one-liner: the loop
has no partial-line handling. When a line does exceed the buffer, the next
fgets returns the remainder of that same line and the parser treats it as a
new cgroup entry, walking it for two : separators that are not there and
appending a separator plus an empty group to output.
LinuxProcessTable_readSmapsFile() in the same file handles exactly this case
with skipEndOfLine(). If anyone cares about >4KB cgroup lines, that is the
real bug in this function, and it would be a separate PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug 🐛 Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants