[Python-checkins] r69793 - in python/branches/py3k: Lib/test/test_os.py Modules/posixmodule.c

amaury.forgeotdarc python-checkins at python.org
Fri Feb 20 00:23:47 CET 2009


Author: amaury.forgeotdarc
Date: Fri Feb 20 00:23:47 2009
New Revision: 69793

Log:
#5306: Fix compilation on Windows by properly merging change 69495.
+ fixed an obvious merge glitch in a windows-only test.

Patch by Hirokazu Yamamoto.

I added a _PyVerify_fd() call to os.device_encoding() (new in python 3.0)
which also uses a raw file descriptor.


Modified:
   python/branches/py3k/Lib/test/test_os.py
   python/branches/py3k/Modules/posixmodule.c

Modified: python/branches/py3k/Lib/test/test_os.py
==============================================================================
--- python/branches/py3k/Lib/test/test_os.py	(original)
+++ python/branches/py3k/Lib/test/test_os.py	Fri Feb 20 00:23:47 2009
@@ -576,12 +576,12 @@
         self.assertRaises(WindowsError, os.chdir, support.TESTFN)
 
     def test_mkdir(self):
-        f = open(test_support.TESTFN, "w")
+        f = open(support.TESTFN, "w")
         try:
             self.assertRaises(WindowsError, os.mkdir, support.TESTFN)
         finally:
             f.close()
-            os.unlink(test_support.TESTFN)
+            os.unlink(support.TESTFN)
 
     def test_utime(self):
         self.assertRaises(WindowsError, os.utime, support.TESTFN, None)

Modified: python/branches/py3k/Modules/posixmodule.c
==============================================================================
--- python/branches/py3k/Modules/posixmodule.c	(original)
+++ python/branches/py3k/Modules/posixmodule.c	Fri Feb 20 00:23:47 2009
@@ -331,6 +331,109 @@
 #endif
 #endif
 
