Skip to content

gh-151763: Fix OOM-0013 crash when the parser or compiler fails to allocate#151968

Open
tonghuaroot wants to merge 2 commits into
python:mainfrom
tonghuaroot:gh-151763-oom-contract
Open

gh-151763: Fix OOM-0013 crash when the parser or compiler fails to allocate#151968
tonghuaroot wants to merge 2 commits into
python:mainfrom
tonghuaroot:gh-151763-oom-contract

Conversation

@tonghuaroot

Copy link
Copy Markdown
Contributor

This fixes OOM-0013 from the gh-151763 umbrella.

compile(), exec(), eval() and ast.parse() can return NULL without
setting an exception when an allocation fails, breaking the result/error
contract every consumer relies on and crashing on the assertion that checks it
(for example the (res != NULL) ^ (PyErr_Occurred()) check reached from the
evaluation loop, and assert(!PyErr_Occurred()) at the top of
_PyAST_Validate).

Three points returned NULL silently under a failed allocation:

  • new_compiler() returned NULL without calling PyErr_NoMemory() when its
    initial PyMem_Calloc failed -- the dominant compile()/exec()/eval()
    path.
  • _PyPegen_run_parser() could return a valid result while leaving a stale
    exception pending.
  • The tokenizer-init helpers could fail silently.

Setting the error indicator at each point makes a failed allocation surface as
MemoryError instead of a NULL-without-exception crash.

Reproduction (debug build, _testcapi.set_nomemory)

  • ast.parse(...) under set_nomemory aborted with "a function returned NULL
    without setting an exception"; a clean MemoryError is raised after the fix.
  • compile() / exec() / eval() under set_nomemory aborted at the
    result/error contract assertion; clean after the fix.
  • Reverting either guard reproduces the corresponding abort (negative control).

No test is added, following the convention for these OOM crash fixes.

… to allocate

compile(), exec(), eval() and ast.parse() could return NULL without an
exception set when an allocation failed, breaking the result/error contract
and crashing on the assertion that checks it.  Set the error indicator at the
points that returned NULL silently: new_compiler(), the _PyPegen_run_parser()
result/exception check, and the tokenizer-init helpers.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant