Skip to content

Commit 59a22d3

Browse files
[3.12] gh-112716: Fix SystemError when __builtins__ is not a dict (GH-112770) (GH-113103)
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 913051d commit 59a22d3

File tree

3 files changed

+33
-9
lines changed

3 files changed

+33
-9
lines changed

Lib/test/test_builtin.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -812,6 +812,32 @@ class customdict(dict): # this one should not do anything fancy
812812
self.assertRaisesRegex(NameError, "name 'superglobal' is not defined",
813813
exec, code, {'__builtins__': customdict()})
814814

815+
def test_eval_builtins_mapping(self):
816+
code = compile("superglobal", "test", "eval")
817+
# works correctly
818+
ns = {'__builtins__': types.MappingProxyType({'superglobal': 1})}
819+
self.assertEqual(eval(code, ns), 1)
820+
# custom builtins mapping is missing key
821+
ns = {'__builtins__': types.MappingProxyType({})}
822+
self.assertRaisesRegex(NameError, "name 'superglobal' is not defined",
823+
eval, code, ns)
824+
825+
def test_exec_builtins_mapping_import(self):
826+
code = compile("import foo.bar", "test", "exec")
827+
ns = {'__builtins__': types.MappingProxyType({})}
828+
self.assertRaisesRegex(ImportError, "__import__ not found", exec, code, ns)
829+
ns = {'__builtins__': types.MappingProxyType({'__import__': lambda *args: args})}
830+
exec(code, ns)
831+
self.assertEqual(ns['foo'], ('foo.bar', ns, ns, None, 0))
832+
833+
def test_eval_builtins_mapping_reduce(self):
834+
# list_iterator.__reduce__() calls _PyEval_GetBuiltin("iter")
835+
code = compile("x.__reduce__()", "test", "eval")
836+
ns = {'__builtins__': types.MappingProxyType({}), 'x': iter([1, 2])}
837+
self.assertRaisesRegex(AttributeError, "iter", eval, code, ns)
838+
ns = {'__builtins__': types.MappingProxyType({'iter': iter}), 'x': iter([1, 2])}
839+
self.assertEqual(eval(code, ns), (iter, ([1, 2],), 0))
840+
815841
def test_exec_redirected(self):
816842
savestdout = sys.stdout
817843
sys.stdout = None # Whatever that cannot flush()
Lines changed: 2 additions & 0 deletions
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

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2308,11 +2308,8 @@ PyObject *
23082308
_PyEval_GetBuiltin(PyObject *name)
23092309
{
23102310
PyThreadState *tstate = _PyThreadState_GET();
2311-
PyObject *attr = PyDict_GetItemWithError(PyEval_GetBuiltins(), name);
2312-
if (attr) {
2313-
Py_INCREF(attr);
2314-
}
2315-
else if (!_PyErr_Occurred(tstate)) {
2311+
PyObject *attr = PyObject_GetItem(PyEval_GetBuiltins(), name);
2312+
if (attr == NULL && _PyErr_ExceptionMatches(tstate, PyExc_KeyError)) {
23162313
_PyErr_SetObject(tstate, PyExc_AttributeError, name);
23172314
}
23182315
return attr;
@@ -2467,16 +2464,17 @@ import_name(PyThreadState *tstate, _PyInterpreterFrame *frame,
24672464
PyObject *import_func, *res;
24682465
PyObject* stack[5];
24692466

2470-
import_func = _PyDict_GetItemWithError(frame->f_builtins, &_Py_ID(__import__));
2467+
import_func = PyObject_GetItem(frame->f_builtins, &_Py_ID(__import__));
24712468
if (import_func == NULL) {
2472-
if (!_PyErr_Occurred(tstate)) {
2469+
if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) {
24732470
_PyErr_SetString(tstate, PyExc_ImportError, "__import__ not found");
24742471
}
24752472
return NULL;
24762473
}
24772474
PyObject *locals = frame->f_locals;
24782475
/* Fast path for not overloaded __import__. */
24792476
if (_PyImport_IsDefaultImportFunc(tstate->interp, import_func)) {
2477+
Py_DECREF(import_func);
24802478
int ilevel = _PyLong_AsInt(level);
24812479
if (ilevel == -1 && _PyErr_Occurred(tstate)) {
24822480
return NULL;
@@ -2490,8 +2488,6 @@ import_name(PyThreadState *tstate, _PyInterpreterFrame *frame,
24902488
return res;
24912489
}
24922490

2493-
Py_INCREF(import_func);
2494-
24952491
stack[0] = name;
24962492
stack[1] = frame->f_globals;
24972493
stack[2] = locals == NULL ? Py_None : locals;

0 commit comments

Comments
 (0)