[Python-checkins] r51875 - in python/branches/bcannon-objcap: Include/interpreter.h Lib/test/test_interpreter.py Modules/interpretermodule.c securing_python.txt setup.py

brett.cannon python-checkins at python.org
Thu Sep 14 02:45:40 CEST 2006


Author: brett.cannon
Date: Thu Sep 14 02:45:39 2006
New Revision: 51875

Added:
   python/branches/bcannon-objcap/Include/interpreter.h   (contents, props changed)
   python/branches/bcannon-objcap/Lib/test/test_interpreter.py   (contents, props changed)
   python/branches/bcannon-objcap/Modules/interpretermodule.c   (contents, props changed)
Modified:
   python/branches/bcannon-objcap/securing_python.txt
   python/branches/bcannon-objcap/setup.py
Log:
Add beginnings of an interpreter module.


Added: python/branches/bcannon-objcap/Include/interpreter.h
==============================================================================
--- (empty file)
+++ python/branches/bcannon-objcap/Include/interpreter.h	Thu Sep 14 02:45:39 2006
@@ -0,0 +1,24 @@
+/*
+   interpreter.h
+*/
+
+#ifndef HAVE_INTERPRETER_H
+#define HAVE_INTERPRETER_H
+
+#ifdef __cpluspus
+extern "C" {
+#endif
+
+typedef struct
+{
+    PyObject_HEAD;
+    PyThreadState *tstate;  /* Main thread state for interpreter */
+    PyInterpreterState *istate;  /* Interpreter state; for convenience to avoid
+				    going through thread state every time. */
+} PyInterpreterObject;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !HAVE_INTERPRETER_H */

Added: python/branches/bcannon-objcap/Lib/test/test_interpreter.py
==============================================================================
--- (empty file)
+++ python/branches/bcannon-objcap/Lib/test/test_interpreter.py	Thu Sep 14 02:45:39 2006
@@ -0,0 +1,110 @@
+"""XXX
+"""
+import interpreter
+
+import unittest
+from test import test_support
+import sys
+import __builtin__
+
+simple_stmt = """
+while True:
+    2 + 3
+    break
+"""
+
+class BaseInterpTests(unittest.TestCase):
+
+    def setUp(self):
+        """Create a new interpreter."""
+
+        self.interp = interpreter.Interpreter()
+
+
+class BasicInterpreterTests(BaseInterpTests):
+
+    def test_basic_expression(self):
+        # Make sure that execucuting a simple expression does not die.
+        self.interp.execute('2 + 3')
+
+    def test_basic_statement(self):
+        # Make sure executing a statement does not die.
+        self.interp.execute(simple_stmt)
+
+
+class BuiltinsTests(BaseInterpTests):
+
+    """Test interpreter.Interpreter().builtins ."""
+
+    def test_get(self):
+        # Test the getting of 'builtins'.
+        builtins = self.interp.builtins
+        self.failUnless(isinstance(builtins, dict))
+        self.failUnless('object' in builtins)
+
+    def test_set(self):
+        # Make sure setting 'builtins' can be done and has proper type
+        # checking.
+        self.interp.builtins = {}
+        self.failUnlessRaises(TypeError, setattr, self.interp, 'builtins', [])
+
+    def test_effect(self):
+        # Make sure that setting 'builtin's actually affects the built-in
+        # namespace.
+        self.interp.builtins['msg'] = "hello"
+        self.interp.execute("msg")
+        self.interp.execute("import __builtin__; __builtin__.__dict__['test1'] = 'test1'")
+        self.failUnless('test1' in self.interp.builtins)
+        del self.interp.builtins['object']
+        #self.failUnlessRaises(XXX, interp.execute, 'object')
+
+    def test_copied(self):
+        # Make sure built-ins are unique per interpreter.
+        self.failUnless(self.interp.builtins is not __builtin__.__dict__)
+
+        try:
+            __builtin__.__dict__['test1'] = 'test1'
+            self.failUnless('test1' not in self.interp.builtins)
+        finally:
+            del __builtin__.__dict__['test1']
+        self.interp.builtins['test2'] = 'test2'
+        self.failUnless('test2' not in __builtin__.__dict__)
+
+
+class ModulesTests(BaseInterpTests):
+
+    """Test interpreter.Interpreter().modules ."""
+
+    def test_get(self):
+        # Make sure a dict is returned.
+        modules = self.interp.modules
+        self.failUnless(isinstance(modules, dict))
+
+    def test_set(self):
+        # Make sure setting 'modules' can be done and has proper type checking.
+        self.interp.modules = {}
+        self.failUnlessRaises(TypeError, setattr, self.interp.modules, [])
+
+    def test_effect(self):
+        # Make sure mutating 'modules' has proper result.
+        # XXX Insert value in 'module', have sub-interpreter set into
+        # __builtin__, and check that same object.
+        pass
+
+    def test_fresh(self):
+        # Make sure that import Python modules are new instances.
+        import token
+        self.interp.execute("import token")
+        self.failUnless(self.interp.modules['token'] is not token)
+
+
+def test_main():
+    test_support.run_unittest(
+            BasicInterpreterTests,
+            BuiltinsTests,
+            ModulesTests,
+    )
+
+
+if __name__ == '__main__':
+    test_main()

Added: python/branches/bcannon-objcap/Modules/interpretermodule.c
==============================================================================
--- (empty file)
+++ python/branches/bcannon-objcap/Modules/interpretermodule.c	Thu Sep 14 02:45:39 2006
@@ -0,0 +1,254 @@
+#include "Python.h"
+#include "interpreter.h"
+
+#define PyInterpreter_GET_INTERP(interp) \
+	(((PyInterpreterObject *)interp)->istate)
+
+/*
+   Destroy the interpreter and dealloc memory.
+*/
+static void
+interpreter_dealloc(PyObject *self)
+{
+    PyThreadState *new_tstate = NULL;
+    PyThreadState *cur_tstate = NULL;
+
+    /* To destory an interpreter using Py_EndInterpreter() it must be the
+       currently running interpreter.  This means you must temporariy make the
+       created interpreter the running interpreter again, destroy it, and then
+       swap back to the interpreter that created the interpreter in the first
+       place. */
+    new_tstate = ((PyInterpreterObject *)self)->tstate;
+    cur_tstate = PyThreadState_Swap(new_tstate);
+
+    Py_EndInterpreter(new_tstate);
+    PyEval_RestoreThread(cur_tstate);
+
+    self->ob_type->tp_free(self);
+}
+
+/*
+   Create a new interpreter.
+*/
+static PyObject *
+interpreter_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+    PyInterpreterObject *self;
+    PyThreadState *cur_tstate;
+
+    self = (PyInterpreterObject *)type->tp_alloc(type, 0);
+    if (self == NULL)
+	return NULL;
+
+    /* Creating a new interpreter swaps out the current one. */
+    cur_tstate = PyThreadState_GET();
+
+    if (Py_NewInterpreter() == NULL) {
+	Py_DECREF(self);
+	/* XXX Exception best exception to use here? */
+	PyErr_SetString(PyExc_Exception, "sub-interpreter creation failed");
+	return NULL;
+    }
+
+    self->tstate = PyThreadState_Swap(cur_tstate);
+    if (self->tstate == NULL) {
+	Py_DECREF(self);
+	PyErr_SetString(PyExc_Exception, "sub-interpreter swap failed");
+	return NULL;
+    }
+    self->istate = (self->tstate)->interp;
+
+    return (PyObject *)self;
+}
+
+/*
+   Execute Python source code in the interpreter.
+*/
+static PyObject *
+interpreter_exec(PyObject *self, PyObject *arg)
+{
+    PyInterpreterObject *interp_self = (PyInterpreterObject *)self;
+    const char *str_arg = NULL;
+    PyThreadState* cur_tstate = NULL;
+    int result = 0;
+
+    if (!PyString_Check(arg)) {
+	PyErr_SetString(PyExc_TypeError, "argument must be a string");
+	return NULL;
+    }
+
+    str_arg = PyString_AsString(arg);
+    if (!str_arg)
+	return NULL;
+
+    cur_tstate = PyThreadState_Swap(interp_self->tstate);
+
+    result = PyRun_SimpleString(str_arg);
+    if (result < 0) {
+	PyErr_Clear();
+    }
+
+    PyThreadState_Swap(cur_tstate);
+
+    if (result < 0) {
+	PyErr_SetString(PyExc_Exception,
+			"exception during execution in interpreter.");
+	return NULL;
+    }
+
+    Py_RETURN_NONE;
+}
+
+static PyMethodDef interpreter_methods[] = {
+    {"execute", interpreter_exec, METH_O,
+	"Execute the passed-in string in the interpreter"},
+    {NULL}
+};
+
+
+/*
+   Getter for 'builtins'.
+*/
+static PyObject *
+interpreter_get_builtins(PyObject *self, void *optional)
+{
+	PyObject *builtins = PyInterpreter_GET_INTERP(self)->builtins;
+
+	Py_INCREF(builtins);
+	return builtins;
+}
+
+/*
+   Setter for 'builtins'.
+*/
+static int
+interpreter_set_builtins(PyObject *self, PyObject *arg, void *optional)
+{
+	PyObject *old_builtins = PyInterpreter_GET_INTERP(self)->builtins;
+
+	if (!PyDict_CheckExact(arg)) {
+		PyErr_SetString(PyExc_TypeError,
+				"'builtins' must be set to a dict");
+		return -1;
+	}
+
+	Py_INCREF(arg);
+	Py_XDECREF(old_builtins);
+	PyInterpreter_GET_INTERP(self)->builtins = arg;
+
+	return 0;
+}
+
+/*
+   Getter for 'modules'.
+*/
+static PyObject *
+interpreter_get_modules(PyObject *self, void *optional)
+{
+	PyObject *modules = PyInterpreter_GET_INTERP(self)->modules;
+
+	Py_INCREF(modules);
+	return modules;
+}
+
+/*
+   Setter for 'modules'.
+*/
+static int
+interpreter_set_modules(PyObject *self, PyObject *arg, void *optional)
+{
+	PyObject *old_modules = PyInterpreter_GET_INTERP(self)->modules;
+
+	if (!PyDict_CheckExact(arg)) {
+		PyErr_SetString(PyExc_TypeError,
+				"'modules' must be set to a dict");
+		return -1;
+	}
+
+	Py_INCREF(arg);
+	Py_XDECREF(old_modules);
+	PyInterpreter_GET_INTERP(self)->modules = arg;
+
+	return 0;
+}
+
+
+static PyGetSetDef interpreter_getset[] = {
+	{"builtins", interpreter_get_builtins, interpreter_set_builtins,
+		"The built-ins dict for the interpreter.", NULL},
+	/*{"sys_dict", XXX, XXX, "The modules dict for 'sys'.", NULL},*/
+	{"modules", interpreter_get_modules, interpreter_set_modules,
+		"The dict used for sys.modules.", NULL},
+	{NULL}
+};
+
+
+PyDoc_STRVAR(interpreter_type_doc,
+"XXX\n\
+\n\
+XXX");
+
+PyTypeObject PyInterpreter_Type = {
+	PyObject_HEAD_INIT(NULL)
+	0,					/* ob_size */
+	"interpreterInterpreter",		/* tp_name */
+	sizeof(PyInterpreterObject),		/* tp_basicsize */
+	0,               			/* tp_itemsize */
+	interpreter_dealloc,                    /* tp_dealloc */
+	0,					/* tp_print */
+	0,			 		/* tp_getattr */
+	0,					/* tp_setattr */
+	0,       				/* tp_compare */
+	0,               			/* tp_repr */
+	0,					/* tp_as_number */
+	0,					/* tp_as_sequence */
+	0,					/* tp_as_mapping */
+	0,                      		/* tp_hash */
+	0,              			/* tp_call */
+	0,					/* tp_str */
+	0,                      		/* tp_getattro */
+	0,	                        	/* tp_setattro */
+	0,					/* tp_as_buffer */
+	Py_TPFLAGS_DEFAULT |
+	    Py_TPFLAGS_BASETYPE,     		/* tp_flags */
+	interpreter_type_doc,    		/* tp_doc */
+	0,                      		/* tp_traverse */
+	0,              			/* tp_clear */
+	0,					/* tp_richcompare */
+	0,                              	/* tp_weaklistoffset */
+	0,					/* tp_iter */
+	0,					/* tp_iternext */
+	interpreter_methods,      		/* tp_methods */
+	0,	         			/* tp_members */
+	interpreter_getset,          		/* tp_getset */
+	0,					/* tp_base */
+	0,					/* tp_dict */
+	0,					/* tp_descr_get */
+	0,					/* tp_descr_set */
+	0,                              	/* tp_dictoffset */
+	0,					/* tp_init */
+	0,					/* tp_alloc */
+	interpreter_new,     			/* tp_new */
+	0,                      		/* tp_free */
+	0,              			/* tp_is_gc */
+};
+
+
+PyMODINIT_FUNC
+initinterpreter(void)
+{
+    PyObject *module;
+
+    module = Py_InitModule3("interpreter", NULL,
+	    "Create other Python interpreters to execute code within.");
+    if (module == NULL)
+	return;
+
+    Py_INCREF(&PyInterpreter_Type);
+    if (PyType_Ready(&PyInterpreter_Type) < 0)
+	return;
+
+    if (PyModule_AddObject(module, "Interpreter",
+			    (PyObject *)&PyInterpreter_Type) < 0)
+	return;
+}

Modified: python/branches/bcannon-objcap/securing_python.txt
==============================================================================
--- python/branches/bcannon-objcap/securing_python.txt	(original)
+++ python/branches/bcannon-objcap/securing_python.txt	Thu Sep 14 02:45:39 2006
@@ -44,6 +44,7 @@
 + Create sandboxed interpreter stdlib module <critical>
     - Be able to specify built-ins
     - Set 'sys' module settings
+    - Set 'sys.modules'
     - API
         * Python
         * C

Modified: python/branches/bcannon-objcap/setup.py
==============================================================================
--- python/branches/bcannon-objcap/setup.py	(original)
+++ python/branches/bcannon-objcap/setup.py	Thu Sep 14 02:45:39 2006
@@ -367,6 +367,8 @@
                                libraries=math_libs) )
         exts.append( Extension('datetime', ['datetimemodule.c', 'timemodule.c'],
                                libraries=math_libs) )
+        # interpreter instantiation
+        exts.append( Extension('interpreter', ['interpretermodule.c']) )
         # random number generator implemented in C
         exts.append( Extension("_random", ["_randommodule.c"]) )
         # fast iterator tools implemented in C


More information about the Python-checkins mailing list