Skip to content

bpo-38631: Replace compiler fatal errors with exceptions #24369

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jan 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Replace :c:func:`Py_FatalError` calls in the compiler with regular
:exc:`SystemError` exceptions. Patch by Victor Stinner.
86 changes: 52 additions & 34 deletions Python/compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
*/

#include "Python.h"
#include "pycore_pymem.h" // _PyMem_IsPtrFreed()
#include "pycore_long.h" // _PyLong_GetZero()

#include "Python-ast.h"
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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;
}

Expand All @@ -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)
Expand All @@ -1935,28 +1934,34 @@ 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,
the name will be considered free *and* local in the
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 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, preserve the comment for the else branch: /* (reftype == FREE) */

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, preserve the comment for the else branch: /* (reftype == FREE) */

See the commit message: the comment is wrong. Try to convert the comment into an assertion.

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);
}
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -2695,7 +2707,11 @@ compiler_lambda(struct compiler *c, expr_ty e)
if (co == NULL)
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);

Expand Down Expand Up @@ -4658,8 +4674,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);

Expand Down Expand Up @@ -5466,8 +5483,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) {
Expand Down Expand Up @@ -6673,4 +6692,3 @@ PyCode_Optimize(PyObject *code, PyObject* Py_UNUSED(consts),
Py_INCREF(code);
return code;
}