Re: [PATCH] add tests for tzset(3)

Jeff Johnston <[email protected]>
Newsgroups gmane.comp.lib.newlib
Message-ID <CAOox84t7JujYsGG5hw9tnrbmGQjYpbb5MU9G5=fOco0eHJWsKg@mail.gmail.com>
Hello, thanks for looking at it.  I forgot to increase the name buffers by
1 and pass 11 to the sscanf.  This will
make the max test trigger when needed.

I have included a new patch.

-- Jeff J.


On Thu, May 12, 2022 at 2:36 PM jdoubleu <[email protected]> wrote:

> Hi Jeff,
>
> I finally found some time to have a look at your patch.
> >       if (sscanf (tzenv, "%10[-+0-9A-Za-z]%n", __tzname_std, &n) <= 0
> >               || n < TZNAME_MIN || TZNAME_MAX < n || '>' != tzenv[n])
>
> > +      else if (n < TZNAME_MIN || TZNAME_MAX < n)
>
> I think the sub-expression "TZNAME_MAX < n" can never be true, can it?
> sscanf will always stop after 10 characters.
>
> What do you think about including the TZNAME_MAX macro inside the format
> string?
>
> > #define STR(s) #s
> > #define STR_LIT(s) STR(s)
> > ...
> > sscanf(tzenv, "%" STR_LIT(TZNAME_MAX) "[-+0-9A-Za-z]%n", __tzname_dst,
> &n)
>
> I'll try to update the tests in the coming days, so I can verify your
> changes work as expected.
>
>
> Cheers
> ---
> 🙎🏻‍♂️ jdoubleu
> On 4/29/2022 5:46 PM, Jeff Johnston wrote:
> > I have revised my tzset_r.c patch so that the tzrules are initialized so
> we
> > don't inherit the previous settings if not specified for a particular TZ.
> > As well, I defaulted them if TZ is not specified.
> >
> > -- Jeff J.
>
>
0001-Modify-tzset_r.c-to-handle-errors.patch (text/x-patch, 5.8 KB)
From 45d794aa7be198fd9fbb10edbd2dab9b802a7b65 Mon Sep 17 00:00:00 2001
From: Jeff Johnston <[email protected]>
Date: Wed, 27 Apr 2022 15:27:00 -0400
Subject: [PATCH] Modify tzset_r.c to handle errors

- change __tzset_r so errors end up setting the timezone to
  unnamed UTC
---
 newlib/libc/time/tzset_r.c | 68 ++++++++++++++++++++++++++++++++--------------
 1 file changed, 48 insertions(+), 20 deletions(-)

diff --git a/newlib/libc/time/tzset_r.c b/newlib/libc/time/tzset_r.c
index 9cb30b1..a6f15f6 100644
--- a/newlib/libc/time/tzset_r.c
+++ b/newlib/libc/time/tzset_r.c
@@ -12,8 +12,8 @@
 #define TZNAME_MIN	3	/* POSIX min TZ abbr size local def */
 #define TZNAME_MAX	10	/* POSIX max TZ abbr size local def */
 
-static char __tzname_std[TZNAME_MAX + 1];
-static char __tzname_dst[TZNAME_MAX + 1];
+static char __tzname_std[TZNAME_MAX + 2];
+static char __tzname_dst[TZNAME_MAX + 2];
 static char *prev_tzenv = NULL;
 
 void
@@ -23,7 +23,9 @@ _tzset_unlocked_r (struct _reent *reent_ptr)
   unsigned short hh, mm, ss, m, w, d;
   int sign, n;
   int i, ch;
+  long offset0, offset1;
   __tzinfo_type *tz = __gettzinfo ();
