Skip to content

Commit d423493

Browse files
[3.11] gh-112716: Fix SystemError when __builtins__ is not a dict (GH-112770) (GH-113105)
It was raised in two cases: * in the import statement when looking up __import__ * in pickling some builtin type when looking up built-ins iter, getattr, etc. (cherry picked from commit 1161c14)
1 parent 08ff6fa commit d423493

File tree

3 files changed

+33
-9
lines changed

3 files changed

+33
-9
lines changed

Lib/test/test_builtin.py

+26
Original file line numberDiff line numberDiff line change
@@ -798,6 +798,32 @@ class customdict(dict): # this one should not do anything fancy
798798
self.assertRaisesRegex(NameError, "name 'superglobal' is not defined",
799799
exec, code, {'__builtins__': customdict()})
800800

801+
def test_eval_builtins_mapping(self):
802+
code = compile("superglobal", "test", "eval")
803+
# works correctly
804+
ns = {'__builtins__': types.MappingProxyType({'superglobal': 1})}
805+
self.assertEqual(eval(code, ns), 1)
806+
# custom builtins mapping is missing key
807+
ns = {'__builtins__': types.MappingProxyType({})}
808+
self.assertRaisesRegex(NameError, "name 'superglobal' is not defined",
809+
eval, code, ns)
810+
811+
def test_exec_builtins_mapping_import(self):
812+
code = compile("import foo.bar", "test", "exec")
813+
ns = {'__builtins__': types.MappingProxyType({})}
814+
self.assertRaisesRegex(ImportError, "__import__ not found", exec, code, ns)
815+
ns = {'__builtins__': types.MappingProxyType({'__import__': lambda *args: args})}
816+
exec(code, ns)
817+
self.assertEqual(ns['foo'], ('foo.bar', ns, ns, None, 0))
818+
819+
def test_eval_builtins_mapping_reduce(self):
820+
# list_iterator.__reduce__() calls _PyEval_GetBuiltin("iter")
821+
code = compile("x.__reduce__()", "test", "eval")
822+
ns = {'__builtins__': types.MappingProxyType({}), 'x': iter([1, 2])}
823+
self.assertRaisesRegex(AttributeError, "iter", eval, code, ns)
824+
ns = {'__builtins__': types.MappingProxyType({'iter': iter}), 'x': iter([1, 2])}
825+
self.assertEqual(eval(code, ns), (iter, ([1, 2],), 0))
826+
801827
def test_exec_redirected(self):
802828
savestdout = sys.stdout
803829
sys.stdout = None # Whatever that cannot flush()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix SystemError in the ``import`` statement and in ``__reduce__()`` methods
2+
of builtin types when ``__builtins__`` is not a dict.

Python/ceval.c

+5-9
Original file line numberDiff line numberDiff line change
@@ -7153,11 +7153,8 @@ PyObject *
71537153
_PyEval_GetBuiltin(PyObject *name)
71547154
{
71557155
PyThreadState *tstate = _PyThreadState_GET();
7156-
PyObject *attr = PyDict_GetItemWithError(PyEval_GetBuiltins(), name);
7157-
if (attr) {
7158-
Py_INCREF(attr);
7159-
}
7160-
else if (!_PyErr_Occurred(tstate)) {
7156+
PyObject *attr = PyObject_GetItem(PyEval_GetBuiltins(), name);
7157+
if (attr == NULL && _PyErr_ExceptionMatches(tstate, PyExc_KeyError)) {
71617158
_PyErr_SetObject(tstate, PyExc_AttributeError, name);
71627159
}
71637160
return attr;
@@ -7407,16 +7404,17 @@ import_name(PyThreadState *tstate, _PyInterpreterFrame *frame,
74077404
PyObject *import_func, *res;
74087405
PyObject* stack[5];
74097406

7410-
import_func = _PyDict_GetItemWithError(frame->f_builtins, &_Py_ID(__import__));
7407+
import_func = PyObject_GetItem(frame->f_builtins, &_Py_ID(__import__));
74117408
if (import_func == NULL) {
7412-
if (!_PyErr_Occurred(tstate)) {
7409+
if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) {
74137410
_PyErr_SetString(tstate, PyExc_ImportError, "__import__ not found");
74147411
}
74157412
return NULL;
74167413
}
74177414
PyObject *locals = frame->f_locals;
74187415
/* Fast path for not overloaded __import__. */
74197416
if (import_func == tstate->interp->import_func) {
7417+
Py_DECREF(import_func);
74207418
int ilevel = _PyLong_AsInt(level);
74217419
if (ilevel == -1 && _PyErr_Occurred(tstate)) {
74227420
return NULL;
@@ -7430,8 +7428,6 @@ import_name(PyThreadState *tstate, _PyInterpreterFrame *frame,
74307428
return res;
74317429
}
74327430

7433-
Py_INCREF(import_func);
7434-
74357431
stack[0] = name;
74367432
stack[1] = frame->f_globals;
74377433
stack[2] = locals == NULL ? Py_None : locals;

0 commit comments

Comments
 (0)