Skip to content

gh-132775: Use _PyFunction_VerifyStateless() and _PyCode_VerifyStateless() #133474

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

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Include/internal/pycore_pyerrors.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,13 +94,13 @@ extern void _PyErr_Fetch(
PyObject **value,
PyObject **traceback);

extern PyObject* _PyErr_GetRaisedException(PyThreadState *tstate);
PyAPI_FUNC(PyObject*) _PyErr_GetRaisedException(PyThreadState *tstate);

PyAPI_FUNC(int) _PyErr_ExceptionMatches(
PyThreadState *tstate,
PyObject *exc);

extern void _PyErr_SetRaisedException(PyThreadState *tstate, PyObject *exc);
PyAPI_FUNC(void) _PyErr_SetRaisedException(PyThreadState *tstate, PyObject *exc);

extern void _PyErr_Restore(
PyThreadState *tstate,
Expand Down
132 changes: 61 additions & 71 deletions Modules/_interpretersmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
#include "Python.h"
#include "pycore_code.h" // _PyCode_HAS_EXECUTORS()
#include "pycore_crossinterp.h" // _PyXIData_t
#include "pycore_pyerrors.h" // _PyErr_GetRaisedException()
#include "pycore_function.h" // _PyFunction_VerifyStateless()
#include "pycore_interp.h" // _PyInterpreterState_IDIncref()
#include "pycore_modsupport.h" // _PyArg_BadArgument()
#include "pycore_namespace.h" // _PyNamespace_New()
Expand Down Expand Up @@ -374,34 +376,17 @@ check_code_str(PyUnicodeObject *text)
return NULL;
}

static const char *
check_code_object(PyCodeObject *code)
#ifndef NDEBUG
static int
code_has_args(PyCodeObject *code)
{
assert(code != NULL);
if (code->co_argcount > 0
return (code->co_argcount > 0
|| code->co_posonlyargcount > 0
|| code->co_kwonlyargcount > 0
|| code->co_flags & (CO_VARARGS | CO_VARKEYWORDS))
{
return "arguments not supported";
}
if (code->co_ncellvars > 0) {
return "closures not supported";
}
// We trust that no code objects under co_consts have unbound cell vars.

if (_PyCode_HAS_EXECUTORS(code) || _PyCode_HAS_INSTRUMENTATION(code)) {
return "only basic functions are supported";
}
if (code->_co_monitoring != NULL) {
return "only basic functions are supported";
}
if (code->co_extra != NULL) {
return "only basic functions are supported";
}

return NULL;
|| code->co_flags & (CO_VARARGS | CO_VARKEYWORDS));
}
#endif

