[3.6] bpo-26669: Fix nan arg value error in pytime.c (GH-3085) (GH-3467)
* Modify NaN check function and error message
* Fix pytime.c when arg is nan
* fix whitespace
(cherry picked from commit 829dacce4fca60fc3c3367980e75e21dfcdbe6be)
diff --git a/Lib/test/test_time.py b/Lib/test/test_time.py
index 810ec37..7093fc6 100644
--- a/Lib/test/test_time.py
+++ b/Lib/test/test_time.py
@@ -489,6 +489,10 @@
self.assertRaises(OSError, time.localtime, invalid_time_t)
self.assertRaises(OSError, time.ctime, invalid_time_t)
+ # Issue #26669: check for localtime() failure
+ self.assertRaises(ValueError, time.localtime, float("nan"))
+ self.assertRaises(ValueError, time.ctime, float("nan"))
+
def test_get_clock_info(self):
clocks = ['clock', 'perf_counter', 'process_time', 'time']
if hasattr(time, 'monotonic'):
@@ -823,6 +827,11 @@
lambda secs: secs * SEC_TO_NS,
value_filter=c_int_filter)
+ # test nan
+ for time_rnd, _ in ROUNDING_MODES:
+ with self.assertRaises(TypeError):
+ PyTime_FromSeconds(float('nan'))
+
def test_FromSecondsObject(self):
from _testcapi import PyTime_FromSecondsObject
@@ -834,6 +843,11 @@
PyTime_FromSecondsObject,
lambda ns: self.decimal_round(ns * SEC_TO_NS))
+ # test nan
+ for time_rnd, _ in ROUNDING_MODES:
+ with self.assertRaises(ValueError):
+ PyTime_FromSecondsObject(float('nan'), time_rnd)
+
def test_AsSecondsDouble(self):
from _testcapi import PyTime_AsSecondsDouble
@@ -847,6 +861,11 @@
float_converter,
NS_TO_SEC)
+ # test nan
+ for time_rnd, _ in ROUNDING_MODES:
+ with self.assertRaises(TypeError):
+ PyTime_AsSecondsDouble(float('nan'))
+
def create_decimal_converter(self, denominator):
denom = decimal.Decimal(denominator)
@@ -952,6 +971,11 @@
self.create_converter(SEC_TO_US),
value_filter=self.time_t_filter)
+ # test nan
+ for time_rnd, _ in ROUNDING_MODES:
+ with self.assertRaises(ValueError):
+ pytime_object_to_timeval(float('nan'), time_rnd)
+
def test_object_to_timespec(self):
from _testcapi import pytime_object_to_timespec
@@ -963,6 +987,11 @@
self.create_converter(SEC_TO_NS),
value_filter=self.time_t_filter)
+ # test nan
+ for time_rnd, _ in ROUNDING_MODES:
+ with self.assertRaises(ValueError):
+ pytime_object_to_timespec(float('nan'), time_rnd)
+
if __name__ == "__main__":
unittest.main()
diff --git a/Python/pytime.c b/Python/pytime.c
index 387657a..b416eff 100644
--- a/Python/pytime.c
+++ b/Python/pytime.c
@@ -133,6 +133,11 @@
if (PyFloat_Check(obj)) {
double d = PyFloat_AsDouble(obj);
+ if (Py_IS_NAN(d)) {
+ *numerator = 0;
+ PyErr_SetString(PyExc_ValueError, "Invalid value NaN (not a number)");
+ return -1;
+ }
return _PyTime_DoubleToDenominator(d, sec, numerator,
denominator, round);
}
@@ -154,6 +159,11 @@
volatile double d;
d = PyFloat_AsDouble(obj);
+ if (Py_IS_NAN(d)) {
+ PyErr_SetString(PyExc_ValueError, "Invalid value NaN (not a number)");
+ return -1;
+ }
+
d = _PyTime_Round(d, round);
(void)modf(d, &intpart);
@@ -301,6 +311,10 @@
if (PyFloat_Check(obj)) {
double d;
d = PyFloat_AsDouble(obj);
+ if (Py_IS_NAN(d)) {
+ PyErr_SetString(PyExc_ValueError, "Invalid value NaN (not a number)");
+ return -1;
+ }
return _PyTime_FromFloatObject(t, d, round, unit_to_ns);
}
else {