Bash-4.3 distribution sources and documentation
[platform/upstream/bash.git] / braces.c
index 2febed7..61c1ab1 100644 (file)
--- a/braces.c
+++ b/braces.c
@@ -1,6 +1,6 @@
 /* braces.c -- code for doing word expansion in curly braces. */
 
-/* Copyright (C) 1987-2009 Free Software Foundation, Inc.
+/* Copyright (C) 1987-2012 Free Software Foundation, Inc.
 
    This file is part of GNU Bash, the Bourne Again SHell.
 
 #  include <unistd.h>
 #endif
 
+#include <errno.h>
+
 #include "bashansi.h"
+#include "bashintl.h"
 
 #if defined (SHELL)
 #  include "shell.h"
 #endif /* SHELL */
 
+#include "typemax.h"           /* INTMAX_MIN, INTMAX_MAX */
 #include "general.h"
 #include "shmbutil.h"
 #include "chartypes.h"
 
+#ifndef errno
+extern int errno;
+#endif
+
 #define brace_whitespace(c) (!(c) || (c) == ' ' || (c) == '\t' || (c) == '\n')
 
 #define BRACE_SEQ_SPECIFIER    ".."
 
 extern int asprintf __P((char **, const char *, ...)) __attribute__((__format__ (printf, 2, 3)));
 
+extern int last_command_exit_value;
+
 /* Basic idea:
 
    Segregate the text into 3 sections: preamble (stuff before an open brace),
@@ -63,7 +73,7 @@ static const int brace_arg_separator = ',';
 static int brace_gobbler __P((char *, size_t, int *, int));
 static char **expand_amble __P((char *, size_t, int));
 static char **expand_seqterm __P((char *, size_t));
-static char **mkseq __P((intmax_t, intmax_t, int, int, int));
+static char **mkseq __P((intmax_t, intmax_t, intmax_t, int, int));
 static char **array_concat __P((char **, char **));
 #else
 static int brace_gobbler ();
@@ -136,7 +146,8 @@ brace_expand (text)
 #endif /* !CSH_BRACE_COMPAT */
 
   preamble = (char *)xmalloc (i + 1);
-  strncpy (preamble, text, i);
+  if (i > 0)
+    strncpy (preamble, text, i);
   preamble[i] = '\0';
 
   result = (char **)xmalloc (2 * sizeof (char *));
@@ -171,6 +182,7 @@ brace_expand (text)
          if (text[j] == brace_arg_separator)
            {   /* { */
              strvec_dispose (result);
+             last_command_exit_value = 1;
              report_error ("no closing `%c' in %s", '}', text);
              throw_to_top_level ();
            }
@@ -218,6 +230,19 @@ brace_expand (text)
       tack = expand_seqterm (amble, alen);
       if (tack)
        goto add_tack;
+      else if (text[i + 1])
+       {
+         /* If the sequence expansion fails (e.g., because the integers
+            overflow), but there is more in the string, try and process
+            the rest of the string, which may contain additional brace
+            expansions.  Treat the unexpanded sequence term as a simple
+            string (including the braces). */
+         tack = strvec_create (2);
+         tack[0] = savestring (text+start-1);
+         tack[0][i-start+2] = '\0';
+         tack[1] = (char *)0;
+         goto add_tack;
+       }
       else
        {
          free (amble);
@@ -232,13 +257,18 @@ brace_expand (text)
 add_tack:
   result = array_concat (result, tack);
   free (amble);
-  strvec_dispose (tack);
+  if (tack != result)
+    strvec_dispose (tack);
 
   postamble = text + i + 1;
 
-  tack = brace_expand (postamble);
-  result = array_concat (result, tack);
-  strvec_dispose (tack);
+  if (postamble && *postamble)
+    {
+      tack = brace_expand (postamble);
+      result = array_concat (result, tack);
+      if (tack != result)
+       strvec_dispose (tack);
+    }
 
   return (result);
 }
