Skip to content

Commit c7c7bbc

Browse files
committed
FreeBSD / pids(): increase buf size if not enough
...dynamically, in case of ENOMEM, instead of crashing. Fixes #2093.
1 parent d2fab7c commit c7c7bbc

File tree

3 files changed

+34
-14
lines changed

3 files changed

+34
-14
lines changed

HISTORY.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@
3131
``min`` and ``max`` are in MHz.
3232
- 2050_, [Linux]: `virtual_memory()`_ may raise ``ValueError`` if running in a
3333
LCX container.
34-
- 2095_, [Linux]: `net_if_stats()` returns incorrect interface speed for 100GbE
34+
- 2093_, [FreeBSD]: `psutil.pids()` may fail with ENOMEM. Dynamically increase
35+
the ``malloc()`` buffer size until it's big enough.
36+
- 2095_, [Linux]: `net_if_stats()` returns incorrect interface speed for 100GbE
3537
network cards
3638

3739
5.9.0

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ clean: ## Remove all build files.
7676
docs/_build/ \
7777
htmlcov/
7878

79+
.PHONY: build
7980
build: ## Compile (in parallel) without installing.
8081
@# "build_ext -i" copies compiled *.so files in ./psutil directory in order
8182
@# to allow "import psutil" when using the interactive interpreter from

psutil/arch/freebsd/proc.c

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount) {
8383
struct kinfo_proc *buf = NULL;
8484
int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_PROC, 0 };
8585
size_t length = 0;
86+
size_t max_length = 12 * 1024 * 1024; // 12MB
8687

8788
assert(procList != NULL);
8889
assert(*procList == NULL);
@@ -95,20 +96,36 @@ psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount) {
9596
return 1;
9697
}
9798

98-
// Allocate an appropriately sized buffer based on the results
99-
// from the previous call.
100-
buf = malloc(length);
101-
if (buf == NULL) {
102-
PyErr_NoMemory();
103-
return 1;
104-
}
99+
while (1) {
100+
// Allocate an appropriately sized buffer based on the results
101+
// from the previous call.
102+
buf = malloc(length);
103+
if (buf == NULL) {
104+
PyErr_NoMemory();
105+
return 1;
106+
}
105107

106-
// Call sysctl again with the new buffer.
107-
err = sysctl(name, 3, buf, &length, NULL, 0);
108-
if (err == -1) {
109-
PyErr_SetFromOSErrnoWithSyscall("sysctl");
110-
free(buf);
111-
return 1;
108+
// Call sysctl again with the new buffer.
109+
err = sysctl(name, 3, buf, &length, NULL, 0);
110+
if (err == -1) {
111+
free(buf);
112+
if (errno == ENOMEM) {
113+
// Sometimes the first sysctl() suggested size is not enough,
114+
// so we dynamically increase it until it's big enough :
115+
// https://github.com/giampaolo/psutil/issues/2093
116+
psutil_debug("errno=ENOMEM, length=%zu; retrying", length);
117+
length *= 2;
118+
if (length < max_length) {
119+
continue;
120+
}
121+
}
122+
123+
PyErr_SetFromOSErrnoWithSyscall("sysctl()");
124+
return 1;
125+
}
126+
else {
127+
break;
128+
}
112129
}
113130

114131
*procList = buf;

0 commit comments

Comments
 (0)