Skip to content

Commit a66bae8

Browse files
gh-132775: Use _PyFunction_VerifyStateless() and _PyCode_VerifyStateless() (gh-134439)
1 parent fb68776 commit a66bae8

File tree

3 files changed

+70
-76
lines changed

3 files changed

+70
-76
lines changed

Include/internal/pycore_pyerrors.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,13 +94,13 @@ extern void _PyErr_Fetch(
9494
PyObject **value,
9595
PyObject **traceback);
9696

97-
extern PyObject* _PyErr_GetRaisedException(PyThreadState *tstate);
97+
PyAPI_FUNC(PyObject*) _PyErr_GetRaisedException(PyThreadState *tstate);
9898

9999
PyAPI_FUNC(int) _PyErr_ExceptionMatches(
100100
PyThreadState *tstate,
101101
PyObject *exc);
102102

103-
extern void _PyErr_SetRaisedException(PyThreadState *tstate, PyObject *exc);
103+
PyAPI_FUNC(void) _PyErr_SetRaisedException(PyThreadState *tstate, PyObject *exc);
104104

105105
extern void _PyErr_Restore(
106106
PyThreadState *tstate,

Lib/test/test__interpreters.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1054,7 +1054,7 @@ def test_closure(self):
10541054
def script():
10551055
assert spam
10561056

1057-
with self.assertRaises(ValueError):
1057+
with self.assertRaises(TypeError):
10581058
_interpreters.run_func(self.id, script)
10591059

10601060
# XXX This hasn't been fixed yet.
@@ -1065,6 +1065,7 @@ def script():
10651065
with self.assertRaises(ValueError):
10661066
_interpreters.run_func(self.id, script)
10671067

1068+
@unittest.skip("we're not quite there yet")
10681069
def test_args(self):
10691070
with self.subTest('args'):
10701071
def script(a, b=0):

Modules/_interpretersmodule.c

Lines changed: 66 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
#include "Python.h"
99
#include "pycore_code.h" // _PyCode_HAS_EXECUTORS()
1010
#include "pycore_crossinterp.h" // _PyXIData_t
11+
#include "pycore_pyerrors.h" // _PyErr_GetRaisedException()
12+
#include "pycore_function.h" // _PyFunction_VerifyStateless()
1113
#include "pycore_interp.h" // _PyInterpreterState_IDIncref()
1214
#include "pycore_modsupport.h" // _PyArg_BadArgument()
1315
#include "pycore_namespace.h" // _PyNamespace_New()
@@ -374,34 +376,17 @@ check_code_str(PyUnicodeObject *text)
374376
return NULL;
375377
}
376378

377-
static const char *
378-
check_code_object(PyCodeObject *code)
379+
#ifndef NDEBUG
380+
static int
381+
code_has_args(PyCodeObject *code)
379382
{
380383
assert(code != NULL);
381-
if (code->co_argcount > 0
384+
return (code->co_argcount > 0
382385
|| code->co_posonlyargcount > 0
383386
|| code->co_kwonlyargcount > 0
384-
|| code->co_flags & (CO_VARARGS | CO_VARKEYWORDS))
385-
{
386-
return "arguments not supported";
387-
}
388-
if (code->co_ncellvars > 0) {
389-
return "closures not supported";
390-
}
391-
// We trust that no code objects under co_consts have unbound cell vars.
392-
393-
if (_PyCode_HAS_EXECUTORS(code) || _PyCode_HAS_INSTRUMENTATION(code)) {
394-
return "only basic functions are supported";
395-
}
396-
if (code->_co_monitoring != NULL) {
397-
return "only basic functions are supported";
398-
}
399-
if (code->co_extra != NULL) {
400-
return "only basic functions are supported";
401-
}
402-
403-
return NULL;
387+
|| code->co_flags & (CO_VARARGS | CO_VARKEYWORDS));
404388
}
389+
#endif
405390

