[Python-modules-commits] [python-subprocess32] 01/08: Import python-subprocess32_3.2.7.orig.tar.gz
Ondřej Nový
onovy-guest at moszumanska.debian.org
Sat Jun 4 12:46:53 UTC 2016
This is an automated email from the git hooks/post-receive script.
onovy-guest pushed a commit to branch master
in repository python-subprocess32.
commit 244bdf570970dd319a91a5e6d1eaa95b9cfd7a34
Author: Ondřej Nový <novy at ondrej.org>
Date: Sat Jun 4 14:16:28 2016 +0200
Import python-subprocess32_3.2.7.orig.tar.gz
---
ChangeLog | 29 ++++++++++++++++
MANIFEST.in | 2 +-
PKG-INFO | 29 ++++++++++++----
README.md | 45 ++++++++++++++++++++++++
README.txt | 16 ---------
_posixsubprocess.c | 94 ++++++++++++++++++++++++++-------------------------
setup.py | 37 ++++++++++++++++----
subprocess32.py | 21 ++++++++----
test_subprocess32.py | 90 ++++++++++++++++++++++++++++++++++++++++++++++++
testdata/fd_status.py | 46 +++++++++++++++----------
10 files changed, 308 insertions(+), 101 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index ff6af02..6ad9d8d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,33 @@
-----------------
+2015-11-15 3.2.7
+-----------------
+
+* Issue #6973: When we know a subprocess.Popen process has died, do
+ not allow the send_signal(), terminate(), or kill() methods to do
+ anything as they could potentially signal a different process.
+* Issue #23564: Fixed a partially broken sanity check in the _posixsubprocess
+ internals regarding how fds_to_pass were passed to the child. The bug had
+ no actual impact as subprocess32.py already avoided it.
+
+-----------------
+2015-11-14 3.2.7rc2
+-----------------
+
+* Moved the repository from code.google.com to github.
+* Added a _WAIT_TIMEOUT to satisfy the unsupported people entirely on
+ their own trying to use this on Windows.
+* Similarly: Updated setup.py to not build the extension on non-posix.
+
+-----------------
+2014-06-01 3.2.7rc1
+-----------------
+
+* Issue #21618: The subprocess module could fail to close open fds that were
+ inherited by the calling process and already higher than POSIX resource
+ limits would otherwise allow. On systems with a functioning /proc/self/fd
+ or /dev/fd interface the max is now ignored and all fds are closed.
+
+-----------------
2014-04-23 3.2.6
-----------------
diff --git a/MANIFEST.in b/MANIFEST.in
index 8b7b39a..e5b5bbb 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,4 +1,4 @@
-include *.txt
+include *.md
include LICENSE*
include setup.py
include setup.cfg
diff --git a/PKG-INFO b/PKG-INFO
index 48cfc1d..6425b16 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,15 +1,30 @@
-Metadata-Version: 1.0
+Metadata-Version: 1.1
Name: subprocess32
-Version: 3.2.6
-Summary: Backport of the subprocess module from Python 3.2/3.3 for use on 2.x.
-Home-page: http://code.google.com/p/python-subprocess32/
+Version: 3.2.7
+Summary: A backport of the subprocess module from Python 3.2/3.3 for use on 2.x.
+Home-page: https://github.com/google/python-subprocess32
Author: Gregory P. Smith
Author-email: greg at krypto.org
License: PSF license
Description:
This is a backport of the subprocess standard library module from
- Python 3.2 & 3.3 for use on Python 2.4, 2.5, 2.6 and 2.7.
- It includes bugfixes and new features. On POSIX systems it is
+ Python 3.2 & 3.3 for use on Python 2.
+ It includes bugfixes and some new features. On POSIX systems it is
guaranteed to be reliable when used in threaded applications.
- Bonus: It includes timeout support from Python 3.3.
+ It includes timeout support from Python 3.3 but otherwise matches
+ 3.2's API. It has not been tested on Windows.
Platform: UNKNOWN
+Classifier: Intended Audience :: Developers
+Classifier: Topic :: Software Development :: Libraries
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: License :: OSI Approved :: Python Software Foundation License
+Classifier: Operating System :: POSIX
+Classifier: Operating System :: POSIX :: BSD
+Classifier: Operating System :: POSIX :: Linux
+Classifier: Operating System :: POSIX :: SunOS/Solaris
+Classifier: Programming Language :: Python :: 2.4
+Classifier: Programming Language :: Python :: 2.5
+Classifier: Programming Language :: Python :: 2.6
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 2 :: Only
+Classifier: Programming Language :: Python :: Implementation :: CPython
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..76eb5ea
--- /dev/null
+++ b/README.md
@@ -0,0 +1,45 @@
+subprocess32
+------------
+
+This is a backport of the Python 3 subprocess module for use on Python 2.
+This code has not been tested on Windows or other non-POSIX platforms.
+
+subprocess32 includes many important reliability bug fixes relevant on
+POSIX platforms. The most important of which is a C extension module
+used internally to handle the code path between fork() and exec().
+This module is reliable when an application is using threads.
+
+Refer to the
+[Python 3.3 subprocess documentation](https://docs.python.org/3.3/library/subprocess.html)
+for usage information.
+
+* Timeout support backported from Python 3.3 is included.
+* Otherwise features are frozen at the 3.2 level.
+
+Usage
+-----
+
+The recommend pattern for cross platform code is to use the following:
+
+```python
+if os.name == 'posix' and sys.version_info[0] < 3:
+ import subprocess32 as subprocess
+else:
+ import subprocess
+```
+
+Or if you fully control your POSIX Python 2.7 installation, just drop
+this in as a replacement for its subprocess module. Users will thank
+you by not filing concurrency bugs.
+
+Got Bugs?
+---------
+
+Try to reproduce them on the latest Python 3.x itself and file bug
+reports on [bugs.python.org](https://bugs.python.org/).
+Add gregory.p.smith to the Nosy list.
+
+If you have reason to believe the issue is specifically with this backport
+and not a problem in Python 3 itself, use the github issue tracker.
+
+-- Gregory P. Smith _greg at krypto.org_
diff --git a/README.txt b/README.txt
deleted file mode 100644
index 8608e7d..0000000
--- a/README.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-This is a backport of the Python 3.2 subprocess module for use on
-Python versions 2.4 through 2.7.
-
-It includes many important bug fixes including a C extension module used
-internally to handle the code path between fork() and exec(). This version
-is reliable when an application is using threads.
-
-Refer to the Python 3.2 documentation for usage information:
- http://docs.python.org/3.2/library/subprocess.html
-
-Timeout support backported from Python 3.3 is also included.
-
-Bugs? Try to reproduce them on the latest Python 3.x itself and file bug
-reports on http://bugs.python.org/. Add gregory.p.smith to the Nosy list.
-
--- Gregory P. Smith greg at krypto.org
diff --git a/_posixsubprocess.c b/_posixsubprocess.c
index cd63054..012715e 100644
--- a/_posixsubprocess.c
+++ b/_posixsubprocess.c
@@ -61,10 +61,6 @@ static int _PyImport_ReleaseLock(void);
#define POSIX_CALL(call) if ((call) == -1) goto error
-/* Maximum file descriptor, initialized on module load. */
-static long max_fd;
-
-
/* Given the gc module call gc.enable() and return 0 on success. */
static int
_enable_gc(PyObject *gc_module)
@@ -125,10 +121,11 @@ _sanity_check_python_fd_sequence(PyObject *fd_sequence)
for (seq_idx = 0; seq_idx < seq_len; ++seq_idx) {
PyObject* py_fd = PySequence_Fast_GET_ITEM(fd_sequence, seq_idx);
long iter_fd = PyLong_AsLong(py_fd);
- if (iter_fd < 0 || iter_fd < prev_fd || iter_fd > INT_MAX) {
+ if (iter_fd < 0 || iter_fd <= prev_fd || iter_fd > INT_MAX) {
/* Negative, overflow, not a Long, unsorted, too big for a fd. */
return 1;
}
+ prev_fd = iter_fd;
}
return 0;
}
@@ -158,14 +155,39 @@ _is_fd_in_sorted_fd_sequence(int fd, PyObject *fd_sequence)
}
-/* Close all file descriptors in the range start_fd inclusive to
- * end_fd exclusive except for those in py_fds_to_keep. If the
- * range defined by [start_fd, end_fd) is large this will take a
- * long time as it calls close() on EVERY possible fd.
+/* Get the maximum file descriptor that could be opened by this process.
+ * This function is async signal safe for use between fork() and exec().
+ */
+static long
+safe_get_max_fd(void)
+{
+ long local_max_fd;
+#if defined(__NetBSD__)
+ local_max_fd = fcntl(0, F_MAXFD);
+ if (local_max_fd >= 0)
+ return local_max_fd;
+#endif
+#ifdef _SC_OPEN_MAX
+ local_max_fd = sysconf(_SC_OPEN_MAX);
+ if (local_max_fd == -1)
+#endif
+ local_max_fd = 256; /* Matches legacy Lib/subprocess.py behavior. */
+ return local_max_fd;
+}
+
+
+/* Close all file descriptors in the range from start_fd and higher
+ * except for those in py_fds_to_keep. If the range defined by
+ * [start_fd, safe_get_max_fd()) is large this will take a long
+ * time as it calls close() on EVERY possible fd.
+ *
+ * It isn't possible to know for sure what the max fd to go up to
+ * is for processes with the capability of raising their maximum.
*/
static void
-_close_fds_by_brute_force(int start_fd, int end_fd, PyObject *py_fds_to_keep)
+_close_fds_by_brute_force(long start_fd, PyObject *py_fds_to_keep)
{
+ long end_fd = safe_get_max_fd();
Py_ssize_t num_fds_to_keep = PySequence_Length(py_fds_to_keep);
Py_ssize_t keep_seq_idx;
int fd_num;
@@ -205,8 +227,8 @@ struct linux_dirent64 {
char d_name[256]; /* Filename (null-terminated) */
};
-/* Close all open file descriptors in the range start_fd inclusive to end_fd
- * exclusive. Do not close any in the sorted py_fds_to_keep list.
+/* Close all open file descriptors in the range from start_fd and higher
+ * Do not close any in the sorted py_fds_to_keep list.
*
* This version is async signal safe as it does not make any unsafe C library
* calls, malloc calls or handle any locks. It is _unfortunate_ to be forced
@@ -221,11 +243,9 @@ struct linux_dirent64 {
* it with some cpp #define magic to work on other OSes as well if you want.
*/
static void
-_close_open_fd_range_safe(int start_fd, int end_fd, PyObject* py_fds_to_keep)
+_close_open_fds_safe(int start_fd, PyObject* py_fds_to_keep)
{
int fd_dir_fd;
- if (start_fd >= end_fd)
- return;
#ifdef O_CLOEXEC
fd_dir_fd = open(FD_DIR, O_RDONLY | O_CLOEXEC, 0);
#else
@@ -240,7 +260,7 @@ _close_open_fd_range_safe(int start_fd, int end_fd, PyObject* py_fds_to_keep)
#endif
if (fd_dir_fd == -1) {
/* No way to get a list of open fds. */
- _close_fds_by_brute_force(start_fd, end_fd, py_fds_to_keep);
+ _close_fds_by_brute_force(start_fd, py_fds_to_keep);
return;
} else {
char buffer[sizeof(struct linux_dirent64)];
@@ -255,23 +275,23 @@ _close_open_fd_range_safe(int start_fd, int end_fd, PyObject* py_fds_to_keep)
entry = (struct linux_dirent64 *)(buffer + offset);
if ((fd = _pos_int_from_ascii(entry->d_name)) < 0)
continue; /* Not a number. */
- if (fd != fd_dir_fd && fd >= start_fd && fd < end_fd &&
+ if (fd != fd_dir_fd && fd >= start_fd &&
!_is_fd_in_sorted_fd_sequence(fd, py_fds_to_keep)) {
while (close(fd) < 0 && errno == EINTR);
}
}
}
- close(fd_dir_fd);
+ while (close(fd_dir_fd) < 0 && errno == EINTR);
}
}
-#define _close_open_fd_range _close_open_fd_range_safe
+#define _close_open_fds _close_open_fds_safe
#else /* NOT (defined(__linux__) && defined(HAVE_SYS_SYSCALL_H)) */
-/* Close all open file descriptors in the range start_fd inclusive to end_fd
- * exclusive. Do not close any in the sorted py_fds_to_keep list.
+/* Close all open file descriptors from start_fd and higher.
+ * Do not close any in the sorted py_fds_to_keep list.
*
* This function violates the strict use of async signal safe functions. :(
* It calls opendir(), readdir() and closedir(). Of these, the one most
@@ -284,17 +304,13 @@ _close_open_fd_range_safe(int start_fd, int end_fd, PyObject* py_fds_to_keep)
* http://womble.decadent.org.uk/readdir_r-advisory.html
*/
static void
-_close_open_fd_range_maybe_unsafe(int start_fd, int end_fd,
- PyObject* py_fds_to_keep)
+_close_open_fds_maybe_unsafe(long start_fd, PyObject* py_fds_to_keep)
{
DIR *proc_fd_dir;
#ifndef HAVE_DIRFD
- while (_is_fd_in_sorted_fd_sequence(start_fd, py_fds_to_keep) &&
- (start_fd < end_fd)) {
+ while (_is_fd_in_sorted_fd_sequence(start_fd, py_fds_to_keep)) {
++start_fd;
}
- if (start_fd >= end_fd)
- return;
/* Close our lowest fd before we call opendir so that it is likely to
* reuse that fd otherwise we might close opendir's file descriptor in
* our loop. This trick assumes that fd's are allocated on a lowest
@@ -302,8 +318,6 @@ _close_open_fd_range_maybe_unsafe(int start_fd, int end_fd,
while (close(start_fd) < 0 && errno == EINTR);
++start_fd;
#endif
- if (start_fd >= end_fd)
- return;
#if defined(__FreeBSD__)
if (!_is_fdescfs_mounted_on_dev_fd())
@@ -313,7 +327,7 @@ _close_open_fd_range_maybe_unsafe(int start_fd, int end_fd,
proc_fd_dir = opendir(FD_DIR);
if (!proc_fd_dir) {
/* No way to get a list of open fds. */
- _close_fds_by_brute_force(start_fd, end_fd, py_fds_to_keep);
+ _close_fds_by_brute_force(start_fd, py_fds_to_keep);
} else {
struct dirent *dir_entry;
#ifdef HAVE_DIRFD
@@ -326,7 +340,7 @@ _close_open_fd_range_maybe_unsafe(int start_fd, int end_fd,
int fd;
if ((fd = _pos_int_from_ascii(dir_entry->d_name)) < 0)
continue; /* Not a number. */
- if (fd != fd_used_by_opendir && fd >= start_fd && fd < end_fd &&
+ if (fd != fd_used_by_opendir && fd >= start_fd &&
!_is_fd_in_sorted_fd_sequence(fd, py_fds_to_keep)) {
while (close(fd) < 0 && errno == EINTR);
}
@@ -334,13 +348,13 @@ _close_open_fd_range_maybe_unsafe(int start_fd, int end_fd,
}
if (errno) {
/* readdir error, revert behavior. Highly Unlikely. */
- _close_fds_by_brute_force(start_fd, end_fd, py_fds_to_keep);
+ _close_fds_by_brute_force(start_fd, py_fds_to_keep);
}
closedir(proc_fd_dir);
}
}
-#define _close_open_fd_range _close_open_fd_range_maybe_unsafe
+#define _close_open_fds _close_open_fds_maybe_unsafe
#endif /* else NOT (defined(__linux__) && defined(HAVE_SYS_SYSCALL_H)) */
@@ -462,14 +476,8 @@ child_exec(char *const exec_array[],
}
if (close_fds) {
- int local_max_fd = max_fd;
-#if defined(__NetBSD__)
- local_max_fd = fcntl(0, F_MAXFD);
- if (local_max_fd < 0)
- local_max_fd = max_fd;
-#endif
/* TODO HP-UX could use pstat_getproc() if anyone cares about it. */
- _close_open_fd_range(3, local_max_fd, py_fds_to_keep);
+ _close_open_fds(3, py_fds_to_keep);
}
/* This loop matches the Lib/os.py _execvpe()'s PATH search when */
@@ -872,12 +880,6 @@ init_posixsubprocess(void)
{
PyObject *m;
-#ifdef _SC_OPEN_MAX
- max_fd = sysconf(_SC_OPEN_MAX);
- if (max_fd == -1)
-#endif
- max_fd = 256; /* Matches Lib/subprocess.py */
-
#if (PY_VERSION_HEX < MIN_PY_VERSION_WITH_PYIMPORT_ACQUIRELOCK)
imp_module = PyImport_ImportModule("imp");
if (imp_module == NULL)
diff --git a/setup.py b/setup.py
index 07d9c37..da410c1 100755
--- a/setup.py
+++ b/setup.py
@@ -1,5 +1,6 @@
#!/usr/bin/python
+import os
import sys
from distutils.core import setup, Extension
@@ -11,25 +12,47 @@ def main():
ext = Extension('_posixsubprocess', ['_posixsubprocess.c'],
depends=['_posixsubprocess_helpers.c'])
+ if os.name == 'posix':
+ ext_modules = [ext]
+ else:
+ ext_modules = []
setup(
name='subprocess32',
- version='3.2.6',
- description='Backport of the subprocess module from Python 3.2/3.3 for use on 2.x.',
+ version='3.2.7',
+ description='A backport of the subprocess module from Python 3.2/3.3 for use on 2.x.',
long_description="""
This is a backport of the subprocess standard library module from
-Python 3.2 & 3.3 for use on Python 2.4, 2.5, 2.6 and 2.7.
-It includes bugfixes and new features. On POSIX systems it is
+Python 3.2 & 3.3 for use on Python 2.
+It includes bugfixes and some new features. On POSIX systems it is
guaranteed to be reliable when used in threaded applications.
-Bonus: It includes timeout support from Python 3.3.""",
+It includes timeout support from Python 3.3 but otherwise matches
+3.2's API. It has not been tested on Windows.""",
license='PSF license',
maintainer='Gregory P. Smith',
maintainer_email='greg at krypto.org',
- url='http://code.google.com/p/python-subprocess32/',
+ url='https://github.com/google/python-subprocess32',
- ext_modules=[ext],
+ ext_modules=ext_modules,
py_modules=['subprocess32'],
+
+ classifiers=[
+ 'Intended Audience :: Developers',
+ 'Topic :: Software Development :: Libraries',
+ 'Development Status :: 5 - Production/Stable',
+ 'License :: OSI Approved :: Python Software Foundation License',
+ 'Operating System :: POSIX',
+ 'Operating System :: POSIX :: BSD',
+ 'Operating System :: POSIX :: Linux',
+ 'Operating System :: POSIX :: SunOS/Solaris',
+ 'Programming Language :: Python :: 2.4',
+ 'Programming Language :: Python :: 2.5',
+ 'Programming Language :: Python :: 2.6',
+ 'Programming Language :: Python :: 2.7',
+ 'Programming Language :: Python :: 2 :: Only',
+ 'Programming Language :: Python :: Implementation :: CPython',
+ ],
)
diff --git a/subprocess32.py b/subprocess32.py
index 567faf6..f1522c0 100644
--- a/subprocess32.py
+++ b/subprocess32.py
@@ -506,6 +506,9 @@ if mswindows:
STD_INPUT_HANDLE, STD_OUTPUT_HANDLE,
STD_ERROR_HANDLE, SW_HIDE,
STARTF_USESTDHANDLES, STARTF_USESHOWWINDOW)
+ # https://msdn.microsoft.com/en-us/library/windows/desktop/ms687032(v=vs.85).aspx
+ # Note: In Python 3.3 this constant is found in the _winapi module.
+ _WAIT_TIMEOUT = 0x102
__all__.extend(["CREATE_NEW_CONSOLE", "CREATE_NEW_PROCESS_GROUP",
"STD_INPUT_HANDLE", "STD_OUTPUT_HANDLE",
@@ -1144,7 +1147,7 @@ class Popen(object):
timeout = int(timeout * 1000)
if self.returncode is None:
result = _subprocess.WaitForSingleObject(self._handle, timeout)
- if result == _subprocess.WAIT_TIMEOUT:
+ if result == _WAIT_TIMEOUT:
raise TimeoutExpired(self.args, timeout)
self.returncode = _subprocess.GetExitCodeProcess(self._handle)
return self.returncode
@@ -1220,8 +1223,10 @@ class Popen(object):
return (stdout, stderr)
def send_signal(self, sig):
- """Send a signal to the process
- """
+ """Send a signal to the process."""
+ # Don't signal a process that we know has already died.
+ if self.returncode is not None:
+ return
if sig == signal.SIGTERM:
self.terminate()
elif sig == signal.CTRL_C_EVENT:
@@ -1232,8 +1237,10 @@ class Popen(object):
raise ValueError("Unsupported signal: %s" % sig)
def terminate(self):
- """Terminates the process
- """
+ """Terminates the process."""
+ # Don't terminate a process that we know has already died.
+ if self.returncode is not None:
+ return
_subprocess.TerminateProcess(self._handle, 1)
kill = terminate
@@ -1878,7 +1885,9 @@ class Popen(object):
def send_signal(self, sig):
"""Send a signal to the process
"""
- os.kill(self.pid, sig)
+ # Skip signalling a process that we know has already died.
+ if self.returncode is None:
+ os.kill(self.pid, sig)
def terminate(self):
"""Terminate the process with SIGTERM
diff --git a/test_subprocess32.py b/test_subprocess32.py
index 818f1cb..c312949 100644
--- a/test_subprocess32.py
+++ b/test_subprocess32.py
@@ -7,6 +7,7 @@ import signal
import os
import errno
import tempfile
+import textwrap
import time
try:
import threading
@@ -1627,6 +1628,60 @@ class POSIXProcessTestCase(BaseTestCase):
"Some fds not in pass_fds were left open")
self.assertIn(1, remaining_fds, "Subprocess failed")
+
+ def test_close_fds_when_max_fd_is_lowered(self):
+ """Confirm that issue21618 is fixed (may fail under valgrind)."""
+ fd_status = test_support.findfile("testdata/fd_status.py")
+
+ open_fds = set()
+ # Add a bunch more fds to pass down.
+ for _ in range(40):
+ fd = os.open("/dev/null", os.O_RDONLY)
+ open_fds.add(fd)
+
+ # Leave a two pairs of low ones available for use by the
+ # internal child error pipe and the stdout pipe.
+ # We also leave 10 more open for use by the Python 2 startup
+ # import machinery which tends to consume several at once.
+ for fd in sorted(open_fds)[:14]:
+ os.close(fd)
+ open_fds.remove(fd)
+
+ for fd in open_fds:
+ self.addCleanup(os.close, fd)
+
+ max_fd_open = max(open_fds)
+
+ import resource
+ rlim_cur, rlim_max = resource.getrlimit(resource.RLIMIT_NOFILE)
+ try:
+ # 29 is lower than the highest fds we are leaving open.
+ resource.setrlimit(resource.RLIMIT_NOFILE, (29, rlim_max))
+ # Launch a new Python interpreter with our low fd rlim_cur that
+ # inherits open fds above that limit. It then uses subprocess
+ # with close_fds=True to get a report of open fds in the child.
+ # An explicit list of fds to check is passed to fd_status.py as
+ # letting fd_status rely on its default logic would miss the
+ # fds above rlim_cur as it normally only checks up to that limit.
+ p = subprocess.Popen(
+ [sys.executable, '-c',
+ textwrap.dedent("""
+ import subprocess32, sys
+ subprocess32.Popen([sys.executable, %(fd_status)r] +
+ [str(x) for x in range(%(max_fd)d)],
+ close_fds=True).wait()
+ """ % dict(fd_status=fd_status, max_fd=max_fd_open+1))],
+ stdout=subprocess.PIPE, close_fds=False)
+ finally:
+ resource.setrlimit(resource.RLIMIT_NOFILE, (rlim_cur, rlim_max))
+
+ output, unused_stderr = p.communicate()
+ remaining_fds = set(map(int, output.strip().split(',')))
+
+ self.assertFalse(remaining_fds & open_fds,
+ msg="Some fds were left open.")
+
+
def test_pass_fds(self):
fd_status = test_support.findfile("testdata/fd_status.py")
@@ -1925,9 +1980,43 @@ class ProcessTestCasePOSIXPurePython(ProcessTestCase, POSIXProcessTestCase):
ProcessTestCase.tearDown(self)
+class POSIXSubprocessModuleTestCase(unittest.TestCase):
+ def test_fork_exec_sorted_fd_sanity_check(self):
+ # Issue #23564: sanity check the fork_exec() fds_to_keep sanity check.
+ _posixsubprocess = subprocess._posixsubprocess
+ gc_enabled = gc.isenabled()
+ try:
+ gc.enable()
+
+ for fds_to_keep in (
+ (-1, 2, 3, 4, 5), # Negative number.
+ ('str', 4), # Not an int.
+ (18, 23, 42, 2**63), # Out of range.
+ (5, 4), # Not sorted.
+ (6, 7, 7, 8), # Duplicate.
+ ):
+ try:
+ _posixsubprocess.fork_exec(
+ ["false"], ["false"],
+ True, fds_to_keep, None, ["env"],
+ -1, -1, -1, -1,
+ 1, 2, 3, 4,
+ True, True, None)
+ except ValueError, exception:
+ self.assertTrue('fds_to_keep' in str(exception),
+ msg=str(exception))
+ else:
+ self.fail("ValueError not raised, fds_to_keep=%s" %
+ (fds_to_keep,))
+ finally:
+ if not gc_enabled:
+ gc.disable()
+
+
if not getattr(subprocess, '_posixsubprocess', False):
print >>sys.stderr, "_posixsubprocess extension module not found."
class ProcessTestCasePOSIXPurePython(unittest.TestCase): pass
+ class POSIXSubprocessModuleTestCase(unittest.TestCase): pass
class HelperFunctionTests(unittest.TestCase):
@@ -2059,6 +2148,7 @@ if sys.version_info[:2] <= (2,4):
def test_main():
unit_tests = (ProcessTestCase,
POSIXProcessTestCase,
+ POSIXSubprocessModuleTestCase,
Win32ProcessTestCase,
ProcessTestCasePOSIXPurePython,
ProcessTestCaseNoPoll,
diff --git a/testdata/fd_status.py b/testdata/fd_status.py
index 1a0b7ed..67fb41c 100644
--- a/testdata/fd_status.py
+++ b/testdata/fd_status.py
@@ -1,24 +1,34 @@
"""When called as a script, print a comma-separated list of the open
-file descriptors on stdout."""
+file descriptors on stdout.
+
+Usage:
+fd_stats.py: check all file descriptors
+fd_status.py fd1 fd2 ...: check only specified file descriptors
+"""
import errno
import os
-import fcntl
-
-try:
- _MAXFD = os.sysconf("SC_OPEN_MAX")
-except:
- _MAXFD = 256
-
-def isopen(fd):
- """Return True if the fd is open, and False otherwise"""
- try:
- fcntl.fcntl(fd, fcntl.F_GETFD, 0)
- except IOError, e:
- if e.errno == errno.EBADF:
- return False
- raise
- return True
+import stat
+import sys
if __name__ == "__main__":
- print(','.join(str(fd) for fd in range(0, _MAXFD) if isopen(fd)))
+ fds = []
+ if len(sys.argv) == 1:
+ try:
+ _MAXFD = os.sysconf("SC_OPEN_MAX")
+ except:
+ _MAXFD = 256
+ test_fds = range(0, _MAXFD)
+ else:
+ test_fds = map(int, sys.argv[1:])
+ for fd in test_fds:
+ try:
+ st = os.fstat(fd)
+ except OSError, e:
+ if e.errno == errno.EBADF:
+ continue
+ raise
+ # Ignore Solaris door files
+ if not hasattr(stat, 'S_ISDOOR') or not stat.S_ISDOOR(st.st_mode):
+ fds.append(fd)
+ print ','.join(map(str, fds))
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-subprocess32.git
More information about the Python-modules-commits
mailing list