Disallow opening files with modes 'aU' or 'wU' as specified by PEP
278. Closes bug 967182.
diff --git a/Lib/test/test_file.py b/Lib/test/test_file.py
index af8eadf..2d2d9c1 100644
--- a/Lib/test/test_file.py
+++ b/Lib/test/test_file.py
@@ -40,6 +40,16 @@
raise TestFailed('expected exception setting file attr %r' % attr)
f.close()
+# check invalid mode strings
+for mode in ("", "aU", "wU+"):
+ try:
+ f = file(TESTFN, mode)
+ except ValueError:
+ pass
+ else:
+ f.close()
+ raise TestFailed('%r is an invalid file mode' % mode)
+
# verify writelines with instance sequence
l = UserList(['1', '2'])
f = open(TESTFN, 'wb')
diff --git a/Misc/NEWS b/Misc/NEWS
index 4d8f3b1..77e059e 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -12,6 +12,9 @@
Core and builtins
-----------------
+- bug #967182: disallow opening files with 'wU' or 'aU' as specified by PEP
+ 278.
+
- patch #1109424: int, long, float, complex, and unicode now check for the
proper magic slot for type conversions when subclassed. Previously the
magic slot was ignored during conversion. Semantics now match the way
diff --git a/Objects/fileobject.c b/Objects/fileobject.c
index c08345c..7e40547 100644
--- a/Objects/fileobject.c
+++ b/Objects/fileobject.c
@@ -128,6 +128,54 @@
return (PyObject *) f;
}
+/* 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
+ universal newline support is expressly forbidden by PEP 278. */
+/* zero return is kewl - one is un-kewl */
+static int
+check_the_mode(char *mode)
+{
+ unsigned int len = strlen(mode);
+
+ switch (len) {
+ case 0:
+ PyErr_SetString(PyExc_ValueError, "empty mode string");
+ return 1;
+
+ /* reject wU, aU */
+ case 2:
+ switch (mode[0]) {
+ case 'w':
+ case 'a':
+ if (mode[1] == 'U') {
+ PyErr_SetString(PyExc_ValueError,
+ "invalid mode string");
+ return 1;
+ }
+ break;
+ }
+ break;
+
+ /* reject w+U, a+U, wU+, aU+ */
+ case 3:
+ switch (mode[0]) {
+ case 'w':
+ case 'a':
+ if ((mode[1] == '+' && mode[2] == 'U') ||
+ (mode[1] == 'U' && mode[2] == '+')) {
+ PyErr_SetString(PyExc_ValueError,
+ "invalid mode string");
+ return 1;
+ }
+ break;
+ }
+ break;
+ }
+
+ return 0;
+}
+
static PyObject *
open_the_file(PyFileObject *f, char *name, char *mode)
{
@@ -142,6 +190,9 @@
assert(mode != NULL);
assert(f->f_fp == NULL);
+ if (check_the_mode(mode))
+ return NULL;
+
/* rexec.py can't stop a user from getting the file() constructor --
all they have to do is get *any* file object f, and then do
type(f). Here we prevent them from doing damage with it. */