[pypy-commit] pypy default: Win32: fix set_inheritable tests

arigo pypy.commits at gmail.com
Tue Nov 8 12:45:46 EST 2016


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r88223:405237fca758
Date: 2016-11-08 18:44 +0100
http://bitbucket.org/pypy/pypy/changeset/405237fca758/

Log:	Win32: fix set_inheritable tests

diff --git a/rpython/rlib/rposix.py b/rpython/rlib/rposix.py
--- a/rpython/rlib/rposix.py
+++ b/rpython/rlib/rposix.py
@@ -1166,6 +1166,10 @@
 @replace_os_function('pipe')
 def pipe(flags=0):
     # 'flags' might be ignored.  Check the result.
+    # The handles returned are always inheritable on Posix.
+    # The situation on Windows is not completely clear: I think
+    # it should always return non-inheritable handles, but CPython
+    # uses SECURITY_ATTRIBUTES to ensure that and we don't.
     if _WIN32:
         # 'flags' ignored
         ralloc = lltype.scoped_alloc(rwin32.LPHANDLE.TO, 1)
@@ -2146,8 +2150,9 @@
         handle_posix_error('mknodat', error)
 
 
-eci_inheritable = eci.merge(ExternalCompilationInfo(
-    separate_module_sources=[r"""
+if not _WIN32:
+    eci_inheritable = eci.merge(ExternalCompilationInfo(
+        separate_module_sources=[r"""
 #include <errno.h>
 #include <sys/ioctl.h>
 
@@ -2200,10 +2205,6 @@
 RPY_EXTERN
 int rpy_dup_noninheritable(int fd)
 {
-#ifdef _WIN32
-#error NotImplementedError
-#endif
-
 #ifdef F_DUPFD_CLOEXEC
     return fcntl(fd, F_DUPFD_CLOEXEC, 0);
 #else
@@ -2221,10 +2222,6 @@
 RPY_EXTERN
 int rpy_dup2_noninheritable(int fd, int fd2)
 {
-#ifdef _WIN32
-#error NotImplementedError
-#endif
-
 #ifdef F_DUP2FD_CLOEXEC
     return fcntl(fd, F_DUP2FD_CLOEXEC, fd2);
 
@@ -2249,33 +2246,41 @@
     return 0;
 #endif
 }
-    """ % {'HAVE_DUP3': HAVE_DUP3}],
-    post_include_bits=['RPY_EXTERN int rpy_set_inheritable(int, int);\n'
-                       'RPY_EXTERN int rpy_get_inheritable(int);\n'
-                       'RPY_EXTERN int rpy_dup_noninheritable(int);\n'
-                       'RPY_EXTERN int rpy_dup2_noninheritable(int, int);\n']))
+        """ % {'HAVE_DUP3': HAVE_DUP3}],
+        post_include_bits=['RPY_EXTERN int rpy_set_inheritable(int, int);\n'
+                           'RPY_EXTERN int rpy_get_inheritable(int);\n'
+                           'RPY_EXTERN int rpy_dup_noninheritable(int);\n'
+                           'RPY_EXTERN int rpy_dup2_noninheritable(int, int);\n'
+                           ]))
 
-c_set_inheritable = external('rpy_set_inheritable', [rffi.INT, rffi.INT],
-                             rffi.INT, save_err=rffi.RFFI_SAVE_ERRNO,
-                             compilation_info=eci_inheritable)
-c_get_inheritable = external('rpy_get_inheritable', [rffi.INT],
-                             rffi.INT, save_err=rffi.RFFI_SAVE_ERRNO,
-                             compilation_info=eci_inheritable)
-c_dup_noninheritable = external('rpy_dup_noninheritable', [rffi.INT],
-                                rffi.INT, save_err=rffi.RFFI_SAVE_ERRNO,
-                                compilation_info=eci_inheritable)
-c_dup2_noninheritable = external('rpy_dup2_noninheritable', [rffi.INT,rffi.INT],
-                                 rffi.INT, save_err=rffi.RFFI_SAVE_ERRNO,
-                                 compilation_info=eci_inheritable)
+    _c_set_inheritable = external('rpy_set_inheritable', [rffi.INT, rffi.INT],
+                                  rffi.INT, save_err=rffi.RFFI_SAVE_ERRNO,
+                                  compilation_info=eci_inheritable)
+    _c_get_inheritable = external('rpy_get_inheritable', [rffi.INT],
+                                  rffi.INT, save_err=rffi.RFFI_SAVE_ERRNO,
+                                  compilation_info=eci_inheritable)
+    c_dup_noninheritable = external('rpy_dup_noninheritable', [rffi.INT],
+                                    rffi.INT, save_err=rffi.RFFI_SAVE_ERRNO,
+                                    compilation_info=eci_inheritable)
+    c_dup2_noninheritable = external('rpy_dup2_noninheritable', [rffi.INT,rffi.INT],
+                                     rffi.INT, save_err=rffi.RFFI_SAVE_ERRNO,
+                                     compilation_info=eci_inheritable)
 
-def set_inheritable(fd, inheritable):
-    result = c_set_inheritable(fd, inheritable)
-    handle_posix_error('set_inheritable', result)
+    def set_inheritable(fd, inheritable):
+        result = _c_set_inheritable(fd, inheritable)
+        handle_posix_error('set_inheritable', result)
 
-def get_inheritable(fd):
-    res = c_get_inheritable(fd)
-    res = handle_posix_error('get_inheritable', res)
-    return res != 0
+    def get_inheritable(fd):
+        res = _c_get_inheritable(fd)
+        res = handle_posix_error('get_inheritable', res)
+        return res != 0
+
+else:
+    # _WIN32
+    from rpython.rlib.rwin32 import set_inheritable, get_inheritable
+    from rpython.rlib.rwin32 import c_dup_noninheritable
+    from rpython.rlib.rwin32 import c_dup2_noninheritable
+
 
 class SetNonInheritableCache(object):
     """Make one prebuilt instance of this for each path that creates
diff --git a/rpython/rlib/rwin32.py b/rpython/rlib/rwin32.py
--- a/rpython/rlib/rwin32.py
+++ b/rpython/rlib/rwin32.py
@@ -112,7 +112,7 @@
                        CTRL_C_EVENT CTRL_BREAK_EVENT
                        MB_ERR_INVALID_CHARS ERROR_NO_UNICODE_TRANSLATION
                        WC_NO_BEST_FIT_CHARS STD_INPUT_HANDLE STD_OUTPUT_HANDLE
-                       STD_ERROR_HANDLE
+                       STD_ERROR_HANDLE HANDLE_FLAG_INHERIT FILE_TYPE_CHAR
                     """
         from rpython.translator.platform import host_factory
         static_platform = host_factory()
@@ -473,3 +473,56 @@
     CONSOLE_SCREEN_BUFFER_INFO_P = lltype.Ptr(CONSOLE_SCREEN_BUFFER_INFO)
     GetConsoleScreenBufferInfo = winexternal(
         "GetConsoleScreenBufferInfo", [HANDLE, CONSOLE_SCREEN_BUFFER_INFO_P], BOOL)
+
+    _GetHandleInformation = winexternal(
+        'GetHandleInformation', [HANDLE, LPDWORD], BOOL)
+    _SetHandleInformation = winexternal(
+        'SetHandleInformation', [HANDLE, DWORD, DWORD], BOOL)
+
+    def set_inheritable(fd, inheritable):
+        handle = get_osfhandle(fd)
+        if inheritable:
+            flags = HANDLE_FLAG_INHERIT
+        else:
+            flags = 0
+        if not _SetHandleInformation(handle, HANDLE_FLAG_INHERIT, flags):
+            raise lastSavedWindowsError("SetHandleInformation")
+
+    def get_inheritable(fd):
+        handle = get_osfhandle(fd)
+        pflags = lltype.malloc(LPDWORD.TO, 1, flavor='raw')
+        try:
+            if not _GetHandleInformation(handle, pflags):
+                raise lastSavedWindowsError("GetHandleInformation")
+            flags = pflags[0]
+        finally:
+            lltype.free(pflags, flavor='raw')
+        return (flags & HANDLE_FLAG_INHERIT) != 0
+
+    _GetFileType = winexternal('GetFileType', [HANDLE], DWORD)
+
+    def c_dup_noninheritable(fd1):
+        from rpython.rlib.rposix import c_dup
+
+        ftype = _GetFileType(get_osfhandle(fd1))
+        fd2 = c_dup(fd1)     # the inheritable version
+        if fd2 >= 0 and ftype != FILE_TYPE_CHAR:
+            try:
+                set_inheritable(fd2, False)
+            except:
+                os.close(fd2)
+                raise
+        return fd2
+
+    def c_dup2_noninheritable(fd1, fd2):
+        from rpython.rlib.rposix import c_dup2
+
+        ftype = _GetFileType(get_osfhandle(fd1))
+        res = c_dup2(fd1, fd2)     # the inheritable version
+        if res >= 0 and ftype != FILE_TYPE_CHAR:
+            try:
+                set_inheritable(fd2, False)
+            except:
+                os.close(fd2)
+                raise
+        return res
diff --git a/rpython/rlib/test/test_rposix.py b/rpython/rlib/test/test_rposix.py
--- a/rpython/rlib/test/test_rposix.py
+++ b/rpython/rlib/test/test_rposix.py
@@ -604,6 +604,9 @@
 def test_SetNonInheritableCache():
     cache = rposix.SetNonInheritableCache()
     fd1, fd2 = os.pipe()
+    if sys.platform == 'win32':
+        rposix.set_inheritable(fd1, True)
+        rposix.set_inheritable(fd2, True)
     assert rposix.get_inheritable(fd1) == True
     assert rposix.get_inheritable(fd1) == True
     assert cache.cached_inheritable == -1
@@ -616,6 +619,24 @@
     os.close(fd1)
     os.close(fd2)
 
+def test_dup_dup2_non_inheritable():
+    for preset in [False, True]:
+        fd1, fd2 = os.pipe()
+        rposix.set_inheritable(fd1, preset)
+        rposix.set_inheritable(fd2, preset)
+        fd3 = rposix.dup(fd1, True)
+        assert rposix.get_inheritable(fd3) == True
+        fd4 = rposix.dup(fd1, False)
+        assert rposix.get_inheritable(fd4) == False
+        rposix.dup2(fd2, fd4, False)
+        assert rposix.get_inheritable(fd4) == False
+        rposix.dup2(fd2, fd3, True)
+        assert rposix.get_inheritable(fd3) == True
+        os.close(fd1)
+        os.close(fd2)
+        os.close(fd3)
+        os.close(fd4)
+
 def test_sync():
     if sys.platform != 'win32':
         rposix.sync()


More information about the pypy-commit mailing list