time: Use 64-bit time values for time zone parsing
[glibc.git] / time / tzfile.c
blob2a385b92bcdefec08576a835293ccd10e5572019
1 /* Copyright (C) 1991-2018 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, see
16 <http://www.gnu.org/licenses/>. */
18 #include <assert.h>
19 #include <limits.h>
20 #include <stdio.h>
21 #include <stdio_ext.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <time.h>
25 #include <unistd.h>
26 #include <sys/stat.h>
27 #include <stdint.h>
29 #include <timezone/tzfile.h>
31 int __use_tzfile;
32 static dev_t tzfile_dev;
33 static ino64_t tzfile_ino;
34 static time_t tzfile_mtime;
36 struct ttinfo
38 long int offset; /* Seconds east of GMT. */
39 unsigned char isdst; /* Used to set tm_isdst. */
40 unsigned char idx; /* Index into `zone_names'. */
41 unsigned char isstd; /* Transition times are in standard time. */
42 unsigned char isgmt; /* Transition times are in GMT. */
45 struct leap
47 internal_time_t transition; /* Time the transition takes effect. */
48 long int change; /* Seconds of correction to apply. */
51 static size_t num_transitions;
52 libc_freeres_ptr (static internal_time_t *transitions);
53 static unsigned char *type_idxs;
54 static size_t num_types;
55 static struct ttinfo *types;
56 static char *zone_names;
57 static long int rule_stdoff;
58 static long int rule_dstoff;
59 static size_t num_leaps;
60 static struct leap *leaps;
61 static char *tzspec;
63 #include <endian.h>
64 #include <byteswap.h>
66 /* Decode the four bytes at PTR as a signed integer in network byte order. */
67 static inline int
68 __attribute ((always_inline))
69 decode (const void *ptr)
71 if (BYTE_ORDER == BIG_ENDIAN && sizeof (int) == 4)
72 return *(const int *) ptr;
73 if (sizeof (int) == 4)
74 return bswap_32 (*(const int *) ptr);
76 const unsigned char *p = ptr;
77 int result = *p & (1 << (CHAR_BIT - 1)) ? ~0 : 0;
79 result = (result << 8) | *p++;
80 result = (result << 8) | *p++;
81 result = (result << 8) | *p++;
82 result = (result << 8) | *p++;
84 return result;
88 static inline int64_t
89 __attribute ((always_inline))
90 decode64 (const void *ptr)
92 if ((BYTE_ORDER == BIG_ENDIAN))
93 return *(const int64_t *) ptr;
95 return bswap_64 (*(const int64_t *) ptr);
99 void
100 __tzfile_read (const char *file, size_t extra, char **extrap)
102 static const char default_tzdir[] = TZDIR;
103 size_t num_isstd, num_isgmt;
104 FILE *f;
105 struct tzhead tzhead;
106 size_t chars;
107 size_t i;
108 size_t total_size;
109 size_t types_idx;
110 size_t leaps_idx;
111 int was_using_tzfile = __use_tzfile;
112 int trans_width = 4;
113 size_t tzspec_len;
114 char *new = NULL;
116 _Static_assert (sizeof (internal_time_t) == 8,
117 "internal_time_t must be eight bytes");
119 __use_tzfile = 0;
121 if (file == NULL)
122 /* No user specification; use the site-wide default. */
123 file = TZDEFAULT;
124 else if (*file == '\0')
125 /* User specified the empty string; use UTC with no leap seconds. */
126 goto ret_free_transitions;
127 else
129 /* We must not allow to read an arbitrary file in a setuid
130 program. So we fail for any file which is not in the
131 directory hierachy starting at TZDIR
132 and which is not the system wide default TZDEFAULT. */
133 if (__libc_enable_secure
134 && ((*file == '/'
135 && memcmp (file, TZDEFAULT, sizeof TZDEFAULT)
136 && memcmp (file, default_tzdir, sizeof (default_tzdir) - 1))
137 || strstr (file, "../") != NULL))
138 /* This test is certainly a bit too restrictive but it should
139 catch all critical cases. */
140 goto ret_free_transitions;
143 if (*file != '/')
145 const char *tzdir;
147 tzdir = getenv ("TZDIR");
148 if (tzdir == NULL || *tzdir == '\0')
149 tzdir = default_tzdir;
150 if (__asprintf (&new, "%s/%s", tzdir, file) == -1)
151 goto ret_free_transitions;
152 file = new;
155 /* If we were already using tzfile, check whether the file changed. */
156 struct stat64 st;
157 if (was_using_tzfile
158 && stat64 (file, &st) == 0
159 && tzfile_ino == st.st_ino && tzfile_dev == st.st_dev
160 && tzfile_mtime == st.st_mtime)
161 goto done; /* Nothing to do. */
163 /* Note the file is opened with cancellation in the I/O functions
164 disabled and if available FD_CLOEXEC set. */
165 f = fopen (file, "rce");
166 if (f == NULL)
167 goto ret_free_transitions;
169 /* Get information about the file we are actually using. */
170 if (fstat64 (__fileno (f), &st) != 0)
172 fclose (f);
173 goto ret_free_transitions;
176 free ((void *) transitions);
177 transitions = NULL;
179 /* Remember the inode and device number and modification time. */
180 tzfile_dev = st.st_dev;
181 tzfile_ino = st.st_ino;
182 tzfile_mtime = st.st_mtime;
184 /* No threads reading this stream. */
185 __fsetlocking (f, FSETLOCKING_BYCALLER);
187 read_again:
188 if (__builtin_expect (__fread_unlocked ((void *) &tzhead, sizeof (tzhead),
189 1, f) != 1, 0)
190 || memcmp (tzhead.tzh_magic, TZ_MAGIC, sizeof (tzhead.tzh_magic)) != 0)
191 goto lose;
193 num_transitions = (size_t) decode (tzhead.tzh_timecnt);
194 num_types = (size_t) decode (tzhead.tzh_typecnt);
195 chars = (size_t) decode (tzhead.tzh_charcnt);
196 num_leaps = (size_t) decode (tzhead.tzh_leapcnt);
197 num_isstd = (size_t) decode (tzhead.tzh_ttisstdcnt);
198 num_isgmt = (size_t) decode (tzhead.tzh_ttisgmtcnt);
200 if (__glibc_unlikely (num_isstd > num_types || num_isgmt > num_types))
201 goto lose;
203 if (trans_width == 4 && tzhead.tzh_version[0] != '\0')
205 /* We use the 8-byte format. */
206 trans_width = 8;
208 /* Position the stream before the second header. */
209 size_t to_skip = (num_transitions * (4 + 1)
210 + num_types * 6
211 + chars
212 + num_leaps * 8
213 + num_isstd
214 + num_isgmt);
215 if (fseek (f, to_skip, SEEK_CUR) != 0)
216 goto lose;
218 goto read_again;
221 if (__builtin_expect (num_transitions
222 > ((SIZE_MAX - (__alignof__ (struct ttinfo) - 1))
223 / (sizeof (internal_time_t) + 1)), 0))
224 goto lose;
225 total_size = num_transitions * (sizeof (internal_time_t) + 1);
226 total_size = ((total_size + __alignof__ (struct ttinfo) - 1)
227 & ~(__alignof__ (struct ttinfo) - 1));
228 types_idx = total_size;
229 if (__builtin_expect (num_types
230 > (SIZE_MAX - total_size) / sizeof (struct ttinfo), 0))
231 goto lose;
232 total_size += num_types * sizeof (struct ttinfo);
233 if (__glibc_unlikely (chars > SIZE_MAX - total_size))
234 goto lose;
235 total_size += chars;
236 if (__builtin_expect (__alignof__ (struct leap) - 1
237 > SIZE_MAX - total_size, 0))
238 goto lose;
239 total_size = ((total_size + __alignof__ (struct leap) - 1)
240 & ~(__alignof__ (struct leap) - 1));
241 leaps_idx = total_size;
242 if (__builtin_expect (num_leaps
243 > (SIZE_MAX - total_size) / sizeof (struct leap), 0))
244 goto lose;
245 total_size += num_leaps * sizeof (struct leap);
246 tzspec_len = 0;
247 if (trans_width == 8)
249 off_t rem = st.st_size - __ftello (f);
250 if (__builtin_expect (rem < 0
251 || (size_t) rem < (num_transitions * (8 + 1)
252 + num_types * 6
253 + chars), 0))
254 goto lose;
255 tzspec_len = (size_t) rem - (num_transitions * (8 + 1)
256 + num_types * 6
257 + chars);
258 if (__builtin_expect (num_leaps > SIZE_MAX / 12
259 || tzspec_len < num_leaps * 12, 0))
260 goto lose;
261 tzspec_len -= num_leaps * 12;
262 if (__glibc_unlikely (tzspec_len < num_isstd))
263 goto lose;
264 tzspec_len -= num_isstd;
265 if (__glibc_unlikely (tzspec_len == 0 || tzspec_len - 1 < num_isgmt))
266 goto lose;
267 tzspec_len -= num_isgmt + 1;
268 if (__glibc_unlikely (tzspec_len == 0
269 || SIZE_MAX - total_size < tzspec_len))
270 goto lose;
272 if (__glibc_unlikely (SIZE_MAX - total_size - tzspec_len < extra))
273 goto lose;
275 /* Allocate enough memory including the extra block requested by the
276 caller. */
277 transitions = malloc (total_size + tzspec_len + extra);
278 if (transitions == NULL)
279 goto lose;
281 type_idxs = (unsigned char *) transitions + (num_transitions
282 * sizeof (internal_time_t));
283 types = (struct ttinfo *) ((char *) transitions + types_idx);
284 zone_names = (char *) types + num_types * sizeof (struct ttinfo);
285 leaps = (struct leap *) ((char *) transitions + leaps_idx);
286 if (trans_width == 8)
287 tzspec = (char *) leaps + num_leaps * sizeof (struct leap) + extra;
288 else
289 tzspec = NULL;
290 if (extra > 0)
291 *extrap = (char *) &leaps[num_leaps];
293 if (__builtin_expect (trans_width == 8, 1))
295 if (__builtin_expect (__fread_unlocked (transitions, trans_width + 1,
296 num_transitions, f)
297 != num_transitions, 0))
298 goto lose;
300 else
302 if (__builtin_expect (__fread_unlocked (transitions, 4,
303 num_transitions, f)
304 != num_transitions, 0)
305 || __builtin_expect (__fread_unlocked (type_idxs, 1, num_transitions,
306 f) != num_transitions, 0))
307 goto lose;
310 /* Check for bogus indices in the data file, so we can hereafter
311 safely use type_idxs[T] as indices into `types' and never crash. */
312 for (i = 0; i < num_transitions; ++i)
313 if (__glibc_unlikely (type_idxs[i] >= num_types))
314 goto lose;
316 if (trans_width == 4)
318 /* Decode the transition times, stored as 4-byte integers in
319 network (big-endian) byte order. We work from the end of the
320 array so as not to clobber the next element to be
321 processed. */
322 i = num_transitions;
323 while (i-- > 0)
324 transitions[i] = decode ((char *) transitions + i * 4);
326 else if (BYTE_ORDER != BIG_ENDIAN)
328 /* Decode the transition times, stored as 8-byte integers in
329 network (big-endian) byte order. */
330 for (i = 0; i < num_transitions; ++i)
331 transitions[i] = decode64 ((char *) transitions + i * 8);
334 for (i = 0; i < num_types; ++i)
336 unsigned char x[4];
337 int c;
338 if (__builtin_expect (__fread_unlocked (x, 1,
339 sizeof (x), f) != sizeof (x),
341 goto lose;
342 c = __getc_unlocked (f);
343 if (__glibc_unlikely ((unsigned int) c > 1u))
344 goto lose;
345 types[i].isdst = c;
346 c = __getc_unlocked (f);
347 if (__glibc_unlikely ((size_t) c > chars))
348 /* Bogus index in data file. */
349 goto lose;
350 types[i].idx = c;
351 types[i].offset = (long int) decode (x);
354 if (__glibc_unlikely (__fread_unlocked (zone_names, 1, chars, f) != chars))
355 goto lose;
357 for (i = 0; i < num_leaps; ++i)
359 unsigned char x[8];
360 if (__builtin_expect (__fread_unlocked (x, 1, trans_width, f)
361 != trans_width, 0))
362 goto lose;
363 if (trans_width == 4)
364 leaps[i].transition = decode (x);
365 else
366 leaps[i].transition = decode64 (x);
368 if (__glibc_unlikely (__fread_unlocked (x, 1, 4, f) != 4))
369 goto lose;
370 leaps[i].change = (long int) decode (x);
373 for (i = 0; i < num_isstd; ++i)
375 int c = __getc_unlocked (f);
376 if (__glibc_unlikely (c == EOF))
377 goto lose;
378 types[i].isstd = c != 0;
380 while (i < num_types)
381 types[i++].isstd = 0;
383 for (i = 0; i < num_isgmt; ++i)
385 int c = __getc_unlocked (f);
386 if (__glibc_unlikely (c == EOF))
387 goto lose;
388 types[i].isgmt = c != 0;
390 while (i < num_types)
391 types[i++].isgmt = 0;
393 /* Read the POSIX TZ-style information if possible. */
394 if (tzspec != NULL)
396 /* Skip over the newline first. */
397 if (__getc_unlocked (f) != '\n'
398 || (__fread_unlocked (tzspec, 1, tzspec_len - 1, f)
399 != tzspec_len - 1))
400 tzspec = NULL;
401 else
402 tzspec[tzspec_len - 1] = '\0';
405 /* Don't use an empty TZ string. */
406 if (tzspec != NULL && tzspec[0] == '\0')
407 tzspec = NULL;
409 fclose (f);
411 /* First "register" all timezone names. */
412 for (i = 0; i < num_types; ++i)
413 (void) __tzstring (&zone_names[types[i].idx]);
415 /* Find the standard and daylight time offsets used by the rule file.
416 We choose the offsets in the types of each flavor that are
417 transitioned to earliest in time. */
418 __tzname[0] = NULL;
419 __tzname[1] = NULL;
420 for (i = num_transitions; i > 0; )
422 int type = type_idxs[--i];
423 int dst = types[type].isdst;
425 if (__tzname[dst] == NULL)
427 int idx = types[type].idx;
429 __tzname[dst] = __tzstring (&zone_names[idx]);
431 if (__tzname[1 - dst] != NULL)
432 break;
435 if (__tzname[0] == NULL)
437 /* This should only happen if there are no transition rules.
438 In this case there should be only one single type. */
439 assert (num_types == 1);
440 __tzname[0] = __tzstring (zone_names);
442 if (__tzname[1] == NULL)
443 __tzname[1] = __tzname[0];
445 if (num_transitions == 0)
446 /* Use the first rule (which should also be the only one). */
447 rule_stdoff = rule_dstoff = types[0].offset;
448 else
450 int stdoff_set = 0, dstoff_set = 0;
451 rule_stdoff = rule_dstoff = 0;
452 i = num_transitions - 1;
455 if (!stdoff_set && !types[type_idxs[i]].isdst)
457 stdoff_set = 1;
458 rule_stdoff = types[type_idxs[i]].offset;
460 else if (!dstoff_set && types[type_idxs[i]].isdst)
462 dstoff_set = 1;
463 rule_dstoff = types[type_idxs[i]].offset;
465 if (stdoff_set && dstoff_set)
466 break;
468 while (i-- > 0);
470 if (!dstoff_set)
471 rule_dstoff = rule_stdoff;
474 __daylight = rule_stdoff != rule_dstoff;
475 __timezone = -rule_stdoff;
477 done:
478 __use_tzfile = 1;
479 free (new);
480 return;
482 lose:
483 fclose (f);
484 ret_free_transitions:
485 free (new);
486 free ((void *) transitions);
487 transitions = NULL;
490 /* The user specified a hand-made timezone, but not its DST rules.
491 We will use the names and offsets from the user, and the rules
492 from the TZDEFRULES file. */
494 void
495 __tzfile_default (const char *std, const char *dst,
496 long int stdoff, long int dstoff)
498 size_t stdlen = strlen (std) + 1;
499 size_t dstlen = strlen (dst) + 1;
500 size_t i;
501 int isdst;
502 char *cp;
504 __tzfile_read (TZDEFRULES, stdlen + dstlen, &cp);
505 if (!__use_tzfile)
506 return;
508 if (num_types < 2)
510 __use_tzfile = 0;
511 return;
514 /* Ignore the zone names read from the file and use the given ones
515 instead. */
516 __mempcpy (__mempcpy (cp, std, stdlen), dst, dstlen);
517 zone_names = cp;
519 /* Now there are only two zones, regardless of what the file contained. */
520 num_types = 2;
522 /* Now correct the transition times for the user-specified standard and
523 daylight offsets from GMT. */
524 isdst = 0;
525 for (i = 0; i < num_transitions; ++i)
527 struct ttinfo *trans_type = &types[type_idxs[i]];
529 /* We will use only types 0 (standard) and 1 (daylight).
530 Fix up this transition to point to whichever matches
531 the flavor of its original type. */
532 type_idxs[i] = trans_type->isdst;
534 if (trans_type->isgmt)
535 /* The transition time is in GMT. No correction to apply. */ ;
536 else if (isdst && !trans_type->isstd)
537 /* The type says this transition is in "local wall clock time", and
538 wall clock time as of the previous transition was DST. Correct
539 for the difference between the rule's DST offset and the user's
540 DST offset. */
541 transitions[i] += dstoff - rule_dstoff;
542 else
543 /* This transition is in "local wall clock time", and wall clock
544 time as of this iteration is non-DST. Correct for the
545 difference between the rule's standard offset and the user's
546 standard offset. */
547 transitions[i] += stdoff - rule_stdoff;
549 /* The DST state of "local wall clock time" for the next iteration is
550 as specified by this transition. */
551 isdst = trans_type->isdst;
554 /* Now that we adjusted the transitions to the requested offsets,
555 reset the rule_stdoff and rule_dstoff values appropriately. They
556 are used elsewhere. */
557 rule_stdoff = stdoff;
558 rule_dstoff = dstoff;
560 /* Reset types 0 and 1 to describe the user's settings. */
561 types[0].idx = 0;
562 types[0].offset = stdoff;
563 types[0].isdst = 0;
564 types[1].idx = stdlen;
565 types[1].offset = dstoff;
566 types[1].isdst = 1;
568 /* Reset the zone names to point to the user's names. */
569 __tzname[0] = (char *) std;
570 __tzname[1] = (char *) dst;
572 /* Set the timezone. */
573 __timezone = -types[0].offset;
575 /* Invalidate the tzfile attribute cache to force rereading
576 TZDEFRULES the next time it is used. */
577 tzfile_dev = 0;
578 tzfile_ino = 0;
579 tzfile_mtime = 0;
582 void
583 __tzfile_compute (internal_time_t timer, int use_localtime,
584 long int *leap_correct, int *leap_hit,
585 struct tm *tp)
587 size_t i;
589 if (use_localtime)
591 __tzname[0] = NULL;
592 __tzname[1] = NULL;
594 if (__glibc_unlikely (num_transitions == 0 || timer < transitions[0]))
596 /* TIMER is before any transition (or there are no transitions).
597 Choose the first non-DST type
598 (or the first if they're all DST types). */
599 i = 0;
600 while (i < num_types && types[i].isdst)
602 if (__tzname[1] == NULL)
603 __tzname[1] = __tzstring (&zone_names[types[i].idx]);
605 ++i;
608 if (i == num_types)
609 i = 0;
610 __tzname[0] = __tzstring (&zone_names[types[i].idx]);
611 if (__tzname[1] == NULL)
613 size_t j = i;
614 while (j < num_types)
615 if (types[j].isdst)
617 __tzname[1] = __tzstring (&zone_names[types[j].idx]);
618 break;
620 else
621 ++j;
624 else if (__glibc_unlikely (timer >= transitions[num_transitions - 1]))
626 if (__glibc_unlikely (tzspec == NULL))
628 use_last:
629 i = num_transitions;
630 goto found;
633 /* Parse the POSIX TZ-style string. */
634 __tzset_parse_tz (tzspec);
636 /* Convert to broken down structure. If this fails do not
637 use the string. */
639 time_t truncated = timer;
640 if (__glibc_unlikely (truncated != timer
641 || ! __offtime (&truncated, 0, tp)))
642 goto use_last;
645 /* Use the rules from the TZ string to compute the change.
646 timer fits into time_t due to the truncation check
647 above. */
648 __tz_compute (timer, tp, 1);
650 /* If tzspec comes from posixrules loaded by __tzfile_default,
651 override the STD and DST zone names with the ones user
652 requested in TZ envvar. */
653 if (__glibc_unlikely (zone_names == (char *) &leaps[num_leaps]))
655 assert (num_types == 2);
656 __tzname[0] = __tzstring (zone_names);
657 __tzname[1] = __tzstring (&zone_names[strlen (zone_names) + 1]);
660 goto leap;
662 else
664 /* Find the first transition after TIMER, and
665 then pick the type of the transition before it. */
666 size_t lo = 0;
667 size_t hi = num_transitions - 1;
668 /* Assume that DST is changing twice a year and guess
669 initial search spot from it. Half of a gregorian year
670 has on average 365.2425 * 86400 / 2 = 15778476 seconds.
671 The value i can be truncated if size_t is smaller than
672 internal_time_t, but this is harmless because it is just
673 a guess. */
674 i = (transitions[num_transitions - 1] - timer) / 15778476;
675 if (i < num_transitions)
677 i = num_transitions - 1 - i;
678 if (timer < transitions[i])
680 if (i < 10 || timer >= transitions[i - 10])
682 /* Linear search. */
683 while (timer < transitions[i - 1])
684 --i;
685 goto found;
687 hi = i - 10;
689 else
691 if (i + 10 >= num_transitions || timer < transitions[i + 10])
693 /* Linear search. */
694 while (timer >= transitions[i])
695 ++i;
696 goto found;
698 lo = i + 10;
702 /* Binary search. */
703 /* assert (timer >= transitions[lo] && timer < transitions[hi]); */
704 while (lo + 1 < hi)
706 i = (lo + hi) / 2;
707 if (timer < transitions[i])
708 hi = i;
709 else
710 lo = i;
712 i = hi;
714 found:
715 /* assert (timer >= transitions[i - 1]
716 && (i == num_transitions || timer < transitions[i])); */
717 __tzname[types[type_idxs[i - 1]].isdst]
718 = __tzstring (&zone_names[types[type_idxs[i - 1]].idx]);
719 size_t j = i;
720 while (j < num_transitions)
722 int type = type_idxs[j];
723 int dst = types[type].isdst;
724 int idx = types[type].idx;
726 if (__tzname[dst] == NULL)
728 __tzname[dst] = __tzstring (&zone_names[idx]);
730 if (__tzname[1 - dst] != NULL)
731 break;
734 ++j;
737 if (__glibc_unlikely (__tzname[0] == NULL))
738 __tzname[0] = __tzname[1];
740 i = type_idxs[i - 1];
743 struct ttinfo *info = &types[i];
744 __daylight = rule_stdoff != rule_dstoff;
745 __timezone = -rule_stdoff;
747 if (__tzname[0] == NULL)
749 /* This should only happen if there are no transition rules.
750 In this case there should be only one single type. */
751 assert (num_types == 1);
752 __tzname[0] = __tzstring (zone_names);
754 if (__tzname[1] == NULL)
755 /* There is no daylight saving time. */
756 __tzname[1] = __tzname[0];
757 tp->tm_isdst = info->isdst;
758 assert (strcmp (&zone_names[info->idx], __tzname[tp->tm_isdst]) == 0);
759 tp->tm_zone = __tzname[tp->tm_isdst];
760 tp->tm_gmtoff = info->offset;
763 leap:
764 *leap_correct = 0L;
765 *leap_hit = 0;
767 /* Find the last leap second correction transition time before TIMER. */
768 i = num_leaps;
770 if (i-- == 0)
771 return;
772 while (timer < leaps[i].transition);
774 /* Apply its correction. */
775 *leap_correct = leaps[i].change;
777 if (timer == leaps[i].transition && /* Exactly at the transition time. */
778 ((i == 0 && leaps[i].change > 0) ||
779 leaps[i].change > leaps[i - 1].change))
781 *leap_hit = 1;
782 while (i > 0
783 && leaps[i].transition == leaps[i - 1].transition + 1
784 && leaps[i].change == leaps[i - 1].change + 1)
786 ++*leap_hit;
787 --i;