From a98680cd149606210f776eb68d02cecfc69e61e2 Mon Sep 17 00:00:00 2001 From: Diedrich Vorberg Date: Mon, 19 Oct 2020 20:38:29 +0100 Subject: [PATCH] Patch for GetCommandForPid() in osdep_darwin.c the function mentioned above caused segfaults on MacOS. The attached patch seems to solve that. Details: The functions provides an array of string pointers (the argument vector) pointing to a buffer allocated and referred to by a static local variable `args`. This buffer was used on each subsequent call. For one thing this would overwrite old values and for another this caused segfaults. My new implementation allocates a buffer for the argument vector plus the actual string data on each call. The caller will wfree() the buffer, but until then has available an independent copy of the strings. --- src/osdep_darwin.c | 56 +++++++++++++++++++++++++++++++++------------- 1 file changed, 40 insertions(+), 16 deletions(-) diff --git a/src/osdep_darwin.c b/src/osdep_darwin.c index b3a7b4fa..01917491 100644 --- a/src/osdep_darwin.c +++ b/src/osdep_darwin.c @@ -1,4 +1,3 @@ - #include #include @@ -23,8 +22,8 @@ Bool GetCommandForPid(int pid, char ***argv, int *argc) #ifdef KERN_PROCARGS2 { - int j, mib[4]; - unsigned int i, idx; + int mib[4]; + unsigned int idx; size_t count; static char *args = NULL; static int argmax = 0; @@ -70,21 +69,46 @@ Bool GetCommandForPid(int pid, char ***argv, int *argc) idx++; /* args[idx] is at at begininng of args now */ - *argv = (char **)wmalloc(sizeof(char *) * (*argc + 1 /* term. null ptr */)); - (*argv)[0] = args + idx; + int found = 0; + char *p = &args[idx]; + while(found < *argc) + { + while(*p != '\0') p++; // look for the next \0 + while(*p == '\0') p++; // skip over padding \0s + found++; - /* go through args, set argv[$next] to the beginning of each string */ - for (i = 0, j = 1; i < count - idx /* do not overrun */; i++) { - if (args[idx + i] != '\0') - continue; - if (args[idx + i] == '\0') - (*argv)[j++] = &args[idx + i + 1]; - if (j == *argc) - break; - } + // Don’t overrun! + if (p-args >= argmax) + { + return False; + } + } + // At this point, p points to the last \0 in the source array. - /* the list of arguments must be terminated by a null pointer */ - (*argv)[j] = NULL; + // Buffer needed for the strings + unsigned stringbuf_size = p - &args[idx]; + + // Buffer needed for the pointers (plus one terminating NULL) + unsigned pointerbuf_size = sizeof(char *) * (*argc + 1); + + *argv = wmalloc(pointerbuf_size + stringbuf_size); + char* stringstart = (char *)(*argv) + pointerbuf_size; + + memcpy(stringstart, &args[idx], stringbuf_size); + + found = 0; + p = stringstart; + while(found < *argc) + { + (*argv)[found] = p; + + while(*p != '\0') p++; // look for the next \0 + while(*p == '\0') p++; // skip over padding \0s + + found++; + } + (*argv)[found] = NULL; // Terminating NULL + return True; } #else /* !KERN_PROCARGS2 */