diff options
author | Brett Cannon <bcannon@gmail.com> | 2004-06-19 20:48:43 (GMT) |
---|---|---|
committer | Brett Cannon <bcannon@gmail.com> | 2004-06-19 20:48:43 (GMT) |
commit | 298c380c74294bedcc0b5999c57e3aca03fb3731 (patch) | |
tree | 3064e192d47ff9049f27351158641410628cd0ef /Modules | |
parent | cdc7923f6d1c9731d81f299569b1ea72de7eb212 (diff) | |
download | cpython-298c380c74294bedcc0b5999c57e3aca03fb3731.zip cpython-298c380c74294bedcc0b5999c57e3aca03fb3731.tar.gz cpython-298c380c74294bedcc0b5999c57e3aca03fb3731.tar.bz2 |
Raise ValueError when value being stored in a time_t variable will result in
more than a second of precision. Primarily affects ctime, localtime, and
gmtime.
Closes bug #919012 thanks to Tim Peters' code.
Tim suggests that the new funciton being introduced, _PyTime_DoubletoTimet(),
should be added to the internal C API and then used in datetime where
appropriate. Not being done now for lack of time.
Diffstat (limited to 'Modules')
-rw-r--r-- | Modules/timemodule.c | 45 |
1 files changed, 40 insertions, 5 deletions
diff --git a/Modules/timemodule.c b/Modules/timemodule.c index ef6ee3e..0783f7f 100644 --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -84,6 +84,35 @@ static double floattime(void); /* For Y2K check */ static PyObject *moddict; +/* Cast double x to time_t, but raise ValueError if x is too large + * to fit in a time_t. ValueError is set on return iff the return + * value is (time_t)-1 and PyErr_Occurred(). + */ +static time_t +_PyTime_DoubleToTimet(double x) +{ + time_t result; + double diff; + + result = (time_t)x; + /* How much info did we lose? time_t may be an integral or + * floating type, and we don't know which. If it's integral, + * we don't know whether C truncates, rounds, returns the floor, + * etc. If we lost a second or more, the C rounding is + * unreasonable, or the input just doesn't fit in a time_t; + * call it an error regardless. Note that the original cast to + * time_t can cause a C error too, but nothing we can do to + * worm around that. + */ + diff = x - (double)result; + if (diff <= -1.0 || diff >= 1.0) { + PyErr_SetString(PyExc_ValueError, + "timestamp out of range for platform time_t"); + result = (time_t)-1; + } + return result; +} + static PyObject * time_time(PyObject *self, PyObject *args) { @@ -231,11 +260,15 @@ tmtotuple(struct tm *p) } static PyObject * -time_convert(time_t when, struct tm * (*function)(const time_t *)) +time_convert(double when, struct tm * (*function)(const time_t *)) { struct tm *p; + time_t whent = _PyTime_DoubleToTimet(when); + + if (whent == (time_t)-1 && PyErr_Occurred()) + return NULL; errno = 0; - p = function(&when); + p = function(&whent); if (p == NULL) { #ifdef EINVAL if (errno == 0) @@ -254,7 +287,7 @@ time_gmtime(PyObject *self, PyObject *args) when = floattime(); if (!PyArg_ParseTuple(args, "|d:gmtime", &when)) return NULL; - return time_convert((time_t)when, gmtime); + return time_convert(when, gmtime); } PyDoc_STRVAR(gmtime_doc, @@ -272,7 +305,7 @@ time_localtime(PyObject *self, PyObject *args) when = floattime(); if (!PyArg_ParseTuple(args, "|d:localtime", &when)) return NULL; - return time_convert((time_t)when, localtime); + return time_convert(when, localtime); } PyDoc_STRVAR(localtime_doc, @@ -480,7 +513,9 @@ time_ctime(PyObject *self, PyObject *args) else { if (!PyArg_ParseTuple(args, "|d:ctime", &dt)) return NULL; - tt = (time_t)dt; + tt = _PyTime_DoubleToTimet(dt); + if (tt == (time_t)-1 && PyErr_Occurred()) + return NULL; } p = ctime(&tt); if (p == NULL) { |