This is the mail archive of the
newlib@sourceware.org
mailing list for the newlib project.
[patch 4/4] wordexp: step past we_offs words when freeing
- From: Peter Rosin <peda at lysator dot liu dot se>
- To: newlib at sourceware dot org
- Date: Fri, 14 Sep 2012 01:04:58 +0200
- Subject: [patch 4/4] wordexp: step past we_offs words when freeing
- References: <20120913230454.392673700@lysator.liu.se>
2012-09-13 Peter Rosin <peda@lysator.liu.se>
* libc/posix/wordexp.c (wordexp): Help wordfree step past
we_offs entries when freeing.
* libc/posix/wordfree.c (wordfree): Step past we_offs words
before starting to free.
Index: newlib/libc/posix/wordexp.c
===================================================================
--- newlib.orig/libc/posix/wordexp.c
+++ newlib/libc/posix/wordexp.c
@@ -63,10 +63,17 @@ wordexp(const char *words, wordexp_t *pw
{
offs = pwordexp->we_offs;
- wordv = (char **)realloc(pwordexp->we_wordv, (pwordexp->we_wordc + offs + 1) * sizeof(char *));
+ /* See the comment near the *other* realloc call for an explanation of
+ * this mess.
+ */
+ wordv = pwordexp->we_wordv;
+ if (wordv)
+ --wordv;
+ wordv = (char **)realloc(wordv, (1 + pwordexp->we_wordc + offs + 1) * sizeof(char *));
if (!wordv)
return err;
- pwordexp->we_wordv = wordv;
+ *wordv = (char *)(wordv + 1 + offs);
+ pwordexp->we_wordv = wordv + 1;
for (i = 0; i < offs; i++)
pwordexp->we_wordv[i] = NULL;
@@ -142,11 +149,25 @@ wordexp(const char *words, wordexp_t *pw
num_words = atoi(tmp);
- wordv = (char **)realloc(pwordexp->we_wordv,
- (pwordexp->we_wordc + num_words + offs + 1) * sizeof(char *));
+ /* POSIX does not give us the liberty to trust the we_offs member if
+ * WRDE_DOOFFS is not given, and we can therefore not use it to store
+ * the fact that no offset has been given. Changing the size of
+ * wordexp_t breaks existing applications. Therefore, when allocating
+ * storage for the expanded words, allocate one extra pointer at the
+ * start and make the we_wordv member point one pointer into the
+ * allocated storage. Use the extra pointer to store where the
+ * real expanded words begin, i.e. always keep track of the offset
+ * even if WRDE_DOOFFS is not given.
+ */
+ wordv = pwordexp->we_wordv;
+ if (wordv)
+ --wordv;
+ wordv = (char **)realloc(wordv,
+ (1 + pwordexp->we_wordc + num_words + offs + 1) * sizeof(char *));
if (!wordv)
goto cleanup;
- pwordexp->we_wordv = wordv;
+ *wordv = (char *)(wordv + 1 + offs);
+ pwordexp->we_wordv = wordv + 1;
/* Get number of bytes required for storage of all num_words words. */
if (!fgets(tmp, MAXLINELEN, f))
Index: newlib/libc/posix/wordfree.c
===================================================================
--- newlib.orig/libc/posix/wordfree.c
+++ newlib/libc/posix/wordfree.c
@@ -25,6 +25,7 @@ void
wordfree(wordexp_t *pwordexp)
{
int i;
+ char **wordv;
if (pwordexp == NULL)
return;
@@ -32,10 +33,15 @@ wordfree(wordexp_t *pwordexp)
if (pwordexp->we_wordv == NULL)
return;
+ /* we_wordv points one pointer into the allocated storage, the
+ * the extra pointer points at the address of the pointer to the
+ * first expanded word.
+ */
+ wordv = (char **)(*(pwordexp->we_wordv - 1));
for(i = 0; i < pwordexp->we_wordc; i++)
- free(pwordexp->we_wordv[i]);
+ free(*wordv++);
- free(pwordexp->we_wordv);
+ free(pwordexp->we_wordv - 1);
pwordexp->we_wordv = NULL;
}