Author: Matti Picus <[email protected]>
Branch: win32-cleanup2
Changeset: r54170:f89544de8192
Date: 2012-04-03 22:37 +0300
http://bitbucket.org/pypy/pypy/changeset/f89544de8192/
Log: adding tests where os.write should fail, add impl of validate_fd
diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -81,7 +81,7 @@
FILEP = rffi.COpaquePtr('FILE')
fopen = rffi.llexternal('fopen', [CONST_STRING, CONST_STRING], FILEP)
-#fclose = rffi.llexternal('fclose', [FILEP], rffi.INT)
+_fclose = rffi.llexternal('fclose', [FILEP], rffi.INT)
def fclose(fp):
try:
fd = fileno(fp)
diff --git a/pypy/rlib/rposix.py b/pypy/rlib/rposix.py
--- a/pypy/rlib/rposix.py
+++ b/pypy/rlib/rposix.py
@@ -1,5 +1,6 @@
import os
-from pypy.rpython.lltypesystem.rffi import CConstant, CExternVariable, INT
+from pypy.rpython.lltypesystem.rffi import (CConstant, CExternVariable,
+ INT, CCHARPP)
from pypy.rpython.lltypesystem import lltype, ll2ctypes, rffi
from pypy.translator.tool.cbuild import ExternalCompilationInfo
from pypy.rlib.rarithmetic import intmask
@@ -18,12 +19,68 @@
def __setitem__(self, index, value):
assert index == 0
ll2ctypes.TLS.errno = value
+if os.name == 'nt':
+ post_include_bits =['''
+ /* Lifted completely from CPython 3.3 Modules/posix_module.c */
+ typedef struct {
+ intptr_t osfhnd;
+ char osfile;
+ } my_ioinfo;
+ extern __declspec(dllimport) char * __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
-errno_eci = ExternalCompilationInfo(
- includes=['errno.h']
+ /* 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);
+
+ static size_t sizeof_ioinfo = 0;
+
+ /* Determine the actual size of the ioinfo structure,
+ * as used by the CRT loaded in memory
+ */
+ if (sizeof_ioinfo == 0 && __pioinfo[0] != NULL) {
+ sizeof_ioinfo = _msize(__pioinfo[0]) / IOINFO_ARRAY_ELTS;
+ }
+ if (sizeof_ioinfo == 0) {
+ /* This should not happen... */
+ goto fail;
+ }
+
+ /* 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 */
+ my_ioinfo* info = (my_ioinfo*)(__pioinfo[i1] + i2 *
sizeof_ioinfo);
+ if (info->osfile & FOPEN) {
+ return 1;
+ }
+ }
+ }
+ fail:
+ errno = EBADF;
+ return 0;
+ }
+ ''']
+else:
+ post_include_bits = []
+eci = ExternalCompilationInfo(
+ includes=['errno.h','stdio.h'],
+ post_include_bits = post_include_bits,
)
-_get_errno, _set_errno = CExternVariable(INT, 'errno', errno_eci,
+_get_errno, _set_errno = CExternVariable(INT, 'errno', eci,
CConstantErrno, sandboxsafe=True,
_nowrapper=True, c_type='int')
# the default wrapper for set_errno is not suitable for use in critical places
@@ -35,12 +92,29 @@
def set_errno(errno):
_set_errno(rffi.cast(INT, errno))
+if os.name == 'nt':
+ def validate_fd_emulator(fd):
+ try:
+ os.fstat(fd)
+ return 1
+ except:
+ return 0
+ validate_fd = rffi.llexternal(
+ "_PyVerify_fd", [rffi.INT], rffi.INT,
+ _callable=validate_fd_emulator, compilation_info=eci,
+ _nowrapper=True, elidable_function=True, sandboxsafe=True,
+ )
+else:
+ def validate_fd(fd):
+ return 1
+
def closerange(fd_low, fd_high):
# this behaves like os.closerange() from Python 2.6.
for fd in xrange(fd_low, fd_high):
try:
- os.close(fd)
+ if validate_fd(fd):
+ os.close(fd)
except OSError:
pass
diff --git a/pypy/rlib/test/test_rposix.py b/pypy/rlib/test/test_rposix.py
--- a/pypy/rlib/test/test_rposix.py
+++ b/pypy/rlib/test/test_rposix.py
@@ -131,3 +131,13 @@
os.rmdir(self.ufilename)
except Exception:
pass
+
+ def test_validate_fd(self):
+ assert rposix.validate_fd(0) == 1
+ fid = open(str(udir.join('validate_test.txt')), 'w')
+ fd = fid.fileno()
+ assert rposix.validate_fd(fd) == 1
+ fid.close()
+ assert rposix.validate_fd(fd) == 0
+
+
diff --git a/pypy/rpython/module/ll_os.py b/pypy/rpython/module/ll_os.py
--- a/pypy/rpython/module/ll_os.py
+++ b/pypy/rpython/module/ll_os.py
@@ -916,6 +916,8 @@
def os_write_llimpl(fd, data):
count = len(data)
+ if not rposix.validate_fd(fd):
+ raise OSError(rposix.get_errno(), 'Bad file descriptor')
buf = rffi.get_nonmovingbuffer(data)
try:
written = rffi.cast(lltype.Signed, os_write(
diff --git a/pypy/rpython/test/test_llinterp.py
b/pypy/rpython/test/test_llinterp.py
--- a/pypy/rpython/test/test_llinterp.py
+++ b/pypy/rpython/test/test_llinterp.py
@@ -139,7 +139,7 @@
got = interp.find_exception(info.value)
except ValueError:
got = None
- assert got is exc, "wrong exception type"
+ assert got is exc, "wrong exception type, expected %r got %r"%(exc, got)
#__________________________________________________________________
# tests
diff --git a/pypy/rpython/test/test_rbuiltin.py
b/pypy/rpython/test/test_rbuiltin.py
--- a/pypy/rpython/test/test_rbuiltin.py
+++ b/pypy/rpython/test/test_rbuiltin.py
@@ -201,6 +201,14 @@
os.close(res)
hello = open(tmpdir).read()
assert hello == "hello world"
+ def throws(fname):
+ fd = os.open(fname, os.O_WRONLY|os.O_CREAT, 777)
+ os.close(fd)
+ os.write(fd, "hello world")
+ return fd
+ def g():
+ return throws(tmpdir)
+ self.interpret_raises(OSError, g, [])
def test_os_write_single_char(self):
tmpdir = str(udir.udir.join("os_write_test_char"))
diff --git a/pypy/translator/c/src/main.h b/pypy/translator/c/src/main.h
--- a/pypy/translator/c/src/main.h
+++ b/pypy/translator/c/src/main.h
@@ -20,7 +20,7 @@
#endif
#ifdef MS_WINDOWS
-#include "src/winstuff.c"
+/*#include "src/winstuff.c"*/
#endif
#ifdef __GNUC__
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit