From 43723d2097fab52cd343e11d5e815f9e9955ebba Mon Sep 17 00:00:00 2001 From: lazerg Date: Sat, 24 Oct 2026 11:28:33 +0500 Subject: [PATCH 1/7] Fix GH-24631: Report delayed OOM when compilation of the main script fails --- NEWS | 2 ++ Zend/tests/oom_compile_failure.phpt | 22 ++++++++++++++++++++++ Zend/zend.c | 10 ++++++++-- 3 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 Zend/tests/oom_compile_failure.phpt diff --git a/NEWS b/NEWS index 6d09ce4a22cc..b37cc17ab292 100644 --- a/NEWS +++ b/NEWS @@ -26,6 +26,8 @@ PHP NEWS . Fixed bug GH-24321 (ZTS: global_map_ptr_last survives zend_shutdown(), so an in-process engine restart keeps growing the map_ptr table). (David Carlier) + . Fixed bug GH-24631 (Delayed OOM raised during compilation is dropped when + compilation fails). (lazerg) - Date: . Fixed bug GH-20503 (Assertion failure with ext/date DateInterval property diff --git a/Zend/tests/oom_compile_failure.phpt b/Zend/tests/oom_compile_failure.phpt new file mode 100644 index 000000000000..112a54b5c67d --- /dev/null +++ b/Zend/tests/oom_compile_failure.phpt @@ -0,0 +1,22 @@ +--TEST-- +OOM: Delayed OOM raised during compilation of the main script is reported when compilation fails +--SKIPIF-- + +--FILE-- +&1'); + +?> +--CLEAN-- + +--EXPECTF-- +Fatal error: Allowed memory size of 6291456 bytes exhausted %S(tried to allocate %d bytes) in %soom_compile_failure.test.php on line 2 diff --git a/Zend/zend.c b/Zend/zend.c index 32028c9c5a0e..a8ea0e9372a1 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -1956,8 +1956,14 @@ ZEND_API zend_result zend_execute_script(int type, zval *retval, zend_file_handl zend_destroy_static_vars(op_array); destroy_op_array(op_array); efree_size(op_array, sizeof(zend_op_array)); - } else if (type == ZEND_REQUIRE) { - ret = FAILURE; + } else { + if (ZEND_HAS_OOM()) { + zend_clear_exception(); + zend_handle_delayed_oom(); + } + if (type == ZEND_REQUIRE) { + ret = FAILURE; + } } return ret; From e305af19d650ffd41cac62f5c668bfbd59999dd7 Mon Sep 17 00:00:00 2001 From: lazerg Date: Sat, 24 Oct 2026 11:53:27 +0500 Subject: [PATCH 2/7] Report delayed OOM on compile failure in fuzzer SAPI --- sapi/fuzzer/fuzzer-sapi.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sapi/fuzzer/fuzzer-sapi.c b/sapi/fuzzer/fuzzer-sapi.c index 107283c84b41..b926f2510374 100644 --- a/sapi/fuzzer/fuzzer-sapi.c +++ b/sapi/fuzzer/fuzzer-sapi.c @@ -284,6 +284,9 @@ int fuzzer_do_request_from_buffer( zend_destroy_static_vars(op_array); destroy_op_array(op_array); efree(op_array); + } else if (ZEND_HAS_OOM()) { + zend_clear_exception(); + zend_handle_delayed_oom(); } } zend_end_try(); From 631a3b818684faf835b709a0957707bf49d365d5 Mon Sep 17 00:00:00 2001 From: lazerg Date: Sat, 24 Oct 2026 15:47:17 +0500 Subject: [PATCH 3/7] Report delayed OOM on compile failure in zend_eval_stringl() and php_lint_script() --- .../oom_compile_failure_eval_string.phpt | 17 +++++++++++ Zend/tests/oom_compile_failure_lint.phpt | 28 +++++++++++++++++++ Zend/zend.c | 2 +- Zend/zend_execute_API.c | 4 +++ main/main.c | 5 ++++ sapi/fuzzer/fuzzer-sapi.c | 2 +- 6 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 Zend/tests/oom_compile_failure_eval_string.phpt create mode 100644 Zend/tests/oom_compile_failure_lint.phpt diff --git a/Zend/tests/oom_compile_failure_eval_string.phpt b/Zend/tests/oom_compile_failure_eval_string.phpt new file mode 100644 index 000000000000..240f3fa95553 --- /dev/null +++ b/Zend/tests/oom_compile_failure_eval_string.phpt @@ -0,0 +1,17 @@ +--TEST-- +OOM: Delayed OOM raised during compilation of php -r code is reported when compilation fails +--SKIPIF-- + +--FILE-- +&1'); + +?> +--EXPECTF-- +Fatal error: Allowed memory size of 4194304 bytes exhausted %S(tried to allocate %d bytes) in Command line code on line 1 diff --git a/Zend/tests/oom_compile_failure_lint.phpt b/Zend/tests/oom_compile_failure_lint.phpt new file mode 100644 index 000000000000..1f160b7d6859 --- /dev/null +++ b/Zend/tests/oom_compile_failure_lint.phpt @@ -0,0 +1,28 @@ +--TEST-- +OOM: Delayed OOM raised during compilation is reported by php -l +--SKIPIF-- + +--FILE-- +&1'); +} + +?> +--CLEAN-- + +--EXPECTF-- +Fatal error: Allowed memory size of 6291456 bytes exhausted %S(tried to allocate %d bytes) in %soom_compile_failure_lint.test.php on line 2 +Errors parsing %soom_compile_failure_lint.test.php + +Fatal error: Allowed memory size of 6291456 bytes exhausted %S(tried to allocate %d bytes) in %soom_compile_failure_lint.test.php on line 2 +Errors parsing %soom_compile_failure_lint.test.php diff --git a/Zend/zend.c b/Zend/zend.c index a8ea0e9372a1..6c13f60986b8 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -1957,7 +1957,7 @@ ZEND_API zend_result zend_execute_script(int type, zval *retval, zend_file_handl destroy_op_array(op_array); efree_size(op_array, sizeof(zend_op_array)); } else { - if (ZEND_HAS_OOM()) { + if (EG(delayed_oom).state == ZEND_OOM_STATE_PENDING) { zend_clear_exception(); zend_handle_delayed_oom(); } diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 30eb6ec8af3d..4083eae198cf 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -1410,6 +1410,10 @@ ZEND_API zend_result zend_eval_stringl(const char *str, size_t str_len, zval *re efree_size(new_op_array, sizeof(zend_op_array)); retval = SUCCESS; } else { + if (EG(delayed_oom).state == ZEND_OOM_STATE_PENDING) { + zend_clear_exception(); + zend_handle_delayed_oom(); + } retval = FAILURE; } zend_string_release(code_str); diff --git a/main/main.c b/main/main.c index bc1725fa9bfd..6279a110ae45 100644 --- a/main/main.c +++ b/main/main.c @@ -2771,6 +2771,11 @@ PHPAPI zend_result php_lint_script(zend_file_handle *file) efree(op_array); retval = SUCCESS; } + if (EG(delayed_oom).state == ZEND_OOM_STATE_PENDING) { + retval = FAILURE; + zend_clear_exception(); + zend_handle_delayed_oom(); + } } zend_end_try(); if (EG(exception)) { zend_exception_error(EG(exception), E_ERROR); diff --git a/sapi/fuzzer/fuzzer-sapi.c b/sapi/fuzzer/fuzzer-sapi.c index b926f2510374..6c40e572710d 100644 --- a/sapi/fuzzer/fuzzer-sapi.c +++ b/sapi/fuzzer/fuzzer-sapi.c @@ -284,7 +284,7 @@ int fuzzer_do_request_from_buffer( zend_destroy_static_vars(op_array); destroy_op_array(op_array); efree(op_array); - } else if (ZEND_HAS_OOM()) { + } else if (EG(delayed_oom).state == ZEND_OOM_STATE_PENDING) { zend_clear_exception(); zend_handle_delayed_oom(); } From 578a3ac741537e218639cad908fd6967b74eb09c Mon Sep 17 00:00:00 2001 From: lazerg Date: Sat, 24 Oct 2026 16:58:05 +0500 Subject: [PATCH 4/7] Make php -r delayed OOM test reliable on 32-bit --- Zend/tests/oom_compile_failure_eval_string.phpt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Zend/tests/oom_compile_failure_eval_string.phpt b/Zend/tests/oom_compile_failure_eval_string.phpt index 240f3fa95553..9ff752a4314d 100644 --- a/Zend/tests/oom_compile_failure_eval_string.phpt +++ b/Zend/tests/oom_compile_failure_eval_string.phpt @@ -7,11 +7,11 @@ if (!getenv('TEST_PHP_EXECUTABLE')) die('skip TEST_PHP_EXECUTABLE is not set'); --FILE-- &1'); +echo shell_exec(escapeshellarg($php) . ' -n -d memory_limit=3M -r ' . escapeshellarg($code) . ' 2>&1'); ?> --EXPECTF-- -Fatal error: Allowed memory size of 4194304 bytes exhausted %S(tried to allocate %d bytes) in Command line code on line 1 +Fatal error: Allowed memory size of 3145728 bytes exhausted %S(tried to allocate %d bytes) in Command line code on line 1 From 8ce5d2e6a4a76cd4d7436cdafa9accf8ee55268f Mon Sep 17 00:00:00 2001 From: lazerg Date: Sun, 25 Oct 2026 10:46:01 +0500 Subject: [PATCH 5/7] Fix delayed OOM compile tests on Windows --- Zend/tests/oom_compile_failure_eval_string.phpt | 1 + Zend/tests/oom_compile_failure_lint.phpt | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Zend/tests/oom_compile_failure_eval_string.phpt b/Zend/tests/oom_compile_failure_eval_string.phpt index 9ff752a4314d..8924ce266429 100644 --- a/Zend/tests/oom_compile_failure_eval_string.phpt +++ b/Zend/tests/oom_compile_failure_eval_string.phpt @@ -3,6 +3,7 @@ OOM: Delayed OOM raised during compilation of php -r code is reported when compi --SKIPIF-- --FILE-- &1'); + // Windows rounds huge blocks up to 2MB, so leave room below the hard limit + echo shell_exec(escapeshellarg($php) . ' -n -d memory_limit=6M -d memory_hard_limit_percent=400 -l ' . escapeshellarg($fname) . ' 2>&1'); } ?> From 4f479a84d85557ad6f1b83a4961b7464ff0ae676 Mon Sep 17 00:00:00 2001 From: lazerg Date: Sun, 25 Oct 2026 16:20:16 +0500 Subject: [PATCH 6/7] Drop NEWS entry --- NEWS | 2 -- 1 file changed, 2 deletions(-) diff --git a/NEWS b/NEWS index b37cc17ab292..6d09ce4a22cc 100644 --- a/NEWS +++ b/NEWS @@ -26,8 +26,6 @@ PHP NEWS . Fixed bug GH-24321 (ZTS: global_map_ptr_last survives zend_shutdown(), so an in-process engine restart keeps growing the map_ptr table). (David Carlier) - . Fixed bug GH-24631 (Delayed OOM raised during compilation is dropped when - compilation fails). (lazerg) - Date: . Fixed bug GH-20503 (Assertion failure with ext/date DateInterval property From a2d33cc7da1f09a00448707705705169b21ab0c5 Mon Sep 17 00:00:00 2001 From: lazerg Date: Mon, 26 Oct 2026 05:55:54 +0500 Subject: [PATCH 7/7] Disable fatal_error_backtraces in OOM tests --- Zend/tests/oom_compile_failure.phpt | 2 +- Zend/tests/oom_compile_failure_eval_string.phpt | 2 +- Zend/tests/oom_compile_failure_lint.phpt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Zend/tests/oom_compile_failure.phpt b/Zend/tests/oom_compile_failure.phpt index 112a54b5c67d..c2902ac566a7 100644 --- a/Zend/tests/oom_compile_failure.phpt +++ b/Zend/tests/oom_compile_failure.phpt @@ -11,7 +11,7 @@ $fname = __DIR__ . '/oom_compile_failure.test.php'; file_put_contents($fname, "&1'); +echo shell_exec(escapeshellarg($php) . ' -n -d fatal_error_backtraces=0 -d memory_limit=6M ' . escapeshellarg($fname) . ' 2>&1'); ?> --CLEAN-- diff --git a/Zend/tests/oom_compile_failure_eval_string.phpt b/Zend/tests/oom_compile_failure_eval_string.phpt index 8924ce266429..2858e7ee86d3 100644 --- a/Zend/tests/oom_compile_failure_eval_string.phpt +++ b/Zend/tests/oom_compile_failure_eval_string.phpt @@ -11,7 +11,7 @@ if (PHP_OS_FAMILY === 'Windows') die('skip the -r code is longer than Windows al $code = '$a = [' . str_repeat('1,', 50000) . ']; )'; $php = getenv('TEST_PHP_EXECUTABLE'); -echo shell_exec(escapeshellarg($php) . ' -n -d memory_limit=3M -r ' . escapeshellarg($code) . ' 2>&1'); +echo shell_exec(escapeshellarg($php) . ' -n -d fatal_error_backtraces=0 -d memory_limit=3M -r ' . escapeshellarg($code) . ' 2>&1'); ?> --EXPECTF-- diff --git a/Zend/tests/oom_compile_failure_lint.phpt b/Zend/tests/oom_compile_failure_lint.phpt index 32fbad640440..329f5d0acef9 100644 --- a/Zend/tests/oom_compile_failure_lint.phpt +++ b/Zend/tests/oom_compile_failure_lint.phpt @@ -13,7 +13,7 @@ $php = getenv('TEST_PHP_EXECUTABLE'); foreach (["\n", "\n)\n"] as $tail) { file_put_contents($fname, "&1'); + echo shell_exec(escapeshellarg($php) . ' -n -d fatal_error_backtraces=0 -d memory_limit=6M -d memory_hard_limit_percent=400 -l ' . escapeshellarg($fname) . ' 2>&1'); } ?>