BASH PATCH REPORT
                            =================

Bash-Release: 3.2
Patch-ID: bash32-005

Bug-Reported-by:        Stuart Shelton <[email protected]>
Bug-Reference-ID:       <[email protected]>
Bug-Reference-URL:      http://lists.gnu.org/archive/html/bug-bash/2006-10/msg00127.html

Bug-Description:

A missing extern declaration for `asprintf' caused `double' arguments to be
passed as `0', leading to incorrect results.  Additionally, a bug in the
replacement asprintf/snprintf function caused an infinite loop when passed
0 arguments to the floating point conversions under some circumstances.

Patch:

*** ../bash-3.2/builtins/printf.def     Mon Sep 18 08:48:42 2006
--- builtins/printf.def Tue Oct 31 08:19:44 2006
***************
*** 49,54 ****
--- 49,60 ----
 #  define INT_MIN             (-2147483647-1)
 #endif

+ #if defined (PREFER_STDARG)
+ #  include <stdarg.h>
+ #else
+ #  include <varargs.h>
+ #endif
+
 #include <stdio.h>
 #include <chartypes.h>

***************
*** 151,156 ****
--- 157,166 ----
 #define SKIP1 "#'-+ 0"
 #define LENMODS "hjlLtz"

+ #ifndef HAVE_ASPRINTF
+ extern int asprintf __P((char **, const char *, ...)) __attribute__((__format__ (printf, 2, 3)));
+ #endif
+
 static void printf_erange __P((char *));
 static int printstr __P((char *, char *, int, int, int));
 static int tescape __P((char *, char *, int *));


*** ../bash-3.2/lib/sh/snprintf.c       Thu Apr  6 09:48:40 2006
--- lib/sh/snprintf.c   Sat Oct 28 00:00:13 2006
***************
*** 471,476 ****
--- 476,483 ----
         10^x ~= r
  * log_10(200) = 2;
  * log_10(250) = 2;
+  *
+  * NOTE: do not call this with r == 0 -- an infinite loop results.
  */
 static int
 log_10(r)
***************
*** 576,583 ****
     {
       integral_part[0] = '0';
       integral_part[1] = '\0';
!       fraction_part[0] = '0';
!       fraction_part[1] = '\0';
       if (fract)
       *fract = fraction_part;
       return integral_part;
--- 583,593 ----
     {
       integral_part[0] = '0';
       integral_part[1] = '\0';
!       /* The fractional part has to take the precision into account */
!       for (ch = 0; ch < precision-1; ch++)
!       fraction_part[ch] = '0';
!       fraction_part[ch] = '0';
!       fraction_part[ch+1] = '\0';
       if (fract)
       *fract = fraction_part;
       return integral_part;
***************
*** 805,810 ****
--- 815,821 ----
       PUT_CHAR(*tmp, p);
       tmp++;
     }
+
   PAD_LEFT(p);
 }

***************
*** 972,982 ****
   if ((p->flags & PF_THOUSANDS) && grouping && (t = groupnum (tmp)))
     tmp = t;

   /* calculate the padding. 1 for the dot */
   p->width = p->width -
           ((d > 0. && p->justify == RIGHT) ? 1:0) -
           ((p->flags & PF_SPACE) ? 1:0) -
!           strlen(tmp) - p->precision - 1;
   PAD_RIGHT(p);
   PUT_PLUS(d, p, 0.);
   PUT_SPACE(d, p, 0.);
--- 983,1003 ----
   if ((p->flags & PF_THOUSANDS) && grouping && (t = groupnum (tmp)))
     tmp = t;

+   if ((*p->pf == 'g' || *p->pf == 'G') && (p->flags & PF_ALTFORM) == 0)
+     {
+       /* smash the trailing zeros unless altform */
+       for (i = strlen(tmp2) - 1; i >= 0 && tmp2[i] == '0'; i--)
+         tmp2[i] = '\0';
+       if (tmp2[0] == '\0')
+       p->precision = 0;
+     }
+
   /* calculate the padding. 1 for the dot */
   p->width = p->width -
           ((d > 0. && p->justify == RIGHT) ? 1:0) -
           ((p->flags & PF_SPACE) ? 1:0) -
!           strlen(tmp) - p->precision -
!           ((p->precision != 0 || (p->flags & PF_ALTFORM)) ? 1 : 0);   /* radix char */
   PAD_RIGHT(p);
   PUT_PLUS(d, p, 0.);
   PUT_SPACE(d, p, 0.);
***************
*** 991,1001 ****
   if (p->precision != 0 || (p->flags & PF_ALTFORM))
     PUT_CHAR(decpoint, p);  /* put the '.' */

-   if ((*p->pf == 'g' || *p->pf == 'G') && (p->flags & PF_ALTFORM) == 0)
-     /* smash the trailing zeros unless altform */
-     for (i = strlen(tmp2) - 1; i >= 0 && tmp2[i] == '0'; i--)
-       tmp2[i] = '\0';
-
   for (; *tmp2; tmp2++)
     PUT_CHAR(*tmp2, p); /* the fraction */

--- 1012,1017 ----
***************
*** 1011,1024 ****
   char *tmp, *tmp2;
   int j, i;

!   if (chkinfnan(p, d, 1) || chkinfnan(p, d, 2))
     return;   /* already printed nan or inf */

   GETLOCALEDATA(decpoint, thoussep, grouping);
   DEF_PREC(p);
!   j = log_10(d);
!   d = d / pow_10(j);  /* get the Mantissa */
!   d = ROUND(d, p);
   tmp = dtoa(d, p->precision, &tmp2);

   /* 1 for unit, 1 for the '.', 1 for 'e|E',
--- 1027,1045 ----
   char *tmp, *tmp2;
   int j, i;

!   if (d != 0 && (chkinfnan(p, d, 1) || chkinfnan(p, d, 2)))
     return;   /* already printed nan or inf */

   GETLOCALEDATA(decpoint, thoussep, grouping);
   DEF_PREC(p);
!   if (d == 0.)
!     j = 0;
!   else
!     {
!       j = log_10(d);
!       d = d / pow_10(j);  /* get the Mantissa */
!       d = ROUND(d, p);
!     }
   tmp = dtoa(d, p->precision, &tmp2);

   /* 1 for unit, 1 for the '.', 1 for 'e|E',
***************
*** 1076,1081 ****
--- 1097,1103 ----
        PUT_CHAR(*tmp, p);
        tmp++;
      }
+
    PAD_LEFT(p);
 }
 #endif
***************
*** 1358,1364 ****
               STAR_ARGS(data);
               DEF_PREC(data);
               d = GETDOUBLE(data);
!               i = log_10(d);
               /*
                * for '%g|%G' ANSI: use f if exponent
                * is in the range or [-4,p] exclusively
--- 1380,1386 ----
               STAR_ARGS(data);
               DEF_PREC(data);
               d = GETDOUBLE(data);
!               i = (d != 0.) ? log_10(d) : -1;
               /*
                * for '%g|%G' ANSI: use f if exponent
                * is in the range or [-4,p] exclusively
*** ../bash-3.2/patchlevel.h    Thu Apr 13 08:31:04 2006
--- patchlevel.h        Mon Oct 16 14:22:54 2006
***************
*** 26,30 ****
    looks for to find the patch level (for the sccs version string). */

! #define PATCHLEVEL 4

 #endif /* _PATCHLEVEL_H_ */
--- 26,30 ----
    looks for to find the patch level (for the sccs version string). */

! #define PATCHLEVEL 5

 #endif /* _PATCHLEVEL_H_ */