Unfortunately we cannot use strtonum(3) here since there may be
non-digit characters following the number.  So, strtoll(3)
it is then.

 - todd

Index: lib/libc/time/strptime.c
===================================================================
RCS file: /cvs/src/lib/libc/time/strptime.c,v
retrieving revision 1.30
diff -u -p -u -r1.30 strptime.c
--- lib/libc/time/strptime.c    12 May 2019 12:49:52 -0000      1.30
+++ lib/libc/time/strptime.c    29 Jan 2023 15:13:53 -0000
@@ -29,8 +29,10 @@
  */
 
 #include <ctype.h>
+#include <errno.h>
+#include <limits.h>
 #include <locale.h>
-#include <stdint.h>
+#include <stdlib.h>
 #include <string.h>
 #include <time.h>
 
@@ -72,8 +74,8 @@ static const int mon_lengths[2][MONSPERY
         { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
 };
 
-static int _conv_num64(const unsigned char **, int64_t *, int64_t, int64_t);
 static int _conv_num(const unsigned char **, int *, int, int);
+static int epoch_to_tm(const unsigned char **, struct tm *);
 static int leaps_thru_end_of(const int y);
 static char *_strptime(const char *, const char *, struct tm *, int);
 static const u_char *_find_string(const u_char *, int *, const char * const *,
@@ -338,15 +340,10 @@ literal:
                        if (!(_conv_num(&bp, &tm->tm_sec, 0, 60)))
                                return (NULL);
                        break;
-               case 's':       /* Seconds since epoch */
-                       {
-                               int64_t i64;
-                               if (!(_conv_num64(&bp, &i64, 0, INT64_MAX)))
-                                       return (NULL);
-                               if (!gmtime_r(&i64, tm))
-                                       return (NULL);
-                               fields = 0xffff;         /* everything */
-                       }
+               case 's':       /* Seconds since epoch. */
+                       if (!(epoch_to_tm(&bp, tm)))
+                               return (NULL);
+                       fields = 0xffff;         /* everything */
                        break;
                case 'U':       /* The week of year, beginning on sunday. */
                case 'W':       /* The week of year, beginning on monday. */
@@ -610,26 +607,27 @@ _conv_num(const unsigned char **buf, int
 }
 
 static int
-_conv_num64(const unsigned char **buf, int64_t *dest, int64_t llim, int64_t 
ulim)
+epoch_to_tm(const unsigned char **buf, struct tm *tm)
 {
-       int result = 0;
-       int64_t rulim = ulim;
-
-       if (**buf < '0' || **buf > '9')
-               return (0);
-
-       /* we use rulim to break out of the loop when we run out of digits */
-       do {
-               result *= 10;
-               result += *(*buf)++ - '0';
-               rulim /= 10;
-       } while ((result * 10 <= ulim) && rulim && **buf >= '0' && **buf <= 
'9');
-
-       if (result < llim || result > ulim)
-               return (0);
-
-       *dest = result;
-       return (1);
+       int saved_errno = errno;
+       int ret = 0;
+       time_t secs;
+       char *ep;
+
+       errno = 0;
+       secs = strtoll(*buf, &ep, 10);
+       if (*buf == (unsigned char *)ep)
+               goto done;
+       if (secs < 0 ||
+           secs == LLONG_MAX && errno == ERANGE)
+               goto done;
+       if (localtime_r(&secs, tm) == NULL)
+               goto done;
+       ret = 1;
+done:
+       *buf = ep;
+       errno = saved_errno;
+       return (ret);
 }
 
 static const u_char *

Reply via email to