#define RUN_TEXT 1
#define RUN_CODE 2
Expand Down Expand Up @@ -429,8 +414,10 @@ get_code_str(PyObject *arg, Py_ssize_t *len_p, PyObject **bytes_p, int *flags_p)
flags = RUN_TEXT;
}
else {
assert(PyCode_Check(arg)
&& (check_code_object((PyCodeObject *)arg) == NULL));
assert(PyCode_Check(arg));
assert(_PyCode_VerifyStateless(
PyThreadState_Get(), (PyCodeObject *)arg, NULL, NULL, NULL) == 0);
assert(!code_has_args((PyCodeObject *)arg));
flags = RUN_CODE;

// Serialize the code object.
Expand Down Expand Up @@ -949,7 +936,8 @@ Bind the given attributes in the interpreter's __main__ module.");


static PyUnicodeObject *
convert_script_arg(PyObject *arg, const char *fname, const char *displayname,
convert_script_arg(PyThreadState *tstate,
PyObject *arg, const char *fname, const char *displayname,
const char *expected)
{
PyUnicodeObject *str = NULL;
Expand All @@ -968,60 +956,50 @@ convert_script_arg(PyObject *arg, const char *fname, const char *displayname,
const char *err = check_code_str(str);
if (err != NULL) {
Py_DECREF(str);
PyErr_Format(PyExc_ValueError,
"%.200s(): bad script text (%s)", fname, err);
_PyErr_Format(tstate, PyExc_ValueError,
"%.200s(): bad script text (%s)", fname, err);
return NULL;
}

return str;
}

static PyCodeObject *
convert_code_arg(PyObject *arg, const char *fname, const char *displayname,
convert_code_arg(PyThreadState *tstate,
PyObject *arg, const char *fname, const char *displayname,
const char *expected)
{
const char *kind = NULL;
PyObject *cause;
PyCodeObject *code = NULL;
if (PyFunction_Check(arg)) {
if (PyFunction_GetClosure(arg) != NULL) {
PyErr_Format(PyExc_ValueError,
"%.200s(): closures not supported", fname);
return NULL;
if (_PyFunction_VerifyStateless(tstate, arg) < 0) {
goto chained;
}
code = (PyCodeObject *)PyFunction_GetCode(arg);
if (code == NULL) {
if (PyErr_Occurred()) {
// This chains.
PyErr_Format(PyExc_ValueError,
"%.200s(): bad func", fname);
}
else {
PyErr_Format(PyExc_ValueError,
"%.200s(): func.__code__ missing", fname);
}
return NULL;
}
Py_INCREF(code);
kind = "func";
}
else if (PyCode_Check(arg)) {
if (_PyCode_VerifyStateless(
tstate, (PyCodeObject *)arg, NULL, NULL, NULL) < 0) {
goto chained;
}
code = (PyCodeObject *)Py_NewRef(arg);
kind = "code object";
}
else {
_PyArg_BadArgument(fname, displayname, expected, arg);
return NULL;
}

const char *err = check_code_object(code);
if (err != NULL) {
Py_DECREF(code);
PyErr_Format(PyExc_ValueError,
"%.200s(): bad %s (%s)", fname, kind, err);
return NULL;
}

return code;

chained:
cause = _PyErr_GetRaisedException(tstate);
assert(cause != NULL);
_PyArg_BadArgument(fname, displayname, expected, arg);
PyObject *exc = _PyErr_GetRaisedException(tstate);
PyException_SetCause(exc, cause);
_PyErr_SetRaisedException(tstate, exc);
return NULL;
}

static int
Expand Down Expand Up @@ -1057,12 +1035,14 @@ _interp_exec(PyObject *self, PyInterpreterState *interp,
static PyObject *
interp_exec(PyObject *self, PyObject *args, PyObject *kwds)
{
#define FUNCNAME MODULE_NAME_STR ".exec"
PyThreadState *tstate = _PyThreadState_GET();
static char *kwlist[] = {"id", "code", "shared", "restrict", NULL};
PyObject *id, *code;
PyObject *shared = NULL;
int restricted = 0;
if (!PyArg_ParseTupleAndKeywords(args, kwds,
"OO|O$p:" MODULE_NAME_STR ".exec", kwlist,
"OO|O$p:" FUNCNAME, kwlist,
&id, &code, &shared, &restricted))
{
return NULL;
Expand All @@ -1077,12 +1057,12 @@ interp_exec(PyObject *self, PyObject *args, PyObject *kwds)

const char *expected = "a string, a function, or a code object";
if (PyUnicode_Check(code)) {
code = (PyObject *)convert_script_arg(code, MODULE_NAME_STR ".exec",
"argument 2", expected);
code = (PyObject *)convert_script_arg(tstate, code, FUNCNAME,
"argument 2", expected);
}
else {
code = (PyObject *)convert_code_arg(code, MODULE_NAME_STR ".exec",
"argument 2", expected);
code = (PyObject *)convert_code_arg(tstate, code, FUNCNAME,
"argument 2", expected);
}
if (code == NULL) {
return NULL;
Expand All @@ -1096,6 +1076,7 @@ interp_exec(PyObject *self, PyObject *args, PyObject *kwds)
return excinfo;
}
Py_RETURN_NONE;
#undef FUNCNAME
}

PyDoc_STRVAR(exec_doc,
Expand All @@ -1118,13 +1099,15 @@ is ignored, including its __globals__ dict.");
static PyObject *
interp_run_string(PyObject *self, PyObject *args, PyObject *kwds)
{
#define FUNCNAME MODULE_NAME_STR ".run_string"
PyThreadState *tstate = _PyThreadState_GET();
static char *kwlist[] = {"id", "script", "shared", "restrict", NULL};
PyObject *id, *script;
PyObject *shared = NULL;
int restricted = 0;
if (!PyArg_ParseTupleAndKeywords(args, kwds,
"OU|O$p:" MODULE_NAME_STR ".run_string",
kwlist, &id, &script, &shared, &restricted))
"OU|O$p:" FUNCNAME, kwlist,
&id, &script, &shared, &restricted))
{
return NULL;
}
Expand All @@ -1136,7 +1119,7 @@ interp_run_string(PyObject *self, PyObject *args, PyObject *kwds)
return NULL;
}

script = (PyObject *)convert_script_arg(script, MODULE_NAME_STR ".run_string",
script = (PyObject *)convert_script_arg(tstate, script, FUNCNAME,
"argument 2", "a string");
if (script == NULL) {
return NULL;
Expand All @@ -1150,6 +1133,7 @@ interp_run_string(PyObject *self, PyObject *args, PyObject *kwds)
return excinfo;
}
Py_RETURN_NONE;
#undef FUNCNAME
}

PyDoc_STRVAR(run_string_doc,
Expand All @@ -1162,13 +1146,15 @@ Execute the provided string in the identified interpreter.\n\
static PyObject *
interp_run_func(PyObject *self, PyObject *args, PyObject *kwds)
{
#define FUNCNAME MODULE_NAME_STR ".run_func"
PyThreadState *tstate = _PyThreadState_GET();
static char *kwlist[] = {"id", "func", "shared", "restrict", NULL};
PyObject *id, *func;
PyObject *shared = NULL;
int restricted = 0;
if (!PyArg_ParseTupleAndKeywords(args, kwds,
"OO|O$p:" MODULE_NAME_STR ".run_func",
kwlist, &id, &func, &shared, &restricted))
"OO|O$p:" FUNCNAME, kwlist,
&id, &func, &shared, &restricted))
{
return NULL;
}
Expand All @@ -1180,7 +1166,7 @@ interp_run_func(PyObject *self, PyObject *args, PyObject *kwds)
return NULL;
}

PyCodeObject *code = convert_code_arg(func, MODULE_NAME_STR ".exec",
PyCodeObject *code = convert_code_arg(tstate, func, FUNCNAME,
"argument 2",
"a function or a code object");
if (code == NULL) {
Expand All @@ -1195,6 +1181,7 @@ interp_run_func(PyObject *self, PyObject *args, PyObject *kwds)
return excinfo;
}
Py_RETURN_NONE;
#undef FUNCNAME
}

PyDoc_STRVAR(run_func_doc,
Expand All @@ -1209,14 +1196,16 @@ are not supported. Methods and other callables are not supported either.\n\
static PyObject *
interp_call(PyObject *self, PyObject *args, PyObject *kwds)
{
#define FUNCNAME MODULE_NAME_STR ".call"
PyThreadState *tstate = _PyThreadState_GET();
static char *kwlist[] = {"id", "callable", "args", "kwargs",
"restrict", NULL};
PyObject *id, *callable;
PyObject *args_obj = NULL;
PyObject *kwargs_obj = NULL;
int restricted = 0;
if (!PyArg_ParseTupleAndKeywords(args, kwds,
"OO|OO$p:" MODULE_NAME_STR ".call", kwlist,
"OO|OO$p:" FUNCNAME, kwlist,
&id, &callable, &args_obj, &kwargs_obj,
&restricted))
{
Expand All @@ -1231,15 +1220,15 @@ interp_call(PyObject *self, PyObject *args, PyObject *kwds)
}

if (args_obj != NULL) {
PyErr_SetString(PyExc_ValueError, "got unexpected args");
_PyErr_SetString(tstate, PyExc_ValueError, "got unexpected args");
return NULL;
}
if (kwargs_obj != NULL) {
PyErr_SetString(PyExc_ValueError, "got unexpected kwargs");
_PyErr_SetString(tstate, PyExc_ValueError, "got unexpected kwargs");
return NULL;
}

PyObject *code = (PyObject *)convert_code_arg(callable, MODULE_NAME_STR ".call",
PyObject *code = (PyObject *)convert_code_arg(tstate, callable, FUNCNAME,
"argument 2", "a function");
if (code == NULL) {
return NULL;
Expand All @@ -1253,6 +1242,7 @@ interp_call(PyObject *self, PyObject *args, PyObject *kwds)
return excinfo;
}
Py_RETURN_NONE;
#undef FUNCNAME
}

PyDoc_STRVAR(call_doc,
Expand Down
Loading