From 9ab800ec9b5959dfe3d4cde50f7a27a763d102f8 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+ndossche@users.noreply.github.com> Date: Sat, 10 Jan 2026 10:52:28 +0100 Subject: [PATCH 1/3] Mark Phar::buildFromIterator() base directory argument as a path This is like buildFromDirectory() which does it right. Closes GH-20892. --- NEWS | 2 ++ ext/phar/phar_object.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index d2da15927ce5..0899163d87b7 100644 --- a/NEWS +++ b/NEWS @@ -54,6 +54,8 @@ PHP NEWS ignored. (ndossche) . Support overridden methods in SplFileInfo for getMTime() and getPathname() when building a phar. (ndossche) + . Mark Phar::buildFromIterator() base directory argument as a path. + (ndossche) - Reflection: . Fixed bug GH-20217 (ReflectionClass::isIterable() incorrectly returns true diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index 338cdc705d08..5dd1dc4090cd 100644 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -1828,7 +1828,7 @@ PHP_METHOD(Phar, buildFromIterator) zend_string *base = ZSTR_EMPTY_ALLOC(); struct _phar_t pass; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|S!", &obj, zend_ce_traversable, &base) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|P!", &obj, zend_ce_traversable, &base) == FAILURE) { RETURN_THROWS(); } From f61b1fc03682ae72df84d58c0d0d7972c7b386bf Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Tue, 6 Jan 2026 00:01:51 +0100 Subject: [PATCH 2/3] Fix block_pass JMP[N]Z optimization In the following optimization: JMPZ(X,L1) JMP(L2) L1: -> JMPNZ(X,L2) NOP L1 must not be followed by another block, so that it may safely be followed by the block containing the JMPNZ. get_next_block() is used to verify L1 is the direct follower. This function also skips empty blocks, including live, empty target blocks, which will then implicitly follow the new follow block. This will result in L1 being followed by two separate blocks, which is not possible. Resolve this by get_next_block() stopping at target blocks. Fixes OSS-Fuzz #472563272 Closes GH-20850 --- NEWS | 1 + Zend/Optimizer/block_pass.c | 2 +- ext/opcache/tests/oss-fuzz-472563272.phpt | 14 ++++++++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 ext/opcache/tests/oss-fuzz-472563272.phpt diff --git a/NEWS b/NEWS index 8201bf8cf9c1..ab7bea69fb6d 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,7 @@ PHP NEWS . Fixed bug GH-20837 (NULL dereference when calling ob_start() in shutdown function triggered by bailout in php_output_lock_error()). (timwolla) . Fix OSS-Fuzz #471533782 (Infinite loop in GC destructor fiber). (ilutov) + . Fix OSS-Fuzz #472563272 (Borked block_pass JMP[N]Z optimization). (ilutov) - MbString: . Fixed bug GH-20833 (mb_str_pad() divide by zero if padding string is diff --git a/Zend/Optimizer/block_pass.c b/Zend/Optimizer/block_pass.c index 6fcbd04f12af..ee70d021f4a9 100644 --- a/Zend/Optimizer/block_pass.c +++ b/Zend/Optimizer/block_pass.c @@ -1152,7 +1152,7 @@ static zend_always_inline zend_basic_block *get_next_block(const zend_cfg *cfg, } next_block++; } - while (next_block->len == 0 && !(next_block->flags & ZEND_BB_PROTECTED)) { + while (next_block->len == 0 && !(next_block->flags & (ZEND_BB_TARGET|ZEND_BB_PROTECTED))) { next_block = cfg->blocks + next_block->successors[0]; } return next_block; diff --git a/ext/opcache/tests/oss-fuzz-472563272.phpt b/ext/opcache/tests/oss-fuzz-472563272.phpt new file mode 100644 index 000000000000..39519abe9ae0 --- /dev/null +++ b/ext/opcache/tests/oss-fuzz-472563272.phpt @@ -0,0 +1,14 @@ +--TEST-- +OSS-Fuzz #472563272: Borked block_pass JMP[N]Z optimization +--EXTENSIONS-- +opcache +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +--FILE-- + +===DONE=== +--EXPECT-- +===DONE=== From 9b0643ea366ed1064784ef6eda284e77384ddceb Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+ndossche@users.noreply.github.com> Date: Sun, 11 Jan 2026 15:08:31 +0100 Subject: [PATCH 3/3] spl: Remove unused fields from spl dllist (#20886) --- ext/spl/spl_dllist.c | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/ext/spl/spl_dllist.c b/ext/spl/spl_dllist.c index 867f492fab16..43b2c020b726 100644 --- a/ext/spl/spl_dllist.c +++ b/ext/spl/spl_dllist.c @@ -75,12 +75,7 @@ struct _spl_dllist_object { spl_ptr_llist_element *traverse_pointer; int traverse_position; int flags; - zend_function *fptr_offset_get; - zend_function *fptr_offset_set; - zend_function *fptr_offset_has; - zend_function *fptr_offset_del; zend_function *fptr_count; - zend_class_entry *ce_get_iterator; zend_object std; }; @@ -322,7 +317,6 @@ static zend_object *spl_dllist_object_new_ex(zend_class_entry *class_type, zend_ if (orig) { spl_dllist_object *other = spl_dllist_from_obj(orig); - intern->ce_get_iterator = other->ce_get_iterator; if (clone_orig) { intern->llist = spl_ptr_llist_init(); @@ -360,22 +354,6 @@ static zend_object *spl_dllist_object_new_ex(zend_class_entry *class_type, zend_ ZEND_ASSERT(parent); if (inherited) { - intern->fptr_offset_get = zend_hash_str_find_ptr(&class_type->function_table, "offsetget", sizeof("offsetget") - 1); - if (intern->fptr_offset_get->common.scope == parent) { - intern->fptr_offset_get = NULL; - } - intern->fptr_offset_set = zend_hash_str_find_ptr(&class_type->function_table, "offsetset", sizeof("offsetset") - 1); - if (intern->fptr_offset_set->common.scope == parent) { - intern->fptr_offset_set = NULL; - } - intern->fptr_offset_has = zend_hash_str_find_ptr(&class_type->function_table, "offsetexists", sizeof("offsetexists") - 1); - if (intern->fptr_offset_has->common.scope == parent) { - intern->fptr_offset_has = NULL; - } - intern->fptr_offset_del = zend_hash_str_find_ptr(&class_type->function_table, "offsetunset", sizeof("offsetunset") - 1); - if (intern->fptr_offset_del->common.scope == parent) { - intern->fptr_offset_del = NULL; - } /* Find count() method */ intern->fptr_count = zend_hash_find_ptr(&class_type->function_table, ZSTR_KNOWN(ZEND_STR_COUNT)); if (intern->fptr_count->common.scope == parent) {