From 7fbea403d33c2117106351c9e1374aa1a6943e58 Mon Sep 17 00:00:00 2001 From: arshidkv12 Date: Tue, 30 Jun 2026 14:25:26 +0530 Subject: [PATCH 1/7] Zend: Fix lazy object registry deletion under OOM conditions --- Zend/tests/gh22520.phpt | 34 ++++++++++++++++++++++++++++++++++ Zend/zend_lazy_objects.c | 4 +++- 2 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 Zend/tests/gh22520.phpt diff --git a/Zend/tests/gh22520.phpt b/Zend/tests/gh22520.phpt new file mode 100644 index 000000000000..22938a4cd34e --- /dev/null +++ b/Zend/tests/gh22520.phpt @@ -0,0 +1,34 @@ +--TEST-- +GH-22520: Lazy object OOM should not crash zend_lazy_object_del_info +--SKIPIF-- + +--INI-- +memory_limit=2M +--FILE-- +newLazyGhost(function () { + return new A(); + }); + + // Try to trigger shutdown GC edge case + unset($obj); + + echo "OK\n"; +} catch (Throwable $e) { + echo "Caught: " . $e->getMessage() . "\n"; +} + +?> +--EXPECTF-- +OK diff --git a/Zend/zend_lazy_objects.c b/Zend/zend_lazy_objects.c index a8316768ef5f..136b79872fc9 100644 --- a/Zend/zend_lazy_objects.c +++ b/Zend/zend_lazy_objects.c @@ -161,7 +161,9 @@ zend_lazy_object_flags_t zend_lazy_object_get_flags(const zend_object *obj) void zend_lazy_object_del_info(const zend_object *obj) { zend_result res = zend_hash_index_del(&EG(lazy_objects_store).infos, obj->handle); - ZEND_ASSERT(res == SUCCESS); + if (UNEXPECTED(res != SUCCESS)) { + return; + } } bool zend_lazy_object_decr_lazy_props(const zend_object *obj) From deac185d602e842e1881d62cfc2877783d02dc52 Mon Sep 17 00:00:00 2001 From: arshidkv12 Date: Tue, 30 Jun 2026 14:32:22 +0530 Subject: [PATCH 2/7] Zend: Fix lazy object registry deletion under OOM conditions --- Zend/tests/gh22520.phpt | 24 ++++++++++-------------- Zend/zend_lazy_objects.c | 2 +- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/Zend/tests/gh22520.phpt b/Zend/tests/gh22520.phpt index 22938a4cd34e..fc533471e18a 100644 --- a/Zend/tests/gh22520.phpt +++ b/Zend/tests/gh22520.phpt @@ -9,26 +9,22 @@ memory_limit=2M --FILE-- newLazyGhost(function () { - return new A(); - }); +$str = str_repeat('a', 1024 * 1024 * 1.25); - // Try to trigger shutdown GC edge case - unset($obj); - - echo "OK\n"; +try { + $reflector = new ReflectionClass(C::class); + for ($i = 0; $i < 10000; $i++) { + $obj = $reflector->newLazyGhost(function ($obj) {}); + $reflector->getProperty('a')->setRawValueWithoutLazyInitialization($obj, $obj); + } } catch (Throwable $e) { echo "Caught: " . $e->getMessage() . "\n"; } ?> --EXPECTF-- -OK +Fatal error: Allowed memory size of %d bytes exhausted at /Users/arshid/Downloads/php-src/Zend/zend_objects_API.c:131 (tried to allocate 16416 bytes) in %s on line %d \ No newline at end of file diff --git a/Zend/zend_lazy_objects.c b/Zend/zend_lazy_objects.c index 136b79872fc9..65fc6d0651cf 100644 --- a/Zend/zend_lazy_objects.c +++ b/Zend/zend_lazy_objects.c @@ -162,7 +162,7 @@ void zend_lazy_object_del_info(const zend_object *obj) { zend_result res = zend_hash_index_del(&EG(lazy_objects_store).infos, obj->handle); if (UNEXPECTED(res != SUCCESS)) { - return; + return; } } From 1c248cceb2f2cc18baa827f0ebab45f5b2af9bc6 Mon Sep 17 00:00:00 2001 From: arshidkv12 Date: Tue, 30 Jun 2026 14:53:39 +0530 Subject: [PATCH 3/7] Zend: Fix lazy object registry deletion under OOM conditions --- Zend/tests/gh22520.phpt | 2 +- Zend/tests/recursive_oom_backtrace.phpt | 29 +++++++++++++++++++++++++ Zend/zend_lazy_objects.c | 2 +- 3 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 Zend/tests/recursive_oom_backtrace.phpt diff --git a/Zend/tests/gh22520.phpt b/Zend/tests/gh22520.phpt index fc533471e18a..4868aa2dfa2f 100644 --- a/Zend/tests/gh22520.phpt +++ b/Zend/tests/gh22520.phpt @@ -27,4 +27,4 @@ try { ?> --EXPECTF-- -Fatal error: Allowed memory size of %d bytes exhausted at /Users/arshid/Downloads/php-src/Zend/zend_objects_API.c:131 (tried to allocate 16416 bytes) in %s on line %d \ No newline at end of file +Fatal error: Allowed memory size of %d bytes exhausted at %s:%d (tried to allocate %d bytes) in %s on line %d diff --git a/Zend/tests/recursive_oom_backtrace.phpt b/Zend/tests/recursive_oom_backtrace.phpt new file mode 100644 index 000000000000..4e4bd83387c0 --- /dev/null +++ b/Zend/tests/recursive_oom_backtrace.phpt @@ -0,0 +1,29 @@ +--TEST-- +Recursion should not crash in zend_fetch_debug_backtrace +--SKIPIF-- + +--INI-- +memory_limit=30G +--FILE-- + +--EXPECTF-- +Caught exception +DONE \ No newline at end of file diff --git a/Zend/zend_lazy_objects.c b/Zend/zend_lazy_objects.c index 65fc6d0651cf..136b79872fc9 100644 --- a/Zend/zend_lazy_objects.c +++ b/Zend/zend_lazy_objects.c @@ -162,7 +162,7 @@ void zend_lazy_object_del_info(const zend_object *obj) { zend_result res = zend_hash_index_del(&EG(lazy_objects_store).infos, obj->handle); if (UNEXPECTED(res != SUCCESS)) { - return; + return; } } From 9f86b69f7df6322097c099c942806c94910da305 Mon Sep 17 00:00:00 2001 From: arshidkv12 Date: Tue, 30 Jun 2026 15:45:37 +0530 Subject: [PATCH 4/7] Zend: Fix lazy object registry deletion under OOM conditions --- Zend/tests/gh22520.phpt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Zend/tests/gh22520.phpt b/Zend/tests/gh22520.phpt index 4868aa2dfa2f..528c4adcdcd0 100644 --- a/Zend/tests/gh22520.phpt +++ b/Zend/tests/gh22520.phpt @@ -2,7 +2,9 @@ GH-22520: Lazy object OOM should not crash zend_lazy_object_del_info --SKIPIF-- --INI-- memory_limit=2M From 24df4e3743094390d8d174f7486d06f707852ed4 Mon Sep 17 00:00:00 2001 From: arshidkv12 Date: Tue, 30 Jun 2026 17:42:53 +0530 Subject: [PATCH 5/7] Zend: Fix lazy object registry deletion under OOM conditions --- Zend/tests/recursive_oom_backtrace.phpt | 29 ------------------------- 1 file changed, 29 deletions(-) delete mode 100644 Zend/tests/recursive_oom_backtrace.phpt diff --git a/Zend/tests/recursive_oom_backtrace.phpt b/Zend/tests/recursive_oom_backtrace.phpt deleted file mode 100644 index 4e4bd83387c0..000000000000 --- a/Zend/tests/recursive_oom_backtrace.phpt +++ /dev/null @@ -1,29 +0,0 @@ ---TEST-- -Recursion should not crash in zend_fetch_debug_backtrace ---SKIPIF-- - ---INI-- -memory_limit=30G ---FILE-- - ---EXPECTF-- -Caught exception -DONE \ No newline at end of file From 0131637c6fad6d6de198bf79f50fc78343845f31 Mon Sep 17 00:00:00 2001 From: arshidkv12 Date: Tue, 30 Jun 2026 20:08:21 +0530 Subject: [PATCH 6/7] Zend: Fix lazy object registry deletion under OOM conditions --- Zend/zend_lazy_objects.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Zend/zend_lazy_objects.c b/Zend/zend_lazy_objects.c index 136b79872fc9..31927385b6e9 100644 --- a/Zend/zend_lazy_objects.c +++ b/Zend/zend_lazy_objects.c @@ -161,9 +161,7 @@ zend_lazy_object_flags_t zend_lazy_object_get_flags(const zend_object *obj) void zend_lazy_object_del_info(const zend_object *obj) { zend_result res = zend_hash_index_del(&EG(lazy_objects_store).infos, obj->handle); - if (UNEXPECTED(res != SUCCESS)) { - return; - } + ZEND_ASSERT(res == SUCCESS || CG(unclean_shutdown)); } bool zend_lazy_object_decr_lazy_props(const zend_object *obj) From 893e9964c50ebcd509bc21fab1322bd300096a7c Mon Sep 17 00:00:00 2001 From: arshidkv12 Date: Tue, 30 Jun 2026 21:44:19 +0530 Subject: [PATCH 7/7] Zend: Fix lazy object registry deletion under OOM conditions --- Zend/tests/gh22520.phpt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Zend/tests/gh22520.phpt b/Zend/tests/gh22520.phpt index 528c4adcdcd0..e5b7ba26169a 100644 --- a/Zend/tests/gh22520.phpt +++ b/Zend/tests/gh22520.phpt @@ -29,4 +29,4 @@ try { ?> --EXPECTF-- -Fatal error: Allowed memory size of %d bytes exhausted at %s:%d (tried to allocate %d bytes) in %s on line %d +Fatal error: Allowed memory size of %d bytes exhausted %s in %s on line %d