1
0
mirror of https://frontier.innolan.net/rainlance/amiga-tz.git synced 2026-05-06 18:19:05 +00:00

Fix EOVERFLOW-related problems noted by Chistos Zoulas.

See: http://mm.icann.org/pipermail/tz/2014-October/021692.html
* asctime.c (asctime_r): Remove now-unnecessary EOVERFLOW ifdef.
* localtime.c (timesub): Set errno to EOVERFLOW on overflow.
POSIX requires this.
(ctime, ctime_r): Return NULL instead of having undefined behavior
when the time stamp is out of struct tm range.  NetBSD does this,
the standards allow it, and it's nicer for users.
* private.h (EOVERFLOW): Default to EINVAL on ancient hosts that lack it.
* NEWS: Document this.
This commit is contained in:
Paul Eggert
2014-10-08 10:45:59 -07:00
parent 3bf56b926f
commit 4d306b3a17
4 changed files with 25 additions and 14 deletions

5
NEWS
View File

@@ -26,6 +26,11 @@ Unreleased, experimental changes
This change is a companion to the tzname change in 2014h, and is
designed to make timezone and altzone more compatible with tzname.
The tz library's functions now set errno to EOVERFLOW if they fail
because the result cannot be represented. ctime and ctime_r now
return NULL and set errno when a time stamp is out of range, rather
than having undefined behavior.
Some bugs associated with the new 2014g functions have been fixed.
This includes a bug that largely incapacitated the new functions
time2posix_z and posix2time_z. (Thanks to Christos Zoulas.)

View File

@@ -112,11 +112,7 @@ asctime_r(register const struct tm *timeptr, char *buf)
if (strlen(result) < STD_ASCTIME_BUF_SIZE || buf == buf_asctime)
return strcpy(buf, result);
else {
#ifdef EOVERFLOW
errno = EOVERFLOW;
#else /* !defined EOVERFLOW */
errno = EINVAL;
#endif /* !defined EOVERFLOW */
return NULL;
}
}

View File

@@ -1541,13 +1541,13 @@ timesub(const time_t *const timep, const int_fast32_t offset,
tdelta = tdays / DAYSPERLYEAR;
if (! ((! TYPE_SIGNED(time_t) || INT_MIN <= tdelta)
&& tdelta <= INT_MAX))
return NULL;
goto out_of_range;
idelta = tdelta;
if (idelta == 0)
idelta = (tdays < 0) ? -1 : 1;
newy = y;
if (increment_overflow(&newy, idelta))
return NULL;
goto out_of_range;
leapdays = leaps_thru_end_of(newy - 1) -
leaps_thru_end_of(y - 1);
tdays -= ((time_t) newy - y) * DAYSPERNYEAR;
@@ -1576,17 +1576,17 @@ timesub(const time_t *const timep, const int_fast32_t offset,
}
while (idays < 0) {
if (increment_overflow(&y, -1))
return NULL;
goto out_of_range;
idays += year_lengths[isleap(y)];
}
while (idays >= year_lengths[isleap(y)]) {
idays -= year_lengths[isleap(y)];
if (increment_overflow(&y, 1))
return NULL;
goto out_of_range;
}
tmp->tm_year = y;
if (increment_overflow(&tmp->tm_year, -TM_YEAR_BASE))
return NULL;
goto out_of_range;
tmp->tm_yday = idays;
/*
** The "extra" mods below avoid overflow problems.
@@ -1617,6 +1617,10 @@ timesub(const time_t *const timep, const int_fast32_t offset,
tmp->TM_GMTOFF = offset;
#endif /* defined TM_GMTOFF */
return tmp;
out_of_range:
errno = EOVERFLOW;
return NULL;
}
char *
@@ -1628,15 +1632,16 @@ ctime(const time_t *const timep)
** to local time in the form of a string. It is equivalent to
** asctime(localtime(timer))
*/
return asctime(localtime(timep));
struct tm *tmp = localtime(timep);
return tmp ? asctime(tmp) : NULL;
}
char *
ctime_r(const time_t *const timep, char *buf)
{
struct tm mytm;
return asctime_r(localtime_r(timep, &mytm), buf);
struct tm mytm;
struct tm *tmp = localtime_r(timep, &mytm);
return tmp ? asctime_r(tmp, buf) : NULL;
}
/*

View File

@@ -101,11 +101,16 @@
#include "sys/types.h" /* for time_t */
#include "stdio.h"
#include "errno.h"
#include "string.h"
#include "limits.h" /* for CHAR_BIT et al. */
#include "stdlib.h"
#include "errno.h"
#ifndef EOVERFLOW
# define EOVERFLOW EINVAL
#endif
#if HAVE_GETTEXT
#include "libintl.h"
#endif /* HAVE_GETTEXT */