[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