Advertising
- martin
- Wednesday, March 14th, 2007 at 6:25:33pm UTC
- diff -u python2.5-2.5/debian/changelog python2.5-2.5/debian/changelog
- --- python2.5-2.5/debian/changelog
- +++ python2.5-2.5/debian/changelog
- @@ -1,3 +1,16 @@
- +python2.5 (2.5-5ubuntu10) feisty; urgency=low
- +
- + * Add debian/patches/z_subprocess-eintr-safety.dpatch:
- + - Create and use wrappers around read(), write(), and os.waitpid() in the
- + subprocess module which retry the operation on an EINTR (which happens
- + if e. g. an alarm was raised while the system call was in progress). It is
- + incredibly hard and inconvenient to sensibly handle this in
- + applications, so let's fix this at the right level.
- + - Add two test cases.
- + - (LP: #87292)
- +
- +
- python2.5 (2.5-5ubuntu9) feisty; urgency=medium
- * Update to 20070307, taken from the 2.5 release branch.
- only in patch2:
- unchanged:
- --- python2.5-2.5.orig/debian/patches/z_subprocess-eintr-safety.dpatch
- +++ python2.5-2.5/debian/patches/z_subprocess-eintr-safety.dpatch
- @@ -0,0 +1,231 @@
- +#! /bin/sh -e
- +
- +dir=
- +if [ $# -eq 3 -a "$2" = '-d' ]; then
- + pdir="-d $3"
- + dir="$3/"
- +elif [ $# -ne 1 ]; then
- + echo >&2 "usage: `basename $0`: -patch|-unpatch [-d <srcdir>]"
- + exit 1
- +fi
- +case "$1" in
- + -patch)
- + patch $pdir -f --no-backup-if-mismatch -p0 < $0
- + #cd ${dir}gcc && autoconf
- + ;;
- + -unpatch)
- + patch $pdir -f --no-backup-if-mismatch -R -p0 < $0
- + #rm ${dir}gcc/configure
- + ;;
- + *)
- + echo >&2 "usage: `basename $0`: -patch|-unpatch [-d <srcdir>]"
- + exit 1
- +esac
- +exit 0
- +
- +--- orig/Lib/subprocess.py 2007-03-14 19:16:36.000000000 +0100
- ++++ new/Lib/subprocess.py 2007-03-14 19:18:50.000000000 +0100
- + stderr = None
- + if self.stdin:
- + if input:
- +- self.stdin.write(input)
- ++ self._fo_write_no_intr(self.stdin, input)
- + self.stdin.close()
- + elif self.stdout:
- +- stdout = self.stdout.read()
- ++ stdout = self._fo_read_no_intr(self.stdout)
- + elif self.stderr:
- +- stderr = self.stderr.read()
- ++ stderr = self._fo_read_no_intr(self.stderr)
- + self.wait()
- + return (stdout, stderr)
- +
- + pass
- +
- +
- ++ def _read_no_intr(self, fd, buffersize):
- ++ """Like os.read, but retries on EINTR"""
- ++ while True:
- ++ try:
- ++ return os.read(fd, buffersize)
- ++ except OSError, e:
- ++ if e.errno == errno.EINTR:
- ++ continue
- ++ else:
- ++ raise
- ++
- ++
- ++ def _read_all(self, fd, buffersize):
- ++ """Like os.read, but retries on EINTR, and reads until EOF"""
- ++ all = ""
- ++ while True:
- ++ data = self._read_no_intr(fd, buffersize)
- ++ all += data
- ++ if data == "":
- ++ return all
- ++
- ++
- ++ def _write_no_intr(self, fd, s):
- ++ """Like os.write, but retries on EINTR"""
- ++ while True:
- ++ try:
- ++ return os.write(fd, s)
- ++ except OSError, e:
- ++ if e.errno == errno.EINTR:
- ++ continue
- ++ else:
- ++ raise
- ++
- ++ def _waitpid_no_intr(self, pid, options):
- ++ """Like os.waitpid, but retries on EINTR"""
- ++ while True:
- ++ try:
- ++ return os.waitpid(pid, options)
- ++ except OSError, e:
- ++ if e.errno == errno.EINTR:
- ++ continue
- ++ else:
- ++ raise
- ++
- ++ def _fo_read_no_intr(self, obj):
- ++ """Like obj.read(), but retries on EINTR"""
- ++ while True:
- ++ try:
- ++ return obj.read()
- ++ except IOError, e:
- ++ if e.errno == errno.EINTR:
- ++ continue
- ++ else:
- ++ raise
- ++
- ++ def _fo_write_no_intr(self, obj, data):
- ++ """Like obj.write(), but retries on EINTR"""
- ++ while True:
- ++ try:
- ++ return obj.write(data)
- ++ except IOError, e:
- ++ if e.errno == errno.EINTR:
- ++ continue
- ++ else:
- ++ raise
- ++
- + def _execute_child(self, args, executable, preexec_fn, close_fds,
- + cwd, env, universal_newlines,
- + startupinfo, creationflags, shell,
- + exc_value,
- + tb)
- + exc_value.child_traceback = ''.join(exc_lines)
- +- os.write(errpipe_write, pickle.dumps(exc_value))
- ++ self._write_no_intr(errpipe_write, pickle.dumps(exc_value))
- +
- + # This exitcode won't be reported to applications, so it
- + # really doesn't matter what we return.
- + os.close(errwrite)
- +
- + # Wait for exec to fail or succeed; possibly raising exception
- +- data = os.read(errpipe_read, 1048576) # Exceptions limited to 1 MB
- ++ data = self._read_all(errpipe_read, 1048576) # Exceptions limited to 1 MB
- + os.close(errpipe_read)
- + if data != "":
- +- os.waitpid(self.pid, 0)
- ++ self._waitpid_no_intr(self.pid, 0)
- + child_exception = pickle.loads(data)
- + raise child_exception
- +
- + attribute."""
- + if self.returncode is None:
- + try:
- +- pid, sts = os.waitpid(self.pid, os.WNOHANG)
- ++ pid, sts = self._waitpid_no_intr(self.pid, os.WNOHANG)
- + if pid == self.pid:
- + self._handle_exitstatus(sts)
- + except os.error:
- + """Wait for child process to terminate. Returns returncode
- + attribute."""
- + if self.returncode is None:
- +- pid, sts = os.waitpid(self.pid, 0)
- ++ pid, sts = self._waitpid_no_intr(self.pid, 0)
- + self._handle_exitstatus(sts)
- + return self.returncode
- +
- +
- + input_offset = 0
- + while read_set or write_set:
- +- rlist, wlist, xlist = select.select(read_set, write_set, [])
- ++ try:
- ++ rlist, wlist, xlist = select.select(read_set, write_set, [])
- ++ except select.error, e:
- ++ if e[0] == errno.EINTR:
- ++ continue
- ++ else:
- ++ raise
- +
- + if self.stdin in wlist:
- + # When select has indicated that the file is writable,
- + # we can write up to PIPE_BUF bytes without risk
- + # blocking. POSIX defines PIPE_BUF >= 512
- +- bytes_written = os.write(self.stdin.fileno(), buffer(input, input_offset, 512))
- ++ bytes_written = self._write_no_intr(self.stdin.fileno(), buffer(input, input_offset, 512))
- + input_offset += bytes_written
- + if input_offset >= len(input):
- + self.stdin.close()
- + write_set.remove(self.stdin)
- +
- + if self.stdout in rlist:
- +- data = os.read(self.stdout.fileno(), 1024)
- ++ data = self._read_no_intr(self.stdout.fileno(), 1024)
- + if data == "":
- + self.stdout.close()
- + read_set.remove(self.stdout)
- + stdout.append(data)
- +
- + if self.stderr in rlist:
- +- data = os.read(self.stderr.fileno(), 1024)
- ++ data = self._read_no_intr(self.stderr.fileno(), 1024)
- + if data == "":
- + self.stderr.close()
- + read_set.remove(self.stderr)
- +--- orig/Lib/test/test_subprocess.py 2007-03-14 19:16:36.000000000 +0100
- ++++ new/Lib/test/test_subprocess.py 2007-03-14 19:18:57.000000000 +0100
- + os.remove(fname)
- + self.assertEqual(rc, 47)
- +
- ++ def test_eintr(self):
- ++ # retries on EINTR for an argv
- ++
- ++ # send ourselves a signal that causes EINTR
- ++ prev_handler = signal.signal(signal.SIGALRM, lambda x,y: 1)
- ++ signal.alarm(1)
- ++ time.sleep(0.5)
- ++
- ++ rc = subprocess.Popen(['sleep', '1'])
- ++ self.assertEqual(rc.wait(), 0)
- ++
- ++ signal.signal(signal.SIGALRM, prev_handler)
- ++
- ++ def test_eintr_out(self):
- ++ # retries on EINTR for a shell call and pipelining
- ++
- ++ # send ourselves a signal that causes EINTR
- ++ prev_handler = signal.signal(signal.SIGALRM, lambda x,y: 1)
- ++ signal.alarm(1)
- ++ time.sleep(0.5)
- ++
- ++ rc = subprocess.Popen("sleep 1; echo hello",
- ++ shell=True, stdout=subprocess.PIPE)
- ++ out = rc.communicate()[0]
- ++ self.assertEqual(rc.returncode, 0)
- ++ self.assertEqual(out, "hello\n")
- ++
- ++ signal.signal(signal.SIGALRM, prev_handler)
- +
- + #
- + # Windows tests
advertising
Update the Post
Either update this post and resubmit it with changes, or make a new post.
You may also comment on this post.
Please note that information posted here will not expire by default. If you do not want it to expire, please set the expiry time above. If it is set to expire, web search engines will not be allowed to index it prior to it expiring. Items that are not marked to expire will be indexable by search engines. Be careful with your passwords. All illegal activities will be reported and any information will be handed over to the authorities, so be good.