Index: Objects/fileobject.c =================================================================== --- Objects/fileobject.c (revision 66486) +++ Objects/fileobject.c (working copy) @@ -305,10 +305,17 @@ #endif /* EINVAL is returned when an invalid filename or * an invalid mode is supplied. */ - if (errno == EINVAL) - PyErr_Format(PyExc_IOError, - "invalid filename: %s or mode: %s", - name, mode); + if (errno == EINVAL) { + PyObject *v; + char message[100]; + PyOS_snprintf(message, 100, + "invalid filename or mode '%.50s'", mode); + v = Py_BuildValue("(isO)", errno, message, f->f_name); + if (v != NULL) { + PyErr_SetObject(PyExc_IOError, v); + Py_DECREF(v); + } + } else PyErr_SetFromErrnoWithFilenameObject(PyExc_IOError, f->f_name); f = NULL; Index: Lib/test/test_file.py =================================================================== --- Lib/test/test_file.py (revision 66486) +++ Lib/test/test_file.py (working copy) @@ -134,6 +134,16 @@ f.close() self.fail('%r is an invalid file mode' % mode) + # Some invalid modes fail on Windows, but pass on Unix + # Issue3965: avoid a crash on Windows when filename is unicode + for name in (TESTFN, unicode(TESTFN), unicode(TESTFN + '\t')): + try: + f = open(name, "rr") + except IOError: + pass + else: + f.close() + def testStdin(self): # This causes the interpreter to exit on OSF1 v5.1. if sys.platform != 'osf1V5':