Blame SOURCES/glibc-rh1234449-2.patch

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