]> granicus.if.org Git - python/commitdiff
Issue #6608: time.asctime is now checking struct tm fields its input
authorAlexander Belopolsky <alexander.belopolsky@gmail.com>
Fri, 1 Oct 2010 14:18:49 +0000 (14:18 +0000)
committerAlexander Belopolsky <alexander.belopolsky@gmail.com>
Fri, 1 Oct 2010 14:18:49 +0000 (14:18 +0000)
before passing it to the system asctime.  Patch by MunSic Jeong.

Lib/test/test_time.py
Misc/ACKS
Misc/NEWS
Modules/timemodule.c

index 4ce90e967a403ad62c31425b8885ad615cad26e0..fbf07eb922f755dcd276c874bd22250222787468 100644 (file)
@@ -37,57 +37,60 @@ class TimeTestCase(unittest.TestCase):
             except ValueError:
                 self.fail('conversion specifier: %r failed.' % format)
 
-    def test_strftime_bounds_checking(self):
+    def _bounds_checking(self, func=time.strftime):
         # Make sure that strftime() checks the bounds of the various parts
         #of the time tuple (0 is valid for *all* values).
 
         # Check year [1900, max(int)]
-        self.assertRaises(ValueError, time.strftime, '',
+        self.assertRaises(ValueError, func,
                             (1899, 1, 1, 0, 0, 0, 0, 1, -1))
         if time.accept2dyear:
-            self.assertRaises(ValueError, time.strftime, '',
+            self.assertRaises(ValueError, func,
                                 (-1, 1, 1, 0, 0, 0, 0, 1, -1))
-            self.assertRaises(ValueError, time.strftime, '',
+            self.assertRaises(ValueError, func,
                                 (100, 1, 1, 0, 0, 0, 0, 1, -1))
         # Check month [1, 12] + zero support
-        self.assertRaises(ValueError, time.strftime, '',
+        self.assertRaises(ValueError, func,
                             (1900, -1, 1, 0, 0, 0, 0, 1, -1))
-        self.assertRaises(ValueError, time.strftime, '',
+        self.assertRaises(ValueError, func,
                             (1900, 13, 1, 0, 0, 0, 0, 1, -1))
         # Check day of month [1, 31] + zero support
-        self.assertRaises(ValueError, time.strftime, '',
+        self.assertRaises(ValueError, func,
                             (1900, 1, -1, 0, 0, 0, 0, 1, -1))
-        self.assertRaises(ValueError, time.strftime, '',
+        self.assertRaises(ValueError, func,
                             (1900, 1, 32, 0, 0, 0, 0, 1, -1))
         # Check hour [0, 23]
-        self.assertRaises(ValueError, time.strftime, '',
+        self.assertRaises(ValueError, func,
                             (1900, 1, 1, -1, 0, 0, 0, 1, -1))
-        self.assertRaises(ValueError, time.strftime, '',
+        self.assertRaises(ValueError, func,
                             (1900, 1, 1, 24, 0, 0, 0, 1, -1))
         # Check minute [0, 59]
-        self.assertRaises(ValueError, time.strftime, '',
+        self.assertRaises(ValueError, func,
                             (1900, 1, 1, 0, -1, 0, 0, 1, -1))
-        self.assertRaises(ValueError, time.strftime, '',
+        self.assertRaises(ValueError, func,
                             (1900, 1, 1, 0, 60, 0, 0, 1, -1))
         # Check second [0, 61]
-        self.assertRaises(ValueError, time.strftime, '',
+        self.assertRaises(ValueError, func,
                             (1900, 1, 1, 0, 0, -1, 0, 1, -1))
         # C99 only requires allowing for one leap second, but Python's docs say
         # allow two leap seconds (0..61)
-        self.assertRaises(ValueError, time.strftime, '',
+        self.assertRaises(ValueError, func,
                             (1900, 1, 1, 0, 0, 62, 0, 1, -1))
         # No check for upper-bound day of week;
         #  value forced into range by a ``% 7`` calculation.
         # Start check at -2 since gettmarg() increments value before taking
         #  modulo.
-        self.assertRaises(ValueError, time.strftime, '',
+        self.assertRaises(ValueError, func,
                             (1900, 1, 1, 0, 0, 0, -2, 1, -1))
         # Check day of the year [1, 366] + zero support
-        self.assertRaises(ValueError, time.strftime, '',
+        self.assertRaises(ValueError, func,
                             (1900, 1, 1, 0, 0, 0, 0, -1, -1))
-        self.assertRaises(ValueError, time.strftime, '',
+        self.assertRaises(ValueError, func,
                             (1900, 1, 1, 0, 0, 0, 0, 367, -1))
 
+    def test_strftime_bounding_check(self):
+        self._bounds_checking(lambda tup: time.strftime('', tup))
+
     def test_default_values_for_zero(self):
         # Make sure that using all zeros uses the proper default values.
         # No test for daylight savings since strftime() does not change output
@@ -120,6 +123,9 @@ class TimeTestCase(unittest.TestCase):
         time.asctime(time.gmtime(self.t))
         self.assertRaises(TypeError, time.asctime, 0)
 
+    def test_asctime_bounding_check(self):
+        self._bounds_checking(time.asctime)
+
     def test_tzset(self):
         if not hasattr(time, "tzset"):
             return # Can't test this; don't want the test suite to fail
index 228dfe7f4127c3dad130e5bda571a6abc7f78951..97792ad1ad47d5ffddd08455077883ab9d0b7664 100644 (file)
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -405,7 +405,7 @@ Jack Jansen
 Bill Janssen
 Drew Jenkins
 Flemming Kjær Jensen
-Jiba
+MunSic Jeong
 Orjan Johansen
 Fredrik Johansson
 Gregory K. Johnson
@@ -462,6 +462,7 @@ Ivan Krstić
 Andrew Kuchling
 Vladimir Kushnir
 Cameron Laird
+Jean-Baptiste "Jiba" Lamy
 Torsten Landschoff
 Łukasz Langa
 Tino Lange
index 9144e25345227f55746789dd593af4e38a2c2a4b..a0d827518daee9239dff51ab7d5229b8914c034a 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -410,6 +410,9 @@ Core and Builtins
 Extensions
 ----------
 
+- Issue #6608: time.asctime is now checking struct tm fields its input
+  before passing it to the system asctime.  Patch by MunSic Jeong.
+
 - Issue #8734: Avoid crash in msvcrt.get_osfhandle() when an invalid file
   descriptor is provided.  Patch by Pascal Chambon.
 
index acd3fc3e07b7dd4578d4e402f56cc4567f1a471e..cbb05cdddca1177b8ef5f5aba8651b25532a97a8 100644 (file)
@@ -315,6 +315,9 @@ PyDoc_STRVAR(localtime_doc,
 Convert seconds since the Epoch to a time tuple expressing local time.\n\
 When 'seconds' is not passed in, convert the current time instead.");
 
+/* Convert 9-item tuple to tm structure.  Return 1 on success, set
+ * an exception and return 0 on error.
+ */
 static int
 gettmarg(PyObject *args, struct tm *p)
 {
@@ -377,6 +380,76 @@ gettmarg(PyObject *args, struct tm *p)
     return 1;
 }
 
+/* Check values of the struct tm fields before it is passed to strftime() and
+ * asctime().  Return 1 if all values are valid, otherwise set an exception
+ * and returns 0.
+ */
+static int 
+checktm(struct tm* buf) 
+{
+    /* Checks added to make sure strftime() and asctime() does not crash Python by    
+       indexing blindly into some array for a textual representation                  
+       by some bad index (fixes bug #897625 and #6608).                               
+                                                                                      
+       Also support values of zero from Python code for arguments in which            
+       that is out of range by forcing that value to the lowest value that            
+       is valid (fixed bug #1520914).                                                 
+                                                                                      
+       Valid ranges based on what is allowed in struct tm:                            
+                                                                                      
+       - tm_year: [0, max(int)] (1)                                                   
+       - tm_mon: [0, 11] (2)                                                          
+       - tm_mday: [1, 31]                                                             
+       - tm_hour: [0, 23]                                                             
+       - tm_min: [0, 59]                                                              
+       - tm_sec: [0, 60]                                                              
+       - tm_wday: [0, 6] (1)                                                          
+       - tm_yday: [0, 365] (2)                                                        
+       - tm_isdst: [-max(int), max(int)]                                              
+                                                                                      
+       (1) gettmarg() handles bounds-checking.                                        
+       (2) Python's acceptable range is one greater than the range in C,              
+       thus need to check against automatic decrement by gettmarg().
+    */
+    if (buf->tm_mon == -1)
+        buf->tm_mon = 0;
+    else if (buf->tm_mon < 0 || buf->tm_mon > 11) {
+        PyErr_SetString(PyExc_ValueError, "month out of range");
+        return 0;
+    }
+    if (buf->tm_mday == 0)
+        buf->tm_mday = 1;
+    else if (buf->tm_mday < 0 || buf->tm_mday > 31) {
+        PyErr_SetString(PyExc_ValueError, "day of month out of range");
+        return 0;
+    }
+    if (buf->tm_hour < 0 || buf->tm_hour > 23) {
+        PyErr_SetString(PyExc_ValueError, "hour out of range");
+        return 0;
+    }
+    if (buf->tm_min < 0 || buf->tm_min > 59) {
+        PyErr_SetString(PyExc_ValueError, "minute out of range");
+        return 0;
+    }
+    if (buf->tm_sec < 0 || buf->tm_sec > 61) {
+        PyErr_SetString(PyExc_ValueError, "seconds out of range");
+        return 0;
+    }
+    /* tm_wday does not need checking of its upper-bound since taking
+    ``% 7`` in gettmarg() automatically restricts the range. */
+    if (buf->tm_wday < 0) {
+        PyErr_SetString(PyExc_ValueError, "day of week out of range");
+        return 0;
+    }
+    if (buf->tm_yday == -1)
+        buf->tm_yday = 0;
+    else if (buf->tm_yday < 0 || buf->tm_yday > 365) {
+        PyErr_SetString(PyExc_ValueError, "day of year out of range");
+        return 0;
+    }
+    return 1;
+}
+
 #ifdef HAVE_STRFTIME
 #ifdef HAVE_WCSFTIME
 #define time_char wchar_t
@@ -415,69 +488,10 @@ time_strftime(PyObject *self, PyObject *args)
     if (tup == NULL) {
         time_t tt = time(NULL);
         buf = *localtime(&tt);
-    } else if (!gettmarg(tup, &buf))
-        return NULL;
-
-    /* Checks added to make sure strftime() does not crash Python by
-       indexing blindly into some array for a textual representation
-       by some bad index (fixes bug #897625).
-
-        Also support values of zero from Python code for arguments in which
-        that is out of range by forcing that value to the lowest value that
-        is valid (fixed bug #1520914).
-
-        Valid ranges based on what is allowed in struct tm:
-
-        - tm_year: [0, max(int)] (1)
-        - tm_mon: [0, 11] (2)
-        - tm_mday: [1, 31]
-        - tm_hour: [0, 23]
-        - tm_min: [0, 59]
-        - tm_sec: [0, 60]
-        - tm_wday: [0, 6] (1)
-        - tm_yday: [0, 365] (2)
-        - tm_isdst: [-max(int), max(int)]
-
-        (1) gettmarg() handles bounds-checking.
-        (2) Python's acceptable range is one greater than the range in C,
-        thus need to check against automatic decrement by gettmarg().
-    */
-    if (buf.tm_mon == -1)
-        buf.tm_mon = 0;
-    else if (buf.tm_mon < 0 || buf.tm_mon > 11) {
-        PyErr_SetString(PyExc_ValueError, "month out of range");
-            return NULL;
-    }
-    if (buf.tm_mday == 0)
-        buf.tm_mday = 1;
-    else if (buf.tm_mday < 0 || buf.tm_mday > 31) {
-        PyErr_SetString(PyExc_ValueError, "day of month out of range");
-            return NULL;
-    }
-    if (buf.tm_hour < 0 || buf.tm_hour > 23) {
-        PyErr_SetString(PyExc_ValueError, "hour out of range");
-        return NULL;
-    }
-    if (buf.tm_min < 0 || buf.tm_min > 59) {
-        PyErr_SetString(PyExc_ValueError, "minute out of range");
-        return NULL;
     }
-    if (buf.tm_sec < 0 || buf.tm_sec > 61) {
-        PyErr_SetString(PyExc_ValueError, "seconds out of range");
+    else if (!gettmarg(tup, &buf) || !checktm(&buf))
         return NULL;
-    }
-    /* tm_wday does not need checking of its upper-bound since taking
-    ``% 7`` in gettmarg() automatically restricts the range. */
-    if (buf.tm_wday < 0) {
-        PyErr_SetString(PyExc_ValueError, "day of week out of range");
-        return NULL;
-    }
-    if (buf.tm_yday == -1)
-        buf.tm_yday = 0;
-    else if (buf.tm_yday < 0 || buf.tm_yday > 365) {
-        PyErr_SetString(PyExc_ValueError, "day of year out of range");
-        return NULL;
-    }
+
     /* Normalize tm_isdst just in case someone foolishly implements %Z
        based on the assumption that tm_isdst falls within the range of
        [-1, 1] */
@@ -603,7 +617,7 @@ time_asctime(PyObject *self, PyObject *args)
     if (tup == NULL) {
         time_t tt = time(NULL);
         buf = *localtime(&tt);
-    } else if (!gettmarg(tup, &buf))
+    } else if (!gettmarg(tup, &buf) || !checktm(&buf))
         return NULL;
     p = asctime(&buf);
     if (p[24] == '\n')