diff options
author | Todd C. Miller <millert@cvs.openbsd.org> | 2005-08-09 16:12:13 +0000 |
---|---|---|
committer | Todd C. Miller <millert@cvs.openbsd.org> | 2005-08-09 16:12:13 +0000 |
commit | 815716551650631f7ff0ca9b922eac1343e7467f (patch) | |
tree | aff9d3b5c88be4795be3187d58776a9a07885ad6 /lib/libc/time | |
parent | b340a115a460e8a06962c171e24cef784339c68f (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.c | 66 |
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) |