Skip to content
Open
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
8 changes: 4 additions & 4 deletions Python/codegen.c
Original file line number Diff line number Diff line change
Expand Up @@ -695,13 +695,13 @@ codegen_enter_scope(compiler *c, identifier name, int scope_type,
* of 0. This is because RETURN_GENERATOR pushes the generator
before returning. */
location loc = LOCATION(lineno, lineno, -1, -1);
ADDOP(c, loc, RETURN_GENERATOR);
ADDOP(c, loc, POP_TOP);
ADDOP_IN_SCOPE(c, loc, RETURN_GENERATOR);
ADDOP_IN_SCOPE(c, loc, POP_TOP);
}

ADDOP_I(c, loc, RESUME, RESUME_AT_FUNC_START);
ADDOP_I_IN_SCOPE(c, loc, RESUME, RESUME_AT_FUNC_START);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think we should also guard the final _PyCompile_ExitScope(c) in _PyCompile_CodeGen() with if (c->u != NULL), as compiler_mod() does?

If allocating the module's initial RESUME fails, this now exits the only scope and leaves c->u as NULL. _PyCompile_CodeGen() then reaches its unconditional final exit (Python/compile.c:1738), which dereferences c->u and segfaults.

I reproduced this with an allocator hook that fails the initial instruction-buffer allocation during:

import ast
import _testinternalcapi

_testinternalcapi.compiler_codegen(ast.parse("pass"), "<test>", 0)

Main propagates MemoryError, whereas this PR crashes. Normal compile() already handles the cleanup correctly.

if (scope_type == COMPILE_SCOPE_MODULE) {
ADDOP(c, loc, ANNOTATIONS_PLACEHOLDER);
ADDOP_IN_SCOPE(c, loc, ANNOTATIONS_PLACEHOLDER);
}
return SUCCESS;
}
Expand Down
Loading