From c7c7bbcfc762d73a50d3cb2ad6f277dad7bb9a6b Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Fri, 2 Sep 2022 11:38:20 +0000 Subject: [PATCH] FreeBSD / pids(): increase buf size if not enough ...dynamically, in case of ENOMEM, instead of crashing. Fixes #2093. --- HISTORY.rst | 4 +++- Makefile | 1 + psutil/arch/freebsd/proc.c | 43 ++++++++++++++++++++++++++------------ 3 files changed, 34 insertions(+), 14 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 7c99a4f62..9bb7d5726 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 0d1ef9583..4bcea213f 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 a2e130b55..214dbc482 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;