From 59a1a7d58e815bb1f195529d796a98a4cedbb560 Mon Sep 17 00:00:00 2001 From: Alexander Belopolsky Date: Sat, 10 Sep 2016 15:58:31 -0400 Subject: Closes #28067: Do not call localtime (gmtime) in datetime module. --- Modules/_datetimemodule.c | 102 +++++++++++++++++++++++++++------------------- 1 file changed, 60 insertions(+), 42 deletions(-) (limited to 'Modules/_datetimemodule.c') diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 13c9d2ff4f..99556c3fe7 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -15,6 +15,12 @@ static struct tm *localtime_r(const time_t *timep, struct tm *result) return result; return NULL; } +static struct tm *gmtime_r(const time_t *timep, struct tm *result) +{ + if (gmime_s(result, timep) == 0) + return result; + return NULL; +} #endif /* Differentiate between building the core module and building extension @@ -2517,14 +2523,13 @@ date_new(PyTypeObject *type, PyObject *args, PyObject *kw) static PyObject * date_local_from_object(PyObject *cls, PyObject *obj) { - struct tm *tm; + struct tm tm; time_t t; if (_PyTime_ObjectToTime_t(obj, &t, _PyTime_ROUND_FLOOR) == -1) return NULL; - tm = localtime(&t); - if (tm == NULL) { + if (localtime_r(&t, &tm) == NULL) { /* unconvertible time */ #ifdef EINVAL if (errno == 0) @@ -2535,9 +2540,9 @@ date_local_from_object(PyObject *cls, PyObject *obj) } return PyObject_CallFunction(cls, "iii", - tm->tm_year + 1900, - tm->tm_mon + 1, - tm->tm_mday); + tm.tm_year + 1900, + tm.tm_mon + 1, + tm.tm_mday); } /* Return new date from current time. @@ -4194,8 +4199,8 @@ datetime_new(PyTypeObject *type, PyObject *args, PyObject *kw) return self; } -/* TM_FUNC is the shared type of localtime() and gmtime(). */ -typedef struct tm *(*TM_FUNC)(const time_t *timer); +/* TM_FUNC is the shared type of localtime_r() and gmtime_r(). */ +typedef struct tm *(*TM_FUNC)(const time_t *timer, struct tm*); /* As of version 2015f max fold in IANA database is * 23 hours at 1969-09-30 13:00:00 in Kwajalein. */ @@ -4244,11 +4249,10 @@ static PyObject * datetime_from_timet_and_us(PyObject *cls, TM_FUNC f, time_t timet, int us, PyObject *tzinfo) { - struct tm *tm; + struct tm tm; int year, month, day, hour, minute, second, fold = 0; - tm = f(&timet); - if (tm == NULL) { + if (f(&timet, &tm) == NULL) { #ifdef EINVAL if (errno == 0) errno = EINVAL; @@ -4256,20 +4260,20 @@ datetime_from_timet_and_us(PyObject *cls, TM_FUNC f, time_t timet, int us, return PyErr_SetFromErrno(PyExc_OSError); } - year = tm->tm_year + 1900; - month = tm->tm_mon + 1; - day = tm->tm_mday; - hour = tm->tm_hour; - minute = tm->tm_min; + year = tm.tm_year + 1900; + month = tm.tm_mon + 1; + day = tm.tm_mday; + hour = tm.tm_hour; + minute = tm.tm_min; /* The platform localtime/gmtime may insert leap seconds, - * indicated by tm->tm_sec > 59. We don't care about them, + * indicated by tm.tm_sec > 59. We don't care about them, * except to the extent that passing them on to the datetime * constructor would raise ValueError for a reason that * made no sense to the user. */ - second = Py_MIN(59, tm->tm_sec); + second = Py_MIN(59, tm.tm_sec); - if (tzinfo == Py_None && f == localtime) { + if (tzinfo == Py_None && f == localtime_r) { long long probe_seconds, result_seconds, transition; result_seconds = utc_to_seconds(year, month, day, @@ -4357,7 +4361,7 @@ datetime_datetime_now_impl(PyTypeObject *type, PyObject *tz) return NULL; self = datetime_best_possible((PyObject *)type, - tz == Py_None ? localtime : gmtime, + tz == Py_None ? localtime_r : gmtime_r, tz); if (self != NULL && tz != Py_None) { /* Convert UTC to tzinfo's zone. */ @@ -4372,7 +4376,7 @@ datetime_datetime_now_impl(PyTypeObject *type, PyObject *tz) static PyObject * datetime_utcnow(PyObject *cls, PyObject *dummy) { - return datetime_best_possible(cls, gmtime, Py_None); + return datetime_best_possible(cls, gmtime_r, Py_None); } /* Return new local datetime from timestamp (Python timestamp -- a double). */ @@ -4391,7 +4395,7 @@ datetime_fromtimestamp(PyObject *cls, PyObject *args, PyObject *kw) return NULL; self = datetime_from_timestamp(cls, - tzinfo == Py_None ? localtime : gmtime, + tzinfo == Py_None ? localtime_r : gmtime_r, timestamp, tzinfo); if (self != NULL && tzinfo != Py_None) { @@ -4409,7 +4413,7 @@ datetime_utcfromtimestamp(PyObject *cls, PyObject *args) PyObject *result = NULL; if (PyArg_ParseTuple(args, "O:utcfromtimestamp", ×tamp)) - result = datetime_from_timestamp(cls, gmtime, timestamp, + result = datetime_from_timestamp(cls, gmtime_r, timestamp, Py_None); return result; } @@ -5032,37 +5036,51 @@ local_timezone_from_timestamp(time_t timestamp) { PyObject *result = NULL; PyObject *delta; - struct tm *local_time_tm; + struct tm local_time_tm; PyObject *nameo = NULL; const char *zone = NULL; - local_time_tm = localtime(×tamp); + if (localtime_r(×tamp, &local_time_tm) == NULL) { +#ifdef EINVAL + if (errno == 0) + errno = EINVAL; +#endif + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } #ifdef HAVE_STRUCT_TM_TM_ZONE - zone = local_time_tm->tm_zone; - delta = new_delta(0, local_time_tm->tm_gmtoff, 0, 1); + zone = local_time_tm.tm_zone; + delta = new_delta(0, local_time_tm.tm_gmtoff, 0, 1); #else /* HAVE_STRUCT_TM_TM_ZONE */ { PyObject *local_time, *utc_time; - struct tm *utc_time_tm; + struct tm utc_time_tm; char buf[100]; - strftime(buf, sizeof(buf), "%Z", local_time_tm); + strftime(buf, sizeof(buf), "%Z", &local_time_tm); zone = buf; - local_time = new_datetime(local_time_tm->tm_year + 1900, - local_time_tm->tm_mon + 1, - local_time_tm->tm_mday, - local_time_tm->tm_hour, - local_time_tm->tm_min, - local_time_tm->tm_sec, 0, Py_None, 0); + local_time = new_datetime(local_time_tm.tm_year + 1900, + local_time_tm.tm_mon + 1, + local_time_tm.tm_mday, + local_time_tm.tm_hour, + local_time_tm.tm_min, + local_time_tm.tm_sec, 0, Py_None, 0); if (local_time == NULL) { return NULL; } - utc_time_tm = gmtime(×tamp); - utc_time = new_datetime(utc_time_tm->tm_year + 1900, - utc_time_tm->tm_mon + 1, - utc_time_tm->tm_mday, - utc_time_tm->tm_hour, - utc_time_tm->tm_min, - utc_time_tm->tm_sec, 0, Py_None, 0); + if (gmtime(×tamp, &utc_time_tm) == NULL) { +#ifdef EINVAL + if (errno == 0) + errno = EINVAL; +#endif + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + utc_time = new_datetime(utc_time_tm.tm_year + 1900, + utc_time_tm.tm_mon + 1, + utc_time_tm.tm_mday, + utc_time_tm.tm_hour, + utc_time_tm.tm_min, + utc_time_tm.tm_sec, 0, Py_None, 0); if (utc_time == NULL) { Py_DECREF(local_time); return NULL; -- cgit v1.2.1