Skip to content

Return an error on reading empty proc pid stat file#1995

Merged
shirou merged 1 commit intoshirou:masterfrom
pgimalac:pgimalac/fix-empty-read-proc-pid-stat-file
Jan 23, 2026
Merged

Return an error on reading empty proc pid stat file#1995
shirou merged 1 commit intoshirou:masterfrom
pgimalac:pgimalac/fix-empty-read-proc-pid-stat-file

Conversation

@pgimalac
Copy link
Copy Markdown
Contributor

@pgimalac pgimalac commented Jan 21, 2026

There is a race when reading /proc/<pid>/stat where the file can be opened while the process still exists but then it's gone when reading the content.
Depending on the underlying procfs, the file can just appear as empty in this case (ie. read just returns EOF directly), and the code happily tries to parse the file with the expected format, eventually resulting in a panic.

Testing whether the content is empty before calling splitProcStat should prevent most similar occurrences.

Note that more subtle cases can still happen, eg. if the file is long enough we might only read some of it, but Go's os.ReadFile uses a big enough buffer by default that it should be very rare.
Ideally the code should still check that the content has the expected format and not blindly access it.

Example

Below is a stack trace from an occurence:

panic: runtime error: slice bounds out of range [1:0]
goroutine 23291 [running]:
github.com/shirou/gopsutil/v4/process.splitProcStat({0xc0030e8a00, 0x0, 0x200})
	/pkg/mod/github.com/shirou/gopsutil/v4@v4.24.12/process/process_linux.go:1198 +0x29e
github.com/shirou/gopsutil/v4/process.(*Process).fillFromTIDStatWithContext(0x777657949328?, {0x5b72770, 0x9557240}, 0x30e4640?)
	/pkg/mod/github.com/shirou/gopsutil/v4@v4.24.12/process/process_linux.go:1053 +0x1de

splitProcStat is given an empty bytes slice, so LastIndexByte returns -1, and we index the empty slice starting at index 1 (-1 + 2), resulting in a panic.

	nameEnd := bytes.LastIndexByte(content, ')')
	restFields := strings.Fields(string(content[nameEnd+2:])) // +2 skip ') '

@pgimalac
Copy link
Copy Markdown
Contributor Author

I used file is empty in the error as it's technically the only thing we can say about it, but in practice I believe it can only mean that the process has been stopped, so we could use a more explicit error instead.

@pgimalac pgimalac force-pushed the pgimalac/fix-empty-read-proc-pid-stat-file branch from d018968 to 656d117 Compare January 21, 2026 18:25
Copy link
Copy Markdown
Owner

@shirou shirou left a comment

Choose a reason for hiding this comment

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

Great catch! I wasn't aware of this stat file behavior. Thank you for this effective fix.

However, as you said, could you change the error message to indicate the likely cause?

Comment thread process/process_linux.go Outdated
@pgimalac pgimalac force-pushed the pgimalac/fix-empty-read-proc-pid-stat-file branch from 248a898 to 62a181c Compare January 22, 2026 16:52
@pgimalac
Copy link
Copy Markdown
Contributor Author

@shirou done ! Thanks for the quick review !
I squashed the commits and CI is passing so should be good to merge

Copy link
Copy Markdown
Owner

@shirou shirou left a comment

Choose a reason for hiding this comment

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

Thank you so much!

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants