mirror of
https://github.com/python/cpython.git
synced 2025-08-31 05:58:33 +00:00
gh-132775: Add _PyCode_VerifyStateless() (gh-133221)
"Stateless" code is a function or code object which does not rely on external state or internal state. It may rely on arguments and builtins, but not globals or a closure. I've left a comment in pycore_code.h that provides more detail. We also add _PyFunction_VerifyStateless(). The new functions will be used in several later changes that facilitate "sharing" functions and code objects between interpreters.
This commit is contained in:
parent
f610bbdf74
commit
d270bb5792
8 changed files with 442 additions and 38 deletions
|
@ -1,12 +1,14 @@
|
|||
/* Function object implementation */
|
||||
|
||||
#include "Python.h"
|
||||
#include "pycore_code.h" // _PyCode_VerifyStateless()
|
||||
#include "pycore_dict.h" // _Py_INCREF_DICT()
|
||||
#include "pycore_function.h" // _PyFunction_Vectorcall
|
||||
#include "pycore_long.h" // _PyLong_GetOne()
|
||||
#include "pycore_modsupport.h" // _PyArg_NoKeywords()
|
||||
#include "pycore_object.h" // _PyObject_GC_UNTRACK()
|
||||
#include "pycore_pyerrors.h" // _PyErr_Occurred()
|
||||
#include "pycore_setobject.h" // _PySet_NextEntry()
|
||||
#include "pycore_stats.h"
|
||||
|
||||
|
||||
|
@ -1240,6 +1242,58 @@ PyTypeObject PyFunction_Type = {
|
|||
};
|
||||
|
||||
|
||||
int
|
||||
_PyFunction_VerifyStateless(PyThreadState *tstate, PyObject *func)
|
||||
{
|
||||
assert(!PyErr_Occurred());
|
||||
assert(PyFunction_Check(func));
|
||||
|
||||
// Check the globals.
|
||||
PyObject *globalsns = PyFunction_GET_GLOBALS(func);
|
||||
if (globalsns != NULL && !PyDict_Check(globalsns)) {
|
||||
_PyErr_Format(tstate, PyExc_TypeError,
|
||||
"unsupported globals %R", globalsns);
|
||||
return -1;
|
||||
}
|
||||
// Check the builtins.
|
||||
PyObject *builtinsns = PyFunction_GET_BUILTINS(func);
|
||||
if (builtinsns != NULL && !PyDict_Check(builtinsns)) {
|
||||
_PyErr_Format(tstate, PyExc_TypeError,
|
||||
"unsupported builtins %R", builtinsns);
|
||||
return -1;
|
||||
}
|
||||
// Disallow __defaults__.
|
||||
PyObject *defaults = PyFunction_GET_DEFAULTS(func);
|
||||
if (defaults != NULL && defaults != Py_None && PyDict_Size(defaults) > 0)
|
||||
{
|
||||
_PyErr_SetString(tstate, PyExc_ValueError, "defaults not supported");
|
||||
return -1;
|
||||
}
|
||||
// Disallow __kwdefaults__.
|
||||
PyObject *kwdefaults = PyFunction_GET_KW_DEFAULTS(func);
|
||||
if (kwdefaults != NULL && kwdefaults != Py_None
|
||||
&& PyDict_Size(kwdefaults) > 0)
|
||||
{
|
||||
_PyErr_SetString(tstate, PyExc_ValueError,
|
||||
"keyword defaults not supported");
|
||||
return -1;
|
||||
}
|
||||
// Disallow __closure__.
|
||||
PyObject *closure = PyFunction_GET_CLOSURE(func);
|
||||
if (closure != NULL && closure != Py_None && PyTuple_GET_SIZE(closure) > 0)
|
||||
{
|
||||
_PyErr_SetString(tstate, PyExc_ValueError, "closures not supported");
|
||||
return -1;
|
||||
}
|
||||
// Check the code.
|
||||
PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func);
|
||||
if (_PyCode_VerifyStateless(tstate, co, NULL, globalsns, builtinsns) < 0) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
functools_copy_attr(PyObject *wrapper, PyObject *wrapped, PyObject *name)
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue