]> Savannah Git Hosting - gnulib.git/commitdiff
parse-datetime: streamline overflow checking
authorPaul Eggert <eggert@cs.ucla.edu>
Thu, 12 Nov 2020 03:16:23 +0000 (19:16 -0800)
committerPaul Eggert <eggert@cs.ucla.edu>
Thu, 12 Nov 2020 03:21:20 +0000 (19:21 -0800)
When parse-datetime.y’s overflow code was written, INT_ADD_WRAPV
did not work for unsigned destinations, and since time_t might
be unsigned that meant it did not work for time_t destinations.
This limitation of INT_ADD_WRAPV has been fixed, so we can
now streamline parse-datetime.y a bit.
* lib/parse-datetime.y: Do not include limits.h, as LONG_MAX
has not been used for a while.
(yylex, parse_datetime2): Assume C99 declarations after statements.
(yyles): Use INT_SUBTRACT_WRAPV instead of an explicit comparison
to TYPE_MINIMUM.
(parse_datetime2): No need for time_overflow now that
INT_ADD_WRAPV works for unsigned results.

ChangeLog
lib/parse-datetime.y

index e1828df64c4db3bc26ce23ad007baa0f6e25111c..530c9a661aab8754dff9ff3bfb3dc0b81a283a7a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,19 @@
 2020-11-11  Paul Eggert  <eggert@cs.ucla.edu>
 
+       parse-datetime: streamline overflow checking
+       When parse-datetime.y’s overflow code was written, INT_ADD_WRAPV
+       did not work for unsigned destinations, and since time_t might
+       be unsigned that meant it did not work for time_t destinations.
+       This limitation of INT_ADD_WRAPV has been fixed, so we can
+       now streamline parse-datetime.y a bit.
+       * lib/parse-datetime.y: Do not include limits.h, as LONG_MAX
+       has not been used for a while.
+       (yylex, parse_datetime2): Assume C99 declarations after statements.
+       (yyles): Use INT_SUBTRACT_WRAPV instead of an explicit comparison
+       to TYPE_MINIMUM.
+       (parse_datetime2): No need for time_overflow now that
+       INT_ADD_WRAPV works for unsigned results.
+
        parse-datetime-tests: port to Alpine Linux 3.12.1
        * tests/test-parse-datetime.c: Include errno.h for errno,
        and unistd.h for _SC_TZNAME_MAX and sysconf.
index 0c624674223c0603d2a759b7be7238227d8eec92..44ae903502e735a2a3383b13f95d46d253e4bbb0 100644 (file)
@@ -27,7 +27,7 @@
    Modified by Paul Eggert <eggert@twinsun.com> in 1999 to do the
    right thing about local DST.  Also modified by Paul Eggert
    <eggert@cs.ucla.edu> in 2004 to support nanosecond-resolution
-   timestamps, in 2004 to support TZ strings in dates, and in 2017 to
+   timestamps, in 2004 to support TZ strings in dates, and in 2017 and 2020 to
    check for integer overflow and to support longer-than-'long'
    'time_t' and 'tv_nsec'.  */
 
@@ -63,7 +63,6 @@
 
 #include <inttypes.h>
 #include <c-ctype.h>
-#include <limits.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -1410,13 +1409,12 @@ yylex (union YYSTYPE *lvalp, parser_control *pc)
 
       if (c_isdigit (c) || c == '-' || c == '+')
         {
-          char const *p;
+          char const *p = pc->input;
           int sign;
-          intmax_t value = 0;
           if (c == '-' || c == '+')
             {
               sign = c == '-' ? -1 : 1;
-              while (c = *++pc->input, c_isspace (c))
+              while (c = *(pc->input = ++p), c_isspace (c))
                 continue;
               if (! c_isdigit (c))
                 /* skip the '-' sign */
@@ -1424,8 +1422,8 @@ yylex (union YYSTYPE *lvalp, parser_control *pc)
             }
           else
             sign = 0;
-          p = pc->input;
 
+          time_t value = 0;
           do
             {
               if (INT_MULTIPLY_WRAPV (value, 10, &value))
@@ -1438,17 +1436,12 @@ yylex (union YYSTYPE *lvalp, parser_control *pc)
 
           if ((c == '.' || c == ',') && c_isdigit (p[1]))
             {
-              time_t s;
-              int ns;
+              time_t s = value;
               int digits;
 
-              if (time_overflow (value))
-                return '?';
-              s = value;
-
               /* Accumulate fraction, to ns precision.  */
               p++;
-              ns = *p++ - '0';
+              int ns = *p++ - '0';
               for (digits = 2; digits <= LOG10_BILLION; digits++)
                 {
                   ns *= 10;
@@ -1472,9 +1465,8 @@ yylex (union YYSTYPE *lvalp, parser_control *pc)
                  negative.  */
               if (sign < 0 && ns)
                 {
-                  if (s == TYPE_MINIMUM (time_t))
+                  if (INT_SUBTRACT_WRAPV (s, 1, &s))
                     return '?';
-                  s--;
                   ns = BILLION - ns;
                 }
 
@@ -1857,11 +1849,9 @@ parse_datetime2 (struct timespec *result, char const *p,
     int quarter;
     for (quarter = 1; quarter <= 3; quarter++)
       {
-        intmax_t iprobe;
-        if (INT_ADD_WRAPV (Start, quarter * (90 * 24 * 60 * 60), &iprobe)
-            || time_overflow (iprobe))
+        time_t probe;
+        if (INT_ADD_WRAPV (Start, quarter * (90 * 24 * 60 * 60), &probe))
           break;
-        time_t probe = iprobe;
         struct tm probe_tm;
         if (localtime_rz (tz, &probe, &probe_tm) && probe_tm.tm_zone
             && probe_tm.tm_isdst != pc.local_time_zone_table[0].value)
@@ -2237,7 +2227,6 @@ parse_datetime2 (struct timespec *result, char const *p,
          so this block must follow others that clobber Start.  */
       if (pc.zones_seen)
         {
-          intmax_t delta = pc.time_zone, t1;
           bool overflow = false;
 #ifdef HAVE_TM_GMTOFF
           long int utcoff = tm.tm_gmtoff;
@@ -2248,9 +2237,11 @@ parse_datetime2 (struct timespec *result, char const *p,
                         ? tm_diff (&tm, &gmt)
                         : (overflow = true, 0));
 #endif
-          overflow |= INT_SUBTRACT_WRAPV (delta, utcoff, &delta);
+          intmax_t delta;
+          overflow |= INT_SUBTRACT_WRAPV (pc.time_zone, utcoff, &delta);
+          time_t t1;
           overflow |= INT_SUBTRACT_WRAPV (Start, delta, &t1);
-          if (overflow || time_overflow (t1))
+          if (overflow)
             {
               if (pc.parse_datetime_debug)
                 dbg_printf (_("error: timezone %d caused time_t overflow\n"),
@@ -2281,14 +2272,14 @@ parse_datetime2 (struct timespec *result, char const *p,
         intmax_t sum_ns = orig_ns + pc.rel.ns;
         int normalized_ns = (sum_ns % BILLION + BILLION) % BILLION;
         int d4 = (sum_ns - normalized_ns) / BILLION;
-        intmax_t d1, t1, d2, t2, t3, t4;
+        intmax_t d1, t1, d2, t2, t3;
+        time_t t4;
         if (INT_MULTIPLY_WRAPV (pc.rel.hour, 60 * 60, &d1)
             || INT_ADD_WRAPV (Start, d1, &t1)
             || INT_MULTIPLY_WRAPV (pc.rel.minutes, 60, &d2)
             || INT_ADD_WRAPV (t1, d2, &t2)
             || INT_ADD_WRAPV (t2, pc.rel.seconds, &t3)
-            || INT_ADD_WRAPV (t3, d4, &t4)
-            || time_overflow (t4))
+            || INT_ADD_WRAPV (t3, d4, &t4))
           {
             if (pc.parse_datetime_debug)
               dbg_printf (_("error: adding relative time caused an "