olga / rpms / glibc

Forked from rpms/glibc 5 years ago
Clone

Blame SOURCES/glibc-rh1234449-2.patch

00db10
commit 42261ad731991df345880b0b509d83b0b9a9b9d8
00db10
Author: Florian Weimer <fweimer@redhat.com>
00db10
Date:   Fri Apr 24 17:34:47 2015 +0200
00db10
00db10
    Make time zone file parser more robust [BZ #17715]
00db10
00db10
commit 6807b1db8233ed84671f061b5d825622233df303
00db10
Author: Kevin Easton <kevin@guarana.org>
00db10
Date:   Tue Feb 24 23:57:07 2015 -0500
00db10
00db10
    Reduce lock contention in __tz_convert() [BZ #16145] (partial fix)
00db10
00db10
commit 9d46370ca338054cb6ea7ebeddcf06c7ac7ad1a9
00db10
Author: Joseph Myers <joseph@codesourcery.com>
00db10
Date:   Fri Oct 16 20:21:49 2015 +0000
00db10
00db10
    Convert 703 function definitions to prototype style.
00db10
    (A subset of these changes (tzset.c) were applied as part of this patch.)
00db10
00db10
commit 0748546f660d27a2ad29fa6174d456e2f6490758
00db10
Author: Paul Eggert <eggert@cs.ucla.edu>
00db10
Date:   Wed Sep 18 13:15:12 2013 -0700
00db10
00db10
    Support TZ transition times < 00:00:00.
00db10
00db10
    This is needed for version-3 tz-format files; it supports time
00db10
    stamps past 2037 for America/Godthab (the only entry in the tz
00db10
    database for which this change is relevant).
00db10
    * manual/time.texi (TZ Variable): Document transition times
00db10
    from -167:59:59 through -00:00:01.
00db10
    * time/tzset.c (tz_rule): Time of day is now signed.
00db10
    (__tzset_parse_tz): Parse negative time of day.
00db10
    (A subset of these changes were applied as part of this patch.)
00db10
00db10
commit 3cc652e951c71785032019fec82e3b8543d85305
00db10
Author: Mike Frysinger <vapier@gentoo.org>
00db10
Date:   Fri Sep 18 13:49:08 2015 -0400
00db10
 
00db10
   timezone: fix parallel check failures
00db10
   
00db10
   The XT testdata install rules expect the testdata dir to already exist in
00db10
   the build tree, but it doesn't actually create it.  Instead, it relies on
00db10
   the build-testdata define happening to be executed before it (which runs
00db10
   zic which creates the dir).  When we run in parallel though, it's easy to
00db10
   hit a failure:
00db10
   $ cd timezone
00db10
   $ rm -rf $objdir/timezone/testdata
00db10
   $ make check -j
00db10
   ...
00db10
   cp testdata/XT1 .../timezone/testdata/XT1
00db10
   cp: cannot create regular file '.../timezone/testdata/XT1': No such file or directory
00db10
   Makefile:116: recipe for target '.../timezone/testdata/XT1' failed
00db10
   make: *** [.../timezone/testdata/XT1] Error 1
00db10
   make: *** Waiting for unfinished jobs....
00db10
00db10
diff --git a/time/tzfile.c b/time/tzfile.c
00db10
--- a/time/tzfile.c
00db10
+++ b/time/tzfile.c
00db10
@@ -213,6 +213,9 @@
00db10
   num_isstd = (size_t) decode (tzhead.tzh_ttisstdcnt);
00db10
   num_isgmt = (size_t) decode (tzhead.tzh_ttisgmtcnt);
00db10
 
00db10
+  if (__glibc_unlikely (num_isstd > num_types || num_isgmt > num_types))
00db10
+    goto lose;
00db10
+
00db10
   /* For platforms with 64-bit time_t we use the new format if available.  */
00db10
   if (sizeof (time_t) == 8 && trans_width == 4
00db10
       && tzhead.tzh_version[0] != '\0')
00db10
@@ -445,12 +448,20 @@
00db10
 	goto lose;
00db10
 
00db10
       tzspec_len = st.st_size - off - 1;
00db10
-      char *tzstr = alloca (tzspec_len);
00db10
+      if (tzspec_len == 0)
00db10
+        goto lose;
00db10
+      char *tzstr = malloc (tzspec_len);
00db10
+      if (tzstr == NULL)
00db10
+        goto lose;
00db10
       if (getc_unlocked (f) != '\n'
00db10
 	  || (fread_unlocked (tzstr, 1, tzspec_len - 1, f) != tzspec_len - 1))
00db10
-	goto lose;
00db10
+        {
00db10
+          free (tzstr);
00db10
+          goto lose;
00db10
+        }
00db10
       tzstr[tzspec_len - 1] = '\0';
00db10
       tzspec = __tzstring (tzstr);
00db10
+      free (tzstr);
00db10
     }
00db10
 
00db10
   /* Don't use an empty TZ string.  */
00db10
00db10
diff --git a/time/tzset.c b/time/tzset.c
00db10
--- a/time/tzset.c
00db10
+++ b/time/tzset.c
00db10
@@ -1,4 +1,4 @@
00db10
-/* Copyright (C) 1991-2012 Free Software Foundation, Inc.
00db10
+/* Copyright (C) 1991-2016 Free Software Foundation, Inc.
00db10
    This file is part of the GNU C Library.
00db10
 
00db10
    The GNU C Library is free software; you can redistribute it and/or
00db10
@@ -18,6 +18,7 @@
00db10
 #include <ctype.h>
00db10
 #include <errno.h>
00db10
 #include <bits/libc-lock.h>
00db10
+#include <stdbool.h>
00db10
 #include <stddef.h>
00db10
 #include <stdio.h>
00db10
 #include <stdlib.h>
00db10
@@ -54,7 +55,7 @@
00db10
     /* When to change.  */
00db10
     enum { J0, J1, M } type;	/* Interpretation of:  */
00db10
     unsigned short int m, n, d;	/* Month, week, day.  */
00db10
-    unsigned int secs;		/* Time of day.  */
00db10
+    int secs;			/* Time of day.  */
00db10
 
00db10
     long int offset;		/* Seconds east of GMT (west if < 0).  */
00db10
 
00db10
@@ -82,15 +83,14 @@
00db10
 
00db10
 static struct tzstring_l *tzstring_list;
00db10
 
00db10
-/* Allocate a permanent home for S.  It will never be moved or deallocated,
00db10
-   but may share space with other strings.
00db10
-   Don't modify the returned string. */
00db10
-char *
00db10
-__tzstring (const char *s)
00db10
+/* Allocate a permanent home for the first LEN characters of S.  It
00db10
+   will never be moved or deallocated, but may share space with other
00db10
+   strings.  Don't modify the returned string. */
00db10
+static char *
00db10
+__tzstring_len (const char *s, size_t len)
00db10
 {
00db10
   char *p;
00db10
   struct tzstring_l *t, *u, *new;
00db10
-  size_t len = strlen (s);
00db10
 
00db10
   /* Walk the list and look for a match.  If this string is the same
00db10
      as the end of an already-allocated string, it can share space. */
00db10
@@ -98,7 +98,7 @@
00db10
     if (len <= t->len)
00db10
       {
00db10
 	p = &t->data[t->len - len];
00db10
-	if (strcmp (s, p) == 0)
00db10
+	if (memcmp (s, p, len) == 0)
00db10
 	  return p;
00db10
       }
00db10
 
00db10
@@ -109,7 +109,8 @@
00db10
 
00db10
   new->next = NULL;
00db10
   new->len = len;
00db10
-  strcpy (new->data, s);
00db10
+  memcpy (new->data, s, len);
00db10
+  new->data[len] = '\0';
00db10
 
00db10
   if (u)
00db10
     u->next = new;
00db10
@@ -118,6 +119,15 @@
00db10
 
00db10
   return new->data;
00db10
 }
00db10
+
00db10
+/* Allocate a permanent home for S.  It will never be moved or
00db10
+   deallocated, but may share space with other strings.  Don't modify
00db10
+   the returned string. */
00db10
+char *
00db10
+__tzstring (const char *s)
00db10
+{
00db10
+  return __tzstring_len (s, strlen (s));
00db10
+}
00db10
 
00db10
 /* Maximum length of a timezone name.  tzset_internal keeps this up to date
00db10
    (never decreasing it) when ! __use_tzfile.
00db10
@@ -125,7 +135,7 @@
00db10
 size_t __tzname_cur_max;
00db10
 
00db10
 long int
00db10
-__tzname_max ()
00db10
+__tzname_max (void)
00db10
 {
00db10
   __libc_lock_lock (tzset_lock);
00db10
 
00db10
@@ -164,243 +174,227 @@
00db10
   return min (ss, 59) + min (mm, 59) * 60 + min (hh, 24) * 60 * 60;
00db10
 }
00db10
 
00db10
-
00db10
-/* Parse the POSIX TZ-style string.  */
00db10
-void
00db10
-__tzset_parse_tz (tz)
00db10
-     const char *tz;
00db10
-{
00db10
-  unsigned short int hh, mm, ss;
00db10
-
00db10
-  /* Clear out old state and reset to unnamed UTC.  */
00db10
-  memset (tz_rules, '\0', sizeof tz_rules);
00db10
-  tz_rules[0].name = tz_rules[1].name = "";
00db10
-
00db10
-  /* Get the standard timezone name.  */
00db10
-  char *tzbuf = strdupa (tz);
00db10
-
00db10
-  int consumed;
00db10
-  if (sscanf (tz, "%[A-Za-z]%n", tzbuf, &consumed) != 1)
00db10
-    {
00db10
-      /* Check for the quoted version.  */
00db10
-      char *wp = tzbuf;
00db10
-      if (__builtin_expect (*tz++ != '<', 0))
00db10
-	goto out;
00db10
-
00db10
-      while (isalnum (*tz) || *tz == '+' || *tz == '-')
00db10
-	*wp++ = *tz++;
00db10
-      if (__builtin_expect (*tz++ != '>' || wp - tzbuf < 3, 0))
00db10
-	goto out;
00db10
-      *wp = '\0';
00db10
+/* Parses the time zone name at *TZP, and writes a pointer to an
00db10
+   interned string to tz_rules[WHICHRULE].name.  On success, advances
00db10
+   *TZP, and returns true.  Returns false otherwise.  */
00db10
+static bool
00db10
+parse_tzname (const char **tzp, int whichrule)
00db10
+{
00db10
+  const char *start = *tzp;
00db10
+  const char *p = start;
00db10
+  while (('a' <= *p && *p <= 'z')
00db10
+	 || ('A' <= *p && *p <= 'Z'))
00db10
+      ++p;
00db10
+  size_t len = p - start;
00db10
+  if (len < 3)
00db10
+    {
00db10
+      p = *tzp;
00db10
+      if (__glibc_unlikely (*p++ != '<'))
00db10
+	return false;
00db10
+      start = p;
00db10
+      while (('a' <= *p && *p <= 'z')
00db10
+	     || ('A' <= *p && *p <= 'Z')
00db10
+	     || ('0' <= *p && *p <= '9')
00db10
+	     || *p == '+' || *p == '-')
00db10
+	++p;
00db10
+      len = p - start;
00db10
+      if (*p++ != '>' || len < 3)
00db10
+	return false;
00db10
     }
00db10
-  else if (__builtin_expect (consumed < 3, 0))
00db10
-    goto out;
00db10
-  else
00db10
-    tz += consumed;
00db10
 
00db10
-  tz_rules[0].name = __tzstring (tzbuf);
00db10
+  tz_rules[whichrule].name = __tzstring_len (start, len);
00db10
+
00db10
+  *tzp = p;
00db10
+  return true;
00db10
+}
00db10
 
00db10
-  /* Figure out the standard offset from UTC.  */
00db10
-  if (*tz == '\0' || (*tz != '+' && *tz != '-' && !isdigit (*tz)))
00db10
-    goto out;
00db10
+/* Parses the time zone offset at *TZP, and writes it to
00db10
+   tz_rules[WHICHRULE].offset.  Returns true if the parse was
00db10
+   successful.  */
00db10
+static bool
00db10
+parse_offset (const char **tzp, int whichrule)
00db10
+{
00db10
+  const char *tz = *tzp;
00db10
+  if (whichrule == 0
00db10
+      && (*tz == '\0' || (*tz != '+' && *tz != '-' && !isdigit (*tz))))
00db10
+    return false;
00db10
 
00db10
+  long sign;
00db10
   if (*tz == '-' || *tz == '+')
00db10
-    tz_rules[0].offset = *tz++ == '-' ? 1L : -1L;
00db10
+    sign = *tz++ == '-' ? 1L : -1L;
00db10
   else
00db10
-    tz_rules[0].offset = -1L;
00db10
-  switch (sscanf (tz, "%hu%n:%hu%n:%hu%n",
00db10
-		  &hh, &consumed, &mm, &consumed, &ss, &consumed))
00db10
-    {
00db10
-    default:
00db10
-      tz_rules[0].offset = 0;
00db10
-      goto out;
00db10
-    case 1:
00db10
-      mm = 0;
00db10
-    case 2:
00db10
-      ss = 0;
00db10
-    case 3:
00db10
-      break;
00db10
-    }
00db10
-  tz_rules[0].offset *= compute_offset (ss, mm, hh);
00db10
-  tz += consumed;
00db10
-
00db10
-  /* Get the DST timezone name (if any).  */
00db10
-  if (*tz != '\0')
00db10
-    {
00db10
-      if (sscanf (tz, "%[A-Za-z]%n", tzbuf, &consumed) != 1)
00db10
-	{
00db10
-	  /* Check for the quoted version.  */
00db10
-	  char *wp = tzbuf;
00db10
-	  const char *rp = tz;
00db10
-	  if (__builtin_expect (*rp++ != '<', 0))
00db10
-	    /* Punt on name, set up the offsets.  */
00db10
-	    goto done_names;
00db10
-
00db10
-	  while (isalnum (*rp) || *rp == '+' || *rp == '-')
00db10
-	    *wp++ = *rp++;
00db10
-	  if (__builtin_expect (*rp++ != '>' || wp - tzbuf < 3, 0))
00db10
-	    /* Punt on name, set up the offsets.  */
00db10
-	    goto done_names;
00db10
-	  *wp = '\0';
00db10
-	  tz = rp;
00db10
-	}
00db10
-      else if (__builtin_expect (consumed < 3, 0))
00db10
-	/* Punt on name, set up the offsets.  */
00db10
-	goto done_names;
00db10
-      else
00db10
-	tz += consumed;
00db10
+    sign = -1L;
00db10
+  *tzp = tz;
00db10
 
00db10
-      tz_rules[1].name = __tzstring (tzbuf);
00db10
-
00db10
-      /* Figure out the DST offset from GMT.  */
00db10
-      if (*tz == '-' || *tz == '+')
00db10
-	tz_rules[1].offset = *tz++ == '-' ? 1L : -1L;
00db10
+  unsigned short int hh;
00db10
+  unsigned short mm = 0;
00db10
+  unsigned short ss = 0;
00db10
+  int consumed = 0;
00db10
+  if (sscanf (tz, "%hu%n:%hu%n:%hu%n",
00db10
+	      &hh, &consumed, &mm, &consumed, &ss, &consumed) > 0)
00db10
+    tz_rules[whichrule].offset = sign * compute_offset (ss, mm, hh);
00db10
+  else
00db10
+    /* Nothing could be parsed. */
00db10
+    if (whichrule == 0)
00db10
+      {
00db10
+	/* Standard time defaults to offset zero.  */
00db10
+	tz_rules[0].offset = 0;
00db10
+	return false;
00db10
+      }
00db10
       else
00db10
-	tz_rules[1].offset = -1L;
00db10
+	/* DST defaults to one hour later than standard time.  */
00db10
+	tz_rules[1].offset = tz_rules[0].offset + (60 * 60);
00db10
+  *tzp = tz + consumed;
00db10
+  return true;
00db10
+}
00db10
 
00db10
-      switch (sscanf (tz, "%hu%n:%hu%n:%hu%n",
00db10
-		      &hh, &consumed, &mm, &consumed, &ss, &consumed))
00db10
+/* Parses the standard <-> DST rules at *TZP.  Updates
00db10
+   tz_rule[WHICHRULE].  On success, advances *TZP and returns true.
00db10
+   Otherwise, returns false.  */
00db10
+static bool
00db10
+parse_rule (const char **tzp, int whichrule)
00db10
+{
00db10
+  const char *tz = *tzp;
00db10
+  tz_rule *tzr = &tz_rules[whichrule];
00db10
+
00db10
+  /* Ignore comma to support string following the incorrect
00db10
+     specification in early POSIX.1 printings.  */
00db10
+  tz += *tz == ',';
00db10
+
00db10
+  /* Get the date of the change.  */
00db10
+  if (*tz == 'J' || isdigit (*tz))
00db10
+    {
00db10
+      char *end;
00db10
+      tzr->type = *tz == 'J' ? J1 : J0;
00db10
+      if (tzr->type == J1 && !isdigit (*++tz))
00db10
+	return false;
00db10
+      unsigned long int d = strtoul (tz, &end, 10);
00db10
+      if (end == tz || d > 365)
00db10
+	return false;
00db10
+      if (tzr->type == J1 && d == 0)
00db10
+	return false;
00db10
+      tzr->d = d;
00db10
+      tz = end;
00db10
+    }
00db10
+  else if (*tz == 'M')
00db10
+    {
00db10
+      tzr->type = M;
00db10
+      int consumed;
00db10
+      if (sscanf (tz, "M%hu.%hu.%hu%n",
00db10
+		  &tzr->m, &tzr->n, &tzr->d, &consumed) != 3
00db10
+	  || tzr->m < 1 || tzr->m > 12
00db10
+	  || tzr->n < 1 || tzr->n > 5 || tzr->d > 6)
00db10
+	return false;
00db10
+      tz += consumed;
00db10
+    }
00db10
+  else if (*tz == '\0')
00db10
+    {
00db10
+      /* Daylight time rules in the U.S. are defined in the U.S. Code,
00db10
+	 Title 15, Chapter 6, Subchapter IX - Standard Time.  These
00db10
+	 dates were established by Congress in the Energy Policy Act
00db10
+	 of 2005 [Pub. L. no. 109-58, 119 Stat 594 (2005)].
00db10
+	 Below is the equivalent of "M3.2.0,M11.1.0" [/2 not needed
00db10
+	 since 2:00AM is the default].  */
00db10
+      tzr->type = M;
00db10
+      if (tzr == &tz_rules[0])
00db10
 	{
00db10
-	default:
00db10
-	  /* Default to one hour later than standard time.  */
00db10
-	  tz_rules[1].offset = tz_rules[0].offset + (60 * 60);
00db10
-	  break;
00db10
-
00db10
-	case 1:
00db10
-	  mm = 0;
00db10
-	case 2:
00db10
-	  ss = 0;
00db10
-	case 3:
00db10
-	  tz_rules[1].offset *= compute_offset (ss, mm, hh);
00db10
-	  tz += consumed;
00db10
-	  break;
00db10
+	  tzr->m = 3;
00db10
+	  tzr->n = 2;
00db10
+	  tzr->d = 0;
00db10
 	}
00db10
-      if (*tz == '\0' || (tz[0] == ',' && tz[1] == '\0'))
00db10
+      else
00db10
 	{
00db10
-	  /* There is no rule.  See if there is a default rule file.  */
00db10
-	  __tzfile_default (tz_rules[0].name, tz_rules[1].name,
00db10
-			    tz_rules[0].offset, tz_rules[1].offset);
00db10
-	  if (__use_tzfile)
00db10
-	    {
00db10
-	      free (old_tz);
00db10
-	      old_tz = NULL;
00db10
-	      return;
00db10
-	    }
00db10
+	  tzr->m = 11;
00db10
+	  tzr->n = 1;
00db10
+	  tzr->d = 0;
00db10
 	}
00db10
     }
00db10
   else
00db10
-    {
00db10
-      /* There is no DST.  */
00db10
-      tz_rules[1].name = tz_rules[0].name;
00db10
-      tz_rules[1].offset = tz_rules[0].offset;
00db10
-      goto out;
00db10
+    return false;
00db10
+
00db10
+  if (*tz != '\0' && *tz != '/' && *tz != ',')
00db10
+    return false;
00db10
+  else if (*tz == '/')
00db10
+    {
00db10
+      /* Get the time of day of the change.  */
00db10
+      int negative;
00db10
+      ++tz;
00db10
+      if (*tz == '\0')
00db10
+	return false;
00db10
+      negative = *tz == '-';
00db10
+      tz += negative;
00db10
+      /* Default to 2:00 AM.  */
00db10
+      unsigned short hh = 2;
00db10
+      unsigned short mm = 0;
00db10
+      unsigned short ss = 0;
00db10
+      int consumed = 0;
00db10
+      sscanf (tz, "%hu%n:%hu%n:%hu%n",
00db10
+	      &hh, &consumed, &mm, &consumed, &ss, &consumed);;
00db10
+      tz += consumed;
00db10
+      tzr->secs = (negative ? -1 : 1) * ((hh * 60 * 60) + (mm * 60) + ss);
00db10
     }
00db10
+  else
00db10
+    /* Default to 2:00 AM.  */
00db10
+    tzr->secs = 2 * 60 * 60;
00db10
 
00db10
- done_names:
00db10
-  /* Figure out the standard <-> DST rules.  */
00db10
-  for (unsigned int whichrule = 0; whichrule < 2; ++whichrule)
00db10
-    {
00db10
-      register tz_rule *tzr = &tz_rules[whichrule];
00db10
+  tzr->computed_for = -1;
00db10
+  *tzp = tz;
00db10
+  return true;
00db10
+}
00db10
 
00db10
-      /* Ignore comma to support string following the incorrect
00db10
-	 specification in early POSIX.1 printings.  */
00db10
-      tz += *tz == ',';
00db10
+/* Parse the POSIX TZ-style string.  */
00db10
+void
00db10
+__tzset_parse_tz (const char *tz)
00db10
+{
00db10
+  /* Clear out old state and reset to unnamed UTC.  */
00db10
+  memset (tz_rules, '\0', sizeof tz_rules);
00db10
+  tz_rules[0].name = tz_rules[1].name = "";
00db10
 
00db10
-      /* Get the date of the change.  */
00db10
-      if (*tz == 'J' || isdigit (*tz))
00db10
-	{
00db10
-	  char *end;
00db10
-	  tzr->type = *tz == 'J' ? J1 : J0;
00db10
-	  if (tzr->type == J1 && !isdigit (*++tz))
00db10
-	    goto out;
00db10
-	  unsigned long int d = strtoul (tz, &end, 10);
00db10
-	  if (end == tz || d > 365)
00db10
-	    goto out;
00db10
-	  if (tzr->type == J1 && d == 0)
00db10
-	    goto out;
00db10
-	  tzr->d = d;
00db10
-	  tz = end;
00db10
-	}
00db10
-      else if (*tz == 'M')
00db10
-	{
00db10
-	  tzr->type = M;
00db10
-	  if (sscanf (tz, "M%hu.%hu.%hu%n",
00db10
-		      &tzr->m, &tzr->n, &tzr->d, &consumed) != 3
00db10
-	      || tzr->m < 1 || tzr->m > 12
00db10
-	      || tzr->n < 1 || tzr->n > 5 || tzr->d > 6)
00db10
-	    goto out;
00db10
-	  tz += consumed;
00db10
-	}
00db10
-      else if (*tz == '\0')
00db10
+  /* Get the standard timezone name.  */
00db10
+  if (parse_tzname (&tz, 0) && parse_offset (&tz, 0))
00db10
+    {
00db10
+      /* Get the DST timezone name (if any).  */
00db10
+      if (*tz != '\0')
00db10
 	{
00db10
-         /* Daylight time rules in the U.S. are defined in the
00db10
-            U.S. Code, Title 15, Chapter 6, Subchapter IX - Standard
00db10
-            Time.  These dates were established by Congress in the
00db10
-            Energy Policy Act of 2005 [Pub. L. no. 109-58, 119 Stat 594
00db10
-            (2005)].
00db10
-	    Below is the equivalent of "M3.2.0,M11.1.0" [/2 not needed
00db10
-	    since 2:00AM is the default].  */
00db10
-	  tzr->type = M;
00db10
-	  if (tzr == &tz_rules[0])
00db10
+	  if (parse_tzname (&tz, 1))
00db10
 	    {
00db10
-	      tzr->m = 3;
00db10
-	      tzr->n = 2;
00db10
-	      tzr->d = 0;
00db10
-	    }
00db10
-	  else
00db10
-	    {
00db10
-	      tzr->m = 11;
00db10
-	      tzr->n = 1;
00db10
-	      tzr->d = 0;
00db10
+	      parse_offset (&tz, 1);
00db10
+	      if (*tz == '\0' || (tz[0] == ',' && tz[1] == '\0'))
00db10
+		{
00db10
+		  /* There is no rule.  See if there is a default rule
00db10
+		     file.  */
00db10
+		  __tzfile_default (tz_rules[0].name, tz_rules[1].name,
00db10
+				    tz_rules[0].offset, tz_rules[1].offset);
00db10
+		  if (__use_tzfile)
00db10
+		    {
00db10
+		      free (old_tz);
00db10
+		      old_tz = NULL;
00db10
+		      return;
00db10
+		    }
00db10
+		}
00db10
 	    }
00db10
+	  /* Figure out the standard <-> DST rules.  */
00db10
+	  if (parse_rule (&tz, 0))
00db10
+	    parse_rule (&tz, 1);
00db10
 	}
00db10
       else
00db10
-	goto out;
00db10
-
00db10
-      if (*tz != '\0' && *tz != '/' && *tz != ',')
00db10
-	goto out;
00db10
-      else if (*tz == '/')
00db10
 	{
00db10
-	  /* Get the time of day of the change.  */
00db10
-	  ++tz;
00db10
-	  if (*tz == '\0')
00db10
-	    goto out;
00db10
-	  consumed = 0;
00db10
-	  switch (sscanf (tz, "%hu%n:%hu%n:%hu%n",
00db10
-			  &hh, &consumed, &mm, &consumed, &ss, &consumed))
00db10
-	    {
00db10
-	    default:
00db10
-	      hh = 2;		/* Default to 2:00 AM.  */
00db10
-	    case 1:
00db10
-	      mm = 0;
00db10
-	    case 2:
00db10
-	      ss = 0;
00db10
-	    case 3:
00db10
-	      break;
00db10
-	    }
00db10
-	  tz += consumed;
00db10
-	  tzr->secs = (hh * 60 * 60) + (mm * 60) + ss;
00db10
+	  /* There is no DST.  */
00db10
+	  tz_rules[1].name = tz_rules[0].name;
00db10
+	  tz_rules[1].offset = tz_rules[0].offset;
00db10
 	}
00db10
-      else
00db10
-	/* Default to 2:00 AM.  */
00db10
-	tzr->secs = 2 * 60 * 60;
00db10
-
00db10
-      tzr->computed_for = -1;
00db10
     }
00db10
 
00db10
- out:
00db10
   update_vars ();
00db10
 }
00db10
 
00db10
 /* Interpret the TZ envariable.  */
00db10
 static void
00db10
 internal_function
00db10
-tzset_internal (always, explicit)
00db10
-     int always;
00db10
-     int explicit;
00db10
+tzset_internal (int always, int explicit)
00db10
 {
00db10
   static int is_initialized;
00db10
-  register const char *tz;
00db10
+  const char *tz;
00db10
 
00db10
   if (is_initialized && !always)
00db10
     return;
00db10
@@ -467,11 +461,9 @@
00db10
    put it in RULE->change, saving YEAR in RULE->computed_for.  */
00db10
 static void
00db10
 internal_function
00db10
-compute_change (rule, year)
00db10
-     tz_rule *rule;
00db10
-     int year;
00db10
+compute_change (tz_rule *rule, int year)
00db10
 {
00db10
-  register time_t t;
00db10
+  time_t t;
00db10
 
00db10
   if (year != -1 && rule->computed_for == year)
00db10
     /* Operations on times in 2 BC will be slower.  Oh well.  */
00db10
@@ -558,10 +550,7 @@
00db10
    `__timezone', and `__daylight' accordingly.  */
00db10
 void
00db10
 internal_function
00db10
-__tz_compute (timer, tm, use_localtime)
00db10
-     time_t timer;
00db10
-     struct tm *tm;
00db10
-     int use_localtime;
00db10
+__tz_compute (time_t timer, struct tm *tm, int use_localtime)
00db10
 {
00db10
   compute_change (&tz_rules[0], 1900 + tm->tm_year);
00db10
   compute_change (&tz_rules[1], 1900 + tm->tm_year);
00db10
@@ -641,6 +630,8 @@
00db10
       leap_extra_secs = 0;
00db10
     }
00db10
 
00db10
+  __libc_lock_unlock (tzset_lock);
00db10
+
00db10
   if (tp)
00db10
     {
00db10
       if (! use_localtime)
00db10
@@ -656,8 +647,6 @@
00db10
 	tp = NULL;
00db10
     }
00db10
 
00db10
-  __libc_lock_unlock (tzset_lock);
00db10
-
00db10
   return tp;
00db10
 }
00db10
 
00db10
diff --git a/timezone/Makefile b/timezone/Makefile
00db10
index 17424b8..5f18545 100644
00db10
--- a/timezone/Makefile
00db10
+++ b/timezone/Makefile
00db10
@@ -23,7 +23,7 @@
00db10
 extra-objs := scheck.o ialloc.o
00db10
 
00db10
 others	:= zdump zic
00db10
-tests	:= test-tz tst-timezone
00db10
+tests	:= test-tz tst-timezone tst-tzset
00db10
 
00db10
 # pacificnew doesn't compile; if it is to be used, it should be included in
00db10
 # northamerica.
00db10
@@ -87,9 +87,11 @@
00db10
 				       Australia/Melbourne \
00db10
 				       America/Sao_Paulo Asia/Tokyo \
00db10
 				       Europe/London)
00db10
+$(objpfx)tst-tzset.out: $(addprefix $(testdata)/XT, 1 2 3 4)
00db10
 
00db10
 test-tz-ENV = TZDIR=$(testdata)
00db10
 tst-timezone-ENV = TZDIR=$(testdata)
00db10
+tst-tzset-ENV = TZDIR=$(testdata)
00db10
 
00db10
 # Note this must come second in the deps list for $(built-program-cmd) to work.
00db10
 zic-deps = $(objpfx)zic $(leapseconds) yearistype
00db10
@@ -111,6 +113,8 @@
00db10
 $(testdata)/Asia/Tokyo: asia $(zic-deps)
00db10
 	$(build-testdata)
00db10
 
00db10
+$(testdata)/XT%: testdata/XT%
00db10
+	cp $< $@
00db10
 
00db10
 $(objpfx)tzselect: tzselect.ksh $(common-objpfx)config.make
00db10
 	sed -e 's|/bin/bash|$(KSH)|g' \
00db10
diff --git a/timezone/README b/timezone/README
00db10
index 7a5e31c..2268f8e 100644
00db10
--- a/timezone/README
00db10
+++ b/timezone/README
00db10
@@ -15,3 +15,6 @@ version of the tzcode and tzdata packages.
00db10
 
00db10
 These packages may be found at ftp://ftp.iana.org/tz/releases/.  Commentary
00db10
 should be addressed to tz@iana.org.
00db10
+
00db10
+The subdirectory testdata contains manually edited data files for
00db10
+regression testing purposes.
00db10
--- /dev/null
00db10
+++ b/timezone/tst-tzset.c
00db10
@@ -0,0 +1,200 @@
00db10
+/* tzset tests with crafted time zone data.
00db10
+   Copyright (C) 2015 Free Software Foundation, Inc.
00db10
+
00db10
+   The GNU C Library is free software; you can redistribute it and/or
00db10
+   modify it under the terms of the GNU Lesser General Public
00db10
+   License as published by the Free Software Foundation; either
00db10
+   version 2.1 of the License, or (at your option) any later version.
00db10
+
00db10
+   The GNU C Library is distributed in the hope that it will be useful,
00db10
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
00db10
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00db10
+   Lesser General Public License for more details.
00db10
+
00db10
+   You should have received a copy of the GNU Lesser General Public
00db10
+   License along with the GNU C Library; if not, see
00db10
+   <http://www.gnu.org/licenses/>.  */
00db10
+
00db10
+#define _GNU_SOURCE 1
00db10
+
00db10
+#include <errno.h>
00db10
+#include <stdio.h>
00db10
+#include <stdlib.h>
00db10
+#include <string.h>
00db10
+#include <sys/resource.h>
00db10
+#include <time.h>
00db10
+#include <unistd.h>
00db10
+
00db10
+static int do_test (void);
00db10
+#define TEST_FUNCTION do_test ()
00db10
+#include "../test-skeleton.c"
00db10
+
00db10
+/* Returns the name of a large TZ file.  */
00db10
+static char *
00db10
+create_tz_file (off64_t size)
00db10
+{
00db10
+  char *path;
00db10
+  int fd = create_temp_file ("tst-tzset-", &path);
00db10
+  if (fd < 0)
00db10
+    exit (1);
00db10
+
00db10
+  // Reopen for large-file support.
00db10
+  close (fd);
00db10
+  fd = open64 (path, O_WRONLY);
00db10
+  if (fd < 0)
00db10
+    {
00db10
+      printf ("open64 (%s) failed: %m\n", path);
00db10
+      exit (1);
00db10
+    }
00db10
+
00db10
+  static const char data[] = {
00db10
+    0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00,
00db10
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00db10
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
00db10
+    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
00db10
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
00db10
+    0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
00db10
+    0x00, 0x00, 0x58, 0x54, 0x47, 0x00, 0x00, 0x00,
00db10
+    0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00,
00db10
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00db10
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
00db10
+    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
00db10
+    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
00db10
+    0x00, 0x00, 0x00, 0x04, 0xf8, 0x00, 0x00, 0x00,
00db10
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00db10
+    0x00, 0x00, 0x00, 0x58, 0x54, 0x47, 0x00, 0x00,
00db10
+    0x00, 0x0a, 0x58, 0x54, 0x47, 0x30, 0x0a
00db10
+  };
00db10
+  ssize_t ret = write (fd, data, sizeof (data));
00db10
+  if (ret < 0)
00db10
+    {
00db10
+      printf ("write failed: %m\n");
00db10
+      exit (1);
00db10
+    }
00db10
+  if ((size_t) ret != sizeof (data))
00db10
+    {
00db10
+      printf ("Short write\n");
00db10
+      exit (1);
00db10
+    }
00db10
+  if (lseek64 (fd, size, SEEK_CUR) < 0)
00db10
+    {
00db10
+      printf ("lseek failed: %m\n");
00db10
+      close (fd);
00db10
+      return NULL;
00db10
+    }
00db10
+  if (write (fd, "", 1) != 1)
00db10
+    {
00db10
+      printf ("Single-byte write failed\n");
00db10
+      close (fd);
00db10
+      return NULL;
00db10
+    }
00db10
+  if (close (fd) != 0)
00db10
+    {
00db10
+      printf ("close failed: %m\n");
00db10
+      exit (1);
00db10
+    }
00db10
+  return path;
00db10
+}
00db10
+
00db10
+static void
00db10
+test_tz_file (off64_t size)
00db10
+{
00db10
+  char *path = create_tz_file (size);
00db10
+  if (setenv ("TZ", path, 1) < 0)
00db10
+    {
00db10
+      printf ("setenv failed: %m\n");
00db10
+      exit (1);
00db10
+    }
00db10
+  tzset ();
00db10
+  free (path);
00db10
+}
00db10
+
00db10
+static int
00db10
+do_test (void)
00db10
+{
00db10
+  /* Limit the size of the process.  Otherwise, some of the tests will
00db10
+     consume a lot of resources.  */
00db10
+  {
00db10
+    struct rlimit limit;
00db10
+    if (getrlimit (RLIMIT_AS, &limit) != 0)
00db10
+      {
00db10
+	printf ("getrlimit (RLIMIT_AS) failed: %m\n");
00db10
+	return 1;
00db10
+      }
00db10
+    long target = 512 * 1024 * 1024;
00db10
+    if (limit.rlim_cur == RLIM_INFINITY || limit.rlim_cur > target)
00db10
+      {
00db10
+	limit.rlim_cur = 512 * 1024 * 1024;
00db10
+	if (setrlimit (RLIMIT_AS, &limit) != 0)
00db10
+	  {
00db10
+	    printf ("setrlimit (RLIMIT_AS) failed: %m\n");
00db10
+	    return 1;
00db10
+	  }
00db10
+      }
00db10
+  }
00db10
+
00db10
+  int errors = 0;
00db10
+  for (int i = 1; i <= 4; ++i)
00db10
+    {
00db10
+      char tz[16];
00db10
+      snprintf (tz, sizeof (tz), "XT%d", i);
00db10
+      if (setenv ("TZ", tz, 1) < 0)
00db10
+	{
00db10
+	  printf ("setenv failed: %m\n");
00db10
+	  return 1;
00db10
+	}
00db10
+      tzset ();
00db10
+      if (strcmp (tzname[0], tz) == 0)
00db10
+	{
00db10
+	  printf ("Unexpected success for %s\n", tz);
00db10
+	  ++errors;
00db10
+	}
00db10
+    }
00db10
+
00db10
+  /* Large TZ files.  */
00db10
+
00db10
+  /* This will succeed on 64-bit architectures, and fail on 32-bit
00db10
+     architectures.  It used to crash on 32-bit.  */
00db10
+  test_tz_file (64 * 1024 * 1024);
00db10
+
00db10
+  /* This will fail on 64-bit and 32-bit architectures.  It used to
00db10
+     cause a test timeout on 64-bit and crash on 32-bit if the TZ file
00db10
+     open succeeded for some reason (it does not use O_LARGEFILE in
00db10
+     regular builds).  */
00db10
+  test_tz_file (4LL * 1024 * 1024 * 1024 - 6);
00db10
+
00db10
+  /* Large TZ variables.  */
00db10
+  {
00db10
+    size_t length = 64 * 1024 * 1024;
00db10
+    char *value = malloc (length + 1);
00db10
+    if (value == NULL)
00db10
+      {
00db10
+	puts ("malloc failed: %m");
00db10
+	return 1;
00db10
+      }
00db10
+    value[length] = '\0';
00db10
+
00db10
+    memset (value, ' ', length);
00db10
+    value[0] = 'U';
00db10
+    value[1] = 'T';
00db10
+    value[2] = 'C';
00db10
+    if (setenv ("TZ", value, 1) < 0)
00db10
+      {
00db10
+	printf ("setenv failed: %m\n");
00db10
+	return 1;
00db10
+      }
00db10
+    tzset ();
00db10
+
00db10
+    memset (value, '0', length);
00db10
+    value[0] = '<';
00db10
+    value[length - 1] = '>';
00db10
+    if (setenv ("TZ", value, 1) < 0)
00db10
+      {
00db10
+	printf ("setenv failed: %m\n");
00db10
+	return 1;
00db10
+      }
00db10
+    tzset ();
00db10
+  }
00db10
+
00db10
+  return errors > 0;
00db10
+}
00db10
diff --git a/timezone/Makefile b/timezone/Makefile
00db10
index 81d4a3e..bfb3463 100644
00db10
--- a/timezone/Makefile
00db10
+++ b/timezone/Makefile
00db10
@@ -113,6 +113,7 @@ $(testdata)/Asia/Tokyo: asia $(zic-deps)
00db10
 	$(build-testdata)
00db10
 
00db10
 $(testdata)/XT%: testdata/XT%
00db10
+	$(make-target-directory)
00db10
 	cp $< $@
00db10
 
00db10
 $(objpfx)tzselect: tzselect.ksh $(common-objpfx)config.make
00db10
diff -Nrup -a a/timezone/testdata/XT1 b/timezone/testdata/XT1
00db10
--- a/timezone/testdata/XT1	1969-12-31 19:00:00.000000000 -0500
00db10
+++ b/timezone/testdata/XT1	2017-09-14 10:19:11.382923956 -0400
00db10
@@ -0,0 +1,2 @@
00db10
+TZif2ÿÿÿÿ???XT1TZif2ÿÿÿÿ????øXT1
00db10
+XT10
00db10
diff -Nrup -a a/timezone/testdata/XT2 b/timezone/testdata/XT2
00db10
--- a/timezone/testdata/XT2	1969-12-31 19:00:00.000000000 -0500
00db10
+++ b/timezone/testdata/XT2	2017-09-14 10:19:11.382923956 -0400
00db10
@@ -0,0 +1,2 @@
00db10
+TZif2?ÿÿÿÿ??XT2TZif2?ÿÿÿÿ???øXT2
00db10
+XT20
00db10
diff -Nrup -a a/timezone/testdata/XT3 b/timezone/testdata/XT3
00db10
--- a/timezone/testdata/XT3	1969-12-31 19:00:00.000000000 -0500
00db10
+++ b/timezone/testdata/XT3	2017-09-14 10:19:11.382923956 -0400
00db10
@@ -0,0 +1,2 @@
00db10
+TZif2????XT3TZif2?????øXT3
00db10
+XT30
00db10
diff -Nrup -a a/timezone/testdata/XT4 b/timezone/testdata/XT4
00db10
--- a/timezone/testdata/XT4	1969-12-31 19:00:00.000000000 -0500
00db10
+++ b/timezone/testdata/XT4	2017-09-14 10:19:11.383923953 -0400
00db10
@@ -0,0 +1,2 @@
00db10
+TZif2????XT4TZif2?????øXT4
00db10
+XT40