diff -r 6762b943ee59 Lib/test/test_builtin.py --- a/Lib/test/test_builtin.py Tue Apr 17 21:42:07 2012 -0400 +++ b/Lib/test/test_builtin.py Wed Apr 18 13:52:54 2012 +0200 @@ -554,6 +554,34 @@ class BuiltinTest(unittest.TestCase): del l['__builtins__'] self.assertEqual((g, l), ({'a': 1}, {'b': 2})) + def test_exec_globals(self): + code = compile("print('Hello World!')", "", "exec") + # no builtin function + self.assertRaisesRegex(NameError, "name 'print' is not defined", + exec, code, {'__builtins__': {}}) + # __builtins__ must be a mapping type + self.assertRaises(TypeError, + exec, code, {'__builtins__': 123}) + + # no __build_class__ function + code = compile("class A: pass", "", "exec") + self.assertRaisesRegex(NameError, "__build_class__ not found", + exec, code, {'__builtins__': {}}) + + class frozendict(dict): + def __setitem__(self, key, value): + raise ValueError("frozendict is readonly") + + # read-only builtins + frozen_builtins = frozendict(__builtins__) + code = compile("__builtins__['superglobal']=2; print(superglobal)", "test", "exec") + self.assertRaises(ValueError, exec, code, {'__builtins__': frozen_builtins}) + + # read-only globals + namespace = frozendict({}) + code = compile("x=1", "test", "exec") + self.assertRaises(ValueError, exec, code, namespace) + def test_exec_redirected(self): savestdout = sys.stdout sys.stdout = None # Whatever that cannot flush() diff -r 6762b943ee59 Objects/frameobject.c --- a/Objects/frameobject.c Tue Apr 17 21:42:07 2012 -0400 +++ b/Objects/frameobject.c Wed Apr 18 13:52:54 2012 +0200 @@ -612,10 +612,8 @@ PyFrame_New(PyThreadState *tstate, PyCod if (builtins) { if (PyModule_Check(builtins)) { builtins = PyModule_GetDict(builtins); - assert(!builtins || PyDict_Check(builtins)); + assert(builtins != NULL); } - else if (!PyDict_Check(builtins)) - builtins = NULL; } if (builtins == NULL) { /* No builtins! Make up a minimal one @@ -634,7 +632,7 @@ PyFrame_New(PyThreadState *tstate, PyCod /* If we share the globals, we share the builtins. Save a lookup and a call. */ builtins = back->f_builtins; - assert(builtins != NULL && PyDict_Check(builtins)); + assert(builtins != NULL); Py_INCREF(builtins); } if (code->co_zombieframe != NULL) { diff -r 6762b943ee59 Python/ceval.c --- a/Python/ceval.c Tue Apr 17 21:42:07 2012 -0400 +++ b/Python/ceval.c Wed Apr 18 13:52:54 2012 +0200 @@ -1932,11 +1932,26 @@ PyEval_EvalFrameEx(PyFrameObject *f, int TARGET(LOAD_BUILD_CLASS) { _Py_IDENTIFIER(__build_class__); - x = _PyDict_GetItemId(f->f_builtins, &PyId___build_class__); - if (x == NULL) { - PyErr_SetString(PyExc_ImportError, - "__build_class__ not found"); - break; + + if (PyDict_CheckExact(f->f_builtins)) { + x = _PyDict_GetItemId(f->f_builtins, &PyId___build_class__); + if (x == NULL) { + PyErr_SetString(PyExc_NameError, + "__build_class__ not found"); + break; + } + } + else { + PyObject *build_class_str = _PyUnicode_FromId(&PyId___build_class__); + if (build_class_str == NULL) + break; + x = PyObject_GetItem(f->f_builtins, build_class_str); + if (x == NULL) { + if (PyErr_ExceptionMatches(PyExc_KeyError)) + PyErr_SetString(PyExc_NameError, + "__build_class__ not found"); + break; + } } Py_INCREF(x); PUSH(x); @@ -2078,12 +2093,24 @@ PyEval_EvalFrameEx(PyFrameObject *f, int if (x == NULL) { x = PyDict_GetItem(f->f_globals, w); if (x == NULL) { - x = PyDict_GetItem(f->f_builtins, w); - if (x == NULL) { - format_exc_check_arg( - PyExc_NameError, - NAME_ERROR_MSG, w); - break; + if (PyDict_CheckExact(f->f_builtins)) { + x = PyDict_GetItem(f->f_builtins, w); + if (x == NULL) { + format_exc_check_arg( + PyExc_NameError, + NAME_ERROR_MSG, w); + break; + } + } + else { + x = PyObject_GetItem(f->f_builtins, w); + if (x == NULL) { + if (PyErr_ExceptionMatches(PyExc_KeyError)) + format_exc_check_arg( + PyExc_NameError, + NAME_ERROR_MSG, w); + break; + } } } Py_INCREF(x); @@ -2093,50 +2120,69 @@ PyEval_EvalFrameEx(PyFrameObject *f, int TARGET(LOAD_GLOBAL) w = GETITEM(names, oparg); - if (PyUnicode_CheckExact(w)) { - /* Inline the PyDict_GetItem() calls. - WARNING: this is an extreme speed hack. - Do not try this at home. */ - Py_hash_t hash = ((PyASCIIObject *)w)->hash; - if (hash != -1) { - PyDictObject *d; - PyDictEntry *e; - d = (PyDictObject *)(f->f_globals); - e = d->ma_lookup(d, w, hash); - if (e == NULL) { - x = NULL; + if (PyDict_CheckExact(f->f_globals) + && PyDict_CheckExact(f->f_builtins)) { + if (PyUnicode_CheckExact(w)) { + /* Inline the PyDict_GetItem() calls. + WARNING: this is an extreme speed hack. + Do not try this at home. */ + Py_hash_t hash = ((PyASCIIObject *)w)->hash; + if (hash != -1) { + PyDictObject *d; + PyDictEntry *e; + d = (PyDictObject *)(f->f_globals); + e = d->ma_lookup(d, w, hash); + if (e == NULL) { + x = NULL; + break; + } + x = e->me_value; + if (x != NULL) { + Py_INCREF(x); + PUSH(x); + DISPATCH(); + } + d = (PyDictObject *)(f->f_builtins); + e = d->ma_lookup(d, w, hash); + if (e == NULL) { + x = NULL; + break; + } + x = e->me_value; + if (x != NULL) { + Py_INCREF(x); + PUSH(x); + DISPATCH(); + } + goto load_global_error; + } + } + /* This is the un-inlined version of the code above */ + x = PyDict_GetItem(f->f_globals, w); + if (x == NULL) { + x = PyDict_GetItem(f->f_builtins, w); + if (x == NULL) { + load_global_error: + format_exc_check_arg( + PyExc_NameError, + GLOBAL_NAME_ERROR_MSG, w); break; } - x = e->me_value; - if (x != NULL) { - Py_INCREF(x); - PUSH(x); - DISPATCH(); - } - d = (PyDictObject *)(f->f_builtins); - e = d->ma_lookup(d, w, hash); - if (e == NULL) { - x = NULL; - break; - } - x = e->me_value; - if (x != NULL) { - Py_INCREF(x); - PUSH(x); - DISPATCH(); - } - goto load_global_error; } + Py_INCREF(x); + PUSH(x); + DISPATCH(); } - /* This is the un-inlined version of the code above */ - x = PyDict_GetItem(f->f_globals, w); + + /* Slow-path if globals or builtins is not a dict */ + x = PyObject_GetItem(f->f_globals, w); if (x == NULL) { - x = PyDict_GetItem(f->f_builtins, w); + x = PyObject_GetItem(f->f_builtins, w); if (x == NULL) { - load_global_error: - format_exc_check_arg( - PyExc_NameError, - GLOBAL_NAME_ERROR_MSG, w); + if (PyErr_ExceptionMatches(PyExc_KeyError)) + format_exc_check_arg( + PyExc_NameError, + GLOBAL_NAME_ERROR_MSG, w); break; } }