[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Bug-tar] Re: argp --help infloop bug
From: |
Sergey Poznyakoff |
Subject: |
[Bug-tar] Re: argp --help infloop bug |
Date: |
Sat, 10 Dec 2005 23:45:05 EET |
Jim Meyering <address@hidden> wrote:
> You can make any argp-using program infloop simply by running it
> with --help and with something like ARGP_HELP_FMT=rmargin=a in the
> environment. Or use a valid (but small) width: ARGP_HELP_FMT=rmargin=2
Fixed in gnulib repository. The following patch is applied (it also
fixes a coredump one would get in some cases, e.g. when running
ARGP_HELP_FMT=rmargin=39 tar --help).
Regards,
Sergey
2005-12-10 Sergey Poznyakoff <address@hidden>
* lib/argp-fmtstream.c (__argp_fmtstream_update): Fix coredump
* lib/argp-help.c (fill_in_uparams): Check if the constructed
struct uparams is valid. Fall back to the default values if it is
not.
* m4/argp.m4: Define HAVE_DECL_PROGRAM_INVOCATION_NAME and
HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME
Index: lib/argp-fmtstream.c
===================================================================
RCS file: /cvsroot/gnulib/gnulib/lib/argp-fmtstream.c,v
retrieving revision 1.6
diff -p -u -r1.6 argp-fmtstream.c
--- lib/argp-fmtstream.c 29 Sep 2005 12:24:42 -0000 1.6
+++ lib/argp-fmtstream.c 10 Dec 2005 21:30:53 -0000
@@ -246,9 +246,10 @@ __argp_fmtstream_update (argp_fmtstream_
Oh well. Put it on an overlong line by itself. */
p = buf + (r + 1 - fs->point_col);
/* Find the end of the long word. */
- do
- ++p;
- while (p < nl && !isblank (*p));
+ if (p < nl)
+ do
+ ++p;
+ while (p < nl && !isblank (*p));
if (p == nl)
{
/* It already ends a line. No fussing required. */
Index: lib/argp-help.c
===================================================================
RCS file: /cvsroot/gnulib/gnulib/lib/argp-help.c,v
retrieving revision 1.19
diff -p -u -r1.19 argp-help.c
--- lib/argp-help.c 9 Dec 2005 12:28:58 -0000 1.19
+++ lib/argp-help.c 10 Dec 2005 21:30:57 -0000
@@ -90,15 +90,15 @@ struct uparams
int dup_args_note;
/* Various output columns. */
- int short_opt_col;
- int long_opt_col;
- int doc_opt_col;
- int opt_doc_col;
- int header_col;
- int usage_indent;
- int rmargin;
+ int short_opt_col; /* column in which short options start */
+ int long_opt_col; /* column in which long options start */
+ int doc_opt_col; /* column in which doc options start */
+ int opt_doc_col; /* column in which option text starts */
+ int header_col; /* column in which group headers are printed */
+ int usage_indent; /* indentation of wrapped usage lines */
+ int rmargin; /* right margin used for wrapping */
- int valid; /* True when the values in here are valid. */
+ int valid; /* True when the values in here are valid. */
};
/* This is a global variable, as user options are only ever read once. */
@@ -132,91 +132,126 @@ static const struct uparam_name uparam_n
{ 0 }
};
-/* Read user options from the environment, and fill in UPARAMS appropiately.
*/
+static void
+validate_uparams (const struct argp_state *state, struct uparams *upptr)
+{
+ const struct uparam_name *up;
+
+ for (up = uparam_names; up->name; up++)
+ {
+ if (up->is_bool
+ || up->uparams_offs == offsetof (struct uparams, rmargin))
+ continue;
+ if (*(int *)((char *)upptr + up->uparams_offs) >= upptr->rmargin)
+ {
+ __argp_failure (state, 0, 0,
+ dgettext (state->root_argp->argp_domain,
+ "\
+ARGP_HELP_FMT: %s value is less then or equal to %s"),
+ "rmargin", up->name);
+ return;
+ }
+ }
+ uparams = *upptr;
+ uparams.valid = 1;
+}
+
+/* Read user options from the environment, and fill in UPARAMS appropiately. */
static void
fill_in_uparams (const struct argp_state *state)
{
const char *var = getenv ("ARGP_HELP_FMT");
-
+ struct uparams new_params = uparams;
+
#define SKIPWS(p) do { while (isspace (*p)) p++; } while (0);
if (var)
- /* Parse var. */
- while (*var)
- {
- SKIPWS (var);
-
- if (isalpha (*var))
- {
- size_t var_len;
- const struct uparam_name *un;
- int unspec = 0, val = 0;
- const char *arg = var;
-
- while (isalnum (*arg) || *arg == '-' || *arg == '_')
- arg++;
- var_len = arg - var;
-
- SKIPWS (arg);
-
- if (*arg == '\0' || *arg == ',')
- unspec = 1;
- else if (*arg == '=')
- {
- arg++;
- SKIPWS (arg);
- }
+ {
+ /* Parse var. */
+ while (*var)
+ {
+ SKIPWS (var);
+
+ if (isalpha (*var))
+ {
+ size_t var_len;
+ const struct uparam_name *un;
+ int unspec = 0, val = 0;
+ const char *arg = var;
- if (unspec)
- {
- if (var[0] == 'n' && var[1] == 'o' && var[2] == '-')
- {
- val = 0;
- var += 3;
- var_len -= 3;
- }
- else
- val = 1;
- }
- else if (isdigit (*arg))
- {
- val = atoi (arg);
- while (isdigit (*arg))
+ while (isalnum (*arg) || *arg == '-' || *arg == '_')
+ arg++;
+ var_len = arg - var;
+
+ SKIPWS (arg);
+
+ if (*arg == '\0' || *arg == ',')
+ unspec = 1;
+ else if (*arg == '=')
+ {
arg++;
- SKIPWS (arg);
- }
-
- for (un = uparam_names; un->name; un++)
- if (strlen (un->name) == var_len
- && strncmp (var, un->name, var_len) == 0)
+ SKIPWS (arg);
+ }
+
+ if (unspec)
{
- if (unspec && !un->is_bool)
- __argp_failure (state, 0, 0,
- dgettext (state->root_argp->argp_domain, "\
-%.*s: ARGP_HELP_FMT parameter requires a value"),
- (int) var_len, var);
+ if (var[0] == 'n' && var[1] == 'o' && var[2] == '-')
+ {
+ val = 0;
+ var += 3;
+ var_len -= 3;
+ }
else
- *(int *)((char *)&uparams + un->uparams_offs) = val;
- break;
+ val = 1;
}
- if (! un->name)
- __argp_failure (state, 0, 0,
- dgettext (state->root_argp->argp_domain, "\
+ else if (isdigit (*arg))
+ {
+ val = atoi (arg);
+ while (isdigit (*arg))
+ arg++;
+ SKIPWS (arg);
+ }
+
+ for (un = uparam_names; un->name; un++)
+ if (strlen (un->name) == var_len
+ && strncmp (var, un->name, var_len) == 0)
+ {
+ if (unspec && !un->is_bool)
+ __argp_failure (state, 0, 0,
+ dgettext (state->root_argp->argp_domain,
+ "\
+%.*s: ARGP_HELP_FMT parameter requires a value"),
+ (int) var_len, var);
+ else if (val < 0)
+ __argp_failure (state, 0, 0,
+ dgettext (state->root_argp->argp_domain,
+ "\
+%.*s: ARGP_HELP_FMT parameter must be positive"),
+ (int) var_len, var);
+ else
+ *(int *)((char *)&new_params + un->uparams_offs) = val;
+ break;
+ }
+ if (! un->name)
+ __argp_failure (state, 0, 0,
+ dgettext (state->root_argp->argp_domain, "\
%.*s: Unknown ARGP_HELP_FMT parameter"),
- (int) var_len, var);
+ (int) var_len, var);
- var = arg;
- if (*var == ',')
- var++;
- }
- else if (*var)
- {
- __argp_failure (state, 0, 0,
- dgettext (state->root_argp->argp_domain,
- "Garbage in ARGP_HELP_FMT: %s"), var);
- break;
- }
- }
+ var = arg;
+ if (*var == ',')
+ var++;
+ }
+ else if (*var)
+ {
+ __argp_failure (state, 0, 0,
+ dgettext (state->root_argp->argp_domain,
+ "Garbage in ARGP_HELP_FMT: %s"), var);
+ break;
+ }
+ }
+ validate_uparams (state, &new_params);
+ }
}
/* Returns true if OPT hasn't been marked invisible. Visibility only affects
Index: m4/argp.m4
===================================================================
RCS file: /cvsroot/gnulib/gnulib/m4/argp.m4,v
retrieving revision 1.7
diff -p -u -r1.7 argp.m4
--- m4/argp.m4 9 Dec 2005 12:30:03 -0000 1.7
+++ m4/argp.m4 10 Dec 2005 21:31:01 -0000
@@ -11,12 +11,14 @@ AC_DEFUN([gl_ARGP],
AC_REQUIRE([gl_GETOPT_SUBSTITUTE])
AC_CHECK_DECL([program_invocation_name],
- :,
+ [AC_DEFINE(HAVE_DECL_PROGRAM_INVOCATION_NAME, 1,
+ [Define if program_invocation_name is declared])],
[AC_DEFINE(GNULIB_PROGRAM_INVOCATION_NAME, 1,
[Define to 1 to add extern declaration of
program_invocation_name to argp-namefrob.h])],
[#include <errno.h>])
AC_CHECK_DECL([program_invocation_short_name],
- :,
+ [AC_DEFINE(HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME, 1,
+ [Define if program_invocation_short_name is
declared])],
[AC_DEFINE(GNULIB_PROGRAM_INVOCATION_SHORT_NAME, 1,
[Define to 1 to add extern declaration of
program_invocation_short_name to argp-namefrob.h])],
[#include <errno.h>])