diff options
-rw-r--r-- | newlib/ChangeLog | 9 | ||||
-rw-r--r-- | newlib/libc/posix/wordexp.c | 61 | ||||
-rw-r--r-- | newlib/libc/posix/wordexp2.h | 21 | ||||
-rw-r--r-- | newlib/libc/posix/wordfree.c | 14 |
4 files changed, 73 insertions, 32 deletions
diff --git a/newlib/ChangeLog b/newlib/ChangeLog index 298fc39..ff157f9 100644 --- a/newlib/ChangeLog +++ b/newlib/ChangeLog @@ -1,5 +1,14 @@ 2012-10-09 Peter Rosin <peda@lysator.liu.se> + * libc/posix/wordfree.c (wordfree): The wrong words are freed + when WRDE_DOOFFS is in use. Restructure the code so that the memory + needed to be freed is instead kept in an internal linked list... + * libc/posix/wordexp2.h: ...as defined here... + * libc/posix/wordexp.c (wordexp): ...and build this internal + linked list here, avoiding wasteful strdup calls in the process. + +2012-10-09 Peter Rosin <peda@lysator.liu.se> + * libc/posix/wordexp.c (wordexp): Return WRDE_NOSPACE on resource allocation failure. Cleanup leftover resources when failing. diff --git a/newlib/libc/posix/wordexp.c b/newlib/libc/posix/wordexp.c index b2f63cf..5c58e46 100644 --- a/newlib/libc/posix/wordexp.c +++ b/newlib/libc/posix/wordexp.c @@ -18,8 +18,10 @@ #include <string.h> #include <unistd.h> #include <sys/wait.h> +#include <sys/queue.h> #include <wordexp.h> +#include "wordexp2.h" #define MAXLINELEN 500 @@ -41,9 +43,9 @@ wordexp(const char *words, wordexp_t *pwordexp, int flags) int fd[2]; int fd_err[2]; int err = WRDE_NOSPACE; - char **wordv; - char *ewords = NULL; + ext_wordv_t *wordv = NULL; char *eword; + struct ewords_entry *entry; if (pwordexp == NULL) { @@ -63,10 +65,14 @@ wordexp(const char *words, wordexp_t *pwordexp, int flags) { offs = pwordexp->we_offs; - wordv = (char **)realloc(pwordexp->we_wordv, (pwordexp->we_wordc + offs + 1) * sizeof(char *)); + if (pwordexp->we_wordv) + wordv = WE_WORDV_TO_EXT_WORDV(pwordexp->we_wordv); + wordv = (ext_wordv_t *)realloc(wordv, sizeof(ext_wordv_t) + (offs + pwordexp->we_wordc) * sizeof(char *)); if (!wordv) return err; - pwordexp->we_wordv = wordv; + if (!pwordexp->we_wordv) + SLIST_INIT(&wordv->list); + pwordexp->we_wordv = wordv->we_wordv; for (i = 0; i < offs; i++) pwordexp->we_wordv[i] = NULL; @@ -142,11 +148,14 @@ wordexp(const char *words, wordexp_t *pwordexp, int flags) num_words = atoi(tmp); - wordv = (char **)realloc(pwordexp->we_wordv, - (pwordexp->we_wordc + num_words + offs + 1) * sizeof(char *)); + if (pwordexp->we_wordv) + wordv = WE_WORDV_TO_EXT_WORDV(pwordexp->we_wordv); + wordv = (ext_wordv_t *)realloc(wordv, sizeof(ext_wordv_t) + (offs + pwordexp->we_wordc + num_words) * sizeof(char *)); if (!wordv) - goto cleanup; - pwordexp->we_wordv = wordv; + return err; + if (!pwordexp->we_wordv) + SLIST_INIT(&wordv->list); + pwordexp->we_wordv = wordv->we_wordv; /* Get number of bytes required for storage of all num_words words. */ if (!fgets(tmp, MAXLINELEN, f)) @@ -157,36 +166,32 @@ wordexp(const char *words, wordexp_t *pwordexp, int flags) num_bytes = atoi(tmp); - /* Get expansion from the shell output. */ - if (!(ewords = (char *)malloc(num_bytes + num_words + 1))) + if (!(entry = (struct ewords_entry *)malloc(sizeof(struct ewords_entry) + num_bytes + num_words))) goto cleanup; - if (!fread(ewords, 1, num_bytes + num_words, f)) + SLIST_INSERT_HEAD(&wordv->list, entry, next); + + /* Get expansion from the shell output. */ + if (!fread(entry->ewords, 1, num_bytes + num_words, f)) goto cleanup; - ewords[num_bytes + num_words] = 0; + entry->ewords[num_bytes + num_words] = 0; /* Store each entry in pwordexp's we_wordv vector. */ - eword = ewords; - for(i = 0; i < num_words; i++) + eword = entry->ewords; + for(i = 0; i < num_words; i++, eword = iter) { - if (eword && (iter = strchr(eword, '\n'))) - *iter = '\0'; - - if (!eword || - !(pwordexp->we_wordv[pwordexp->we_wordc + offs + i] = strdup(eword))) - { - pwordexp->we_wordv[pwordexp->we_wordc + offs + i] = NULL; - pwordexp->we_wordc += i; - goto cleanup; - } - eword = iter ? iter + 1 : iter; + if (!eword) + break; + pwordexp->we_wordv[offs + pwordexp->we_wordc + i] = eword; + if ((iter = strchr(eword, '\n'))) + *iter++ = '\0'; } - pwordexp->we_wordv[pwordexp->we_wordc + offs + i] = NULL; + pwordexp->we_wordv[offs + pwordexp->we_wordc + i] = NULL; pwordexp->we_wordc += num_words; - err = WRDE_SUCCESS; + if (i == num_words) + err = WRDE_SUCCESS; cleanup: - free(ewords); if (f) fclose(f); else diff --git a/newlib/libc/posix/wordexp2.h b/newlib/libc/posix/wordexp2.h new file mode 100644 index 0000000..2030832 --- /dev/null +++ b/newlib/libc/posix/wordexp2.h @@ -0,0 +1,21 @@ +/* Copyright (C) 2012 by Peter Rosin. All rights reserved. + * + * Permission to use, copy, modify, and distribute this software + * is freely granted, provided that this notice is preserved. + */ +#ifndef _WORDEXP2_H_ + +struct ewords_entry { + SLIST_ENTRY(ewords_entry) next; + char ewords[1]; +}; + +typedef struct { + SLIST_HEAD(ewords_head, ewords_entry) list; + char *we_wordv[1]; +} ext_wordv_t; + +#define WE_WORDV_TO_EXT_WORDV(wordv) \ + (ext_wordv_t *)((void *)(wordv) - offsetof(ext_wordv_t, we_wordv)) + +#endif /* !_WORDEXP2_H_ */ diff --git a/newlib/libc/posix/wordfree.c b/newlib/libc/posix/wordfree.c index 2d1208c..024a619 100644 --- a/newlib/libc/posix/wordfree.c +++ b/newlib/libc/posix/wordfree.c @@ -18,13 +18,15 @@ #include <stdlib.h> #include <string.h> #include <unistd.h> +#include <sys/queue.h> #include <wordexp.h> +#include "wordexp2.h" void wordfree(wordexp_t *pwordexp) { - int i; + ext_wordv_t *wordv; if (pwordexp == NULL) return; @@ -32,10 +34,14 @@ wordfree(wordexp_t *pwordexp) if (pwordexp->we_wordv == NULL) return; - for(i = 0; i < pwordexp->we_wordc; i++) - free(pwordexp->we_wordv[i]); + wordv = WE_WORDV_TO_EXT_WORDV(pwordexp->we_wordv); + while (!SLIST_EMPTY(&wordv->list)) { + struct ewords_entry *entry = SLIST_FIRST(&wordv->list); + SLIST_REMOVE_HEAD(&wordv->list, next); + free(entry); + } - free(pwordexp->we_wordv); + free(wordv); pwordexp->we_wordv = NULL; } |