[pypy-svn] r45824 - in pypy/branch/pypy-more-rtti-inprogress/translator/sandbox: . test
arigo at codespeak.net
arigo at codespeak.net
Fri Aug 17 19:52:21 CEST 2007
Author: arigo
Date: Fri Aug 17 19:52:19 2007
New Revision: 45824
Modified:
pypy/branch/pypy-more-rtti-inprogress/translator/sandbox/pypy_interact.py
pypy/branch/pypy-more-rtti-inprogress/translator/sandbox/sandlib.py
pypy/branch/pypy-more-rtti-inprogress/translator/sandbox/test/test_sandlib.py
Log:
Works! works! At least enough to start pypy-c-sandbox
interactively and type stuff in it.
Modified: pypy/branch/pypy-more-rtti-inprogress/translator/sandbox/pypy_interact.py
==============================================================================
--- pypy/branch/pypy-more-rtti-inprogress/translator/sandbox/pypy_interact.py (original)
+++ pypy/branch/pypy-more-rtti-inprogress/translator/sandbox/pypy_interact.py Fri Aug 17 19:52:19 2007
@@ -13,9 +13,11 @@
from pypy.translator.sandbox.sandlib import VirtualizedSandboxedProc
class PyPySandboxedProc(VirtualizedSandboxedProc, SimpleIOSandboxedProc):
+ debug = True
argv0 = '/opt/pypy-c'
virtual_cwd = '/tmp'
- virtual_env = {}
+ virtual_env = {'PYTHONSTARTUP': ''}
+ virtual_console_isatty = True
def __init__(self, executable, arguments):
super(PyPySandboxedProc, self).__init__([self.argv0] + arguments,
Modified: pypy/branch/pypy-more-rtti-inprogress/translator/sandbox/sandlib.py
==============================================================================
--- pypy/branch/pypy-more-rtti-inprogress/translator/sandbox/sandlib.py (original)
+++ pypy/branch/pypy-more-rtti-inprogress/translator/sandbox/sandlib.py Fri Aug 17 19:52:19 2007
@@ -4,10 +4,24 @@
for the outer process, which can run CPython or PyPy.
"""
-import marshal, sys, os, posixpath
+import py
+import marshal, sys, os, posixpath, errno
from pypy.rpython.module.ll_os_stat import STAT_FIELDS, s_tuple_StatResult
+from pypy.tool.ansi_print import AnsiLog
from py.compat import subprocess
+class MyAnsiLog(AnsiLog):
+ KW_TO_COLOR = {
+ 'call': ((34,), False),
+ 'result': ((34,), False),
+ 'exception': ((34,), False),
+ 'vpath': ((35,), False),
+ }
+
+log = py.log.Producer("sandlib")
+py.log.setconsumer("sandlib", MyAnsiLog())
+
+
def read_message(f, timeout=None):
# warning: 'timeout' is not really reliable and should only be used
# for testing. Also, it doesn't work if the file f does any buffering.
@@ -45,16 +59,25 @@
(9, RuntimeError),
]
-def write_exception(g, exception):
+def write_exception(g, exception, tb=None):
for i, excclass in EXCEPTION_TABLE:
if isinstance(exception, excclass):
write_message(g, i)
if excclass is OSError:
- write_message(g, exception.errno)
+ error = exception.errno
+ if error is None:
+ error = errno.EPERM
+ write_message(g, error)
break
else:
- raise Exception("cannot report %s exception to the subprocess" % (
- exception.__class__.__name__,))
+ # just re-raise the exception
+ raise exception.__class__, exception, tb
+
+def shortrepr(x):
+ r = repr(x)
+ if len(r) >= 80:
+ r = r[:20] + '...' + r[-8:]
+ return r
class SandboxedProc(object):
@@ -62,6 +85,8 @@
Inherit from this class and implement all the do_xxx() methods
for the external functions xxx that you want to support.
"""
+ debug = False
+
def __init__(self, args, executable=None):
"""'args' should a sequence of argument for the subprocess,
starting with the full path of the executable.
@@ -89,9 +114,24 @@
args = read_message(self.popen.stdout)
except EOFError, e:
break
- answer, resulttype = self.handle_message(fnname, *args)
- write_message(self.popen.stdin, 0) # error code - always 0 for now
- write_message(self.popen.stdin, answer, resulttype)
+ if self.debug:
+ log.call('%s(%s)' % (fnname,
+ ', '.join([shortrepr(x) for x in args])))
+ try:
+ answer, resulttype = self.handle_message(fnname, *args)
+ except Exception, e:
+ tb = sys.exc_info()[2]
+ write_exception(self.popen.stdin, e, tb)
+ if self.debug:
+ if str(e):
+ log.exception('%s: %s' % (e.__class__.__name__, e))
+ else:
+ log.exception('%s' % (e.__class__.__name__,))
+ else:
+ if self.debug:
+ log.result(shortrepr(answer))
+ write_message(self.popen.stdin, 0) # error code - 0 for ok
+ write_message(self.popen.stdin, answer, resulttype)
returncode = self.popen.wait()
return returncode
@@ -148,6 +188,11 @@
if fd == 0:
if self._input is None:
return ""
+ elif self._input.isatty():
+ # don't wait for all 'size' chars if reading from a tty,
+ # to avoid blocking
+ # (XXX slow, but should not matter for interactive usage)
+ return self._input.read(1)
else:
return self._input.read(size)
raise OSError("trying to read from fd %d" % (fd,))
@@ -171,8 +216,14 @@
"""
virtual_env = {}
virtual_cwd = '/tmp'
+ virtual_console_isatty = False
+ virtual_fd_range = range(3, 50)
path_mapping = {} # maps virtual paths to real paths
+ def __init__(self, *args, **kwds):
+ super(VirtualizedSandboxedProc, self).__init__(*args, **kwds)
+ self.open_fds = {} # {virtual_fd: real_file_object}
+
def do_ll_os__ll_os_envitems(self):
return self.virtual_env.items()
@@ -199,7 +250,7 @@
result = os.path.join(result, *remaining_components)
if vpath.endswith(os.sep):
result += os.sep # re-add a trailing '/' if one was specified
- print 'VPATH:', vpath, '=>', result
+ log.vpath('%s => %s' % (vpath, result))
return result
def build_stat_result(self, st):
@@ -218,3 +269,41 @@
st = os.lstat(pathname)
return self.build_stat_result(st)
do_ll_os__ll_os_lstat.resulttype = s_tuple_StatResult
+
+ def do_ll_os__ll_os_isatty(self, fd):
+ return self.virtual_console_isatty and fd in (0, 1, 2)
+
+ def allocate_fd(self, f):
+ for fd in self.virtual_fd_range:
+ if fd not in self.open_fds:
+ self.open_fds[fd] = f
+ return fd
+ else:
+ raise VirtualOSError("trying to open too many files")
+
+ def do_ll_os__ll_os_open(self, vpathname, flags, mode):
+ pathname = self.translate_path(vpathname)
+ if flags & (os.O_RDONLY|os.O_WRONLY|os.O_RDWR) != os.O_RDONLY:
+ raise OSError(errno.EPERM, "write access denied")
+ # all other flags are ignored
+ f = open(pathname, "rb")
+ return self.allocate_fd(f)
+
+ def do_ll_os__ll_os_close(self, fd):
+ try:
+ f = self.open_fds.pop(fd)
+ except KeyError:
+ raise OSError(errno.EBADF, "closing a bad file descriptor")
+ else:
+ f.close()
+
+ def do_ll_os__ll_os_read(self, fd, size):
+ try:
+ f = self.open_fds[fd]
+ except KeyError:
+ return super(VirtualizedSandboxedProc, self).do_ll_os__ll_os_read(
+ fd, size)
+ else:
+ if not (0 <= size <= sys.maxint):
+ raise VirtualOSError("invalid read size")
+ return f.read(size)
Modified: pypy/branch/pypy-more-rtti-inprogress/translator/sandbox/test/test_sandlib.py
==============================================================================
--- pypy/branch/pypy-more-rtti-inprogress/translator/sandbox/test/test_sandlib.py (original)
+++ pypy/branch/pypy-more-rtti-inprogress/translator/sandbox/test/test_sandlib.py Fri Aug 17 19:52:19 2007
@@ -21,6 +21,8 @@
assert name == expectedmsg
assert input == expectedinput
self.seen += 1
+ if isinstance(output, Exception):
+ raise output
return output
return func_with_new_name(do_xxx, 'do_%s' % name)
@@ -96,3 +98,20 @@
output, error = proc.communicate("21\n")
assert output == "Please enter a number:\nThe double is: 42\n"
assert error == ""
+
+def test_oserror():
+ def entry_point(argv):
+ try:
+ os.open("/tmp/foobar", os.O_RDONLY, 0777)
+ except OSError, e:
+ os.close(e.errno) # nonsense, just to see outside
+ return 0
+ t = Translation(entry_point, backend='c', standalone=True, sandbox=True)
+ exe = t.compile()
+
+ proc = MySandboxedProc([exe], expected = [
+ ("open", ("/tmp/foobar", os.O_RDONLY, 0777), OSError(-42, "baz")),
+ ("close", (-42,), None),
+ ])
+ proc.handle_forever()
+ assert proc.seen == len(proc.expected)
More information about the Pypy-commit
mailing list