Mercurial > hg > octave-nkf > gnulib-hg
changeset 17920:7a288a43abf9
getopt: don't crash on memory exhaustion
* lib/getopt.c (_getopt_internal_r): Use degraded diagnostics on
memory exhaustion. In the _LIBC case we use alloca() as is
already done in glibc, so we don't need to consider the separate
error path in that awkward case. Also fix a memory leak when
ambiguous options are present.
Reported by Tobias Stoeckmann
author | Pádraig Brady <P@draigBrady.com> |
---|---|
date | Wed, 18 Feb 2015 02:23:35 +0000 |
parents | c3b0e9dd56c5 |
children | 58c1b50299a6 |
files | ChangeLog lib/getopt.c |
diffstat | 2 files changed, 50 insertions(+), 11 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2015-02-18 Pádraig Brady <P@draigBrady.com> + + getopt: don't crash on memory exhaustion + * lib/getopt.c (_getopt_internal_r): Use degraded diagnostics on + memory exhaustion. In the _LIBC case we use alloca() as is + already done in glibc, so we don't need to consider the separate + error path in that awkward case. Also fix a memory leak when + ambiguous options are present. + Reported by Tobias Stoeckmann + 2015-02-17 Mike Miller <mtmiller@ieee.org> tempname: allow compilation with C++ (trivial)
--- a/lib/getopt.c +++ b/lib/getopt.c @@ -487,7 +487,20 @@ const struct option *p; struct option_list *next; } *ambig_list = NULL; +#ifdef _LIBC +/* malloc() not used for _LIBC to simplify failure messages. */ +# define free_option_list(l) +#else +# define free_option_list(l) \ + while (l != NULL) \ + { \ + struct option_list *pn = l->next; \ + free (l); \ + l = pn; \ + } +#endif int exact = 0; + int ambig = 0; int indfound = -1; int option_index; @@ -520,16 +533,30 @@ || pfound->val != p->val) { /* Second or later nonexact match found. */ +#ifdef _LIBC + struct option_list *newp = alloca (sizeof (*newp)); +#else struct option_list *newp = malloc (sizeof (*newp)); - newp->p = p; - newp->next = ambig_list; - ambig_list = newp; + if (newp == NULL) + { + ambig = 1; /* Use simpler fallback message. */ + free_option_list (ambig_list); + ambig_list = NULL; + break; + } + else +#endif + { + newp->p = p; + newp->next = ambig_list; + ambig_list = newp; + } } } - if (ambig_list != NULL && !exact) + if ((ambig || ambig_list) && !exact) { - if (print_errors) + if (print_errors && ambig_list) { struct option_list first; first.p = pfound; @@ -585,18 +612,20 @@ fputc ('\n', stderr); #endif } + else if (print_errors && ambig) + { + fprintf (stderr, + _("%s: option '%s' is ambiguous\n"), + argv[0], argv[d->optind]); + } d->__nextchar += strlen (d->__nextchar); d->optind++; d->optopt = 0; + free_option_list (ambig_list); return '?'; } - while (ambig_list != NULL) - { - struct option_list *pn = ambig_list->next; - free (ambig_list); - ambig_list = pn; - } + free_option_list (ambig_list); if (pfound != NULL) {