bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: argp --help infloop bug


From: Sergey Poznyakoff
Subject: 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>])





reply via email to

[Prev in Thread] Current Thread [Next in Thread]