+  struct __tzrule_struct default_tzrule = {'J', 0, 0, 0, 0, (time_t)0, 0L };
 
   if ((tzenv = _getenv_r (reent_ptr, "TZ")) == NULL)
       {
@@ -31,6 +33,8 @@ _tzset_unlocked_r (struct _reent *reent_ptr)
 	_daylight = 0;
 	_tzname[0] = "GMT";
 	_tzname[1] = "GMT";
+	tz->__tzrule[0] = default_tzrule;
+	tz->__tzrule[1] = default_tzrule;
 	free(prev_tzenv);
 	prev_tzenv = NULL;
 	return;
@@ -44,6 +48,14 @@ _tzset_unlocked_r (struct _reent *reent_ptr)
   if (prev_tzenv != NULL)
     strcpy (prev_tzenv, tzenv);
 
+  /* default to unnamed UTC in case of error */
+  _timezone = 0;
+  _daylight = 0;
+  _tzname[0] = "";
+  _tzname[1] = "";
+  tz->__tzrule[0] = default_tzrule;
+  tz->__tzrule[1] = default_tzrule;
+
   /* ignore implementation-specific format specifier */
   if (*tzenv == ':')
     ++tzenv;  
@@ -54,7 +66,7 @@ _tzset_unlocked_r (struct _reent *reent_ptr)
       ++tzenv;
 
       /* quit if no items, too few or too many chars, or no close quote '>' */
-      if (sscanf (tzenv, "%10[-+0-9A-Za-z]%n", __tzname_std, &n) <= 0
+      if (sscanf (tzenv, "%11[-+0-9A-Za-z]%n", __tzname_std, &n) <= 0
 		|| n < TZNAME_MIN || TZNAME_MAX < n || '>' != tzenv[n])
         return;
 
@@ -63,7 +75,7 @@ _tzset_unlocked_r (struct _reent *reent_ptr)
   else
     {
       /* allow POSIX unquoted alphabetic tz abbr e.g. MESZ */
-      if (sscanf (tzenv, "%10[A-Za-z]%n", __tzname_std, &n) <= 0
+      if (sscanf (tzenv, "%11[A-Za-z]%n", __tzname_std, &n) <= 0
 				|| n < TZNAME_MIN || TZNAME_MAX < n)
         return;
     }
@@ -85,8 +97,7 @@ _tzset_unlocked_r (struct _reent *reent_ptr)
   if (sscanf (tzenv, "%hu%n:%hu%n:%hu%n", &hh, &n, &mm, &n, &ss, &n) < 1)
     return;
   
-  tz->__tzrule[0].offset = sign * (ss + SECSPERMIN * mm + SECSPERHOUR * hh);
-  _tzname[0] = __tzname_std;
+  offset0 = sign * (ss + SECSPERMIN * mm + SECSPERHOUR * hh);
   tzenv += n;
 
   /* allow POSIX angle bracket < > quoted signed alphanumeric tz abbr e.g. <MESZ+0330> */
@@ -95,12 +106,16 @@ _tzset_unlocked_r (struct _reent *reent_ptr)
       ++tzenv;
 
       /* quit if no items, too few or too many chars, or no close quote '>' */
-      if (sscanf (tzenv, "%10[-+0-9A-Za-z]%n", __tzname_dst, &n) <= 0
-		|| n < TZNAME_MIN || TZNAME_MAX < n || '>' != tzenv[n])
+      if (sscanf (tzenv, "%11[-+0-9A-Za-z]%n", __tzname_dst, &n) <= 0 && tzenv[0] == '>')
 	{ /* No dst */
-	  _tzname[1] = _tzname[0];
-	  _timezone = tz->__tzrule[0].offset;
-	  _daylight = 0;
+          _tzname[0] = __tzname_std;
+          _tzname[1] = _tzname[0];
+          tz->__tzrule[0].offset = offset0;
+          _timezone = offset0;
+	  return;
+        }
+      else if (n < TZNAME_MIN || TZNAME_MAX < n || '>' != tzenv[n])
+	{ /* error */
 	  return;
 	}
 
@@ -109,17 +124,20 @@ _tzset_unlocked_r (struct _reent *reent_ptr)
   else
     {
       /* allow POSIX unquoted alphabetic tz abbr e.g. MESZ */
-      if (sscanf (tzenv, "%10[A-Za-z]%n", __tzname_dst, &n) <= 0
-				|| n < TZNAME_MIN || TZNAME_MAX < n)
+      if (sscanf (tzenv, "%11[A-Za-z]%n", __tzname_dst, &n) <= 0)
 	{ /* No dst */
-	  _tzname[1] = _tzname[0];
-	  _timezone = tz->__tzrule[0].offset;
-	  _daylight = 0;
+          _tzname[0] = __tzname_std;
+          _tzname[1] = _tzname[0];
+          tz->__tzrule[0].offset = offset0;
+          _timezone = offset0;
+	  return;
+        }
+      else if (n < TZNAME_MIN || TZNAME_MAX < n)
+	{ /* error */
 	  return;
 	}
     }
 
-  _tzname[1] = __tzname_dst;
   tzenv += n;
 
   /* otherwise we have a dst name, look for the offset */
@@ -138,9 +156,9 @@ _tzset_unlocked_r (struct _reent *reent_ptr)
   
   n  = 0;
   if (sscanf (tzenv, "%hu%n:%hu%n:%hu%n", &hh, &n, &mm, &n, &ss, &n) <= 0)
-    tz->__tzrule[1].offset = tz->__tzrule[0].offset - 3600;
+    offset1 = offset0 - 3600;
   else
-    tz->__tzrule[1].offset = sign * (ss + SECSPERMIN * mm + SECSPERHOUR * hh);
+    offset1 = sign * (ss + SECSPERMIN * mm + SECSPERHOUR * hh);
 
   tzenv += n;
 
@@ -211,13 +229,23 @@ _tzset_unlocked_r (struct _reent *reent_ptr)
       n = 0;
       
       if (*tzenv == '/')
-	sscanf (tzenv, "/%hu%n:%hu%n:%hu%n", &hh, &n, &mm, &n, &ss, &n);
+	if (sscanf (tzenv, "/%hu%n:%hu%n:%hu%n", &hh, &n, &mm, &n, &ss, &n) <= 0)
+	  {
+	    /* error in time format, restore tz rules to default and return */
+	    tz->__tzrule[0] = default_tzrule;
+	    tz->__tzrule[1] = default_tzrule;
+            return;
+          }
 
       tz->__tzrule[i].s = ss + SECSPERMIN * mm + SECSPERHOUR  * hh;
       
       tzenv += n;
     }
 
+  tz->__tzrule[0].offset = offset0;
+  tz->__tzrule[1].offset = offset1;
+  _tzname[0] = __tzname_std;
+  _tzname[1] = __tzname_dst;
   __tzcalc_limits (tz->__tzyear);
   _timezone = tz->__tzrule[0].offset;  
   _daylight = tz->__tzrule[0].offset != tz->__tzrule[1].offset;
-- 
1.8.3.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.