diff options
Diffstat (limited to 'localtime.c')
| -rw-r--r-- | localtime.c | 115 |
1 files changed, 51 insertions, 64 deletions
diff --git a/localtime.c b/localtime.c index 1d22d35146b7..818d58f8e7be 100644 --- a/localtime.c +++ b/localtime.c @@ -28,10 +28,6 @@ static int lock(void) { return 0; } static void unlock(void) { } #endif -#ifndef TZ_ABBR_MAX_LEN -# define TZ_ABBR_MAX_LEN 16 -#endif /* !defined TZ_ABBR_MAX_LEN */ - #ifndef TZ_ABBR_CHAR_SET # define TZ_ABBR_CHAR_SET \ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._" @@ -109,12 +105,11 @@ static char const UNSPEC[] = "-00"; for ttunspecified to work without crashing. */ enum { CHARS_EXTRA = max(sizeof UNSPEC, 2) - 1 }; -#ifdef TZNAME_MAX -# define MY_TZNAME_MAX TZNAME_MAX -#endif /* defined TZNAME_MAX */ -#ifndef TZNAME_MAX -# define MY_TZNAME_MAX 255 -#endif /* !defined TZNAME_MAX */ +/* Limit to time zone abbreviation length in POSIX-style TZ strings. + This is distinct from TZ_MAX_CHARS, which limits TZif file contents. */ +#ifndef TZNAME_MAXIMUM +# define TZNAME_MAXIMUM 255 +#endif struct state { int leapcnt; @@ -127,7 +122,7 @@ struct state { unsigned char types[TZ_MAX_TIMES]; struct ttinfo ttis[TZ_MAX_TYPES]; char chars[max(max(TZ_MAX_CHARS + CHARS_EXTRA, sizeof "UTC"), - 2 * (MY_TZNAME_MAX + 1))]; + 2 * (TZNAME_MAXIMUM + 1))]; struct lsinfo lsis[TZ_MAX_LEAPS]; /* The time type to use for early times or if no transitions. @@ -186,9 +181,14 @@ static int lcl_is_set; ** ctime, gmtime, localtime] return values in one of two static ** objects: a broken-down time structure and an array of char. ** Thanks to Paul Eggert for noting this. +** +** This requirement was removed in C99, so support it only if requested, +** as support is more likely to lead to bugs in badly written programs. */ +#if SUPPORT_C89 static struct tm tm; +#endif #if 2 <= HAVE_TZNAME + TZ_TIME_T char * tzname[2] = { @@ -340,27 +340,28 @@ settzname(void) #endif } -static void +/* Replace bogus characters in time zone abbreviations. + Return 0 on success, an errno value if a time zone abbreviation is + too long. */ +static int scrub_abbrs(struct state *sp) { int i; - /* - ** First, replace bogus characters. - */ + + /* Reject overlong abbreviations. */ + for (i = 0; i < sp->charcnt - (TZNAME_MAXIMUM + 1); ) { + int len = strlen(&sp->chars[i]); + if (TZNAME_MAXIMUM < len) + return EOVERFLOW; + i += len + 1; + } + + /* Replace bogus characters. */ for (i = 0; i < sp->charcnt; ++i) if (strchr(TZ_ABBR_CHAR_SET, sp->chars[i]) == NULL) sp->chars[i] = TZ_ABBR_ERR_CHAR; - /* - ** Second, truncate long abbreviations. - */ - for (i = 0; i < sp->typecnt; ++i) { - register const struct ttinfo * const ttisp = &sp->ttis[i]; - char *cp = &sp->chars[ttisp->tt_desigidx]; - if (strlen(cp) > TZ_ABBR_MAX_LEN && - strcmp(cp, GRANDPARENTED) != 0) - *(cp + TZ_ABBR_MAX_LEN) = '\0'; - } + return 0; } /* Input buffer for data read from a compiled tz file. */ @@ -838,7 +839,7 @@ is_digit(char c) ** Return a pointer to that character. */ -static ATTRIBUTE_REPRODUCIBLE const char * +ATTRIBUTE_REPRODUCIBLE static const char * getzname(register const char *strp) { register char c; @@ -859,7 +860,7 @@ getzname(register const char *strp) ** We don't do any checking here; checking is done later in common-case code. */ -static ATTRIBUTE_REPRODUCIBLE const char * +ATTRIBUTE_REPRODUCIBLE static const char * getqzname(register const char *strp, const int delim) { register int c; @@ -1139,14 +1140,12 @@ tzparse(const char *name, struct state *sp, struct state *basep) name = getzname(name); stdlen = name - stdname; } - if (!stdlen) + if (! (0 < stdlen && stdlen <= TZNAME_MAXIMUM)) return false; name = getoffset(name, &stdoffset); if (name == NULL) return false; charcnt = stdlen + 1; - if (sizeof sp->chars < charcnt) - return false; if (basep) { if (0 < basep->timecnt) atlo = basep->ats[basep->timecnt - 1]; @@ -1173,11 +1172,9 @@ tzparse(const char *name, struct state *sp, struct state *basep) name = getzname(name); dstlen = name - dstname; /* length of DST abbr. */ } - if (!dstlen) + if (! (0 < dstlen && dstlen <= TZNAME_MAXIMUM)) return false; charcnt += dstlen + 1; - if (sizeof sp->chars < charcnt) - return false; if (*name != '\0' && *name != ',' && *name != ';') { name = getoffset(name, &dstoffset); if (name == NULL) @@ -1420,7 +1417,7 @@ zoneinit(struct state *sp, char const *name) if (err != 0 && name && name[0] != ':' && tzparse(name, sp, NULL)) err = 0; if (err == 0) - scrub_abbrs(sp); + err = scrub_abbrs(sp); return err; } } @@ -1623,7 +1620,8 @@ localsub(struct state const *sp, time_t const *timep, int_fast32_t setname, #if NETBSD_INSPIRED struct tm * -localtime_rz(struct state *sp, time_t const *timep, struct tm *tmp) +localtime_rz(struct state *restrict sp, time_t const *restrict timep, + struct tm *restrict tmp) { return localsub(sp, timep, 0, tmp); } @@ -1648,11 +1646,14 @@ localtime_tzset(time_t const *timep, struct tm *tmp, bool setname) struct tm * localtime(const time_t *timep) { +#if !SUPPORT_C89 + static struct tm tm; +#endif return localtime_tzset(timep, &tm, true); } struct tm * -localtime_r(const time_t *timep, struct tm *tmp) +localtime_r(const time_t *restrict timep, struct tm *restrict tmp) { return localtime_tzset(timep, tmp, false); } @@ -1685,7 +1686,7 @@ gmtsub(ATTRIBUTE_MAYBE_UNUSED struct state const *sp, time_t const *timep, */ struct tm * -gmtime_r(const time_t *timep, struct tm *tmp) +gmtime_r(time_t const *restrict timep, struct tm *restrict tmp) { gmtcheck(); return gmtsub(gmtptr, timep, 0, tmp); @@ -1694,19 +1695,26 @@ gmtime_r(const time_t *timep, struct tm *tmp) struct tm * gmtime(const time_t *timep) { +#if !SUPPORT_C89 + static struct tm tm; +#endif return gmtime_r(timep, &tm); } -#ifdef STD_INSPIRED +#if STD_INSPIRED struct tm * offtime(const time_t *timep, long offset) { gmtcheck(); + +#if !SUPPORT_C89 + static struct tm tm; +#endif return gmtsub(gmtptr, timep, offset, &tm); } -#endif /* defined STD_INSPIRED */ +#endif /* ** Return the number of leap years through the end of the given year @@ -1842,27 +1850,6 @@ timesub(const time_t *timep, int_fast32_t offset, return tmp; } -char * -ctime(const time_t *timep) -{ -/* -** Section 4.12.3.2 of X3.159-1989 requires that -** The ctime function converts the calendar time pointed to by timer -** to local time in the form of a string. It is equivalent to -** asctime(localtime(timer)) -*/ - struct tm *tmp = localtime(timep); - return tmp ? asctime(tmp) : NULL; -} - -char * -ctime_r(const time_t *timep, char *buf) -{ - struct tm mytm; - struct tm *tmp = localtime_r(timep, &mytm); - return tmp ? asctime_r(tmp, buf) : NULL; -} - /* ** Adapted from code provided by Robert Elz, who writes: ** The "best" way to do mktime I think is based on an idea of Bob @@ -2303,7 +2290,7 @@ mktime_tzname(struct state *sp, struct tm *tmp, bool setname) #if NETBSD_INSPIRED time_t -mktime_z(struct state *sp, struct tm *tmp) +mktime_z(struct state *restrict sp, struct tm *restrict tmp) { return mktime_tzname(sp, tmp, false); } @@ -2325,7 +2312,7 @@ mktime(struct tm *tmp) return t; } -#ifdef STD_INSPIRED +#if STD_INSPIRED time_t timelocal(struct tm *tmp) { @@ -2377,7 +2364,7 @@ leapcorr(struct state const *sp, time_t t) ** XXX--is the below the right way to conditionalize?? */ -#ifdef STD_INSPIRED +#if STD_INSPIRED /* NETBSD_INSPIRED_EXTERN functions are exported to callers if NETBSD_INSPIRED is defined, and are private otherwise. */ @@ -2462,7 +2449,7 @@ posix2time(time_t t) return t; } -#endif /* defined STD_INSPIRED */ +#endif /* STD_INSPIRED */ #if TZ_TIME_T |
