#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()
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
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.
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;
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;
}
}
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;
- }
- 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;
+ // For now we allow globals, so we can't use
+ // _PyFunction_VerifyStateless().
+ PyObject *codeobj = PyFunction_GetCode(arg);
+ if (_PyCode_VerifyStateless(
+ tstate, (PyCodeObject *)codeobj, NULL, NULL, NULL) < 0) {
+ goto chained;
}
- Py_INCREF(code);
- kind = "func";
+ code = (PyCodeObject *)Py_NewRef(codeobj);
}
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
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;
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;
return excinfo;
}
Py_RETURN_NONE;
+#undef FUNCNAME
}
PyDoc_STRVAR(exec_doc,
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;
}
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;
return excinfo;
}
Py_RETURN_NONE;
+#undef FUNCNAME
}
PyDoc_STRVAR(run_string_doc,
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;
}
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) {
return excinfo;
}
Py_RETURN_NONE;
+#undef FUNCNAME
}
PyDoc_STRVAR(run_func_doc,
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 *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))
{
}
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;
return excinfo;
}
Py_RETURN_NONE;
+#undef FUNCNAME
}
PyDoc_STRVAR(call_doc,