mailing list of musl libc
 help / color / mirror / code / Atom feed
* [PATCH] Add support for leap seconds in zoneinfo files
@ 2013-11-26 18:53 Laurent Bercot
  2013-11-26 18:59 ` Laurent Bercot
  2013-11-26 23:32 ` Rich Felker
  0 siblings, 2 replies; 31+ messages in thread
From: Laurent Bercot @ 2013-11-26 18:53 UTC (permalink / raw)
  To: musl

[-- Attachment #1: Type: text/plain, Size: 1299 bytes --]


  Attached.

  I tried to make it as simple and musl-coding-style-compliant as possible.
  One line adds support for TZif3 (it costs nothing once we have TZif2 and
we can ignore the extensions).
  The other changes are ifdef-guarded and can be ignored with -DNO_LEAPSECONDS,
for hardcore POSIX fans. ;) But posix/ rules don't have leap seconds anyway,
only right/ ones do: if you don't like #ifdef forests, feel free to remove the
guards.

  By the way, what's the musl policy on internal sanity checks ? In __tz.c,
musl doesn't check anything after the magic numbers, so if the zoneinfo file
is bad later on, musl can crash, or worse, silently return inconsistent or
wrong results. I understand that it's impossible to escalate an error to the
user when the entry point returns a void, but wouldn't it be safer, in this
case as well as in similar cases, to abort the program ? I tend to think that
even raising a SIGSEGV manually would be better than silent undefined
behaviour.

  I can also confirm that strftime() fails to null-terminate its output in some
circumstances, most likely when the format string ends with a regular character
instead of a conversion specifier. I'll submit a patch as soon as I have time to
investigate more, unless you can fix it before I get to it.

-- 
  Laurent


[-- Attachment #2: leapsecs.patch --]
[-- Type: text/plain, Size: 4078 bytes --]

diff -rNU3 musl-old/src/time/__secs_to_tm.c musl/src/time/__secs_to_tm.c
--- musl-old/src/time/__secs_to_tm.c	2013-11-25 11:57:25.138608721 +0100
+++ musl/src/time/__secs_to_tm.c	2013-11-26 10:55:00.944118059 +0100
@@ -8,6 +8,21 @@
 #define DAYS_PER_100Y (365*100 + 24)
 #define DAYS_PER_4Y   (365*4   + 1)
 
+#ifndef NO_LEAPSECONDS
+static int leapsecs_sub(long long *t)
+{
+	unsigned int i = 0;
+	int hit = 0;
+	for (; i < __leapsecs_num; i++)
+		if (*t >= __leapsecs_table[i].trans) break;
+	if (i < __leapsecs_num) {
+		if (*t == __leapsecs_table[i].trans) hit = 1;
+		*t -= __leapsecs_table[i].corr;
+	}
+	return hit;
+}
+#endif
+
 int __secs_to_tm(long long t, struct tm *tm)
 {
 	long long days, secs;
@@ -21,6 +36,9 @@
 	if (t < INT_MIN * 31622400LL || t > INT_MAX * 31622400LL)
 		return -1;
 
+#ifndef NO_LEAPSECONDS
+	int hit = leapsecs_sub(&t);
+#endif
 	secs = t - LEAPOCH;
 	days = secs / 86400;
 	remsecs = secs % 86400;
@@ -76,6 +94,9 @@
 	tm->tm_hour = remsecs / 3600;
 	tm->tm_min = remsecs / 60 % 60;
 	tm->tm_sec = remsecs % 60;
+#ifndef NO_LEAPSECONDS
+	if (hit) tm->tm_sec++;
+#endif
 
 	return 0;
 }
diff -rNU3 musl-old/src/time/time_impl.h musl/src/time/time_impl.h
--- musl-old/src/time/time_impl.h	2013-11-25 11:57:25.138608721 +0100
+++ musl/src/time/time_impl.h	2013-11-26 10:48:40.712450191 +0100
@@ -7,3 +7,12 @@
 int __secs_to_tm(long long, struct tm *);
 void __secs_to_zone(long long, int, int *, long *, long *, const char **);
 const unsigned char *__map_file(const char *, size_t *);
+
+#ifndef NO_LEAPSECONDS
+struct lsinfo_s {
+  long long trans;
+  int corr;
+} ;
+extern struct lsinfo_s *__leapsecs_table;
+extern unsigned int __leapsecs_num;
+#endif
diff -rNU3 musl-old/src/time/__tm_to_secs.c musl/src/time/__tm_to_secs.c
--- musl-old/src/time/__tm_to_secs.c	2013-11-25 11:57:25.138608721 +0100
+++ musl/src/time/__tm_to_secs.c	2013-11-26 10:54:16.153921563 +0100
@@ -1,5 +1,16 @@
 #include "time_impl.h"
 
+#ifndef NO_LEAPSECONDS
+static void leapsecs_add(long long *t, int hit)
+{
+	unsigned int i = 0;
+	for (; i < __leapsecs_num; i++)
+		if (*t >= __leapsecs_table[i].trans) break;
+	if (i < __leapsecs_num)
+		*t += __leapsecs_table[i].corr + (hit && (*t == __leapsecs_table[i].trans));
+}
+#endif
+
 long long __tm_to_secs(const struct tm *tm)
 {
 	int is_leap;
@@ -20,5 +31,8 @@
 	t += 3600LL * tm->tm_hour;
 	t += 60LL * tm->tm_min;
 	t += tm->tm_sec;
+#ifndef NO_LEAPSECONDS
+	leapsecs_add(&t, tm->tm_sec==60);
+#endif
 	return t;
 }
diff -rNU3 musl-old/src/time/__tz.c musl/src/time/__tz.c
--- musl-old/src/time/__tz.c	2013-11-25 11:57:25.138608721 +0100
+++ musl/src/time/__tz.c	2013-11-26 12:41:31.142337204 +0100
@@ -118,6 +118,28 @@
 
 int __munmap(void *, size_t);
 
+#ifndef NO_LEAPSECONDS
+
+#define LEAPSECONDS_MAX 50  /* value in tzcode, probably too much */
+static struct lsinfo_s leapsecond_table[LEAPSECONDS_MAX<<1];
+struct lsinfo_s *__leapsecs_table = leapsecond_table;
+unsigned int __leapsecs_num = 0;
+
+static inline uint64_t zi_read64(const unsigned char *z)
+{
+	return ((uint64_t)zi_read32(z) << 32) + zi_read32(z+4);
+}
+
+static void parse_leapsecs(const unsigned char *z, unsigned int i, int lsize)
+{
+	__leapsecs_num = i;
+	for (; i; i--, z += lsize+4) {
+		__leapsecs_table[i-1].trans = (long long)(lsize == 8 ? zi_read64(z) : zi_read32(z));
+		__leapsecs_table[i-1].corr = zi_read32(z+lsize);
+	}
+}
+#endif
+
 static void do_tzset()
 {
 	char buf[NAME_MAX+25], *pathname=buf+24;
@@ -175,7 +197,7 @@
 	zi = map;
 	if (map) {
 		int scale = 2;
-		if (sizeof(time_t) > 4 && map[4]=='2') {
+		if (sizeof(time_t) > 4 && ((map[4]=='2') || (map[4]=='3'))) {
 			size_t skip = zi_dotprod(zi+20, VEC(1,1,8,5,6,1), 6);
 			trans = zi+skip+44+44;
 			scale++;
@@ -186,6 +208,9 @@
 		types = index + zi_read32(trans-12);
 		abbrevs = types + 6*zi_read32(trans-8);
 		abbrevs_end = abbrevs + zi_read32(trans-4);
+#ifndef NO_LEAPSECONDS
+		parse_leapsecs(abbrevs_end, zi_read32(trans-16), 1 << scale);
+#endif
 		if (zi[map_size-1] == '\n') {
 			for (s = (const char *)zi+map_size-2; *s!='\n'; s--);
 			s++;

^ permalink raw reply	[flat|nested] 31+ messages in thread

end of thread, other threads:[~2013-12-07  8:52 UTC | newest]

Thread overview: 31+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-11-26 18:53 [PATCH] Add support for leap seconds in zoneinfo files Laurent Bercot
2013-11-26 18:59 ` Laurent Bercot
2013-11-26 23:32 ` Rich Felker
2013-11-27  1:06   ` Rich Felker
2013-11-27  4:10   ` Laurent Bercot
2013-11-27  4:25     ` Rich Felker
2013-11-27  5:53       ` Laurent Bercot
2013-11-27 18:43         ` Szabolcs Nagy
2013-11-27 20:33           ` Laurent Bercot
2013-12-05  1:13             ` [PATCHv2] " Laurent Bercot
2013-12-05  5:18               ` Szabolcs Nagy
2013-12-05  8:58                 ` Laurent Bercot
2013-12-05 14:21                   ` Szabolcs Nagy
2013-12-05 14:43               ` Rich Felker
2013-12-05 16:31                 ` Laurent Bercot
2013-12-05 16:40                   ` Rich Felker
2013-12-06  0:36                     ` Laurent Bercot
2013-12-06  0:45                       ` Rich Felker
2013-12-06  1:15                         ` Laurent Bercot
2013-12-06  5:31                           ` Szabolcs Nagy
2013-12-06 10:48                             ` Laurent Bercot
2013-12-06 11:38                               ` Raphael Cohn
2013-12-06 23:29                                 ` Laurent Bercot
2013-12-07  2:31                                   ` Rich Felker
2013-12-07  4:02                                     ` Szabolcs Nagy
2013-12-07  8:52                                     ` Laurent Bercot
2013-12-06  6:29                           ` Rich Felker
2013-12-06 10:37                             ` Laurent Bercot
2013-12-06 12:50                               ` Rich Felker
2013-12-06 13:27                                 ` Szabolcs Nagy
2013-12-06 15:48                                   ` Rich Felker

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/musl/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).