From 7219e1ddc1e8606dda18c1105df0d45d8e8e0e09 Mon Sep 17 00:00:00 2001 From: Richard Levitte Date: Mon, 29 Jun 2020 11:56:00 -0400 Subject: [PATCH] Fix incorrect handling of leftovers with poptStuffArgs If poptStuffArgs() is used twice with the same context, it will invariably cause memory corruption and possibly memory leaks or a crash. Change the allocation of leftOvers so it adapts to the input on the fly instead of trying to pre-allocate it in one go. --- src/popt.c | 24 ++++++++++++++++++++++-- src/poptint.h | 1 + 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/popt.c b/src/popt.c index b7d9478..ab7b54f 100644 --- a/src/popt.c +++ b/src/popt.c @@ -168,6 +168,7 @@ poptContext poptGetContext(const char * name, int argc, const char ** argv, con->os->next = 1; /* skip argv[0] */ con->leftovers = calloc( (size_t)(argc + 1), sizeof(*con->leftovers) ); + con->allocLeftovers = argc + 1; con->options = options; con->aliases = NULL; con->numAliases = 0; @@ -1272,8 +1273,21 @@ int poptGetNextOpt(poptContext con) con->os->nextArg = xstrdup(origOptString); return 0; } - if (con->leftovers != NULL) /* XXX can't happen */ - con->leftovers[con->numLeftovers++] = origOptString; + if (con->leftovers != NULL) { /* XXX can't happen */ + /* One might think we can never overflow the leftovers + array. Actually, that's true, as long as you don't + use poptStuffArgs()... */ + if ((con->numLeftovers + 1) >= (con->allocLeftovers)) { + con->allocLeftovers += 10; + con->leftovers = + realloc(con->leftovers, + sizeof(*con->leftovers) * con->allocLeftovers); + } + con->leftovers[con->numLeftovers++] + = xstrdup(origOptString); /* so a free of a stuffed + argv doesn't give us a + dangling pointer */ + } continue; } @@ -1521,6 +1535,8 @@ poptItem poptFreeItems(poptItem items, int nitems) poptContext poptFreeContext(poptContext con) { + int i; + if (con == NULL) return con; poptResetContext(con); @@ -1530,7 +1546,11 @@ poptContext poptFreeContext(poptContext con) con->execs = poptFreeItems(con->execs, con->numExecs); con->numExecs = 0; + for (i = 0; i < con->numLeftovers; i++) { + con->leftovers[i] = _free(&con->leftovers[i]); + } con->leftovers = _free(con->leftovers); + con->finalArgv = _free(con->finalArgv); con->appName = _free(con->appName); con->otherHelp = _free(con->otherHelp); diff --git a/src/poptint.h b/src/poptint.h index b64e123..d4d6e90 100644 --- a/src/poptint.h +++ b/src/poptint.h @@ -94,6 +94,7 @@ struct poptContext_s { struct optionStackEntry * os; poptArgv leftovers; int numLeftovers; + int allocLeftovers; int nextLeftover; const struct poptOption * options; int restLeftover; -- 2.27.0