bpo-42990: Functions inherit current builtins (GH-24564)
The types.FunctionType constructor now inherits the current builtins
if the globals dictionary has no "__builtins__" key, rather than
using {"None": None} as builtins: same behavior as eval() and exec()
functions.
Defining a function with "def function(...): ..." in Python is not
affected, globals cannot be overriden with this syntax: it also
inherits the current builtins.
PyFrame_New(), PyEval_EvalCode(), PyEval_EvalCodeEx(),
PyFunction_New() and PyFunction_NewWithQualName() now inherits the
current builtins namespace if the globals dictionary has no
"__builtins__" key.
* Add _PyEval_GetBuiltins() function.
* _PyEval_BuiltinsFromGlobals() now uses _PyEval_GetBuiltins() if
builtins cannot be found in globals.
* Add tstate parameter to _PyEval_BuiltinsFromGlobals().
diff --git a/Objects/frameobject.c b/Objects/frameobject.c
index 0571bfe..056d42a 100644
--- a/Objects/frameobject.c
+++ b/Objects/frameobject.c
@@ -847,7 +847,7 @@ PyFrameObject*
PyFrame_New(PyThreadState *tstate, PyCodeObject *code,
PyObject *globals, PyObject *locals)
{
- PyObject *builtins = _PyEval_BuiltinsFromGlobals(globals);
+ PyObject *builtins = _PyEval_BuiltinsFromGlobals(tstate, globals);
if (builtins == NULL) {
return NULL;
}
@@ -862,7 +862,6 @@ PyFrame_New(PyThreadState *tstate, PyCodeObject *code,
.fc_closure = NULL
};
PyFrameObject *f = _PyFrame_New_NoTrack(tstate, &desc, locals);
- Py_DECREF(builtins);
if (f) {
_PyObject_GC_TRACK(f);
}
@@ -1163,7 +1162,7 @@ PyFrame_GetBack(PyFrameObject *frame)
}
PyObject*
-_PyEval_BuiltinsFromGlobals(PyObject *globals)
+_PyEval_BuiltinsFromGlobals(PyThreadState *tstate, PyObject *globals)
{
PyObject *builtins = _PyDict_GetItemIdWithError(globals, &PyId___builtins__);
if (builtins) {
@@ -1171,21 +1170,11 @@ _PyEval_BuiltinsFromGlobals(PyObject *globals)
builtins = PyModule_GetDict(builtins);
assert(builtins != NULL);
}
- return Py_NewRef(builtins);
+ return builtins;
}
-
if (PyErr_Occurred()) {
return NULL;
}
- /* No builtins! Make up a minimal one. Give them 'None', at least. */
- builtins = PyDict_New();
- if (builtins == NULL) {
- return NULL;
- }
- if (PyDict_SetItemString(builtins, "None", Py_None) < 0) {
- Py_DECREF(builtins);
- return NULL;
- }
- return builtins;
+ return _PyEval_GetBuiltins(tstate);
}