@@ -253,7 +283,7 @@ expand_amble (text, tlen, flags)
      size_t tlen;
      int flags;
 {
-  char **result, **partial;
+  char **result, **partial, **tresult;
   char *tem;
   int start, i, c;
 
@@ -285,7 +315,16 @@ expand_amble (text, tlen, flags)
          lr = strvec_len (result);
          lp = strvec_len (partial);
 
-         result = strvec_resize (result, lp + lr + 1);
+         tresult = strvec_mresize (result, lp + lr + 1);
+         if (tresult == 0)
+           {
+             internal_error (_("brace expansion: cannot allocate memory for %s"), tem);
+             strvec_dispose (result);
+             result = (char **)NULL;
+             return result;
+           }
+         else
+           result = tresult;
 
          for (j = 0; j < lp; j++)
            result[lr + j] = partial[j];
@@ -305,25 +344,75 @@ expand_amble (text, tlen, flags)
 #define ST_CHAR        2
 #define ST_ZINT        3
 
+#ifndef sh_imaxabs
+#  define sh_imaxabs(x)        (((x) >= 0) ? (x) : -(x))
+#endif
+
+/* Handle signed arithmetic overflow and underflow.  Have to do it this way
+   to avoid compilers optimizing out simpler overflow checks. */
+
+/* Make sure that a+b does not exceed MAXV or is smaller than MINV (if b < 0).
+   Assumes that b > 0 if a > 0 and b < 0 if a < 0 */
+#define ADDOVERFLOW(a,b,minv,maxv) \
+       ((((a) > 0) && ((b) > ((maxv) - (a)))) || \
+        (((a) < 0) && ((b) < ((minv) - (a)))))
+
+/* Make sure that a-b is not smaller than MINV or exceeds MAXV (if b < 0).
+   Assumes that b > 0 if a > 0 and b < 0 if a < 0 */
+#define SUBOVERFLOW(a,b,minv,maxv) \
+       ((((b) > 0) && ((a) < ((minv) + (b)))) || \
+        (((b) < 0) && ((a) > ((maxv) + (b)))))
+
 static char **
 mkseq (start, end, incr, type, width)
-     intmax_t start, end;
-     int incr, type, width;
+     intmax_t start, end, incr;
+     int type, width;
 {
-  intmax_t n;
-  int i;
+  intmax_t n, prevn;
+  int i, j, nelem;
   char **result, *t;
 
-  i = abs (end - start) + 1;
-  result = strvec_create (i + 1);
-
   if (incr == 0)
     incr = 1;
-  
+
   if (start > end && incr > 0)
     incr = -incr;
   else if (start < end && incr < 0)
-    incr = -incr;
+    {
+      if (incr == INTMAX_MIN)          /* Don't use -INTMAX_MIN */
+       return ((char **)NULL);
+      incr = -incr;
+    }
+
+  /* Check that end-start will not overflow INTMAX_MIN, INTMAX_MAX.  The +3
+     and -2, not strictly necessary, are there because of the way the number
+     of elements and value passed to strvec_create() are calculated below. */
+  if (SUBOVERFLOW (end, start, INTMAX_MIN+3, INTMAX_MAX-2))
+    return ((char **)NULL);
+
+  prevn = sh_imaxabs (end - start);
+  /* Need to check this way in case INT_MAX == INTMAX_MAX */
+  if (INT_MAX == INTMAX_MAX && (ADDOVERFLOW (prevn, 2, INT_MIN, INT_MAX)))
+    return ((char **)NULL);
+  /* Make sure the assignment to nelem below doesn't end up <= 0 due to
+     intmax_t overflow */
+  else if (ADDOVERFLOW ((prevn/sh_imaxabs(incr)), 1, INTMAX_MIN, INTMAX_MAX))
+    return ((char **)NULL);
+
+  /* XXX - TOFIX: potentially allocating a lot of extra memory if
+     imaxabs(incr) != 1 */
+  /* Instead of a simple nelem = prevn + 1, something like:
+       nelem = (prevn / imaxabs(incr)) + 1;
+     would work */
+  nelem = (prevn / sh_imaxabs(incr)) + 1;
+  if (nelem > INT_MAX - 2)             /* Don't overflow int */
+    return ((char **)NULL);
+  result = strvec_mcreate (nelem + 1);
+  if (result == 0)
+    {
+      internal_error (_("brace expansion: failed to allocate memory for %d elements"), nelem);
+      return ((char **)NULL);
+    }
 
   /* Make sure we go through the loop at least once, so {3..3} prints `3' */
   i = 0;
@@ -334,7 +423,7 @@ mkseq (start, end, incr, type, width)
       QUIT;            /* XXX - memory leak here */
 #endif
       if (type == ST_INT)
-       result[i++] = itos (n);
+       result[i++] = t = itos (n);
       else if (type == ST_ZINT)
        {
          int len, arg;
@@ -344,12 +433,33 @@ mkseq (start, end, incr, type, width)
        }
       else
        {
-         t = (char *)xmalloc (2);
-         t[0] = n;
-         t[1] = '\0';
+         if (t = (char *)malloc (2))
+           {
+             t[0] = n;
+             t[1] = '\0';
+           }
          result[i++] = t;
        }
+
+      /* We failed to allocate memory for this number, so we bail. */
+      if (t == 0)
+       {
+         char *p, lbuf[INT_STRLEN_BOUND(intmax_t) + 1];
+
+         /* Easier to do this than mess around with various intmax_t printf
+            formats (%ld? %lld? %jd?) and PRIdMAX. */
+         p = inttostr (n, lbuf, sizeof (lbuf));
+         internal_error (_("brace expansion: failed to allocate memory for `%s'"), p);
+         strvec_dispose (result);
+         return ((char **)NULL);
+       }
+
+      /* Handle overflow and underflow of n+incr */
+      if (ADDOVERFLOW (n, incr, INTMAX_MIN, INTMAX_MAX))
+        break;
+
       n += incr;
+
       if ((incr < 0 && n < end) || (incr > 0 && n > end))
        break;
     }
@@ -365,8 +475,8 @@ expand_seqterm (text, tlen)
      size_t tlen;
 {
   char *t, *lhs, *rhs;
-  int i, lhs_t, rhs_t, incr, lhs_l, rhs_l, width;
-  intmax_t lhs_v, rhs_v;
+  int i, lhs_t, rhs_t, lhs_l, rhs_l, width;
+  intmax_t lhs_v, rhs_v, incr;
   intmax_t tl, tr;
   char **result, *ep, *oep;
 
@@ -396,8 +506,9 @@ expand_seqterm (text, tlen)
   if (ISDIGIT (rhs[0]) || ((rhs[0] == '+' || rhs[0] == '-') && ISDIGIT (rhs[1])))
     {
       rhs_t = ST_INT;
+      errno = 0;
       tr = strtoimax (rhs, &ep, 10);
-      if (ep && *ep != 0 && *ep != '.')
+      if (errno == ERANGE || (ep && *ep != 0 && *ep != '.'))
        rhs_t = ST_BAD;                 /* invalid */
     }
   else if (ISALPHA (rhs[0]) && (rhs[1] == 0 || rhs[1] == '.'))
@@ -415,10 +526,11 @@ expand_seqterm (text, tlen)
   if (rhs_t != ST_BAD)
     {
       oep = ep;
+      errno = 0;
       if (ep && *ep == '.' && ep[1] == '.' && ep[2])
        incr = strtoimax (ep + 2, &ep, 10);
-      if (*ep != 0)
-       rhs_t = ST_BAD;                 /* invalid incr */
+      if (*ep != 0 || errno == ERANGE)
+       rhs_t = ST_BAD;                 /* invalid incr or overflow */
       tlen -= ep - oep;
     }
 
@@ -535,6 +647,11 @@ brace_gobbler (text, tlen, indx, satisfy)
        {
          if (c == quoted)
            quoted = 0;
+#if defined (SHELL)
+         /* The shell allows quoted command substitutions */
+         if (quoted == '"' && c == '$' && text[i+1] == '(')    /*)*/
+           goto comsub;
+#endif
          ADVANCE_CHAR (text, tlen, i);
          continue;
        }
@@ -550,6 +667,7 @@ brace_gobbler (text, tlen, indx, satisfy)
       /* Pass new-style command and process substitutions through unchanged. */
       if ((c == '$' || c == '<' || c == '>') && text[i+1] == '(')                      /* ) */
        {
+comsub:
          si = i + 2;
          t = extract_command_subst (text, &si, 0);
          i = si;
@@ -594,6 +712,20 @@ brace_gobbler (text, tlen, indx, satisfy)
   return (c);
 }
 
+/* Return 1 if ARR has any non-empty-string members.  Used to short-circuit
+   in array_concat() below. */
+static int
+degenerate_array (arr)
+     char **arr;
+{
+  register int i;
+
+  for (i = 0; arr[i]; i++)
+    if (arr[i][0] != '\0')
+      return 0;
+  return 1;
+}
+
 /* Return a new array of strings which is the result of appending each
    string in ARR2 to each string in ARR1.  The resultant array is
    len (arr1) * len (arr2) long.  For convenience, ARR1 (and its contents)
@@ -607,10 +739,22 @@ array_concat (arr1, arr2)
   register char **result;
 
   if (arr1 == 0)
-    return (strvec_copy (arr2));
+    return (arr2);             /* XXX - see if we can get away without copying? */
 
   if (arr2 == 0)
-    return (strvec_copy (arr1));
+    return (arr1);             /* XXX - caller expects us to free arr1 */
+
+  /* We can only short-circuit if the array consists of a single null element;
+     otherwise we need to replicate the contents of the other array and
+     prefix (or append, below) an empty element to each one. */
+  if (arr1[0] && arr1[0][0] == 0 && arr1[1] == 0)
+    {
+      strvec_dispose (arr1);
+      return (arr2);           /* XXX - use flags to see if we can avoid copying here */
+    }
+
+  if (arr2[0] && arr2[0][0] == 0 && arr2[1] == 0)
+    return (arr1);             /* XXX - rather than copying and freeing it */
 
   len1 = strvec_len (arr1);
   len2 = strvec_len (arr2);