Skip to content

Commit

Permalink
FreeBSD / pids(): increase buf size if not enough
Browse files Browse the repository at this point in the history
...dynamically, in case of ENOMEM, instead of crashing.
Fixes #2093.
  • Loading branch information
giampaolo committed Sep 2, 2022
1 parent d2fab7c commit c7c7bbc
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 14 deletions.
4 changes: 3 additions & 1 deletion HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@
``min`` and ``max`` are in MHz.
- 2050_, [Linux]: `virtual_memory()`_ may raise ``ValueError`` if running in a
LCX container.
- 2095_, [Linux]: `net_if_stats()` returns incorrect interface speed for 100GbE
- 2093_, [FreeBSD]: `psutil.pids()` may fail with ENOMEM. Dynamically increase
the ``malloc()`` buffer size until it's big enough.
- 2095_, [Linux]: `net_if_stats()` returns incorrect interface speed for 100GbE
network cards

5.9.0
Expand Down
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ clean: ## Remove all build files.
docs/_build/ \
htmlcov/

.PHONY: build
build: ## Compile (in parallel) without installing.
@# "build_ext -i" copies compiled *.so files in ./psutil directory in order
@# to allow "import psutil" when using the interactive interpreter from
Expand Down
43 changes: 30 additions & 13 deletions psutil/arch/freebsd/proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount) {
struct kinfo_proc *buf = NULL;
int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_PROC, 0 };
size_t length = 0;
size_t max_length = 12 * 1024 * 1024; // 12MB

assert(procList != NULL);
assert(*procList == NULL);
Expand All @@ -95,20 +96,36 @@ psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount) {
return 1;
}

// Allocate an appropriately sized buffer based on the results
// from the previous call.
buf = malloc(length);
if (buf == NULL) {
PyErr_NoMemory();
return 1;
}
while (1) {
// Allocate an appropriately sized buffer based on the results
// from the previous call.
buf = malloc(length);
if (buf == NULL) {
PyErr_NoMemory();
return 1;
}

// Call sysctl again with the new buffer.
err = sysctl(name, 3, buf, &length, NULL, 0);
if (err == -1) {
PyErr_SetFromOSErrnoWithSyscall("sysctl");
free(buf);
return 1;
// Call sysctl again with the new buffer.
err = sysctl(name, 3, buf, &length, NULL, 0);
if (err == -1) {
free(buf);
if (errno == ENOMEM) {
// Sometimes the first sysctl() suggested size is not enough,
// so we dynamically increase it until it's big enough :
// https://github.com/giampaolo/psutil/issues/2093
psutil_debug("errno=ENOMEM, length=%zu; retrying", length);
length *= 2;
if (length < max_length) {
continue;
}
}

PyErr_SetFromOSErrnoWithSyscall("sysctl()");
return 1;
}
else {
break;
}
}

*procList = buf;
Expand Down

0 comments on commit c7c7bbc

Please sign in to comment.