From 72df9302415460908bc9018a07b68f7198e564ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= Date: Tue, 17 Nov 2020 15:17:19 +0100 Subject: [PATCH] DarwinProcessList: retry getting list of all processes on ENOMEM The process count might change between the two sysctl() calls getting the size and getting the data. Retry (3 times) in case the data-retrieval sysctl() call fails with ENOMEM. see http://mirror.informatimago.com/next/developer.apple.com/qa/qa2001/qa1123.html Related: #118 --- darwin/DarwinProcessList.c | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/darwin/DarwinProcessList.c b/darwin/DarwinProcessList.c index 66f5daa6..ae1efb15 100644 --- a/darwin/DarwinProcessList.c +++ b/darwin/DarwinProcessList.c @@ -8,6 +8,7 @@ in the source distribution for its full text. #include "DarwinProcessList.h" #include +#include #include #include #include @@ -107,27 +108,24 @@ static struct kinfo_proc* ProcessList_getKInfoProcs(size_t* count) { int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 }; struct kinfo_proc* processes = NULL; - /* Note the two calls to sysctl(). One to get length and one to get the - * data. This -does- mean that the second call could end up with a missing - * process entry or two. - */ - *count = 0; - if (sysctl(mib, 4, NULL, count, NULL, 0) < 0) { - CRT_fatalError("Unable to get size of kproc_infos"); + for (int retry = 3; retry > 0; retry--) { + size_t size = 0; + if (sysctl(mib, 4, NULL, &size, NULL, 0) < 0 || size == 0) { + CRT_fatalError("Unable to get size of kproc_infos"); + } + + processes = xRealloc(processes, size); + + if (sysctl(mib, 4, processes, &size, NULL, 0) == 0) { + *count = size / sizeof(struct kinfo_proc); + return processes; + } + + if (errno != ENOMEM) + break; } - processes = xMalloc(*count); - if (processes == NULL) { - CRT_fatalError("Out of memory for kproc_infos"); - } - - if (sysctl(mib, 4, processes, count, NULL, 0) < 0) { - CRT_fatalError("Unable to get kinfo_procs"); - } - - *count = *count / sizeof(struct kinfo_proc); - - return processes; + CRT_fatalError("Unable to get kinfo_procs"); } ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, uid_t userId) {