bpo-38631: Replace compiler fatal errors with exceptions (GH-24369)

* Replace Py_FatalError() calls with regular SystemError exceptions.
* compiler_exit_scope() calls _PyErr_WriteUnraisableMsg() to log the
  PySequence_DelItem() failure.
* compiler_unit_check() uses _PyMem_IsPtrFreed().
* compiler_make_closure(): remove "(reftype == FREE)" comment since
  reftype can also be LOCAL or GLOBAL_EXPLICIT.
This commit is contained in:
Victor Stinner 2021-01-30 01:46:44 +01:00 committed by GitHub
parent 7fdab8331b
commit ba7a99ddb5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 54 additions and 34 deletions

View file

@ -22,6 +22,7 @@
*/
#include "Python.h"
#include "pycore_pymem.h" // _PyMem_IsPtrFreed()
#include "pycore_long.h" // _PyLong_GetZero()
#include "Python-ast.h"
@ -520,9 +521,7 @@ compiler_unit_check(struct compiler_unit *u)
{
basicblock *block;
for (block = u->u_blocks; block != NULL; block = block->b_list) {
assert((uintptr_t)block != 0xcbcbcbcbU);
assert((uintptr_t)block != 0xfbfbfbfbU);
assert((uintptr_t)block != 0xdbdbdbdbU);
assert(!_PyMem_IsPtrFreed(block));
if (block->b_instr != NULL) {
assert(block->b_ialloc > 0);
assert(block->b_iused >= 0);
@ -681,7 +680,8 @@ compiler_exit_scope(struct compiler *c)
assert(c->u);
/* we are deleting from a list so this really shouldn't fail */
if (PySequence_DelItem(c->c_stack, n) < 0) {
Py_FatalError("PySequence_DelItem failed");
_PyErr_WriteUnraisableMsg("on removing the last compiler "
"stack item", NULL);
}
compiler_unit_check(c->u);
}
@ -1898,17 +1898,15 @@ get_ref_type(struct compiler *c, PyObject *name)
return CELL;
scope = PyST_GetScope(c->u->u_ste, name);
if (scope == 0) {
_Py_FatalErrorFormat(__func__,
"unknown scope for %.100s in %.100s(%s)\n"
"symbols: %s\nlocals: %s\nglobals: %s",
PyUnicode_AsUTF8(name),
PyUnicode_AsUTF8(c->u->u_name),
PyUnicode_AsUTF8(PyObject_Repr(c->u->u_ste->ste_id)),
PyUnicode_AsUTF8(PyObject_Repr(c->u->u_ste->ste_symbols)),
PyUnicode_AsUTF8(PyObject_Repr(c->u->u_varnames)),
PyUnicode_AsUTF8(PyObject_Repr(c->u->u_names)));
PyErr_Format(PyExc_SystemError,
"PyST_GetScope(name=%R) failed: "
"unknown scope in unit %S (%R); "
"symbols: %R; locals: %R; globals: %R",
name,
c->u->u_name, c->u->u_ste->ste_id,
c->u->u_ste->ste_symbols, c->u->u_varnames, c->u->u_names);
return -1;
}
return scope;
}
@ -1923,7 +1921,8 @@ compiler_lookup_arg(PyObject *dict, PyObject *name)
}
static int
compiler_make_closure(struct compiler *c, PyCodeObject *co, Py_ssize_t flags, PyObject *qualname)
compiler_make_closure(struct compiler *c, PyCodeObject *co, Py_ssize_t flags,
PyObject *qualname)
{
Py_ssize_t i, free = PyCode_GetNumFree(co);
if (qualname == NULL)
@ -1935,7 +1934,6 @@ compiler_make_closure(struct compiler *c, PyCodeObject *co, Py_ssize_t flags, Py
LOAD_DEREF but LOAD_CLOSURE is needed.
*/
PyObject *name = PyTuple_GET_ITEM(co->co_freevars, i);
int arg, reftype;
/* Special case: If a class contains a method with a
free variable that has the same name as a method,
@ -1943,20 +1941,27 @@ compiler_make_closure(struct compiler *c, PyCodeObject *co, Py_ssize_t flags, Py
class. It should be handled by the closure, as
well as by the normal name lookup logic.
*/
reftype = get_ref_type(c, name);
if (reftype == CELL)
int reftype = get_ref_type(c, name);
if (reftype == -1) {
return 0;
}
int arg;
if (reftype == CELL) {
arg = compiler_lookup_arg(c->u->u_cellvars, name);
else /* (reftype == FREE) */
}
else {
arg = compiler_lookup_arg(c->u->u_freevars, name);
}
if (arg == -1) {
_Py_FatalErrorFormat(__func__,
"lookup %s in %s %d %d\n"
"freevars of %s: %s\n",
PyUnicode_AsUTF8(PyObject_Repr(name)),
PyUnicode_AsUTF8(c->u->u_name),
reftype, arg,
PyUnicode_AsUTF8(co->co_name),
PyUnicode_AsUTF8(PyObject_Repr(co->co_freevars)));
PyErr_Format(PyExc_SystemError,
"compiler_lookup_arg(name=%R) with reftype=%d failed in %S; "
"freevars of code %S: %R",
name,
reftype,
c->u->u_name,
co->co_name,
co->co_freevars);
return 0;
}
ADDOP_I(c, LOAD_CLOSURE, arg);
}
@ -2294,7 +2299,11 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async)
return 0;
}
compiler_make_closure(c, co, funcflags, qualname);
if (!compiler_make_closure(c, co, funcflags, qualname)) {
Py_DECREF(qualname);
Py_DECREF(co);
return 0;
}
Py_DECREF(qualname);
Py_DECREF(co);
@ -2419,7 +2428,10 @@ compiler_class(struct compiler *c, stmt_ty s)
ADDOP(c, LOAD_BUILD_CLASS);
/* 3. load a function (or closure) made from the code object */
compiler_make_closure(c, co, 0, NULL);
if (!compiler_make_closure(c, co, 0, NULL)) {
Py_DECREF(co);
return 0;
}
Py_DECREF(co);
/* 4. load class name */
@ -2697,7 +2709,11 @@ compiler_lambda(struct compiler *c, expr_ty e)
return 0;
}
compiler_make_closure(c, co, funcflags, qualname);
if (!compiler_make_closure(c, co, funcflags, qualname)) {
Py_DECREF(qualname);
Py_DECREF(co);
return 0;
}
Py_DECREF(qualname);
Py_DECREF(co);
@ -4660,8 +4676,9 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type,
if (co == NULL)
goto error;
if (!compiler_make_closure(c, co, 0, qualname))
if (!compiler_make_closure(c, co, 0, qualname)) {
goto error;
}
Py_DECREF(qualname);
Py_DECREF(co);
@ -5468,8 +5485,10 @@ stackdepth(struct compiler *c)
struct instr *instr = &b->b_instr[i];
int effect = stack_effect(instr->i_opcode, instr->i_oparg, 0);
if (effect == PY_INVALID_STACK_EFFECT) {
_Py_FatalErrorFormat(__func__,
"opcode = %d", instr->i_opcode);
PyErr_Format(PyExc_SystemError,
"compiler stack_effect(opcode=%d, arg=%i) failed",
instr->i_opcode, instr->i_oparg);
return -1;
}
int new_depth = depth + effect;
if (new_depth > maxdepth) {
@ -6675,4 +6694,3 @@ PyCode_Optimize(PyObject *code, PyObject* Py_UNUSED(consts),
Py_INCREF(code);
return code;
}