summaryrefslogtreecommitdiff
path: root/lib/libc/time
diff options
context:
space:
mode:
authorTodd C. Miller <millert@cvs.openbsd.org>2005-08-09 16:12:13 +0000
committerTodd C. Miller <millert@cvs.openbsd.org>2005-08-09 16:12:13 +0000
commit815716551650631f7ff0ca9b922eac1343e7467f (patch)
treeaff9d3b5c88be4795be3187d58776a9a07885ad6 /lib/libc/time
parentb340a115a460e8a06962c171e24cef784339c68f (diff)
Re-add the change from tzcode2005c, this time with an added bounds
check from Arthur David Olson that fixes a possible infinite loop.
Diffstat (limited to 'lib/libc/time')
-rw-r--r--lib/libc/time/localtime.c66
1 files changed, 46 insertions, 20 deletions
diff --git a/lib/libc/time/localtime.c b/lib/libc/time/localtime.c
index 77ee0461a85..f403bd05e79 100644
--- a/lib/libc/time/localtime.c
+++ b/lib/libc/time/localtime.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: localtime.c,v 1.29 2005/08/09 03:22:06 millert Exp $ */
+/* $OpenBSD: localtime.c,v 1.30 2005/08/09 16:12:12 millert Exp $ */
/*
** This file is in the public domain, so clarified as of
** 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov).
@@ -1539,10 +1539,11 @@ const int do_norm_secs;
{
register const struct state * sp;
register int dir;
- register int bits;
register int i, j;
register int saved_seconds;
register long li;
+ register time_t lo;
+ register time_t hi;
long y;
time_t newt;
time_t t;
@@ -1616,28 +1617,53 @@ const int do_norm_secs;
yourtm.tm_sec = 0;
}
/*
- ** Divide the search space in half
- ** (this works whether time_t is signed or unsigned).
+ ** Do a binary search (this works whatever time_t's type is).
*/
- bits = TYPE_BIT(time_t) - 1;
- /*
- ** If time_t is signed, then 0 is just above the median,
- ** assuming two's complement arithmetic.
- ** If time_t is unsigned, then (1 << bits) is just above the median.
- */
- t = TYPE_SIGNED(time_t) ? 0 : (((unsigned long) 1) << bits);
+ if (!TYPE_SIGNED(time_t)) {
+ lo = 0;
+ hi = lo - 1;
+ } else if (!TYPE_INTEGRAL(time_t)) {
+ if (sizeof(time_t) > sizeof(float))
+ hi = (time_t) DBL_MAX;
+ else hi = (time_t) FLT_MAX;
+ lo = -hi;
+ } else {
+ lo = 1;
+ for (i = 0; i < (int) TYPE_BIT(time_t) - 1; ++i)
+ lo *= 2;
+ hi = -(lo + 1);
+ }
for ( ; ; ) {
- if ((*funcp)(&t, offset, &mytm) == NULL)
- return WRONG; /* XXX probably wrong */
- dir = tmcomp(&mytm, &yourtm);
+ t = lo / 2 + hi / 2;
+ if (t < lo)
+ t = lo;
+ else if (t > hi)
+ t = hi;
+ if ((*funcp)(&t, offset, &mytm) == NULL) {
+ /*
+ ** Assume that t is too extreme to be represented in
+ ** a struct tm; arrange things so that it is less
+ ** extreme on the next pass.
+ */
+ dir = (t > 0) ? 1 : -1;
+ } else dir = tmcomp(&mytm, &yourtm);
if (dir != 0) {
- if (bits-- < 0)
+ if (t == lo) {
+ ++t;
+ if (t <= lo)
+ return WRONG;
+ ++lo;
+ } else if (t == hi) {
+ --t;
+ if (t >= hi)
+ return WRONG;
+ --hi;
+ }
+ if (lo > hi)
return WRONG;
- if (bits < 0)
- --t; /* may be needed if new t is minimal */
- else if (dir > 0)
- t -= ((long) 1) << bits;
- else t += ((long) 1) << bits;
+ if (dir > 0)
+ hi = t;
+ else lo = t;
continue;
}
if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)