[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