Thu Jan 6 02:41:34 2011 UTC ()
Since localsub and gmtsub are called recursively to search for the local
time, setting EOVERFLOW at the inmost level will unfortunately persist,
even if later calls to those functions succeed. Move the EOVERFLOW setting
to the top level calls.


(christos)
diff -r1.50 -r1.51 src/lib/libc/time/localtime.c

cvs diff -r1.50 -r1.51 src/lib/libc/time/localtime.c (expand / switch to unified diff)

--- src/lib/libc/time/localtime.c 2010/12/17 23:11:57 1.50
+++ src/lib/libc/time/localtime.c 2011/01/06 02:41:34 1.51
@@ -1,26 +1,26 @@ @@ -1,26 +1,26 @@
1/* $NetBSD: localtime.c,v 1.50 2010/12/17 23:11:57 christos Exp $ */ 1/* $NetBSD: localtime.c,v 1.51 2011/01/06 02:41:34 christos Exp $ */
2 2
3/* 3/*
4** This file is in the public domain, so clarified as of 4** This file is in the public domain, so clarified as of
5** 1996-06-05 by Arthur David Olson. 5** 1996-06-05 by Arthur David Olson.
6*/ 6*/
7 7
8#include <sys/cdefs.h> 8#include <sys/cdefs.h>
9#if defined(LIBC_SCCS) && !defined(lint) 9#if defined(LIBC_SCCS) && !defined(lint)
10#if 0 10#if 0
11static char elsieid[] = "@(#)localtime.c 8.9"; 11static char elsieid[] = "@(#)localtime.c 8.9";
12#else 12#else
13__RCSID("$NetBSD: localtime.c,v 1.50 2010/12/17 23:11:57 christos Exp $"); 13__RCSID("$NetBSD: localtime.c,v 1.51 2011/01/06 02:41:34 christos Exp $");
14#endif 14#endif
15#endif /* LIBC_SCCS and not lint */ 15#endif /* LIBC_SCCS and not lint */
16 16
17/* 17/*
18** Leap second handling from Bradley White. 18** Leap second handling from Bradley White.
19** POSIX-style TZ environment variable handling from Guy Harris. 19** POSIX-style TZ environment variable handling from Guy Harris.
20*/ 20*/
21 21
22/*LINTLIBRARY*/ 22/*LINTLIBRARY*/
23 23
24#include "namespace.h" 24#include "namespace.h"
25#include "private.h" 25#include "private.h"
26#include "tzfile.h" 26#include "tzfile.h"
@@ -1338,43 +1338,39 @@ localsub(const timezone_t sp, const time @@ -1338,43 +1338,39 @@ localsub(const timezone_t sp, const time
1338 --seconds; 1338 --seconds;
1339 tcycles = seconds / YEARSPERREPEAT / AVGSECSPERYEAR; 1339 tcycles = seconds / YEARSPERREPEAT / AVGSECSPERYEAR;
1340 ++tcycles; 1340 ++tcycles;
1341 icycles = tcycles; 1341 icycles = tcycles;
1342 if (tcycles - icycles >= 1 || icycles - tcycles >= 1) 1342 if (tcycles - icycles >= 1 || icycles - tcycles >= 1)
1343 return NULL; 1343 return NULL;
1344 seconds = (time_t) icycles; 1344 seconds = (time_t) icycles;
1345 seconds *= YEARSPERREPEAT; 1345 seconds *= YEARSPERREPEAT;
1346 seconds *= AVGSECSPERYEAR; 1346 seconds *= AVGSECSPERYEAR;
1347 if (t < sp->ats[0]) 1347 if (t < sp->ats[0])
1348 newt += seconds; 1348 newt += seconds;
1349 else newt -= seconds; 1349 else newt -= seconds;
1350 if (newt < sp->ats[0] || 1350 if (newt < sp->ats[0] ||
1351 newt > sp->ats[sp->timecnt - 1]) { 1351 newt > sp->ats[sp->timecnt - 1])
1352 errno = EOVERFLOW; 
1353 return NULL; /* "cannot happen" */ 1352 return NULL; /* "cannot happen" */
1354 } 
1355 result = localsub(sp, &newt, offset, tmp); 1353 result = localsub(sp, &newt, offset, tmp);
1356 if (result == tmp) { 1354 if (result == tmp) {
1357 time_t newy; 1355 time_t newy;
1358 1356
1359 newy = tmp->tm_year; 1357 newy = tmp->tm_year;
1360 if (t < sp->ats[0]) 1358 if (t < sp->ats[0])
1361 newy -= (time_t)icycles * YEARSPERREPEAT; 1359 newy -= (time_t)icycles * YEARSPERREPEAT;
1362 else newy += (time_t)icycles * YEARSPERREPEAT; 1360 else newy += (time_t)icycles * YEARSPERREPEAT;
1363 tmp->tm_year = (int)newy; 1361 tmp->tm_year = (int)newy;
1364 if (tmp->tm_year != newy) { 1362 if (tmp->tm_year != newy)
1365 errno = EOVERFLOW; 
1366 return NULL; 1363 return NULL;
1367 } 
1368 } 1364 }
1369 return result; 1365 return result;
1370 } 1366 }
1371 if (sp->timecnt == 0 || t < sp->ats[0]) { 1367 if (sp->timecnt == 0 || t < sp->ats[0]) {
1372 i = 0; 1368 i = 0;
1373 while (sp->ttis[i].tt_isdst) 1369 while (sp->ttis[i].tt_isdst)
1374 if (++i >= sp->typecnt) { 1370 if (++i >= sp->typecnt) {
1375 i = 0; 1371 i = 0;
1376 break; 1372 break;
1377 } 1373 }
1378 } else { 1374 } else {
1379 int lo = 1; 1375 int lo = 1;
1380 int hi = sp->timecnt; 1376 int hi = sp->timecnt;
@@ -1418,29 +1414,32 @@ localtime_r(const time_t * __restrict ti @@ -1418,29 +1414,32 @@ localtime_r(const time_t * __restrict ti
1418 return tmp; 1414 return tmp;
1419} 1415}
1420 1416
1421struct tm * 1417struct tm *
1422localtime(const time_t *const timep) 1418localtime(const time_t *const timep)
1423{ 1419{
1424 return localtime_r(timep, &tm); 1420 return localtime_r(timep, &tm);
1425} 1421}
1426 1422
1427struct tm * 1423struct tm *
1428localtime_rz(const timezone_t sp, const time_t * __restrict timep, struct tm *tmp) 1424localtime_rz(const timezone_t sp, const time_t * __restrict timep, struct tm *tmp)
1429{ 1425{
1430 if (sp == NULL) 1426 if (sp == NULL)
1431 return gmtsub(NULL, timep, 0L, tmp); 1427 tmp = gmtsub(NULL, timep, 0L, tmp);
1432 else 1428 else
1433 return localsub(sp, timep, 0L, tmp); 1429 tmp = localsub(sp, timep, 0L, tmp);
 1430 if (tmp == NULL)
 1431 errno = EOVERFLOW;
 1432 return tmp;
1434} 1433}
1435 1434
1436/* 1435/*
1437** gmtsub is to gmtime as localsub is to localtime. 1436** gmtsub is to gmtime as localsub is to localtime.
1438*/ 1437*/
1439 1438
1440static struct tm * 1439static struct tm *
1441gmtsub(const timezone_t sp, const time_t * const timep, const long offset, 1440gmtsub(const timezone_t sp, const time_t * const timep, const long offset,
1442 struct tm *const tmp) 1441 struct tm *const tmp)
1443{ 1442{
1444 struct tm * result; 1443 struct tm * result;
1445#ifdef _REENTRANT 1444#ifdef _REENTRANT
1446 static mutex_t gmt_mutex = MUTEX_INITIALIZER; 1445 static mutex_t gmt_mutex = MUTEX_INITIALIZER;
@@ -1557,37 +1556,33 @@ timesub(const timezone_t sp, const time_ @@ -1557,37 +1556,33 @@ timesub(const timezone_t sp, const time_
1557 } 1556 }
1558 } 1557 }
1559 y = EPOCH_YEAR; 1558 y = EPOCH_YEAR;
1560 tdays = *timep / SECSPERDAY; 1559 tdays = *timep / SECSPERDAY;
1561 rem = (long) (*timep - tdays * SECSPERDAY); 1560 rem = (long) (*timep - tdays * SECSPERDAY);
1562 while (tdays < 0 || tdays >= year_lengths[isleap(y)]) { 1561 while (tdays < 0 || tdays >= year_lengths[isleap(y)]) {
1563 int newy; 1562 int newy;
1564 time_t tdelta; 1563 time_t tdelta;
1565 int idelta; 1564 int idelta;
1566 int leapdays; 1565 int leapdays;
1567 1566
1568 tdelta = tdays / DAYSPERLYEAR; 1567 tdelta = tdays / DAYSPERLYEAR;
1569 idelta = (int) tdelta; 1568 idelta = (int) tdelta;
1570 if (tdelta - idelta >= 1 || idelta - tdelta >= 1) { 1569 if (tdelta - idelta >= 1 || idelta - tdelta >= 1)
1571 errno = EOVERFLOW; 
1572 return NULL; 1570 return NULL;
1573 } 
1574 if (idelta == 0) 1571 if (idelta == 0)
1575 idelta = (tdays < 0) ? -1 : 1; 1572 idelta = (tdays < 0) ? -1 : 1;
1576 newy = y; 1573 newy = y;
1577 if (increment_overflow(&newy, idelta)) { 1574 if (increment_overflow(&newy, idelta))
1578 errno = EOVERFLOW; 
1579 return NULL; 1575 return NULL;
1580 } 
1581 leapdays = leaps_thru_end_of(newy - 1) - 1576 leapdays = leaps_thru_end_of(newy - 1) -
1582 leaps_thru_end_of(y - 1); 1577 leaps_thru_end_of(y - 1);
1583 tdays -= ((time_t) newy - y) * DAYSPERNYEAR; 1578 tdays -= ((time_t) newy - y) * DAYSPERNYEAR;
1584 tdays -= leapdays; 1579 tdays -= leapdays;
1585 y = newy; 1580 y = newy;
1586 } 1581 }
1587 { 1582 {
1588 long seconds; 1583 long seconds;
1589 1584
1590 seconds = tdays * SECSPERDAY + 0.5; 1585 seconds = tdays * SECSPERDAY + 0.5;
1591 tdays = seconds / SECSPERDAY; 1586 tdays = seconds / SECSPERDAY;
1592 rem += (long) (seconds - tdays * SECSPERDAY); 1587 rem += (long) (seconds - tdays * SECSPERDAY);
1593 } 1588 }
@@ -1595,44 +1590,38 @@ timesub(const timezone_t sp, const time_ @@ -1595,44 +1590,38 @@ timesub(const timezone_t sp, const time_
1595 ** Given the range, we can now fearlessly cast... 1590 ** Given the range, we can now fearlessly cast...
1596 */ 1591 */
1597 idays = (int) tdays; 1592 idays = (int) tdays;
1598 rem += offset - corr; 1593 rem += offset - corr;
1599 while (rem < 0) { 1594 while (rem < 0) {
1600 rem += SECSPERDAY; 1595 rem += SECSPERDAY;
1601 --idays; 1596 --idays;
1602 } 1597 }
1603 while (rem >= SECSPERDAY) { 1598 while (rem >= SECSPERDAY) {
1604 rem -= SECSPERDAY; 1599 rem -= SECSPERDAY;
1605 ++idays; 1600 ++idays;
1606 } 1601 }
1607 while (idays < 0) { 1602 while (idays < 0) {
1608 if (increment_overflow(&y, -1)) { 1603 if (increment_overflow(&y, -1))
1609 errno = EOVERFLOW; 
1610 return NULL; 1604 return NULL;
1611 } 
1612 idays += year_lengths[isleap(y)]; 1605 idays += year_lengths[isleap(y)];
1613 } 1606 }
1614 while (idays >= year_lengths[isleap(y)]) { 1607 while (idays >= year_lengths[isleap(y)]) {
1615 idays -= year_lengths[isleap(y)]; 1608 idays -= year_lengths[isleap(y)];
1616 if (increment_overflow(&y, 1)) { 1609 if (increment_overflow(&y, 1))
1617 errno = EOVERFLOW; 
1618 return NULL; 1610 return NULL;
1619 } 
1620 } 1611 }
1621 tmp->tm_year = y; 1612 tmp->tm_year = y;
1622 if (increment_overflow(&tmp->tm_year, -TM_YEAR_BASE)) { 1613 if (increment_overflow(&tmp->tm_year, -TM_YEAR_BASE))
1623 errno = EOVERFLOW; 
1624 return NULL; 1614 return NULL;
1625 } 
1626 tmp->tm_yday = idays; 1615 tmp->tm_yday = idays;
1627 /* 1616 /*
1628 ** The "extra" mods below avoid overflow problems. 1617 ** The "extra" mods below avoid overflow problems.
1629 */ 1618 */
1630 tmp->tm_wday = EPOCH_WDAY + 1619 tmp->tm_wday = EPOCH_WDAY +
1631 ((y - EPOCH_YEAR) % DAYSPERWEEK) * 1620 ((y - EPOCH_YEAR) % DAYSPERWEEK) *
1632 (DAYSPERNYEAR % DAYSPERWEEK) + 1621 (DAYSPERNYEAR % DAYSPERWEEK) +
1633 leaps_thru_end_of(y - 1) - 1622 leaps_thru_end_of(y - 1) -
1634 leaps_thru_end_of(EPOCH_YEAR - 1) + 1623 leaps_thru_end_of(EPOCH_YEAR - 1) +
1635 idays; 1624 idays;
1636 tmp->tm_wday %= DAYSPERWEEK; 1625 tmp->tm_wday %= DAYSPERWEEK;
1637 if (tmp->tm_wday < 0) 1626 if (tmp->tm_wday < 0)
1638 tmp->tm_wday += DAYSPERWEEK; 1627 tmp->tm_wday += DAYSPERWEEK;
@@ -1692,27 +1681,27 @@ ctime_rz(const timezone_t sp, const time @@ -1692,27 +1681,27 @@ ctime_rz(const timezone_t sp, const time
1692 return asctime_r(rtm, buf); 1681 return asctime_r(rtm, buf);
1693} 1682}
1694 1683
1695/* 1684/*
1696** Adapted from code provided by Robert Elz, who writes: 1685** Adapted from code provided by Robert Elz, who writes:
1697** The "best" way to do mktime I think is based on an idea of Bob 1686** The "best" way to do mktime I think is based on an idea of Bob
1698** Kridle's (so its said...) from a long time ago. 1687** Kridle's (so its said...) from a long time ago.
1699** It does a binary search of the time_t space. Since time_t's are 1688** It does a binary search of the time_t space. Since time_t's are
1700** just 32 bits, its a max of 32 iterations (even at 64 bits it 1689** just 32 bits, its a max of 32 iterations (even at 64 bits it
1701** would still be very reasonable). 1690** would still be very reasonable).
1702*/ 1691*/
1703 1692
1704#ifndef WRONG 1693#ifndef WRONG
1705#define WRONG (-1) 1694#define WRONG ((time_t)-1)
1706#endif /* !defined WRONG */ 1695#endif /* !defined WRONG */
1707 1696
1708/* 1697/*
1709** Simplified normalize logic courtesy Paul Eggert. 1698** Simplified normalize logic courtesy Paul Eggert.
1710*/ 1699*/
1711 1700
1712static int 1701static int
1713increment_overflow(int *number, int delta) 1702increment_overflow(int *number, int delta)
1714{ 1703{
1715 int number0; 1704 int number0;
1716 1705
1717 number0 = *number; 1706 number0 = *number;
1718 *number += delta; 1707 *number += delta;
@@ -1933,29 +1922,31 @@ time2sub(const timezone_t sp, struct tm  @@ -1933,29 +1922,31 @@ time2sub(const timezone_t sp, struct tm
1933 ** We have a match. 1922 ** We have a match.
1934 */ 1923 */
1935 t = newt; 1924 t = newt;
1936 goto label; 1925 goto label;
1937 } 1926 }
1938 } 1927 }
1939 return WRONG; 1928 return WRONG;
1940 } 1929 }
1941label: 1930label:
1942 newt = t + saved_seconds; 1931 newt = t + saved_seconds;
1943 if ((newt < t) != (saved_seconds < 0)) 1932 if ((newt < t) != (saved_seconds < 0))
1944 return WRONG; 1933 return WRONG;
1945 t = newt; 1934 t = newt;
1946 if ((*funcp)(sp, &t, offset, tmp)) 1935 if ((*funcp)(sp, &t, offset, tmp)) {
1947 *okayp = TRUE; 1936 *okayp = TRUE;
1948 return t; 1937 return t;
 1938 } else
 1939 return WRONG;
1949} 1940}
1950 1941
1951static time_t 1942static time_t
1952time2(const timezone_t sp, struct tm *const tmp, subfun_t funcp, 1943time2(const timezone_t sp, struct tm *const tmp, subfun_t funcp,
1953 const long offset, int *const okayp) 1944 const long offset, int *const okayp)
1954{ 1945{
1955 time_t t; 1946 time_t t;
1956 1947
1957 /* 1948 /*
1958 ** First try without normalization of seconds 1949 ** First try without normalization of seconds
1959 ** (in case tm_sec contains a value associated with a leap second). 1950 ** (in case tm_sec contains a value associated with a leap second).
1960 ** If that fails, try with normalization of seconds. 1951 ** If that fails, try with normalization of seconds.
1961 */ 1952 */
@@ -2023,30 +2014,34 @@ time1(const timezone_t sp, struct tm *co @@ -2023,30 +2014,34 @@ time1(const timezone_t sp, struct tm *co
2023 if (okay) 2014 if (okay)
2024 return t; 2015 return t;
2025 tmp->tm_sec -= (int)(sp->ttis[otheri].tt_gmtoff - 2016 tmp->tm_sec -= (int)(sp->ttis[otheri].tt_gmtoff -
2026 sp->ttis[samei].tt_gmtoff); 2017 sp->ttis[samei].tt_gmtoff);
2027 tmp->tm_isdst = !tmp->tm_isdst; 2018 tmp->tm_isdst = !tmp->tm_isdst;
2028 } 2019 }
2029 } 2020 }
2030 return WRONG; 2021 return WRONG;
2031} 2022}
2032 2023
2033time_t 2024time_t
2034mktime_z(const timezone_t sp, struct tm *tmp) 2025mktime_z(const timezone_t sp, struct tm *tmp)
2035{ 2026{
 2027 time_t t;
2036 if (sp == NULL) 2028 if (sp == NULL)
2037 return time1(NULL, tmp, gmtsub, 0L); 2029 t = time1(NULL, tmp, gmtsub, 0L);
2038 else 2030 else
2039 return time1(sp, tmp, localsub, 0L); 2031 t = time1(sp, tmp, localsub, 0L);
 2032 if (t == WRONG)
 2033 errno = EOVERFLOW;
 2034 return t;
2040} 2035}
2041 2036
2042time_t 2037time_t
2043mktime(struct tm * const tmp) 2038mktime(struct tm * const tmp)
2044{ 2039{
2045 time_t result; 2040 time_t result;
2046 2041
2047 rwlock_wrlock(&lcl_lock); 2042 rwlock_wrlock(&lcl_lock);
2048 tzset_unlocked(); 2043 tzset_unlocked();
2049 result = mktime_z(lclptr, tmp); 2044 result = mktime_z(lclptr, tmp);
2050 rwlock_unlock(&lcl_lock); 2045 rwlock_unlock(&lcl_lock);
2051 return result; 2046 return result;
2052} 2047}
@@ -2061,35 +2056,45 @@ timelocal_z(const timezone_t sp, struct  @@ -2061,35 +2056,45 @@ timelocal_z(const timezone_t sp, struct
2061 return mktime_z(sp, tmp); 2056 return mktime_z(sp, tmp);
2062} 2057}
2063 2058
2064time_t 2059time_t
2065timelocal(struct tm *const tmp) 2060timelocal(struct tm *const tmp)
2066{ 2061{
2067 tmp->tm_isdst = -1; /* in case it wasn't initialized */ 2062 tmp->tm_isdst = -1; /* in case it wasn't initialized */
2068 return mktime(tmp); 2063 return mktime(tmp);
2069} 2064}
2070 2065
2071time_t 2066time_t
2072timegm(struct tm *const tmp) 2067timegm(struct tm *const tmp)
2073{ 2068{
 2069 time_t t;
 2070
2074 tmp->tm_isdst = 0; 2071 tmp->tm_isdst = 0;
2075 return time1(gmtptr, tmp, gmtsub, 0L); 2072 t = time1(gmtptr, tmp, gmtsub, 0L);
 2073 if (t == WRONG)
 2074 errno = EOVERFLOW;
 2075 return t;
2076} 2076}
2077 2077
2078time_t 2078time_t
2079timeoff(struct tm *const tmp, const long offset) 2079timeoff(struct tm *const tmp, const long offset)
2080{ 2080{
 2081 time_t t;
 2082
2081 tmp->tm_isdst = 0; 2083 tmp->tm_isdst = 0;
2082 return time1(gmtptr, tmp, gmtsub, offset); 2084 t = time1(gmtptr, tmp, gmtsub, offset);
 2085 if (t == WRONG)
 2086 errno = EOVERFLOW;
 2087 return t;
2083} 2088}
2084 2089
2085#endif /* defined STD_INSPIRED */ 2090#endif /* defined STD_INSPIRED */
2086 2091
2087#ifdef CMUCS 2092#ifdef CMUCS
2088 2093
2089/* 2094/*
2090** The following is supplied for compatibility with 2095** The following is supplied for compatibility with
2091** previous versions of the CMUCS runtime library. 2096** previous versions of the CMUCS runtime library.
2092*/ 2097*/
2093 2098
2094long 2099long
2095gtime(struct tm *const tmp) 2100gtime(struct tm *const tmp)