mirror of
https://github.com/python/cpython.git
synced 2025-07-07 19:35:27 +00:00
gh-135443: Sometimes Fall Back to __main__.__dict__ For Globals (gh-135491)
For several builtin functions, we now fall back to __main__.__dict__ for the globals when there is no current frame and _PyInterpreterState_IsRunningMain() returns true. This allows those functions to be run with Interpreter.call(). The affected builtins: * exec() * eval() * globals() * locals() * vars() * dir() We take a similar approach with "stateless" functions, which don't use any global variables.
This commit is contained in:
parent
68b7e1a667
commit
a450a0ddec
7 changed files with 394 additions and 68 deletions
|
@ -239,6 +239,16 @@ static inline void _Py_LeaveRecursiveCall(void) {
|
||||||
|
|
||||||
extern _PyInterpreterFrame* _PyEval_GetFrame(void);
|
extern _PyInterpreterFrame* _PyEval_GetFrame(void);
|
||||||
|
|
||||||
|
extern PyObject * _PyEval_GetGlobalsFromRunningMain(PyThreadState *);
|
||||||
|
extern int _PyEval_EnsureBuiltins(
|
||||||
|
PyThreadState *,
|
||||||
|
PyObject *,
|
||||||
|
PyObject **p_builtins);
|
||||||
|
extern int _PyEval_EnsureBuiltinsWithModule(
|
||||||
|
PyThreadState *,
|
||||||
|
PyObject *,
|
||||||
|
PyObject **p_builtins);
|
||||||
|
|
||||||
PyAPI_FUNC(PyObject *)_Py_MakeCoro(PyFunctionObject *func);
|
PyAPI_FUNC(PyObject *)_Py_MakeCoro(PyFunctionObject *func);
|
||||||
|
|
||||||
/* Handle signals, pending calls, GIL drop request
|
/* Handle signals, pending calls, GIL drop request
|
||||||
|
|
|
@ -1414,6 +1414,113 @@ class TestInterpreterCall(TestBase):
|
||||||
with self.assertRaises(interpreters.NotShareableError):
|
with self.assertRaises(interpreters.NotShareableError):
|
||||||
interp.call(func, op, 'eggs!')
|
interp.call(func, op, 'eggs!')
|
||||||
|
|
||||||
|
def test_callable_requires_frame(self):
|
||||||
|
# There are various functions that require a current frame.
|
||||||
|
interp = interpreters.create()
|
||||||
|
for call, expected in [
|
||||||
|
((eval, '[1, 2, 3]'),
|
||||||
|
[1, 2, 3]),
|
||||||
|
((eval, 'sum([1, 2, 3])'),
|
||||||
|
6),
|
||||||
|
((exec, '...'),
|
||||||
|
None),
|
||||||
|
]:
|
||||||
|
with self.subTest(str(call)):
|
||||||
|
res = interp.call(*call)
|
||||||
|
self.assertEqual(res, expected)
|
||||||
|
|
||||||
|
result_not_pickleable = [
|
||||||
|
globals,
|
||||||
|
locals,
|
||||||
|
vars,
|
||||||
|
]
|
||||||
|
for func, expectedtype in {
|
||||||
|
globals: dict,
|
||||||
|
locals: dict,
|
||||||
|
vars: dict,
|
||||||
|
dir: list,
|
||||||
|
}.items():
|
||||||
|
with self.subTest(str(func)):
|
||||||
|
if func in result_not_pickleable:
|
||||||
|
with self.assertRaises(interpreters.NotShareableError):
|
||||||
|
interp.call(func)
|
||||||
|
else:
|
||||||
|
res = interp.call(func)
|
||||||
|
self.assertIsInstance(res, expectedtype)
|
||||||
|
self.assertIn('__builtins__', res)
|
||||||
|
|
||||||
|
def test_globals_from_builtins(self):
|
||||||
|
# The builtins exec(), eval(), globals(), locals(), vars(),
|
||||||
|
# and dir() each runs relative to the target interpreter's
|
||||||
|
# __main__ module, when called directly. However,
|
||||||
|
# globals(), locals(), and vars() don't work when called
|
||||||
|
# directly so we don't check them.
|
||||||
|
from _frozen_importlib import BuiltinImporter
|
||||||
|
interp = interpreters.create()
|
||||||
|
|
||||||
|
names = interp.call(dir)
|
||||||
|
self.assertEqual(names, [
|
||||||
|
'__builtins__',
|
||||||
|
'__doc__',
|
||||||
|
'__loader__',
|
||||||
|
'__name__',
|
||||||
|
'__package__',
|
||||||
|
'__spec__',
|
||||||
|
])
|
||||||
|
|
||||||
|
values = {name: interp.call(eval, name)
|
||||||
|
for name in names if name != '__builtins__'}
|
||||||
|
self.assertEqual(values, {
|
||||||
|
'__name__': '__main__',
|
||||||
|
'__doc__': None,
|
||||||
|
'__spec__': None, # It wasn't imported, so no module spec?
|
||||||
|
'__package__': None,
|
||||||
|
'__loader__': BuiltinImporter,
|
||||||
|
})
|
||||||
|
with self.assertRaises(ExecutionFailed):
|
||||||
|
interp.call(eval, 'spam'),
|
||||||
|
|
||||||
|
interp.call(exec, f'assert dir() == {names}')
|
||||||
|
|
||||||
|
# Update the interpreter's __main__.
|
||||||
|
interp.prepare_main(spam=42)
|
||||||
|
expected = names + ['spam']
|
||||||
|
|
||||||
|
names = interp.call(dir)
|
||||||
|
self.assertEqual(names, expected)
|
||||||
|
|
||||||
|
value = interp.call(eval, 'spam')
|
||||||
|
self.assertEqual(value, 42)
|
||||||
|
|
||||||
|
interp.call(exec, f'assert dir() == {expected}, dir()')
|
||||||
|
|
||||||
|
def test_globals_from_stateless_func(self):
|
||||||
|
# A stateless func, which doesn't depend on any globals,
|
||||||
|
# doesn't go through pickle, so it runs in __main__.
|
||||||
|
def set_global(name, value):
|
||||||
|
globals()[name] = value
|
||||||
|
|
||||||
|
def get_global(name):
|
||||||
|
return globals().get(name)
|
||||||
|
|
||||||
|
interp = interpreters.create()
|
||||||
|
|
||||||
|
modname = interp.call(get_global, '__name__')
|
||||||
|
self.assertEqual(modname, '__main__')
|
||||||
|
|
||||||
|
res = interp.call(get_global, 'spam')
|
||||||
|
self.assertIsNone(res)
|
||||||
|
|
||||||
|
interp.exec('spam = True')
|
||||||
|
res = interp.call(get_global, 'spam')
|
||||||
|
self.assertTrue(res)
|
||||||
|
|
||||||
|
interp.call(set_global, 'spam', 42)
|
||||||
|
res = interp.call(get_global, 'spam')
|
||||||
|
self.assertEqual(res, 42)
|
||||||
|
|
||||||
|
interp.exec('assert spam == 42, repr(spam)')
|
||||||
|
|
||||||
def test_call_in_thread(self):
|
def test_call_in_thread(self):
|
||||||
interp = interpreters.create()
|
interp = interpreters.create()
|
||||||
|
|
||||||
|
|
|
@ -2084,9 +2084,25 @@ _dir_locals(void)
|
||||||
PyObject *names;
|
PyObject *names;
|
||||||
PyObject *locals;
|
PyObject *locals;
|
||||||
|
|
||||||
locals = _PyEval_GetFrameLocals();
|
if (_PyEval_GetFrame() != NULL) {
|
||||||
if (locals == NULL)
|
locals = _PyEval_GetFrameLocals();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PyThreadState *tstate = _PyThreadState_GET();
|
||||||
|
locals = _PyEval_GetGlobalsFromRunningMain(tstate);
|
||||||
|
if (locals == NULL) {
|
||||||
|
if (!_PyErr_Occurred(tstate)) {
|
||||||
|
locals = _PyEval_GetFrameLocals();
|
||||||
|
assert(_PyErr_Occurred(tstate));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Py_INCREF(locals);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (locals == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
names = PyMapping_Keys(locals);
|
names = PyMapping_Keys(locals);
|
||||||
Py_DECREF(locals);
|
Py_DECREF(locals);
|
||||||
|
|
|
@ -957,6 +957,7 @@ builtin_eval_impl(PyObject *module, PyObject *source, PyObject *globals,
|
||||||
PyObject *locals)
|
PyObject *locals)
|
||||||
/*[clinic end generated code: output=0a0824aa70093116 input=7c7bce5299a89062]*/
|
/*[clinic end generated code: output=0a0824aa70093116 input=7c7bce5299a89062]*/
|
||||||
{
|
{
|
||||||
|
PyThreadState *tstate = _PyThreadState_GET();
|
||||||
PyObject *result = NULL, *source_copy;
|
PyObject *result = NULL, *source_copy;
|
||||||
const char *str;
|
const char *str;
|
||||||
|
|
||||||
|
@ -970,35 +971,46 @@ builtin_eval_impl(PyObject *module, PyObject *source, PyObject *globals,
|
||||||
: "globals must be a dict");
|
: "globals must be a dict");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (globals == Py_None) {
|
|
||||||
globals = PyEval_GetGlobals();
|
int fromframe = 0;
|
||||||
if (locals == Py_None) {
|
if (globals != Py_None) {
|
||||||
locals = _PyEval_GetFrameLocals();
|
Py_INCREF(globals);
|
||||||
if (locals == NULL)
|
}
|
||||||
return NULL;
|
else if (_PyEval_GetFrame() != NULL) {
|
||||||
}
|
fromframe = 1;
|
||||||
else {
|
globals = PyEval_GetGlobals();
|
||||||
Py_INCREF(locals);
|
assert(globals != NULL);
|
||||||
}
|
Py_INCREF(globals);
|
||||||
}
|
}
|
||||||
else if (locals == Py_None)
|
|
||||||
locals = Py_NewRef(globals);
|
|
||||||
else {
|
else {
|
||||||
|
globals = _PyEval_GetGlobalsFromRunningMain(tstate);
|
||||||
|
if (globals == NULL) {
|
||||||
|
if (!_PyErr_Occurred(tstate)) {
|
||||||
|
PyErr_SetString(PyExc_TypeError,
|
||||||
|
"eval must be given globals and locals "
|
||||||
|
"when called without a frame");
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
Py_INCREF(globals);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (locals != Py_None) {
|
||||||
Py_INCREF(locals);
|
Py_INCREF(locals);
|
||||||
}
|
}
|
||||||
|
else if (fromframe) {
|
||||||
if (globals == NULL || locals == NULL) {
|
locals = _PyEval_GetFrameLocals();
|
||||||
PyErr_SetString(PyExc_TypeError,
|
if (locals == NULL) {
|
||||||
"eval must be given globals and locals "
|
assert(PyErr_Occurred());
|
||||||
"when called without a frame");
|
Py_DECREF(globals);
|
||||||
goto error;
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
locals = Py_NewRef(globals);
|
||||||
}
|
}
|
||||||
|
|
||||||
int r = PyDict_Contains(globals, &_Py_ID(__builtins__));
|
if (_PyEval_EnsureBuiltins(tstate, globals, NULL) < 0) {
|
||||||
if (r == 0) {
|
|
||||||
r = PyDict_SetItem(globals, &_Py_ID(__builtins__), PyEval_GetBuiltins());
|
|
||||||
}
|
|
||||||
if (r < 0) {
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1039,6 +1051,7 @@ builtin_eval_impl(PyObject *module, PyObject *source, PyObject *globals,
|
||||||
}
|
}
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
Py_XDECREF(globals);
|
||||||
Py_XDECREF(locals);
|
Py_XDECREF(locals);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -1069,29 +1082,44 @@ builtin_exec_impl(PyObject *module, PyObject *source, PyObject *globals,
|
||||||
PyObject *locals, PyObject *closure)
|
PyObject *locals, PyObject *closure)
|
||||||
/*[clinic end generated code: output=7579eb4e7646743d input=25e989b6d87a3a21]*/
|
/*[clinic end generated code: output=7579eb4e7646743d input=25e989b6d87a3a21]*/
|
||||||
{
|
{
|
||||||
|
PyThreadState *tstate = _PyThreadState_GET();
|
||||||
PyObject *v;
|
PyObject *v;
|
||||||
|
|
||||||
if (globals == Py_None) {
|
int fromframe = 0;
|
||||||
|
if (globals != Py_None) {
|
||||||
|
Py_INCREF(globals);
|
||||||
|
}
|
||||||
|
else if (_PyEval_GetFrame() != NULL) {
|
||||||
|
fromframe = 1;
|
||||||
globals = PyEval_GetGlobals();
|
globals = PyEval_GetGlobals();
|
||||||
if (locals == Py_None) {
|
assert(globals != NULL);
|
||||||
locals = _PyEval_GetFrameLocals();
|
Py_INCREF(globals);
|
||||||
if (locals == NULL)
|
}
|
||||||
return NULL;
|
else {
|
||||||
|
globals = _PyEval_GetGlobalsFromRunningMain(tstate);
|
||||||
|
if (globals == NULL) {
|
||||||
|
if (!_PyErr_Occurred(tstate)) {
|
||||||
|
PyErr_SetString(PyExc_SystemError,
|
||||||
|
"globals and locals cannot be NULL");
|
||||||
|
}
|
||||||
|
goto error;
|
||||||
}
|
}
|
||||||
else {
|
Py_INCREF(globals);
|
||||||
Py_INCREF(locals);
|
}
|
||||||
}
|
|
||||||
if (!globals || !locals) {
|
if (locals != Py_None) {
|
||||||
PyErr_SetString(PyExc_SystemError,
|
Py_INCREF(locals);
|
||||||
"globals and locals cannot be NULL");
|
}
|
||||||
|
else if (fromframe) {
|
||||||
|
locals = _PyEval_GetFrameLocals();
|
||||||
|
if (locals == NULL) {
|
||||||
|
assert(PyErr_Occurred());
|
||||||
|
Py_DECREF(globals);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (locals == Py_None) {
|
|
||||||
locals = Py_NewRef(globals);
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
Py_INCREF(locals);
|
locals = Py_NewRef(globals);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!PyDict_Check(globals)) {
|
if (!PyDict_Check(globals)) {
|
||||||
|
@ -1105,11 +1133,8 @@ builtin_exec_impl(PyObject *module, PyObject *source, PyObject *globals,
|
||||||
Py_TYPE(locals)->tp_name);
|
Py_TYPE(locals)->tp_name);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
int r = PyDict_Contains(globals, &_Py_ID(__builtins__));
|
|
||||||
if (r == 0) {
|
if (_PyEval_EnsureBuiltins(tstate, globals, NULL) < 0) {
|
||||||
r = PyDict_SetItem(globals, &_Py_ID(__builtins__), PyEval_GetBuiltins());
|
|
||||||
}
|
|
||||||
if (r < 0) {
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1186,11 +1211,13 @@ builtin_exec_impl(PyObject *module, PyObject *source, PyObject *globals,
|
||||||
}
|
}
|
||||||
if (v == NULL)
|
if (v == NULL)
|
||||||
goto error;
|
goto error;
|
||||||
|
Py_DECREF(globals);
|
||||||
Py_DECREF(locals);
|
Py_DECREF(locals);
|
||||||
Py_DECREF(v);
|
Py_DECREF(v);
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
Py_XDECREF(globals);
|
||||||
Py_XDECREF(locals);
|
Py_XDECREF(locals);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -1240,10 +1267,21 @@ static PyObject *
|
||||||
builtin_globals_impl(PyObject *module)
|
builtin_globals_impl(PyObject *module)
|
||||||
/*[clinic end generated code: output=e5dd1527067b94d2 input=9327576f92bb48ba]*/
|
/*[clinic end generated code: output=e5dd1527067b94d2 input=9327576f92bb48ba]*/
|
||||||
{
|
{
|
||||||
PyObject *d;
|
PyObject *globals;
|
||||||
|
if (_PyEval_GetFrame() != NULL) {
|
||||||
d = PyEval_GetGlobals();
|
globals = PyEval_GetGlobals();
|
||||||
return Py_XNewRef(d);
|
assert(globals != NULL);
|
||||||
|
return Py_NewRef(globals);
|
||||||
|
}
|
||||||
|
PyThreadState *tstate = _PyThreadState_GET();
|
||||||
|
globals = _PyEval_GetGlobalsFromRunningMain(tstate);
|
||||||
|
if (globals == NULL) {
|
||||||
|
if (_PyErr_Occurred(tstate)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
return Py_NewRef(globals);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1887,7 +1925,21 @@ static PyObject *
|
||||||
builtin_locals_impl(PyObject *module)
|
builtin_locals_impl(PyObject *module)
|
||||||
/*[clinic end generated code: output=b46c94015ce11448 input=7874018d478d5c4b]*/
|
/*[clinic end generated code: output=b46c94015ce11448 input=7874018d478d5c4b]*/
|
||||||
{
|
{
|
||||||
return _PyEval_GetFrameLocals();
|
PyObject *locals;
|
||||||
|
if (_PyEval_GetFrame() != NULL) {
|
||||||
|
locals = _PyEval_GetFrameLocals();
|
||||||
|
assert(locals != NULL || PyErr_Occurred());
|
||||||
|
return locals;
|
||||||
|
}
|
||||||
|
PyThreadState *tstate = _PyThreadState_GET();
|
||||||
|
locals = _PyEval_GetGlobalsFromRunningMain(tstate);
|
||||||
|
if (locals == NULL) {
|
||||||
|
if (_PyErr_Occurred(tstate)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
return Py_NewRef(locals);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2623,7 +2675,22 @@ builtin_vars(PyObject *self, PyObject *args)
|
||||||
if (!PyArg_UnpackTuple(args, "vars", 0, 1, &v))
|
if (!PyArg_UnpackTuple(args, "vars", 0, 1, &v))
|
||||||
return NULL;
|
return NULL;
|
||||||
if (v == NULL) {
|
if (v == NULL) {
|
||||||
d = _PyEval_GetFrameLocals();
|
if (_PyEval_GetFrame() != NULL) {
|
||||||
|
d = _PyEval_GetFrameLocals();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PyThreadState *tstate = _PyThreadState_GET();
|
||||||
|
d = _PyEval_GetGlobalsFromRunningMain(tstate);
|
||||||
|
if (d == NULL) {
|
||||||
|
if (!_PyErr_Occurred(tstate)) {
|
||||||
|
d = _PyEval_GetFrameLocals();
|
||||||
|
assert(_PyErr_Occurred(tstate));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Py_INCREF(d);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (PyObject_GetOptionalAttr(v, &_Py_ID(__dict__), &d) == 0) {
|
if (PyObject_GetOptionalAttr(v, &_Py_ID(__dict__), &d) == 0) {
|
||||||
|
|
119
Python/ceval.c
119
Python/ceval.c
|
@ -2746,10 +2746,9 @@ _PyEval_GetFrameLocals(void)
|
||||||
return locals;
|
return locals;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *
|
static PyObject *
|
||||||
PyEval_GetGlobals(void)
|
_PyEval_GetGlobals(PyThreadState *tstate)
|
||||||
{
|
{
|
||||||
PyThreadState *tstate = _PyThreadState_GET();
|
|
||||||
_PyInterpreterFrame *current_frame = _PyThreadState_GetFrame(tstate);
|
_PyInterpreterFrame *current_frame = _PyThreadState_GetFrame(tstate);
|
||||||
if (current_frame == NULL) {
|
if (current_frame == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -2757,6 +2756,120 @@ PyEval_GetGlobals(void)
|
||||||
return current_frame->f_globals;
|
return current_frame->f_globals;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
PyEval_GetGlobals(void)
|
||||||
|
{
|
||||||
|
PyThreadState *tstate = _PyThreadState_GET();
|
||||||
|
return _PyEval_GetGlobals(tstate);
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
_PyEval_GetGlobalsFromRunningMain(PyThreadState *tstate)
|
||||||
|
{
|
||||||
|
if (!_PyInterpreterState_IsRunningMain(tstate->interp)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
PyObject *mod = _Py_GetMainModule(tstate);
|
||||||
|
if (_Py_CheckMainModule(mod) < 0) {
|
||||||
|
Py_XDECREF(mod);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
PyObject *globals = PyModule_GetDict(mod); // borrowed
|
||||||
|
Py_DECREF(mod);
|
||||||
|
return globals;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
get_globals_builtins(PyObject *globals)
|
||||||
|
{
|
||||||
|
PyObject *builtins = NULL;
|
||||||
|
if (PyDict_Check(globals)) {
|
||||||
|
if (PyDict_GetItemRef(globals, &_Py_ID(__builtins__), &builtins) < 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (PyMapping_GetOptionalItem(
|
||||||
|
globals, &_Py_ID(__builtins__), &builtins) < 0)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return builtins;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
set_globals_builtins(PyObject *globals, PyObject *builtins)
|
||||||
|
{
|
||||||
|
if (PyDict_Check(globals)) {
|
||||||
|
if (PyDict_SetItem(globals, &_Py_ID(__builtins__), builtins) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (PyObject_SetItem(globals, &_Py_ID(__builtins__), builtins) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
_PyEval_EnsureBuiltins(PyThreadState *tstate, PyObject *globals,
|
||||||
|
PyObject **p_builtins)
|
||||||
|
{
|
||||||
|
PyObject *builtins = get_globals_builtins(globals);
|
||||||
|
if (builtins == NULL) {
|
||||||
|
if (_PyErr_Occurred(tstate)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
builtins = PyEval_GetBuiltins(); // borrowed
|
||||||
|
if (builtins == NULL) {
|
||||||
|
assert(_PyErr_Occurred(tstate));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
Py_INCREF(builtins);
|
||||||
|
if (set_globals_builtins(globals, builtins) < 0) {
|
||||||
|
Py_DECREF(builtins);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (p_builtins != NULL) {
|
||||||
|
*p_builtins = builtins;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Py_DECREF(builtins);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
_PyEval_EnsureBuiltinsWithModule(PyThreadState *tstate, PyObject *globals,
|
||||||
|
PyObject **p_builtins)
|
||||||
|
{
|
||||||
|
PyObject *builtins = get_globals_builtins(globals);
|
||||||
|
if (builtins == NULL) {
|
||||||
|
if (_PyErr_Occurred(tstate)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
builtins = PyImport_ImportModuleLevel("builtins", NULL, NULL, NULL, 0);
|
||||||
|
if (builtins == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (set_globals_builtins(globals, builtins) < 0) {
|
||||||
|
Py_DECREF(builtins);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (p_builtins != NULL) {
|
||||||
|
*p_builtins = builtins;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Py_DECREF(builtins);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
PyObject*
|
PyObject*
|
||||||
PyEval_GetFrameLocals(void)
|
PyEval_GetFrameLocals(void)
|
||||||
{
|
{
|
||||||
|
|
|
@ -722,16 +722,26 @@ _PyFunction_FromXIData(_PyXIData_t *xidata)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
// Create a new function.
|
// Create a new function.
|
||||||
|
// For stateless functions (no globals) we use __main__ as __globals__,
|
||||||
|
// just like we do for builtins like exec().
|
||||||
assert(PyCode_Check(code));
|
assert(PyCode_Check(code));
|
||||||
PyObject *globals = PyDict_New();
|
|
||||||
if (globals == NULL) {
|
|
||||||
Py_DECREF(code);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
PyThreadState *tstate = _PyThreadState_GET();
|
PyThreadState *tstate = _PyThreadState_GET();
|
||||||
if (PyDict_SetItem(globals, &_Py_ID(__builtins__),
|
PyObject *globals = _PyEval_GetGlobalsFromRunningMain(tstate); // borrowed
|
||||||
tstate->interp->builtins) < 0)
|
if (globals == NULL) {
|
||||||
{
|
if (_PyErr_Occurred(tstate)) {
|
||||||
|
Py_DECREF(code);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
globals = PyDict_New();
|
||||||
|
if (globals == NULL) {
|
||||||
|
Py_DECREF(code);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Py_INCREF(globals);
|
||||||
|
}
|
||||||
|
if (_PyEval_EnsureBuiltins(tstate, globals, NULL) < 0) {
|
||||||
Py_DECREF(code);
|
Py_DECREF(code);
|
||||||
Py_DECREF(globals);
|
Py_DECREF(globals);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
@ -3960,25 +3960,28 @@ PyImport_Import(PyObject *module_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the builtins from current globals */
|
/* Get the builtins from current globals */
|
||||||
globals = PyEval_GetGlobals();
|
globals = PyEval_GetGlobals(); // borrowed
|
||||||
if (globals != NULL) {
|
if (globals != NULL) {
|
||||||
Py_INCREF(globals);
|
Py_INCREF(globals);
|
||||||
|
// XXX Use _PyEval_EnsureBuiltins()?
|
||||||
builtins = PyObject_GetItem(globals, &_Py_ID(__builtins__));
|
builtins = PyObject_GetItem(globals, &_Py_ID(__builtins__));
|
||||||
if (builtins == NULL) {
|
if (builtins == NULL) {
|
||||||
// XXX Fall back to interp->builtins or sys.modules['builtins']?
|
// XXX Fall back to interp->builtins or sys.modules['builtins']?
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (_PyErr_Occurred(tstate)) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
/* No globals -- use standard builtins, and fake globals */
|
/* No globals -- use standard builtins, and fake globals */
|
||||||
builtins = PyImport_ImportModuleLevel("builtins",
|
globals = PyDict_New();
|
||||||
NULL, NULL, NULL, 0);
|
if (globals == NULL) {
|
||||||
if (builtins == NULL) {
|
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
globals = Py_BuildValue("{OO}", &_Py_ID(__builtins__), builtins);
|
if (_PyEval_EnsureBuiltinsWithModule(tstate, globals, &builtins) < 0) {
|
||||||
if (globals == NULL)
|
|
||||||
goto err;
|
goto err;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the __import__ function from the builtins */
|
/* Get the __import__ function from the builtins */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue