bpo-40679: Fix _PyEval_EvalCode() crash if qualname is NULL (GH-20615)

If name is NULL, name is now set to co->co_name.
If qualname is NULL, qualname is now set to name.

qualname must not be NULL: it is used to build error messages.

Cleanup also the code: declare variables where they are initialized.
Rename "name" local variables to "varname" to avoid overriding "name"
parameter.
This commit is contained in:
Victor Stinner 2020-06-04 15:19:02 +02:00 committed by GitHub
parent b022e5cffb
commit 232dda6cbc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 37 additions and 22 deletions

View File

@ -0,0 +1 @@
Fix a ``_PyEval_EvalCode()`` crash if *qualname* argument is NULL.

View File

@ -4107,14 +4107,22 @@ _PyEval_EvalCode(PyThreadState *tstate,
{ {
assert(is_tstate_valid(tstate)); assert(is_tstate_valid(tstate));
PyCodeObject* co = (PyCodeObject*)_co; PyCodeObject *co = (PyCodeObject*)_co;
PyFrameObject *f;
if (!name) {
name = co->co_name;
}
assert(name != NULL);
assert(PyUnicode_Check(name));
if (!qualname) {
qualname = name;
}
assert(qualname != NULL);
assert(PyUnicode_Check(qualname));
PyObject *retval = NULL; PyObject *retval = NULL;
PyObject **fastlocals, **freevars;
PyObject *x, *u;
const Py_ssize_t total_args = co->co_argcount + co->co_kwonlyargcount; const Py_ssize_t total_args = co->co_argcount + co->co_kwonlyargcount;
Py_ssize_t i, j, n;
PyObject *kwdict;
if (globals == NULL) { if (globals == NULL) {
_PyErr_SetString(tstate, PyExc_SystemError, _PyErr_SetString(tstate, PyExc_SystemError,
@ -4123,14 +4131,16 @@ _PyEval_EvalCode(PyThreadState *tstate,
} }
/* Create the frame */ /* Create the frame */
f = _PyFrame_New_NoTrack(tstate, co, globals, locals); PyFrameObject *f = _PyFrame_New_NoTrack(tstate, co, globals, locals);
if (f == NULL) { if (f == NULL) {
return NULL; return NULL;
} }
fastlocals = f->f_localsplus; PyObject **fastlocals = f->f_localsplus;
freevars = f->f_localsplus + co->co_nlocals; PyObject **freevars = f->f_localsplus + co->co_nlocals;
/* Create a dictionary for keyword parameters (**kwags) */ /* Create a dictionary for keyword parameters (**kwags) */
PyObject *kwdict;
Py_ssize_t i;
if (co->co_flags & CO_VARKEYWORDS) { if (co->co_flags & CO_VARKEYWORDS) {
kwdict = PyDict_New(); kwdict = PyDict_New();
if (kwdict == NULL) if (kwdict == NULL)
@ -4146,6 +4156,7 @@ _PyEval_EvalCode(PyThreadState *tstate,
} }
/* Copy all positional arguments into local variables */ /* Copy all positional arguments into local variables */
Py_ssize_t j, n;
if (argcount > co->co_argcount) { if (argcount > co->co_argcount) {
n = co->co_argcount; n = co->co_argcount;
} }
@ -4153,14 +4164,14 @@ _PyEval_EvalCode(PyThreadState *tstate,
n = argcount; n = argcount;
} }
for (j = 0; j < n; j++) { for (j = 0; j < n; j++) {
x = args[j]; PyObject *x = args[j];
Py_INCREF(x); Py_INCREF(x);
SETLOCAL(j, x); SETLOCAL(j, x);
} }
/* Pack other positional arguments into the *args argument */ /* Pack other positional arguments into the *args argument */
if (co->co_flags & CO_VARARGS) { if (co->co_flags & CO_VARARGS) {
u = _PyTuple_FromArray(args + n, argcount - n); PyObject *u = _PyTuple_FromArray(args + n, argcount - n);
if (u == NULL) { if (u == NULL) {
goto fail; goto fail;
} }
@ -4186,16 +4197,16 @@ _PyEval_EvalCode(PyThreadState *tstate,
normally interned this should almost always hit. */ normally interned this should almost always hit. */
co_varnames = ((PyTupleObject *)(co->co_varnames))->ob_item; co_varnames = ((PyTupleObject *)(co->co_varnames))->ob_item;
for (j = co->co_posonlyargcount; j < total_args; j++) { for (j = co->co_posonlyargcount; j < total_args; j++) {
PyObject *name = co_varnames[j]; PyObject *varname = co_varnames[j];
if (name == keyword) { if (varname == keyword) {
goto kw_found; goto kw_found;
} }
} }
/* Slow fallback, just in case */ /* Slow fallback, just in case */
for (j = co->co_posonlyargcount; j < total_args; j++) { for (j = co->co_posonlyargcount; j < total_args; j++) {
PyObject *name = co_varnames[j]; PyObject *varname = co_varnames[j];
int cmp = PyObject_RichCompareBool( keyword, name, Py_EQ); int cmp = PyObject_RichCompareBool( keyword, varname, Py_EQ);
if (cmp > 0) { if (cmp > 0) {
goto kw_found; goto kw_found;
} }
@ -4209,7 +4220,8 @@ _PyEval_EvalCode(PyThreadState *tstate,
if (co->co_posonlyargcount if (co->co_posonlyargcount
&& positional_only_passed_as_keyword(tstate, co, && positional_only_passed_as_keyword(tstate, co,
kwcount, kwnames, qualname)) kwcount, kwnames,
qualname))
{ {
goto fail; goto fail;
} }
@ -4238,7 +4250,8 @@ _PyEval_EvalCode(PyThreadState *tstate,
/* Check the number of positional arguments */ /* Check the number of positional arguments */
if ((argcount > co->co_argcount) && !(co->co_flags & CO_VARARGS)) { if ((argcount > co->co_argcount) && !(co->co_flags & CO_VARARGS)) {
too_many_positional(tstate, co, argcount, defcount, fastlocals, qualname); too_many_positional(tstate, co, argcount, defcount, fastlocals,
qualname);
goto fail; goto fail;
} }
@ -4252,7 +4265,8 @@ _PyEval_EvalCode(PyThreadState *tstate,
} }
} }
if (missing) { if (missing) {
missing_arguments(tstate, co, missing, defcount, fastlocals, qualname); missing_arguments(tstate, co, missing, defcount, fastlocals,
qualname);
goto fail; goto fail;
} }
if (n > m) if (n > m)
@ -4272,12 +4286,11 @@ _PyEval_EvalCode(PyThreadState *tstate,
if (co->co_kwonlyargcount > 0) { if (co->co_kwonlyargcount > 0) {
Py_ssize_t missing = 0; Py_ssize_t missing = 0;
for (i = co->co_argcount; i < total_args; i++) { for (i = co->co_argcount; i < total_args; i++) {
PyObject *name;
if (GETLOCAL(i) != NULL) if (GETLOCAL(i) != NULL)
continue; continue;
name = PyTuple_GET_ITEM(co->co_varnames, i); PyObject *varname = PyTuple_GET_ITEM(co->co_varnames, i);
if (kwdefs != NULL) { if (kwdefs != NULL) {
PyObject *def = PyDict_GetItemWithError(kwdefs, name); PyObject *def = PyDict_GetItemWithError(kwdefs, varname);
if (def) { if (def) {
Py_INCREF(def); Py_INCREF(def);
SETLOCAL(i, def); SETLOCAL(i, def);
@ -4290,7 +4303,8 @@ _PyEval_EvalCode(PyThreadState *tstate,
missing++; missing++;
} }
if (missing) { if (missing) {
missing_arguments(tstate, co, missing, -1, fastlocals, qualname); missing_arguments(tstate, co, missing, -1, fastlocals,
qualname);
goto fail; goto fail;
} }
} }