Update.
authorUlrich Drepper <drepper@redhat.com>
Sun, 19 Jan 2003 10:05:55 +0000 (10:05 +0000)
committerUlrich Drepper <drepper@redhat.com>
Sun, 19 Jan 2003 10:05:55 +0000 (10:05 +0000)
2003-01-19  Ulrich Drepper  <drepper@redhat.com>

* time/strftime.c (my_strftime): Handle very large width
specifications for numeric values correctly.  Improve checks for
overflow.
* time/Makefile (tests): Add tst-strftime.
* time/tst-strftime.c: New file.

ChangeLog
time/Makefile
time/strftime.c
time/tst-strftime.c [new file with mode: 0644]

index 86ae489..f162670 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2003-01-19  Ulrich Drepper  <drepper@redhat.com>
+
+       * time/strftime.c (my_strftime): Handle very large width
+       specifications for numeric values correctly.  Improve checks for
+       overflow.
+       * time/Makefile (tests): Add tst-strftime.
+       * time/tst-strftime.c: New file.
+
 2003-01-18  Ulrich Drepper  <drepper@redhat.com>
 
        * nis/nss_nis/nis-hosts.c: Make _nss_nis_endhostent an alias of
index 532066b..a7fe2f9 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (C) 1991-1999,2000,01,02 Free Software Foundation, Inc.
+# Copyright (C) 1991-2002, 2003 Free Software Foundation, Inc.
 # This file is part of the GNU C Library.
 
 # The GNU C Library is free software; you can redistribute it and/or
@@ -34,7 +34,7 @@ aux :=            era alt_digit lc-time-cleanup
 distribute := datemsk
 
 tests  := test_time clocktest tst-posixtz tst-strptime tst_wcsftime \
-          tst-getdate tst-mktime tst-ftime_l
+          tst-getdate tst-mktime tst-ftime_l tst-strftime
 
 include ../Rules
 
index 807bb5c..a3256ea 100644 (file)
@@ -1,4 +1,5 @@
-/* Copyright (C) 1991-1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+/* Copyright (C) 1991-1999, 2000, 2001, 2002, 2003
+   Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -263,7 +264,7 @@ static const CHAR_T zeroes[16] = /* "0000000000000000" */
       int _n = (n);                                                          \
       int _delta = width - _n;                                               \
       int _incr = _n + (_delta > 0 ? _delta : 0);                            \
-      if (i + _incr >= maxsize)                                                      \
+      if ((size_t) _incr >= maxsize - i)                                     \
        return 0;                                                             \
       if (p)                                                                 \
        {                                                                     \
@@ -743,8 +744,15 @@ my_strftime (s, maxsize, format, tp ut_argument LOCALE_PARAM)
          width = 0;
          do
            {
-             width *= 10;
-             width += *f - L_('0');
+             if (width > INT_MAX / 10
+                 || (width == INT_MAX / 10 && *f - L_('0') > INT_MAX % 10))
+               /* Avoid overflow.  */
+               width = INT_MAX;
+             else
+               {
+                 width *= 10;
+                 width += *f - L_('0');
+               }
              ++f;
            }
          while (ISDIGIT (*f));
@@ -768,10 +776,10 @@ my_strftime (s, maxsize, format, tp ut_argument LOCALE_PARAM)
       switch (format_char)
        {
 #define DO_NUMBER(d, v) \
-         digits = width == -1 ? d : width;                                   \
+         digits = d > width ? d : width;                                     \
          number_value = v; goto do_number
 #define DO_NUMBER_SPACEPAD(d, v) \
-         digits = width == -1 ? d : width;                                   \
+         digits = d > width ? d : width;                                     \
          number_value = v; goto do_number_spacepad
 
        case L_('%'):
@@ -1033,18 +1041,37 @@ my_strftime (s, maxsize, format, tp ut_argument LOCALE_PARAM)
              int padding = digits - (buf + (sizeof (buf) / sizeof (buf[0]))
                                      - bufp);
 
-             if (pad == L_('_'))
-               {
-                 while (0 < padding--)
-                   *--bufp = L_(' ');
-               }
-             else
+             if (padding > 0)
                {
-                 bufp += negative_number;
-                 while (0 < padding--)
-                   *--bufp = L_('0');
-                 if (negative_number)
-                   *--bufp = L_('-');
+                 if (pad == L_('_'))
+                   {
+                     if ((size_t) padding >= maxsize - i)
+                       return 0;
+
+                     if (p)
+                       memset_space (p, padding);
+                     i += padding;
+                     width = width > padding ? width - padding : 0;
+                   }
+                 else
+                   {
+                     if ((size_t) digits >= maxsize - i)
+                       return 0;
+
+                     if (negative_number)
+                       {
+                         ++bufp;
+
+                         if (p)
+                           *p++ = L_('-');
+                         ++i;
+                       }
+
+                     if (p)
+                       memset_zero (p, padding);
+                     i += padding;
+                     width = 0;
+                   }
                }
            }
 
diff --git a/time/tst-strftime.c b/time/tst-strftime.c
new file mode 100644 (file)
index 0000000..1feb741
--- /dev/null
@@ -0,0 +1,74 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+
+static struct
+{
+  const char *fmt;
+  size_t min;
+  size_t max;
+} tests[] =
+  {
+    { "%2000Y", 2000, 4000 },
+    { "%02000Y", 2000, 4000 },
+    { "%_2000Y", 2000, 4000 },
+    { "%-2000Y", 2000, 4000 },
+  };
+#define ntests (sizeof (tests) / sizeof (tests[0]))
+
+
+static int
+do_test (void)
+{
+  size_t cnt;
+  int result = 0;
+
+  time_t tnow = time (NULL);
+  struct tm *now = localtime (&tnow);
+
+  for (cnt = 0; cnt < ntests; ++cnt)
+    {
+      size_t size = 0;
+      int res;
+      char *buf = NULL;
+
+      do
+       {
+         size += 500;
+         buf = (char *) realloc (buf, size);
+         if (buf == NULL)
+           {
+             puts ("out of memory");
+             exit (1);
+           }
+
+         res = strftime (buf, size, tests[cnt].fmt, now);
+         if (res != 0)
+           break;
+       }
+      while (size < tests[cnt].max);
+
+      if (res == 0)
+       {
+         printf ("%Zu: %s: res == 0 despite size == %Zu\n",
+                 cnt, tests[cnt].fmt, size);
+         result = 1;
+       }
+      else if (size < tests[cnt].min)
+       {
+         printf ("%Zu: %s: size == %Zu was enough\n",
+                 cnt, tests[cnt].fmt, size);
+         result = 1;
+       }
+      else
+       printf ("%Zu: %s: size == %Zu: OK\n", cnt, tests[cnt].fmt, size);
+
+      free (buf);
+    }
+
+  return result;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"