+#if defined _MSC_VER && _MSC_VER >= 1400
+/* Microsoft CRT in VS2005 and higher will verify that a filehandle is
+ * valid and throw an assertion if it isn't.
+ * Normally, an invalid fd is likely to be a C program error and therefore
+ * an assertion can be useful, but it does contradict the POSIX standard
+ * which for write(2) states:
+ *    "Otherwise, -1 shall be returned and errno set to indicate the error."
+ *    "[EBADF] The fildes argument is not a valid file descriptor open for
+ *     writing."
+ * Furthermore, python allows the user to enter any old integer
+ * as a fd and should merely raise a python exception on error.
+ * The Microsoft CRT doesn't provide an official way to check for the
+ * validity of a file descriptor, but we can emulate its internal behaviour
+ * by using the exported __pinfo data member and knowledge of the 
+ * internal structures involved.
+ * The structures below must be updated for each version of visual studio
+ * according to the file internal.h in the CRT source, until MS comes
+ * up with a less hacky way to do this.
+ * (all of this is to avoid globally modifying the CRT behaviour using
+ * _set_invalid_parameter_handler() and _CrtSetReportMode())
+ */
+#if _MSC_VER >= 1500 /* VS 2008 */
+typedef struct {
+        intptr_t osfhnd;
+        char osfile;
+        char pipech;
+        int lockinitflag;
+        CRITICAL_SECTION lock;
+#ifndef _SAFECRT_IMPL
+        char textmode : 7;
+        char unicode : 1;
+        char pipech2[2];
+        __int64 startpos;
+        BOOL utf8translations;
+        char dbcsBuffer;
+        BOOL dbcsBufferUsed;
+#endif  /* _SAFECRT_IMPL */
+    }   ioinfo;
+#elif _MSC_VER >= 1400  /* VS 2005 */
+typedef struct {
+        intptr_t osfhnd;
+        char osfile;
+        char pipech;
+        int lockinitflag;
+        CRITICAL_SECTION lock;
+#ifndef _SAFECRT_IMPL
+        char textmode : 7;
+        char unicode : 1;
+        char pipech2[2];
+        __int64 startpos;
+        BOOL utf8translations;
+#endif  /* _SAFECRT_IMPL */
+    }   ioinfo;
+#endif
+
+extern __declspec(dllimport) ioinfo * __pioinfo[];
+#define IOINFO_L2E 5
+#define IOINFO_ARRAY_ELTS   (1 << IOINFO_L2E)
+#define IOINFO_ARRAYS 64
+#define _NHANDLE_           (IOINFO_ARRAYS * IOINFO_ARRAY_ELTS)
+#define FOPEN 0x01
+#define _NO_CONSOLE_FILENO (intptr_t)-2
+
+/* This function emulates what the windows CRT does to validate file handles */
+int
+_PyVerify_fd(int fd)
+{
+	const int i1 = fd >> IOINFO_L2E;
+	const int i2 = fd & ((1 << IOINFO_L2E) - 1);
+
+	/* See that it isn't a special CLEAR fileno */
+	if (fd != _NO_CONSOLE_FILENO) {
+		/* Microsoft CRT would check that 0<=fd<_nhandle but we can't do that.  Instead
+		 * we check pointer validity and other info
+		 */
+		if (0 <= i1 && i1 < IOINFO_ARRAYS && __pioinfo[i1] != NULL) {
+			/* finally, check that the file is open */
+			if (__pioinfo[i1][i2].osfile & FOPEN)
+				return 1;
+		}
+	}
+	errno = EBADF;
+	return 0;
+}
+
+/* the special case of checking dup2.  The target fd must be in a sensible range */
+static int
+_PyVerify_fd_dup2(int fd1, int fd2)
+{
+	if (!_PyVerify_fd(fd1))
+		return 0;
+	if (fd2 == _NO_CONSOLE_FILENO)
+		return 0;
+	if ((unsigned)fd2 < _NHANDLE_)
+		return 1;
+	else
+		return 0;
+}
+#else
+/* dummy version. _PyVerify_fd() is already defined in fileobject.h */
+#define _PyVerify_fd_dup2(A, B) (1)
+#endif
+
 /* Return a dictionary corresponding to the POSIX environment table */
 #ifdef WITH_NEXT_FRAMEWORK
 /* On Darwin/MacOSX a shared library or framework has no access to
@@ -606,6 +709,8 @@
 	fd = PyObject_AsFileDescriptor(fdobj);
 	if (fd < 0)
 		return NULL;
+	if (!_PyVerify_fd(fd))
+		return posix_error();
 	Py_BEGIN_ALLOW_THREADS
 	res = (*func)(fd);
 	Py_END_ALLOW_THREADS
@@ -4725,6 +4830,8 @@
 	int fd, res;
 	if (!PyArg_ParseTuple(args, "i:close", &fd))
 		return NULL;
+	if (!_PyVerify_fd(fd))
+		return posix_error();
 	Py_BEGIN_ALLOW_THREADS
 	res = close(fd);
 	Py_END_ALLOW_THREADS
@@ -4747,7 +4854,8 @@
 		return NULL;
 	Py_BEGIN_ALLOW_THREADS
 	for (i = fd_from; i < fd_to; i++)
-		close(i);
+		if (_PyVerify_fd(i))
+			close(i);
 	Py_END_ALLOW_THREADS
 	Py_RETURN_NONE;
 }
@@ -4763,6 +4871,8 @@
 	int fd;
 	if (!PyArg_ParseTuple(args, "i:dup", &fd))
 		return NULL;
+	if (!_PyVerify_fd(fd))
+		return posix_error();
 	Py_BEGIN_ALLOW_THREADS
 	fd = dup(fd);
 	Py_END_ALLOW_THREADS
@@ -4782,6 +4892,8 @@
 	int fd, fd2, res;
 	if (!PyArg_ParseTuple(args, "ii:dup2", &fd, &fd2))
 		return NULL;
+	if (!_PyVerify_fd_dup2(fd, fd2))
+		return posix_error();
 	Py_BEGIN_ALLOW_THREADS
 	res = dup2(fd, fd2);
 	Py_END_ALLOW_THREADS
@@ -4826,6 +4938,8 @@
 	if (PyErr_Occurred())
 		return NULL;
 
+	if (!_PyVerify_fd(fd))
+		return posix_error();
 	Py_BEGIN_ALLOW_THREADS
 #if defined(MS_WIN64) || defined(MS_WINDOWS)
 	res = _lseeki64(fd, pos, how);
@@ -4863,6 +4977,8 @@
 	buffer = PyBytes_FromStringAndSize((char *)NULL, size);
 	if (buffer == NULL)
 		return NULL;
+	if (!_PyVerify_fd(fd))
+		return posix_error();
 	Py_BEGIN_ALLOW_THREADS
 	n = read(fd, PyBytes_AS_STRING(buffer), size);
 	Py_END_ALLOW_THREADS
@@ -4889,6 +5005,8 @@
 
 	if (!PyArg_ParseTuple(args, "iy*:write", &fd, &pbuf))
 		return NULL;
+	if (!_PyVerify_fd(fd))
+		return posix_error();
 	Py_BEGIN_ALLOW_THREADS
 	size = write(fd, pbuf.buf, (size_t)pbuf.len);
 	Py_END_ALLOW_THREADS
@@ -4915,6 +5033,8 @@
         /* on OpenVMS we must ensure that all bytes are written to the file */
         fsync(fd);
 #endif
+	if (!_PyVerify_fd(fd))
+		return posix_error();
 	Py_BEGIN_ALLOW_THREADS
 	res = FSTAT(fd, &st);
 	Py_END_ALLOW_THREADS
@@ -4940,6 +5060,8 @@
 	int fd;
 	if (!PyArg_ParseTuple(args, "i:isatty", &fd))
 		return NULL;
+	if (!_PyVerify_fd(fd))
+		return PyBool_FromLong(0);
 	return PyBool_FromLong(isatty(fd));
 }
 
@@ -6702,6 +6824,8 @@
 	int fd;
 	if (!PyArg_ParseTuple(args, "i:device_encoding", &fd))
 		return NULL;
+	if (!_PyVerify_fd(fd))
+		return posix_error();
 	if (!isatty(fd)) {
 		Py_INCREF(Py_None);
 		return Py_None;


More information about the Python-checkins mailing list