summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGiampaolo Rodola <g.rodola@gmail.com>2022-09-02 11:38:20 +0000
committerGiampaolo Rodola <g.rodola@gmail.com>2022-09-02 11:39:08 +0000
commitc7c7bbcfc762d73a50d3cb2ad6f277dad7bb9a6b (patch)
treeecc034b178f6a9d3f89fab6ccec45e9bd018aff2
parentd2fab7c8de16b6ffbfb0faa3e832845bc1ef0df0 (diff)
downloadpsutil-c7c7bbcfc762d73a50d3cb2ad6f277dad7bb9a6b.tar.gz
FreeBSD / pids(): increase buf size if not enough
...dynamically, in case of ENOMEM, instead of crashing. Fixes #2093.
-rw-r--r--HISTORY.rst4
-rw-r--r--Makefile1
-rw-r--r--psutil/arch/freebsd/proc.c43
3 files changed, 34 insertions, 14 deletions
diff --git a/HISTORY.rst b/HISTORY.rst
index 7c99a4f6..9bb7d572 100644
--- a/HISTORY.rst
+++ b/HISTORY.rst
@@ -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
diff --git a/Makefile b/Makefile
index 0d1ef958..4bcea213 100644
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/psutil/arch/freebsd/proc.c b/psutil/arch/freebsd/proc.c
index a2e130b5..214dbc48 100644
--- a/psutil/arch/freebsd/proc.c
+++ b/psutil/arch/freebsd/proc.c
@@ -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);
@@ -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;