Skip to content

gh-151763: Restore exception if parser recovery path leaves none set (OOM-0021)#154717

Closed
Vamsi-klu wants to merge 1 commit into
python:mainfrom
Vamsi-klu:fix-gh151763-oom-0021-pegen-recovery
Closed

gh-151763: Restore exception if parser recovery path leaves none set (OOM-0021)#154717
Vamsi-klu wants to merge 1 commit into
python:mainfrom
Vamsi-klu:fix-gh151763-oom-0021-pegen-recovery

Conversation

@Vamsi-klu

Copy link
Copy Markdown

Summary

Fix OOM-0021 under umbrella gh-151763: the parser recovery / diagnostic second pass can return NULL with no exception set, which later trips Py_FatalError("a function returned NULL without setting an exception") in _Py_CheckFunctionResult.


What the issue is

_PyPegen_run_parser already guards res != NULL && PyErr_Occurred() (OOM-0013). On res == NULL it still runs a heavier second parse pass and _PyPegen_set_syntax_error_metadata, which can PyErr_Clear() internally. Under sustained OOM the recovery path can finish with tstate->current_exception == NULL and return NULL, violating the C-API result/error contract. Callers such as the symtable path then fatal in Objects/call.c.


Why I solved it that way

  1. Restore the contract at the return site with:

    if (!PyErr_Occurred()) {
        PyErr_NoMemory();
    }

    This matches the idiom already used nearby after OOM-0013 (Parser/pegen.c other arms). PyErr_NoMemory() is safe under OOM (preallocated singleton).

  2. Do not remove _Py_CheckFunctionResult's fatal — that enforces the contract for the whole C API; weakening it would hide extension bugs.

  3. Do not yet rewrite _PyPegen_set_syntax_error_metadata to save/restore around its PyErr_Clear calls — that is a nicer long-term fix but larger and riskier; the belt at the return site closes the crash now.

  4. Separate PR from other OOM findings per umbrella policy (one PR per bug).


How I did it

At the end of the res == NULL block in _PyPegen_run_parser, after syntax-error metadata setup and before return NULL:

if (!PyErr_Occurred()) {
    /* Under OOM the recovery pass can clear the exception and fail
       silently; restore the result/error contract. */
    PyErr_NoMemory();
}
return NULL;

NEWS under Core and Builtins for gh-151763 (OOM-0021).


Impact

  • Converts a hard fatal / abort under parser OOM into a normal MemoryError.
  • Success-path parsing unchanged.
  • Complements OOM-0013 rather than duplicating it (that fix covered the res != NULL contradiction).

Testing plan

  • Rebuild debug interpreter.
  • Parser-related tests via normal suite smoke; full test_peg_generator needs extra resources (skipped in default run).
  • Optional: fusil/OOM-0021 gist repro with set_nomemory sweep — not automated here.
  • CI: full parser / test_grammar / test_syntax jobs.

Everything else


Requested reviewers (subject-matter experts)

Could the following SMEs take a look when convenient (I cannot formally request reviews from this fork account):

  • lysnikolaou / pablogsal — parser / pegen
  • devdanzin — OOM umbrella

Thank you!

…e set

After the diagnostic second parse pass, call PyErr_NoMemory() when no
exception is set so callers do not hit _Py_CheckFunctionResult fatals
(OOM-0021).
@python-cla-bot

python-cla-bot Bot commented Jul 26, 2026

Copy link
Copy Markdown

All commit authors signed the Contributor License Agreement.

CLA signed

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Another round soon, please!

Reviewed commit: f459c4bdf1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@Vamsi-klu
Vamsi-klu marked this pull request as draft July 26, 2026 08:01
@Vamsi-klu

Copy link
Copy Markdown
Author

Closing this PR. Thank you for the review attention.

@Vamsi-klu Vamsi-klu closed this Jul 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant