From: Laurent Bercot <ska-dietlibc@skarnet.org>
To: musl@lists.openwall.com
Subject: [PATCH] Add support for leap seconds in zoneinfo files
Date: Tue, 26 Nov 2013 18:53:41 +0000 [thread overview]
Message-ID: <5294EE35.8040603@skarnet.org> (raw)
[-- 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++;
next reply other threads:[~2013-11-26 18:53 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-11-26 18:53 Laurent Bercot [this message]
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
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=5294EE35.8040603@skarnet.org \
--to=ska-dietlibc@skarnet.org \
--cc=musl@lists.openwall.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).