Skip to content

Report delayed OOM raised during compilation even when compilation fails - #24694

Open
srayuth089 wants to merge 1 commit into
php:masterfrom
srayuth089:fix/gh24631-compile-oom
Open

srayuth089 wants to merge 1 commit into
php:masterfrom
srayuth089:fix/gh24631-compile-oom

Conversation

@srayuth089

Copy link
Copy Markdown

Fixes GH-24631.

A delayed OOM recorded while compiling the main script is only consumed by zend_execute_script() when zend_compile_file() returns an op_array. When compilation fails afterwards — e.g. the OOM-truncated source yields a parse error — op_array is NULL, zend_handle_delayed_oom() is never reached, and the pending EG(delayed_oom) is silently dropped: the parse error is reported instead of the real out-of-memory error.

This mirrors the gap @bhaak noted for sapi/fuzzer/fuzzer-sapi.c, where the same if (op_array) guard hides a compile-time OOM.

Fix

Handle the delayed OOM right after zend_compile_file(), regardless of whether an op_array was produced. A pending exception at that point (the parse error from the truncated source) is a downstream artifact of the OOM, so it is discarded in favour of the OOM, which is the real error.

Reproduce

php -n -r 'file_put_contents("oom.php", "<?php\n\$a = \x27" . str_repeat("A", 3 << 19) . "\x27;\n)\n");'
php -n -d memory_limit=4M oom.php

Before:

Parse error: Unmatched ')' in oom.php on line 3

After:

Fatal error: Allowed memory size of 4194304 bytes exhausted (tried to allocate 2097152 bytes) in oom.php on line 2

Testing

  • New regression test Zend/tests/gh24631.phpt.
  • Verified on master (8.7.0-dev): case A (huge literal + stray )) now reports only the OOM; a clean huge literal still reports the OOM; an ordinary parse error (no OOM) is unaffected.
  • Full Zend/tests run: 0 failed, 0 warned (175 skipped for the minimal --disable-all --enable-cli build, 1 expected-fail).
  • The issue reproduces on the 8.4.27 stable release as well, not only 8.5-dev, so a backport is likely warranted.

A delayed OOM recorded during compilation was only handled when
zend_compile_file() returned an op_array. If compilation then failed
(e.g. a parse error on the OOM-truncated source), the pending
EG(delayed_oom) was dropped and the parse error reported instead of the
real out-of-memory error. Handle it regardless of whether an op_array was
produced, discarding the downstream parse-error exception in favour of the
OOM.

Fixes phpGH-24631.
@anun333

anun333 commented Oct 25, 2026

Copy link
Copy Markdown

Quoted below: written with Claude, an LLM, as CONTRIBUTING.md asks us to mark. The builds and test runs behind it are on my machine; the commands to repeat them are under the fold.

#24632 fixes GH-24631 too. It was opened a day earlier against PHP-8.4, and it has already been reworked in review by ndossche: it checks EG(delayed_oom).state == ZEND_OOM_STATE_PENDING rather than ZEND_HAS_OOM(), so an OOM that was already handled doesn't clear an unrelated exception, and it also covers zend_eval_stringl() (php -r, eval) and php_lint_script() (php -l).

I built both. Running #24632's tests against this branch (9764502cb82):

Case this PR #24632
main script that runs out of memory while compiling, then fails to parse the memory error the memory error
php -r with the same code Parse error: Unmatched ')' the memory error
php -l on the same file No syntax errors detected, then Parse error: Unmatched ')' the memory error, then Errors parsing

And this PR's gh24631.phpt passes on #24632's build.

How this was tested

Builds (Linux x86_64, gcc 13.3), each tree the same way:

./buildconf --force
./configure --enable-debug --with-mysqli --disable-cgi --disable-phpdbg --disable-fileinfo
make -j4

This branch (on master) and pull/24632/head (4f479a84d85, on PHP-8.4); #24632's tests Zend/tests/oom_compile_failure{,_eval_string,_lint}.phpt run on this build with TEST_PHP_EXECUTABLE=sapi/cli/php sapi/cli/php run-tests.php -q -n <test>. On master the main-script case also prints a Stack trace: because fatal_error_backtraces is on; that part isn't this PR's doing.

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.

Delayed OOM raised during compilation is dropped when compilation fails

3 participants