Fix several memory leaks, and crashes, in iconvlist(3).

- Both curitem and curitem (via the names list) was always leaked.
- malloc(3) failures lead to some leaks.
- __bsd___iconv_get_list() failure lead to a crash since its error was not
  handles and __bsd___iconv_free_list() is not NULL-safe.

I have slightly refactored this to avoid extra malloc and free logic in cases
of malloc(3) failing.

There are still bad assumptions here that I did not deal with.  One of which is
that the data will always have a '/' so the strchr(3) will not return NULL.

Coverity CID:	1130055 1130054 1130053
This commit is contained in:
Bryan Drewery 2015-10-29 23:02:34 +00:00
parent 5da8f2b69b
commit d8a7885b36
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=290168

View File

@ -207,43 +207,51 @@ __bsd_iconvlist(int (*do_one) (unsigned int, const char * const *,
const char * const *np;
char *curitem, *curkey, *slashpos;
size_t sz;
unsigned int i, j;
unsigned int i, j, n;
i = 0;
names = NULL;
if (__bsd___iconv_get_list(&list, &sz, true))
if (__bsd___iconv_get_list(&list, &sz, true)) {
list = NULL;
goto out;
}
qsort((void *)list, sz, sizeof(char *), qsort_helper);
while (i < sz) {
j = 0;
slashpos = strchr(list[i], '/');
curkey = (char *)malloc(slashpos - list[i] + 2);
names = (char **)malloc(sz * sizeof(char *));
if ((curkey == NULL) || (names == NULL)) {
__bsd___iconv_free_list(list, sz);
return;
}
strlcpy(curkey, list[i], slashpos - list[i] + 1);
names = malloc(sz * sizeof(char *));
if (names == NULL)
goto out;
curkey = strndup(list[i], slashpos - list[i]);
if (curkey == NULL)
goto out;
names[j++] = curkey;
for (; (i < sz) && (memcmp(curkey, list[i], strlen(curkey)) == 0); i++) {
slashpos = strchr(list[i], '/');
curitem = (char *)malloc(strlen(slashpos) + 1);
if (curitem == NULL) {
__bsd___iconv_free_list(list, sz);
return;
}
strlcpy(curitem, &slashpos[1], strlen(slashpos) + 1);
if (strcmp(curkey, curitem) == 0) {
if (strcmp(curkey, &slashpos[1]) == 0)
continue;
}
curitem = strdup(&slashpos[1]);
if (curitem == NULL)
goto out;
names[j++] = curitem;
}
np = (const char * const *)names;
do_one(j, np, data);
for (n = 0; n < j; n++)
free(names[n]);
free(names);
names = NULL;
}
__bsd___iconv_free_list(list, sz);
out:
if (names != NULL) {
for (n = 0; n < j; n++)
free(names[n]);
free(names);
}
if (list != NULL)
__bsd___iconv_free_list(list, sz);
}
__inline const char *