406391
#define RUN_TEXT 1
407392
#define RUN_CODE 2
@@ -429,8 +414,10 @@ get_code_str(PyObject *arg, Py_ssize_t *len_p, PyObject **bytes_p, int *flags_p)
429414
flags = RUN_TEXT;
430415
}
431416
else {
432-
assert(PyCode_Check(arg)
433-
&& (check_code_object((PyCodeObject *)arg) == NULL));
417+
assert(PyCode_Check(arg));
418+
assert(_PyCode_VerifyStateless(
419+
PyThreadState_Get(), (PyCodeObject *)arg, NULL, NULL, NULL) == 0);
420+
assert(!code_has_args((PyCodeObject *)arg));
434421
flags = RUN_CODE;
435422

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

950937

951938
static PyUnicodeObject *
952-
convert_script_arg(PyObject *arg, const char *fname, const char *displayname,
939+
convert_script_arg(PyThreadState *tstate,
940+
PyObject *arg, const char *fname, const char *displayname,
953941
const char *expected)
954942
{
955943
PyUnicodeObject *str = NULL;
@@ -968,60 +956,53 @@ convert_script_arg(PyObject *arg, const char *fname, const char *displayname,
968956
const char *err = check_code_str(str);
969957
if (err != NULL) {
970958
Py_DECREF(str);
971-
PyErr_Format(PyExc_ValueError,
972-
"%.200s(): bad script text (%s)", fname, err);
959+
_PyErr_Format(tstate, PyExc_ValueError,
960+
"%.200s(): bad script text (%s)", fname, err);
973961
return NULL;
974962
}
975963

976964
return str;
977965
}
978966

979967
static PyCodeObject *
980-
convert_code_arg(PyObject *arg, const char *fname, const char *displayname,
968+
convert_code_arg(PyThreadState *tstate,
969+
PyObject *arg, const char *fname, const char *displayname,
981970
const char *expected)
982971
{
983-
const char *kind = NULL;
972+
PyObject *cause;
984973
PyCodeObject *code = NULL;
985974
if (PyFunction_Check(arg)) {
986-
if (PyFunction_GetClosure(arg) != NULL) {
987-
PyErr_Format(PyExc_ValueError,
988-
"%.200s(): closures not supported", fname);
989-
return NULL;
990-
}
991-
code = (PyCodeObject *)PyFunction_GetCode(arg);
992-
if (code == NULL) {
993-
if (PyErr_Occurred()) {
994-
// This chains.
995-
PyErr_Format(PyExc_ValueError,
996-
"%.200s(): bad func", fname);
997-
}
998-
else {
999-
PyErr_Format(PyExc_ValueError,
1000-
"%.200s(): func.__code__ missing", fname);
1001-
}
1002-
return NULL;
975+
// For now we allow globals, so we can't use
976+
// _PyFunction_VerifyStateless().
977+
PyObject *codeobj = PyFunction_GetCode(arg);
978+
if (_PyCode_VerifyStateless(
979+
tstate, (PyCodeObject *)codeobj, NULL, NULL, NULL) < 0) {
980+
goto chained;
1003981
}
1004-
Py_INCREF(code);
1005-
kind = "func";
982+
code = (PyCodeObject *)Py_NewRef(codeobj);
1006983
}
1007984
else if (PyCode_Check(arg)) {
985+
if (_PyCode_VerifyStateless(
986+
tstate, (PyCodeObject *)arg, NULL, NULL, NULL) < 0) {
987+
goto chained;
988+
}
1008989
code = (PyCodeObject *)Py_NewRef(arg);
1009-
kind = "code object";
1010990
}
1011991
else {
1012992
_PyArg_BadArgument(fname, displayname, expected, arg);
1013993
return NULL;
1014994
}
1015995

1016-
const char *err = check_code_object(code);
1017-
if (err != NULL) {
1018-
Py_DECREF(code);
1019-
PyErr_Format(PyExc_ValueError,
1020-
"%.200s(): bad %s (%s)", fname, kind, err);
1021-
return NULL;
1022-
}
1023-
1024996
return code;
997+
998+
chained:
999+
cause = _PyErr_GetRaisedException(tstate);
1000+
assert(cause != NULL);
1001+
_PyArg_BadArgument(fname, displayname, expected, arg);
1002+
PyObject *exc = _PyErr_GetRaisedException(tstate);
1003+
PyException_SetCause(exc, cause);
1004+
_PyErr_SetRaisedException(tstate, exc);
1005+
return NULL;
10251006
}
10261007

10271008
static int
@@ -1057,12 +1038,14 @@ _interp_exec(PyObject *self, PyInterpreterState *interp,
10571038
static PyObject *
10581039
interp_exec(PyObject *self, PyObject *args, PyObject *kwds)
10591040
{
1041+
#define FUNCNAME MODULE_NAME_STR ".exec"
1042+
PyThreadState *tstate = _PyThreadState_GET();
10601043
static char *kwlist[] = {"id", "code", "shared", "restrict", NULL};
10611044
PyObject *id, *code;
10621045
PyObject *shared = NULL;
10631046
int restricted = 0;
10641047
if (!PyArg_ParseTupleAndKeywords(args, kwds,
1065-
"OO|O$p:" MODULE_NAME_STR ".exec", kwlist,
1048+
"OO|O$p:" FUNCNAME, kwlist,
10661049
&id, &code, &shared, &restricted))
10671050
{
10681051
return NULL;
@@ -1077,12 +1060,12 @@ interp_exec(PyObject *self, PyObject *args, PyObject *kwds)
10771060

10781061
const char *expected = "a string, a function, or a code object";
10791062
if (PyUnicode_Check(code)) {
1080-
code = (PyObject *)convert_script_arg(code, MODULE_NAME_STR ".exec",
1081-
"argument 2", expected);
1063+
code = (PyObject *)convert_script_arg(tstate, code, FUNCNAME,
1064+
"argument 2", expected);
10821065
}
10831066
else {
1084-
code = (PyObject *)convert_code_arg(code, MODULE_NAME_STR ".exec",
1085-
"argument 2", expected);
1067+
code = (PyObject *)convert_code_arg(tstate, code, FUNCNAME,
1068+
"argument 2", expected);
10861069
}
10871070
if (code == NULL) {
10881071
return NULL;
@@ -1096,6 +1079,7 @@ interp_exec(PyObject *self, PyObject *args, PyObject *kwds)
10961079
return excinfo;
10971080
}
10981081
Py_RETURN_NONE;
1082+
#undef FUNCNAME
10991083
}
11001084

11011085
PyDoc_STRVAR(exec_doc,
@@ -1118,13 +1102,15 @@ is ignored, including its __globals__ dict.");
11181102
static PyObject *
11191103
interp_run_string(PyObject *self, PyObject *args, PyObject *kwds)
11201104
{
1105+
#define FUNCNAME MODULE_NAME_STR ".run_string"
1106+
PyThreadState *tstate = _PyThreadState_GET();
11211107
static char *kwlist[] = {"id", "script", "shared", "restrict", NULL};
11221108
PyObject *id, *script;
11231109
PyObject *shared = NULL;
11241110
int restricted = 0;
11251111
if (!PyArg_ParseTupleAndKeywords(args, kwds,
1126-
"OU|O$p:" MODULE_NAME_STR ".run_string",
1127-
kwlist, &id, &script, &shared, &restricted))
1112+
"OU|O$p:" FUNCNAME, kwlist,
1113+
&id, &script, &shared, &restricted))
11281114
{
11291115
return NULL;
11301116
}
@@ -1136,7 +1122,7 @@ interp_run_string(PyObject *self, PyObject *args, PyObject *kwds)
11361122
return NULL;
11371123
}
11381124

1139-
script = (PyObject *)convert_script_arg(script, MODULE_NAME_STR ".run_string",
1125+
script = (PyObject *)convert_script_arg(tstate, script, FUNCNAME,
11401126
"argument 2", "a string");
11411127
if (script == NULL) {
11421128
return NULL;
@@ -1150,6 +1136,7 @@ interp_run_string(PyObject *self, PyObject *args, PyObject *kwds)
11501136
return excinfo;
11511137
}
11521138
Py_RETURN_NONE;
1139+
#undef FUNCNAME
11531140
}
11541141

11551142
PyDoc_STRVAR(run_string_doc,
@@ -1162,13 +1149,15 @@ Execute the provided string in the identified interpreter.\n\
11621149
static PyObject *
11631150
interp_run_func(PyObject *self, PyObject *args, PyObject *kwds)
11641151
{
1152+
#define FUNCNAME MODULE_NAME_STR ".run_func"
1153+
PyThreadState *tstate = _PyThreadState_GET();
11651154
static char *kwlist[] = {"id", "func", "shared", "restrict", NULL};
11661155
PyObject *id, *func;
11671156
PyObject *shared = NULL;
11681157
int restricted = 0;
11691158
if (!PyArg_ParseTupleAndKeywords(args, kwds,
1170-
"OO|O$p:" MODULE_NAME_STR ".run_func",
1171-
kwlist, &id, &func, &shared, &restricted))
1159+
"OO|O$p:" FUNCNAME, kwlist,
1160+
&id, &func, &shared, &restricted))
11721161
{
11731162
return NULL;
11741163
}
@@ -1180,7 +1169,7 @@ interp_run_func(PyObject *self, PyObject *args, PyObject *kwds)
11801169
return NULL;
11811170
}
11821171

1183-
PyCodeObject *code = convert_code_arg(func, MODULE_NAME_STR ".exec",
1172+
PyCodeObject *code = convert_code_arg(tstate, func, FUNCNAME,
11841173
"argument 2",
11851174
"a function or a code object");
11861175
if (code == NULL) {
@@ -1195,6 +1184,7 @@ interp_run_func(PyObject *self, PyObject *args, PyObject *kwds)
11951184
return excinfo;
11961185
}
11971186
Py_RETURN_NONE;
1187+
#undef FUNCNAME
11981188
}
11991189

12001190
PyDoc_STRVAR(run_func_doc,
@@ -1209,14 +1199,16 @@ are not supported. Methods and other callables are not supported either.\n\
12091199
static PyObject *
12101200
interp_call(PyObject *self, PyObject *args, PyObject *kwds)
12111201
{
1202+
#define FUNCNAME MODULE_NAME_STR ".call"
1203+
PyThreadState *tstate = _PyThreadState_GET();
12121204
static char *kwlist[] = {"id", "callable", "args", "kwargs",
12131205
"restrict", NULL};
12141206
PyObject *id, *callable;
12151207
PyObject *args_obj = NULL;
12161208
PyObject *kwargs_obj = NULL;
12171209
int restricted = 0;
12181210
if (!PyArg_ParseTupleAndKeywords(args, kwds,
1219-
"OO|OO$p:" MODULE_NAME_STR ".call", kwlist,
1211+
"OO|OO$p:" FUNCNAME, kwlist,
12201212
&id, &callable, &args_obj, &kwargs_obj,
12211213
&restricted))
12221214
{
@@ -1231,15 +1223,15 @@ interp_call(PyObject *self, PyObject *args, PyObject *kwds)
12311223
}
12321224

12331225
if (args_obj != NULL) {
1234-
PyErr_SetString(PyExc_ValueError, "got unexpected args");
1226+
_PyErr_SetString(tstate, PyExc_ValueError, "got unexpected args");
12351227
return NULL;
12361228
}
12371229
if (kwargs_obj != NULL) {
1238-
PyErr_SetString(PyExc_ValueError, "got unexpected kwargs");
1230+
_PyErr_SetString(tstate, PyExc_ValueError, "got unexpected kwargs");
12391231
return NULL;
12401232
}
12411233

1242-
PyObject *code = (PyObject *)convert_code_arg(callable, MODULE_NAME_STR ".call",
1234+
PyObject *code = (PyObject *)convert_code_arg(tstate, callable, FUNCNAME,
12431235
"argument 2", "a function");
12441236
if (code == NULL) {
12451237
return NULL;
@@ -1253,6 +1245,7 @@ interp_call(PyObject *self, PyObject *args, PyObject *kwds)
12531245
return excinfo;
12541246
}
12551247
Py_RETURN_NONE;
1248+
#undef FUNCNAME
12561249
}
12571250

12581251
PyDoc_STRVAR(call_doc,

0 commit comments

Comments
 (0)