gh-132775: Use _PyFunction_VerifyStateless() and _PyCode_VerifyStateless() (gh-134439)

This commit is contained in:
Eric Snow 2025-05-21 14:16:55 -06:00 committed by GitHub
parent fb68776591
commit a66bae8bb5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 70 additions and 76 deletions

View file

@ -94,13 +94,13 @@ extern void _PyErr_Fetch(
PyObject **value, PyObject **value,
PyObject **traceback); PyObject **traceback);
extern PyObject* _PyErr_GetRaisedException(PyThreadState *tstate); PyAPI_FUNC(PyObject*) _PyErr_GetRaisedException(PyThreadState *tstate);
PyAPI_FUNC(int) _PyErr_ExceptionMatches( PyAPI_FUNC(int) _PyErr_ExceptionMatches(
PyThreadState *tstate, PyThreadState *tstate,
PyObject *exc); PyObject *exc);
extern void _PyErr_SetRaisedException(PyThreadState *tstate, PyObject *exc); PyAPI_FUNC(void) _PyErr_SetRaisedException(PyThreadState *tstate, PyObject *exc);
extern void _PyErr_Restore( extern void _PyErr_Restore(
PyThreadState *tstate, PyThreadState *tstate,

View file

@ -1054,7 +1054,7 @@ class RunFuncTests(TestBase):
def script(): def script():
assert spam assert spam
with self.assertRaises(ValueError): with self.assertRaises(TypeError):
_interpreters.run_func(self.id, script) _interpreters.run_func(self.id, script)
# XXX This hasn't been fixed yet. # XXX This hasn't been fixed yet.
@ -1065,6 +1065,7 @@ class RunFuncTests(TestBase):
with self.assertRaises(ValueError): with self.assertRaises(ValueError):
_interpreters.run_func(self.id, script) _interpreters.run_func(self.id, script)
@unittest.skip("we're not quite there yet")
def test_args(self): def test_args(self):
with self.subTest('args'): with self.subTest('args'):
def script(a, b=0): def script(a, b=0):

View file

@ -8,6 +8,8 @@
#include "Python.h" #include "Python.h"
#include "pycore_code.h" // _PyCode_HAS_EXECUTORS() #include "pycore_code.h" // _PyCode_HAS_EXECUTORS()
#include "pycore_crossinterp.h" // _PyXIData_t #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_interp.h" // _PyInterpreterState_IDIncref()
#include "pycore_modsupport.h" // _PyArg_BadArgument() #include "pycore_modsupport.h" // _PyArg_BadArgument()
#include "pycore_namespace.h" // _PyNamespace_New() #include "pycore_namespace.h" // _PyNamespace_New()
@ -374,34 +376,17 @@ check_code_str(PyUnicodeObject *text)
return NULL; return NULL;
} }
static const char * #ifndef NDEBUG
check_code_object(PyCodeObject *code) static int
code_has_args(PyCodeObject *code)
{ {
assert(code != NULL); assert(code != NULL);
if (code->co_argcount > 0 return (code->co_argcount > 0
|| code->co_posonlyargcount > 0 || code->co_posonlyargcount > 0
|| code->co_kwonlyargcount > 0 || code->co_kwonlyargcount > 0
|| code->co_flags & (CO_VARARGS | CO_VARKEYWORDS)) || 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;
} }
#endif
#define RUN_TEXT 1 #define RUN_TEXT 1
#define RUN_CODE 2 #define RUN_CODE 2
@ -429,8 +414,10 @@ get_code_str(PyObject *arg, Py_ssize_t *len_p, PyObject **bytes_p, int *flags_p)
flags = RUN_TEXT; flags = RUN_TEXT;
} }
else { else {
assert(PyCode_Check(arg) assert(PyCode_Check(arg));
&& (check_code_object((PyCodeObject *)arg) == NULL)); assert(_PyCode_VerifyStateless(
PyThreadState_Get(), (PyCodeObject *)arg, NULL, NULL, NULL) == 0);
assert(!code_has_args((PyCodeObject *)arg));
flags = RUN_CODE; flags = RUN_CODE;
// Serialize the code object. // Serialize the code object.
@ -949,7 +936,8 @@ Bind the given attributes in the interpreter's __main__ module.");
static PyUnicodeObject * 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) const char *expected)
{ {
PyUnicodeObject *str = NULL; PyUnicodeObject *str = NULL;
@ -968,8 +956,8 @@ convert_script_arg(PyObject *arg, const char *fname, const char *displayname,
const char *err = check_code_str(str); const char *err = check_code_str(str);
if (err != NULL) { if (err != NULL) {
Py_DECREF(str); Py_DECREF(str);
PyErr_Format(PyExc_ValueError, _PyErr_Format(tstate, PyExc_ValueError,
"%.200s(): bad script text (%s)", fname, err); "%.200s(): bad script text (%s)", fname, err);
return NULL; return NULL;
} }
@ -977,51 +965,44 @@ convert_script_arg(PyObject *arg, const char *fname, const char *displayname,
} }
static PyCodeObject * 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 *expected)
{ {
const char *kind = NULL; PyObject *cause;
PyCodeObject *code = NULL; PyCodeObject *code = NULL;
if (PyFunction_Check(arg)) { if (PyFunction_Check(arg)) {
if (PyFunction_GetClosure(arg) != NULL) { // For now we allow globals, so we can't use
PyErr_Format(PyExc_ValueError, // _PyFunction_VerifyStateless().
"%.200s(): closures not supported", fname); PyObject *codeobj = PyFunction_GetCode(arg);
return NULL; if (_PyCode_VerifyStateless(
tstate, (PyCodeObject *)codeobj, NULL, NULL, NULL) < 0) {
goto chained;
} }
code = (PyCodeObject *)PyFunction_GetCode(arg); code = (PyCodeObject *)Py_NewRef(codeobj);
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)) { else if (PyCode_Check(arg)) {
if (_PyCode_VerifyStateless(
tstate, (PyCodeObject *)arg, NULL, NULL, NULL) < 0) {
goto chained;
}
code = (PyCodeObject *)Py_NewRef(arg); code = (PyCodeObject *)Py_NewRef(arg);
kind = "code object";
} }
else { else {
_PyArg_BadArgument(fname, displayname, expected, arg); _PyArg_BadArgument(fname, displayname, expected, arg);
return NULL; 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; 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 static int
@ -1057,12 +1038,14 @@ _interp_exec(PyObject *self, PyInterpreterState *interp,
static PyObject * static PyObject *
interp_exec(PyObject *self, PyObject *args, PyObject *kwds) 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}; static char *kwlist[] = {"id", "code", "shared", "restrict", NULL};
PyObject *id, *code; PyObject *id, *code;
PyObject *shared = NULL; PyObject *shared = NULL;
int restricted = 0; int restricted = 0;
if (!PyArg_ParseTupleAndKeywords(args, kwds, if (!PyArg_ParseTupleAndKeywords(args, kwds,
"OO|O$p:" MODULE_NAME_STR ".exec", kwlist, "OO|O$p:" FUNCNAME, kwlist,
&id, &code, &shared, &restricted)) &id, &code, &shared, &restricted))
{ {
return NULL; return NULL;
@ -1077,12 +1060,12 @@ interp_exec(PyObject *self, PyObject *args, PyObject *kwds)
const char *expected = "a string, a function, or a code object"; const char *expected = "a string, a function, or a code object";
if (PyUnicode_Check(code)) { if (PyUnicode_Check(code)) {
code = (PyObject *)convert_script_arg(code, MODULE_NAME_STR ".exec", code = (PyObject *)convert_script_arg(tstate, code, FUNCNAME,
"argument 2", expected); "argument 2", expected);
} }
else { else {
code = (PyObject *)convert_code_arg(code, MODULE_NAME_STR ".exec", code = (PyObject *)convert_code_arg(tstate, code, FUNCNAME,
"argument 2", expected); "argument 2", expected);
} }
if (code == NULL) { if (code == NULL) {
return NULL; return NULL;
@ -1096,6 +1079,7 @@ interp_exec(PyObject *self, PyObject *args, PyObject *kwds)
return excinfo; return excinfo;
} }
Py_RETURN_NONE; Py_RETURN_NONE;
#undef FUNCNAME
} }
PyDoc_STRVAR(exec_doc, PyDoc_STRVAR(exec_doc,
@ -1118,13 +1102,15 @@ is ignored, including its __globals__ dict.");
static PyObject * static PyObject *
interp_run_string(PyObject *self, PyObject *args, PyObject *kwds) 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}; static char *kwlist[] = {"id", "script", "shared", "restrict", NULL};
PyObject *id, *script; PyObject *id, *script;
PyObject *shared = NULL; PyObject *shared = NULL;
int restricted = 0; int restricted = 0;
if (!PyArg_ParseTupleAndKeywords(args, kwds, if (!PyArg_ParseTupleAndKeywords(args, kwds,
"OU|O$p:" MODULE_NAME_STR ".run_string", "OU|O$p:" FUNCNAME, kwlist,
kwlist, &id, &script, &shared, &restricted)) &id, &script, &shared, &restricted))
{ {
return NULL; return NULL;
} }
@ -1136,7 +1122,7 @@ interp_run_string(PyObject *self, PyObject *args, PyObject *kwds)
return NULL; 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"); "argument 2", "a string");
if (script == NULL) { if (script == NULL) {
return NULL; return NULL;
@ -1150,6 +1136,7 @@ interp_run_string(PyObject *self, PyObject *args, PyObject *kwds)
return excinfo; return excinfo;
} }
Py_RETURN_NONE; Py_RETURN_NONE;
#undef FUNCNAME
} }
PyDoc_STRVAR(run_string_doc, PyDoc_STRVAR(run_string_doc,
@ -1162,13 +1149,15 @@ Execute the provided string in the identified interpreter.\n\
static PyObject * static PyObject *
interp_run_func(PyObject *self, PyObject *args, PyObject *kwds) 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}; static char *kwlist[] = {"id", "func", "shared", "restrict", NULL};
PyObject *id, *func; PyObject *id, *func;
PyObject *shared = NULL; PyObject *shared = NULL;
int restricted = 0; int restricted = 0;
if (!PyArg_ParseTupleAndKeywords(args, kwds, if (!PyArg_ParseTupleAndKeywords(args, kwds,
"OO|O$p:" MODULE_NAME_STR ".run_func", "OO|O$p:" FUNCNAME, kwlist,
kwlist, &id, &func, &shared, &restricted)) &id, &func, &shared, &restricted))
{ {
return NULL; return NULL;
} }
@ -1180,7 +1169,7 @@ interp_run_func(PyObject *self, PyObject *args, PyObject *kwds)
return NULL; return NULL;
} }
PyCodeObject *code = convert_code_arg(func, MODULE_NAME_STR ".exec", PyCodeObject *code = convert_code_arg(tstate, func, FUNCNAME,
"argument 2", "argument 2",
"a function or a code object"); "a function or a code object");
if (code == NULL) { if (code == NULL) {
@ -1195,6 +1184,7 @@ interp_run_func(PyObject *self, PyObject *args, PyObject *kwds)
return excinfo; return excinfo;
} }
Py_RETURN_NONE; Py_RETURN_NONE;
#undef FUNCNAME
} }
PyDoc_STRVAR(run_func_doc, PyDoc_STRVAR(run_func_doc,
@ -1209,6 +1199,8 @@ are not supported. Methods and other callables are not supported either.\n\
static PyObject * static PyObject *
interp_call(PyObject *self, PyObject *args, PyObject *kwds) 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", static char *kwlist[] = {"id", "callable", "args", "kwargs",
"restrict", NULL}; "restrict", NULL};
PyObject *id, *callable; PyObject *id, *callable;
@ -1216,7 +1208,7 @@ interp_call(PyObject *self, PyObject *args, PyObject *kwds)
PyObject *kwargs_obj = NULL; PyObject *kwargs_obj = NULL;
int restricted = 0; int restricted = 0;
if (!PyArg_ParseTupleAndKeywords(args, kwds, if (!PyArg_ParseTupleAndKeywords(args, kwds,
"OO|OO$p:" MODULE_NAME_STR ".call", kwlist, "OO|OO$p:" FUNCNAME, kwlist,
&id, &callable, &args_obj, &kwargs_obj, &id, &callable, &args_obj, &kwargs_obj,
&restricted)) &restricted))
{ {
@ -1231,15 +1223,15 @@ interp_call(PyObject *self, PyObject *args, PyObject *kwds)
} }
if (args_obj != NULL) { if (args_obj != NULL) {
PyErr_SetString(PyExc_ValueError, "got unexpected args"); _PyErr_SetString(tstate, PyExc_ValueError, "got unexpected args");
return NULL; return NULL;
} }
if (kwargs_obj != NULL) { if (kwargs_obj != NULL) {
PyErr_SetString(PyExc_ValueError, "got unexpected kwargs"); _PyErr_SetString(tstate, PyExc_ValueError, "got unexpected kwargs");
return NULL; 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"); "argument 2", "a function");
if (code == NULL) { if (code == NULL) {
return NULL; return NULL;
@ -1253,6 +1245,7 @@ interp_call(PyObject *self, PyObject *args, PyObject *kwds)
return excinfo; return excinfo;
} }
Py_RETURN_NONE; Py_RETURN_NONE;
#undef FUNCNAME
} }
PyDoc_STRVAR(call_doc, PyDoc_STRVAR(call_doc,