From 6fa31e52cb3547f3c89b3a4c6547d1d92292ac15 Mon Sep 17 00:00:00 2001
From: =?utf8?q?P=C3=A1draig=20Brady?=
Date: Wed, 18 Feb 2015 02:23:35 +0000
Subject: [PATCH] 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
---
ChangeLog | 10 ++++++++++
lib/getopt.c | 51 ++++++++++++++++++++++++++++++++++++++++-----------
2 files changed, 50 insertions(+), 11 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 37b77485b8..eacb80bd97 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2015-02-18 Pádraig Brady
+
+ 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
tempname: allow compilation with C++ (trivial)
diff --git a/lib/getopt.c b/lib/getopt.c
index 3b9c585a28..6474ba74c9 100644
--- a/lib/getopt.c
+++ b/lib/getopt.c
@@ -487,7 +487,20 @@ _getopt_internal_r (int argc, char **argv, const char *optstring,
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 @@ _getopt_internal_r (int argc, char **argv, const char *optstring,
|| 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 @@ _getopt_internal_r (int argc, char **argv, const char *optstring,
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)
{
--
2.39.5