]> granicus.if.org Git - python/commitdiff
issue 4804: Provide checks for the format string of strftime, and for the "mode...
authorKristján Valur Jónsson <kristjan@ccpgames.com>
Wed, 4 Feb 2009 10:05:25 +0000 (10:05 +0000)
committerKristján Valur Jónsson <kristjan@ccpgames.com>
Wed, 4 Feb 2009 10:05:25 +0000 (10:05 +0000)
Lib/test/test_file.py
Modules/timemodule.c
Objects/fileobject.c

index b4f494ba96a234fe4d6806db56f66a0437d5b580..a134a89c0571db1572d95bbad7b5623ee332a95d 100644 (file)
@@ -154,7 +154,7 @@ class OtherFileTests(unittest.TestCase):
         for name in (TESTFN, unicode(TESTFN), unicode(TESTFN + '\t')):
             try:
                 f = open(name, "rr")
-            except IOError:
+            except (IOError, ValueError):
                 pass
             else:
                 f.close()
index e8de2c5706e22e5bbe2aa69c119925e70f60d58e..2f4092d64e184e65349d3f948ee390cd2aa65a41 100644 (file)
@@ -470,6 +470,23 @@ time_strftime(PyObject *self, PyObject *args)
             return NULL;
         }
 
+#ifdef MS_WINDOWS
+       /* check that the format string contains only valid directives */
+       for(outbuf = strchr(fmt, '%');
+               outbuf != NULL;
+               outbuf = strchr(outbuf+2, '%'))
+       {
+               if (outbuf[1]=='#')
+                       ++outbuf; /* not documented by python, */
+               if (outbuf[1]=='\0' ||
+                       !strchr("aAbBcdfHIjmMpSUwWxXyYzZ%", outbuf[1]))
+               {
+                       PyErr_SetString(PyExc_ValueError, "Invalid format string");
+                       return 0;
+               }
+       }
+#endif
+
        fmtlen = strlen(fmt);
 
        /* I hate these functions that presume you know how big the output
index e01f38efdd0dc87247ac2a9d25a5852759892d43..77724d494216b84ba3b416a4bdd12a4b292ae769 100644 (file)
@@ -181,6 +181,87 @@ fill_file_fields(PyFileObject *f, FILE *fp, PyObject *name, char *mode,
        return (PyObject *) f;
 }
 
+#if defined _MSC_VER && _MSC_VER >= 1400 && defined(__STDC_SECURE_LIB__)
+#define Py_VERIFY_WINNT
+/* The CRT on windows compiled with Visual Studio 2005 and higher may
+ * assert if given invalid mode strings.  This is all fine and well
+ * in static languages like C where the mode string is typcially hard
+ * coded.  But in Python, were we pass in the mode string from the user,
+ * we need to verify it first manually
+ */
+static int _PyVerify_Mode_WINNT(const char *mode)
+{
+       /* See if mode string is valid on Windows to avoid hard assertions */
+       /* remove leading spacese */
+       int singles = 0;
+       int pairs = 0;
+       int encoding = 0;
+       const char *s, *c;
+
+       while(*mode == ' ') /* strip initial spaces */
+               ++mode;
+       if (!strchr("rwa", *mode)) /* must start with one of these */
+               return 0;
+       while (*++mode) {
+               if (*mode == ' ' || *mode == 'N') /* ignore spaces and N */
+                       continue;
+               s = "+TD"; /* each of this can appear only once */
+               c = strchr(s, *mode);
+               if (c) {
+                       ptrdiff_t idx = s-c;
+                       if (singles & (1<<idx))
+                               return 0;
+                       singles |= (1<<idx);
+                       continue;
+               }
+               s = "btcnSR"; /* only one of each letter in the pairs allowed */
+               c = strchr(s, *mode);
+               if (c) {
+                       ptrdiff_t idx = (s-c)/2;
+                       if (pairs & (1<<idx))
+                               return 0;
+                       pairs |= (1<<idx);
+                       continue;
+               }
+               if (*mode == ',') {
+                       encoding = 1;
+                       break;
+               }
+               return 0; /* found an invalid char */
+       }
+
+       if (encoding) {
+               char *e[] = {"UTF-8", "UTF-16LE", "UNICODE"};
+               while (*mode == ' ')
+                       ++mode;
+               /* find 'ccs =' */
+               if (strncmp(mode, "ccs", 3))
+                       return 0;
+               mode += 3;
+               while (*mode == ' ')
+                       ++mode;
+               if (*mode != '=')
+                       return 0;
+               while (*mode == ' ')
+                       ++mode;
+               for(encoding = 0; encoding<_countof(e); ++encoding) {
+                       size_t l = strlen(e[encoding]);
+                       if (!strncmp(mode, e[encoding], l)) {
+                               mode += l; /* found a valid encoding */
+                               break;
+                       }
+               }
+               if (encoding == _countof(e))
+                       return 0;
+       }
+       /* skip trailing spaces */
+       while (*mode == ' ')
+               ++mode;
+
+       return *mode == '\0'; /* must be at the end of the string */
+}
+#endif
+
 /* check for known incorrect mode strings - problem is, platforms are
    free to accept any mode characters they like and are supposed to
    ignore stuff they don't understand... write or append mode with
@@ -223,7 +304,13 @@ _PyFile_SanitizeMode(char *mode)
                            "one of 'r', 'w', 'a' or 'U', not '%.200s'", mode);
                return -1;
        }
-
+#ifdef Py_VERIFY_WINNT
+       /* additional checks on NT with visual studio 2005 and higher */
+       if (!_PyVerify_Mode_WINNT(mode)) {
+               PyErr_Format(PyExc_ValueError, "Invalid mode ('%.50s')", mode);
+               return -1;
+       }
+#endif
        return 0;
 }