bpo-42990: Refactor _PyFrame_New_NoTrack() (GH-24566)

* Refactor _PyFrame_New_NoTrack() and PyFunction_NewWithQualName()
  code.
* PyFrame_New() checks for _PyEval_BuiltinsFromGlobals() failure.
* Fix a ref leak in _PyEval_BuiltinsFromGlobals() error path.
* Complete PyFunction_GetModule() documentation: it returns a
  borrowed reference and it can return NULL.
* Move _PyEval_BuiltinsFromGlobals() definition to the internal C
  API.
* PyFunction_NewWithQualName() uses _Py_IDENTIFIER() API for the
  "__name__" string to make it compatible with subinterpreters.
This commit is contained in:
Victor Stinner 2021-02-18 19:20:16 +01:00 committed by GitHub
parent cc96231f0a
commit 44085a3fc9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 117 additions and 115 deletions

View file

@ -2,83 +2,90 @@
/* Function object implementation */
#include "Python.h"
#include "pycore_object.h"
#include "frameobject.h"
#include "code.h"
#include "pycore_ceval.h" // _PyEval_BuiltinsFromGlobals()
#include "pycore_object.h" // _PyObject_GC_UNTRACK()
#include "structmember.h" // PyMemberDef
PyObject *
PyFunction_NewWithQualName(PyObject *code, PyObject *globals, PyObject *qualname)
{
PyFunctionObject *op;
PyObject *doc, *consts, *module;
static PyObject *__name__ = NULL;
assert(globals != NULL);
assert(PyDict_Check(globals));
Py_INCREF(globals);
if (__name__ == NULL) {
__name__ = PyUnicode_InternFromString("__name__");
if (__name__ == NULL)
return NULL;
PyCodeObject *code_obj = (PyCodeObject *)code;
Py_INCREF(code_obj);
PyObject *name = code_obj->co_name;
assert(name != NULL);
Py_INCREF(name);
if (!qualname) {
qualname = name;
}
Py_INCREF(qualname);
PyObject *consts = code_obj->co_consts;
assert(PyTuple_Check(consts));
PyObject *doc;
if (PyTuple_Size(consts) >= 1) {
doc = PyTuple_GetItem(consts, 0);
if (!PyUnicode_Check(doc)) {
doc = Py_None;
}
}
else {
doc = Py_None;
}
Py_INCREF(doc);
// __module__: Use globals['__name__'] if it exists, or NULL.
_Py_IDENTIFIER(__name__);
PyObject *module = _PyDict_GetItemIdWithError(globals, &PyId___name__);
PyObject *builtins = NULL;
if (module == NULL && PyErr_Occurred()) {
goto error;
}
Py_XINCREF(module);
builtins = _PyEval_BuiltinsFromGlobals(globals);
if (builtins == NULL) {
goto error;
}
/* __module__: If module name is in globals, use it.
Otherwise, use None. */
module = PyDict_GetItemWithError(globals, __name__);
if (module) {
Py_INCREF(module);
}
else if (PyErr_Occurred()) {
return NULL;
}
op = PyObject_GC_New(PyFunctionObject, &PyFunction_Type);
PyFunctionObject *op = PyObject_GC_New(PyFunctionObject, &PyFunction_Type);
if (op == NULL) {
Py_XDECREF(module);
return NULL;
goto error;
}
/* Note: No failures from this point on, since func_dealloc() does not
expect a partially-created object. */
op->func_weakreflist = NULL;
Py_INCREF(code);
op->func_code = code;
assert(globals != NULL);
Py_INCREF(globals);
op->func_globals = globals;
PyObject *builtins = _PyEval_BuiltinsFromGlobals(globals);
if (builtins == NULL) {
return NULL;
}
op->func_builtins = builtins;
op->func_name = ((PyCodeObject *)code)->co_name;
Py_INCREF(op->func_name);
op->func_defaults = NULL; /* No default arguments */
op->func_kwdefaults = NULL; /* No keyword only defaults */
op->func_name = name;
op->func_qualname = qualname;
op->func_code = (PyObject*)code_obj;
op->func_defaults = NULL; // No default positional arguments
op->func_kwdefaults = NULL; // No default keyword arguments
op->func_closure = NULL;
op->vectorcall = _PyFunction_Vectorcall;
op->func_module = module;
consts = ((PyCodeObject *)code)->co_consts;
if (PyTuple_Size(consts) >= 1) {
doc = PyTuple_GetItem(consts, 0);
if (!PyUnicode_Check(doc))
doc = Py_None;
}
else
doc = Py_None;
Py_INCREF(doc);
op->func_doc = doc;
op->func_dict = NULL;
op->func_weakreflist = NULL;
op->func_module = module;
op->func_annotations = NULL;
if (qualname)
op->func_qualname = qualname;
else
op->func_qualname = op->func_name;
Py_INCREF(op->func_qualname);
op->vectorcall = _PyFunction_Vectorcall;
_PyObject_GC_TRACK(op);
return (PyObject *)op;
error:
Py_DECREF(globals);
Py_DECREF(code_obj);
Py_DECREF(name);
Py_DECREF(qualname);
Py_DECREF(doc);
Py_XDECREF(module);
Py_XDECREF(builtins);
return NULL;
}
PyObject *