Content-Length: 408847 | pFad | http://github.com/python/cpython/pull/110251/commits/a25c7c763ba98ad7ee207b24d668d748c3809e15

7B gh-76785: Support Running Some Functions in Subinterpreters by ericsnowcurrently · Pull Request #110251 · python/cpython · GitHub
Skip to content

gh-76785: Support Running Some Functions in Subinterpreters #110251

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Prev Previous commit
Next Next commit
Support passing basic functions to Interpreter.run().
  • Loading branch information
ericsnowcurrently committed Oct 2, 2023
commit a25c7c763ba98ad7ee207b24d668d748c3809e15
127 changes: 108 additions & 19 deletions Modules/_xxsubinterpretersmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -335,30 +335,96 @@ _sharedexception_apply(_sharedexception *exc, PyObject *wrapperclass)

/* Python code **************************************************************/

static int
validate_code_object(PyCodeObject *code)
{
if (code->co_argcount > 0
|| code->co_posonlyargcount > 0
|| code->co_kwonlyargcount > 0)
{
PyErr_SetString(PyExc_ValueError, "arguments not supported");
return -1;
}
if (code->co_ncellvars > 0) {
PyErr_SetString(PyExc_ValueError, "closures not supported");
return -1;
}
// We trust that no code objects under co_consts have unbound cell vars.

if (code->co_executors != NULL
|| code->_co_instrumentation_version > 0)
{
PyErr_SetString(PyExc_ValueError, "only basic functions are supported");
return -1;
}
if (code->_co_monitoring != NULL) {
PyErr_SetString(PyExc_ValueError, "only basic functions are supported");
return -1;
}
if (code->co_extra != NULL) {
PyErr_SetString(PyExc_ValueError, "only basic functions are supported");
return -1;
}

return 0;
}

#define RUN_TEXT 1
#define RUN_CODE 2

static const char *
get_code_str(PyObject *arg, int *flags_p)
get_code_str(PyObject *arg, Py_ssize_t *len_p, PyObject **bytes_p, int *flags_p)
{
const char *codestr = NULL;
Py_ssize_t len = -1;
PyObject *bytes_obj = NULL;
int flags = 0;

if (PyUnicode_Check(arg)) {
Py_ssize_t size;
const char *codestr = PyUnicode_AsUTF8AndSize(arg, &size);
// XXX Validate that it parses?
codestr = PyUnicode_AsUTF8AndSize(arg, &len);
if (codestr == NULL) {
return NULL;
}
if (strlen(codestr) != (size_t)size) {
if (strlen(codestr) != (size_t)len) {
PyErr_SetString(PyExc_ValueError,
"source code string cannot contain null bytes");
return NULL;
}
*flags_p = RUN_TEXT;
return codestr;
flags = RUN_TEXT;
}
else {
PyErr_SetString(PyExc_TypeError,
"unsupported code arg");
return NULL;
PyObject *code = arg;
if (PyFunction_Check(arg)) {
if (PyFunction_GetClosure(arg)) {
PyErr_SetString(PyExc_ValueError, "closures not supported");
return NULL;
}
code = PyFunction_GetCode(arg);
}
else if (!PyCode_Check(arg)) {
PyErr_SetString(PyExc_TypeError, "unsupported type");
return NULL;
}
flags = RUN_CODE;

if (validate_code_object((PyCodeObject *)code) < 0) {
return NULL;
}

// Serialize the code object.
bytes_obj = PyMarshal_WriteObjectToString(code, Py_MARSHAL_VERSION);
if (bytes_obj == NULL) {
return NULL;
}
codestr = PyBytes_AS_STRING(bytes_obj);
len = PyBytes_GET_SIZE(bytes_obj);
}

*flags_p = flags;
*bytes_p = bytes_obj;
*len_p = len;
return codestr;
}


Expand Down Expand Up @@ -389,7 +455,8 @@ exceptions_init(PyObject *mod)
}

static int
_run_script(PyInterpreterState *interp, const char *codestr,
_run_script(PyInterpreterState *interp,
const char *codestr, Py_ssize_t codestrlen,
_sharedns *shared, _sharedexception *sharedexc, int flags)
{
if (_PyInterpreterState_SetRunningMain(interp) < 0) {
Expand Down Expand Up @@ -422,8 +489,14 @@ _run_script(PyInterpreterState *interp, const char *codestr,
if (flags & RUN_TEXT) {
result = PyRun_StringFlags(codestr, Py_file_input, ns, ns, NULL);
}
else if (flags & RUN_CODE) {
PyObject *code = PyMarshal_ReadObjectFromString(codestr, codestrlen);
if (code != NULL) {
result = PyEval_EvalCode(code, ns, ns);
}
}
else {
Py_FatalError("unsupported codestr");
Py_UNREACHABLE();
}
Py_DECREF(ns);
if (result == NULL) {
Expand Down Expand Up @@ -454,7 +527,8 @@ _run_script(PyInterpreterState *interp, const char *codestr,

static int
_run_in_interpreter(PyObject *mod, PyInterpreterState *interp,
const char *codestr, PyObject *shareables, int flags)
const char *codestr, Py_ssize_t codestrlen,
PyObject *shareables, int flags)
{
module_state *state = get_module_state(mod);

Expand Down Expand Up @@ -492,7 +566,7 @@ _run_in_interpreter(PyObject *mod, PyInterpreterState *interp,

// Run the script.
_sharedexception exc = {NULL, NULL};
int result = _run_script(interp, codestr, shared, &exc, flags);
int result = _run_script(interp, codestr, codestrlen, shared, &exc, flags);

// Switch back.
if (save_tstate != NULL) {
Expand Down Expand Up @@ -709,7 +783,7 @@ interp_exec(PyObject *self, PyObject *args, PyObject *kwds)
PyObject *id, *code_arg;
PyObject *shared = NULL;
if (!PyArg_ParseTupleAndKeywords(args, kwds,
"OU|O:" MODULE_NAME ".exec", kwlist,
"OO|O:" MODULE_NAME ".exec", kwlist,
&id, &code_arg, &shared)) {
return NULL;
}
Expand All @@ -721,26 +795,41 @@ interp_exec(PyObject *self, PyObject *args, PyObject *kwds)
}

// Extract code.
Py_ssize_t codestrlen = -1;
PyObject *bytes_obj = NULL;
int flags = 0;
const char *codestr = get_code_str(code_arg, &flags);
const char *codestr = get_code_str(code_arg,
&codestrlen, &bytes_obj, &flags);
if (codestr == NULL) {
return NULL;
}

// Run the code in the interpreter.
if (_run_in_interpreter(self, interp, codestr, shared, flags) != 0) {
int res = _run_in_interpreter(self, interp, codestr, codestrlen,
shared, flags);
Py_XDECREF(bytes_obj);
if (res != 0) {
return NULL;
}
Py_RETURN_NONE;
}

PyDoc_STRVAR(exec_doc,
"exec(id, script, shared)\n\
"exec(id, code, shared)\n\
\n\
Execute the provided string in the identified interpreter.\n\
Execute the provided code in the identified interpreter.\n\
This is equivalent to running the builtin exec() under the target\n\
interpreter, using the __dict__ of its __main__ module as both\n\
globals and locals.");
globals and locals.\n\
\n\
\"code\" may be a string containing the text of a Python script.\n\
\n\
Functions (and code objects) are also supported, with some restrictions.\n\
The code/function must not take any arguments or be a closure\n\
(i.e. have cell vars).\n\
\n\
If a function is provided, its code object is used and all its state\n\
is ignored, including its __globals__ dict.");


static PyObject *
Expand Down








ApplySandwichStrip

pFad - (p)hone/(F)rame/(a)nonymizer/(d)eclutterfier!      Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

Fetched URL: http://github.com/python/cpython/pull/110251/commits/a25c7c763ba98ad7ee207b24d668d748c3809e15

Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy