From e5850340f49eab3853f9ee693cfd45d8513eb949 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcos=20=27Marc=C3=A3o=27=20Aurelio?= Date: Mon, 13 Apr 2026 07:15:05 -0300 Subject: [PATCH 01/16] Fix GH-21699: callable resolution must fail if error handler threw during self/parent/static deprecations (#21712) When resolving string callables using self::, parent::, or static::, zend_is_callable_check_class() emits E_DEPRECATED. If the user error handler throws, EG(exception) is set but the function could still return true, leading to trampoline allocation and a failed assertion in shutdown_executor(). Return false from zend_is_callable_check_class() when EG(exception) is set after handling. --- NEWS | 2 ++ Zend/tests/gh16799.phpt | 7 ++++++- Zend/tests/gh_21699.phpt | 31 +++++++++++++++++++++++++++++++ Zend/tests/gh_21699_parent.phpt | 32 ++++++++++++++++++++++++++++++++ Zend/tests/gh_21699_static.phpt | 31 +++++++++++++++++++++++++++++++ Zend/zend_API.c | 4 ++++ 6 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 Zend/tests/gh_21699.phpt create mode 100644 Zend/tests/gh_21699_parent.phpt create mode 100644 Zend/tests/gh_21699_static.phpt diff --git a/NEWS b/NEWS index 24846881de96..a09ef9491f08 100644 --- a/NEWS +++ b/NEWS @@ -8,6 +8,8 @@ PHP NEWS . Fixed bug GH-21478 (Forward property operations to real instance for initialized lazy proxies). (iliaal) . Fixed bug GH-21605 (Missing addref for Countable::count()). (ilutov) + . Fixed bug GH-21699 (Assertion failure in shutdown_executor when resolving + self::/parent::/static:: callables if the error handler throws). - Curl: . Add support for brotli and zstd on Windows. (Shivam Mathur) diff --git a/Zend/tests/gh16799.phpt b/Zend/tests/gh16799.phpt index ce1dbd5b1655..d31d1a5705c6 100644 --- a/Zend/tests/gh16799.phpt +++ b/Zend/tests/gh16799.phpt @@ -15,7 +15,12 @@ Test::test(); --EXPECTF-- Fatal error: Uncaught Exception: Use of "static" in callables is deprecated in %s:%d Stack trace: -#0 %s(%d): {closure:%s:%d}(8192, 'Use of "static"...', %s, %d) +#0 %s(%d): {closure:%s}(8192, 'Use of "static"%s', '%s', %d) #1 %s(%d): Test::test() #2 {main} + +Next TypeError: call_user_func(): Argument #1 ($callback) must be a valid callback, (null) in %s:%d +Stack trace: +#0 %s(%d): Test::test() +#1 {main} thrown in %s on line %d diff --git a/Zend/tests/gh_21699.phpt b/Zend/tests/gh_21699.phpt new file mode 100644 index 000000000000..49b58365dabf --- /dev/null +++ b/Zend/tests/gh_21699.phpt @@ -0,0 +1,31 @@ +--TEST-- +GH-21699: Assertion failure in shutdown_executor when error handler throws during self:: callable resolution +--FILE-- +test(); +?> +--EXPECTF-- +Fatal error: Uncaught Exception in %s:%d +Stack trace: +#0 %s(%d): {closure:%s}(%d, 'Use of "self" i%s', '%s', %d) +#1 %s(%d): bar->test() +#2 {main} + +Next TypeError: call_user_func(): Argument #1 ($callback) must be a valid callback, (null) in %s:%d +Stack trace: +#0 %s(%d): bar->test() +#1 {main} + thrown in %s on line %d diff --git a/Zend/tests/gh_21699_parent.phpt b/Zend/tests/gh_21699_parent.phpt new file mode 100644 index 000000000000..73cae41f3f5b --- /dev/null +++ b/Zend/tests/gh_21699_parent.phpt @@ -0,0 +1,32 @@ +--TEST-- +GH-21699 (parent::): no shutdown_executor trampoline assertion when error handler throws during parent:: callable resolution +--FILE-- +test(); +?> +--EXPECTF-- +Fatal error: Uncaught Exception in %s:%d +Stack trace: +#0 %s(%d): {closure:%s}(%d, 'Use of "parent"%s', '%s', %d) +#1 %s(%d): Child->test() +#2 {main} + +Next TypeError: call_user_func(): Argument #1 ($callback) must be a valid callback, (null) in %s:%d +Stack trace: +#0 %s(%d): Child->test() +#1 {main} + thrown in %s on line %d diff --git a/Zend/tests/gh_21699_static.phpt b/Zend/tests/gh_21699_static.phpt new file mode 100644 index 000000000000..4d9604ebe77b --- /dev/null +++ b/Zend/tests/gh_21699_static.phpt @@ -0,0 +1,31 @@ +--TEST-- +GH-21699 (static::): no shutdown_executor trampoline assertion when error handler throws during static:: callable resolution +--FILE-- +test(); +?> +--EXPECTF-- +Fatal error: Uncaught Exception in %s:%d +Stack trace: +#0 %s(%d): {closure:%s}(%d, 'Use of "static"%s', '%s', %d) +#1 %s(%d): bar->test() +#2 {main} + +Next TypeError: call_user_func(): Argument #1 ($callback) must be a valid callback, (null) in %s:%d +Stack trace: +#0 %s(%d): bar->test() +#1 {main} + thrown in %s on line %d diff --git a/Zend/zend_API.c b/Zend/zend_API.c index e529c48b5ac2..3c9891a00e92 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -3849,6 +3849,10 @@ static bool zend_is_callable_check_class(zend_string *name, zend_class_entry *sc if (error) zend_spprintf(error, 0, "class \"%.*s\" not found", (int)name_len, ZSTR_VAL(name)); } ZSTR_ALLOCA_FREE(lcname, use_heap); + /* User error handlers may throw from deprecations above; do not report callable as valid. */ + if (UNEXPECTED(EG(exception))) { + return false; + } return ret; } /* }}} */ From d64eb790f6aa63bdc23dd2788630afc50ce4a387 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Mon, 13 Apr 2026 11:16:07 +0100 Subject: [PATCH 02/16] Fix-up NEWS --- NEWS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS b/NEWS index a09ef9491f08..6c284c501b0a 100644 --- a/NEWS +++ b/NEWS @@ -9,7 +9,7 @@ PHP NEWS initialized lazy proxies). (iliaal) . Fixed bug GH-21605 (Missing addref for Countable::count()). (ilutov) . Fixed bug GH-21699 (Assertion failure in shutdown_executor when resolving - self::/parent::/static:: callables if the error handler throws). + self::/parent::/static:: callables if the error handler throws). (macoaure) - Curl: . Add support for brotli and zstd on Windows. (Shivam Mathur) From 08dad097025bddd5a6d11cd864866a25b0966e67 Mon Sep 17 00:00:00 2001 From: Ilia Alshanetsky Date: Mon, 13 Apr 2026 06:35:20 -0400 Subject: [PATCH 03/16] Fix GH-8561, GH-8562, GH-8563, GH-8564: SplFileObject iterator desync (#21679) * Fix GH-8562: SplFileObject::current() returns wrong value after next() SplFileObject::next() without READ_AHEAD cleared the cached line and incremented current_line_num but didn't advance the stream. When called without a preceding current() (e.g. rewind() then next()), the stream position stayed put, so the subsequent current() read stale data. Read a line to advance the stream when next() is called with no cached line. Closes GH-8562 * Fix GH-8561: SplFileObject key()/current() desync after fgets() fgets() read a line into the cache and incremented the line counter, but left the cached line in place. The subsequent current() returned the stale cached value instead of reading the next line from the stream's actual position. Clear the cached line after fgets() copies it to the return value. This forces current() to re-read from the stream, which has already advanced past the fgets'd line. Closes GH-8561 * Fix GH-8563, GH-8564: SplFileObject EOF handling for seek() and next() spl_filesystem_file_read_ex() treated a NULL buffer from php_stream_get_line as a successful read of an empty line, creating a phantom cached line at EOF. This caused seek() to give inconsistent results between SplFileObject and SplTempFileObject (GH-8563), and next() to increment the line counter indefinitely past EOF (GH-8564). Return FAILURE when php_stream_get_line returns NULL, matching the behavior of the existing php_stream_eof check. In seek(), break out of the loop on EOF instead of returning, so the post-loop cleanup runs consistently. In next(), return early at EOF without incrementing. Make __toString() return empty string at EOF instead of throwing. Closes GH-8563 Closes GH-8564 * Refine fgets() to reuse cached line when present When current() reads a line into the cache without advancing line_num, a subsequent fgets() would re-read the stream and return the next line, skipping the cached one and leaving key() out of sync with current() for the rest of the iteration. Use the cached line if present; otherwise read a fresh line. Either way, advance line_num by one. --- ext/spl/spl_directory.c | 51 ++++++++++++------- .../SplFileObject_key_error001.phpt | 2 +- .../SplFileObject_key_error002.phpt | 2 +- ext/spl/tests/SplFileObject/bug81477.phpt | 1 - .../SplFileObject/fgetcsv_blank_file.phpt | 5 +- ext/spl/tests/SplFileObject/gh8561.phpt | 30 +++++++++++ ext/spl/tests/SplFileObject/gh8563.phpt | 29 +++++++++++ ext/spl/tests/SplFileObject/gh8564.phpt | 20 ++++++++ ext/spl/tests/gh13685.phpt | 4 +- ext/spl/tests/gh8562.phpt | 27 ++++++++++ 10 files changed, 144 insertions(+), 27 deletions(-) create mode 100644 ext/spl/tests/SplFileObject/gh8561.phpt create mode 100644 ext/spl/tests/SplFileObject/gh8563.phpt create mode 100644 ext/spl/tests/SplFileObject/gh8564.phpt create mode 100644 ext/spl/tests/gh8562.phpt diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c index cae8ffabc672..1468cec6ccf3 100644 --- a/ext/spl/spl_directory.c +++ b/ext/spl/spl_directory.c @@ -1811,21 +1811,24 @@ static zend_result spl_filesystem_file_read_ex(spl_filesystem_object *intern, bo } if (!buf) { - intern->u.file.current_line = ZSTR_EMPTY_ALLOC(); - } else { - if (!csv && SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_DROP_NEW_LINE)) { - if (line_len > 0 && buf[line_len - 1] == '\n') { + if (!silent) { + spl_filesystem_file_cannot_read(intern); + } + return FAILURE; + } + + if (!csv && SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_DROP_NEW_LINE)) { + if (line_len > 0 && buf[line_len - 1] == '\n') { + line_len--; + if (line_len > 0 && buf[line_len - 1] == '\r') { line_len--; - if (line_len > 0 && buf[line_len - 1] == '\r') { - line_len--; - } - buf[line_len] = '\0'; } + buf[line_len] = '\0'; } - - intern->u.file.current_line = zend_string_init(buf, line_len, /* persistent */ false); - efree(buf); } + + intern->u.file.current_line = zend_string_init(buf, line_len, /* persistent */ false); + efree(buf); intern->u.file.current_line_num += line_add; return SUCCESS; @@ -2091,10 +2094,17 @@ PHP_METHOD(SplFileObject, fgets) CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern); - if (spl_filesystem_file_read_ex(intern, /* silent */ false, /* line_add */ 1, /* csv */ false) == FAILURE) { - RETURN_THROWS(); + if (intern->u.file.current_line) { + RETVAL_STR_COPY(intern->u.file.current_line); + spl_filesystem_file_free_line(intern); + intern->u.file.current_line_num++; + } else { + if (spl_filesystem_file_read_ex(intern, /* silent */ false, /* line_add */ 1, /* csv */ false) == FAILURE) { + RETURN_THROWS(); + } + RETVAL_STR_COPY(intern->u.file.current_line); + spl_filesystem_file_free_line(intern); } - RETURN_STR_COPY(intern->u.file.current_line); } /* }}} */ /* {{{ Return current line from file */ @@ -2140,6 +2150,12 @@ PHP_METHOD(SplFileObject, next) ZEND_PARSE_PARAMETERS_NONE(); + if (!intern->u.file.current_line && Z_ISUNDEF(intern->u.file.current_zval)) { + if (spl_filesystem_file_read_line(ZEND_THIS, intern, true) == FAILURE) { + return; + } + } + spl_filesystem_file_free_line(intern); if (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_AHEAD)) { spl_filesystem_file_read_line(ZEND_THIS, intern, true); @@ -2627,7 +2643,7 @@ PHP_METHOD(SplFileObject, seek) for (i = 0; i < line_pos; i++) { if (spl_filesystem_file_read_line(ZEND_THIS, intern, true) == FAILURE) { - return; + break; } } if (line_pos > 0 && !SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_AHEAD)) { @@ -2646,9 +2662,8 @@ PHP_METHOD(SplFileObject, __toString) if (!intern->u.file.current_line) { ZEND_ASSERT(Z_ISUNDEF(intern->u.file.current_zval)); - zend_result result = spl_filesystem_file_read_line(ZEND_THIS, intern, false); - if (UNEXPECTED(result != SUCCESS)) { - RETURN_THROWS(); + if (spl_filesystem_file_read_line(ZEND_THIS, intern, true) == FAILURE) { + RETURN_EMPTY_STRING(); } } diff --git a/ext/spl/tests/SplFileObject/SplFileObject_key_error001.phpt b/ext/spl/tests/SplFileObject/SplFileObject_key_error001.phpt index 0c21d0b905e9..7d0e3ae8d969 100644 --- a/ext/spl/tests/SplFileObject/SplFileObject_key_error001.phpt +++ b/ext/spl/tests/SplFileObject/SplFileObject_key_error001.phpt @@ -18,5 +18,5 @@ var_dump($s->key()); var_dump($s->valid()); ?> --EXPECT-- -int(14) +int(12) bool(false) diff --git a/ext/spl/tests/SplFileObject/SplFileObject_key_error002.phpt b/ext/spl/tests/SplFileObject/SplFileObject_key_error002.phpt index 8fc9b7fef0a5..0834dbc0524f 100644 --- a/ext/spl/tests/SplFileObject/SplFileObject_key_error002.phpt +++ b/ext/spl/tests/SplFileObject/SplFileObject_key_error002.phpt @@ -18,5 +18,5 @@ var_dump($s->key()); var_dump($s->valid()); ?> --EXPECT-- -int(13) +int(12) bool(false) diff --git a/ext/spl/tests/SplFileObject/bug81477.phpt b/ext/spl/tests/SplFileObject/bug81477.phpt index f7730a791aa0..421c74dc4d68 100644 --- a/ext/spl/tests/SplFileObject/bug81477.phpt +++ b/ext/spl/tests/SplFileObject/bug81477.phpt @@ -21,7 +21,6 @@ string(8) "baz,bat " string(10) "more,data " -string(0) "" --CLEAN-- rewind(); var_dump($file->fgetcsv()); ?> --EXPECT-- -array(1) { - [0]=> - NULL -} +bool(false) bool(false) diff --git a/ext/spl/tests/SplFileObject/gh8561.phpt b/ext/spl/tests/SplFileObject/gh8561.phpt new file mode 100644 index 000000000000..adf36afb8b29 --- /dev/null +++ b/ext/spl/tests/SplFileObject/gh8561.phpt @@ -0,0 +1,30 @@ +--TEST-- +GH-8561 (SplFileObject: key() and current() unsynchronized after fgets()) +--FILE-- +fwrite("line {$i}" . PHP_EOL); +} + +// Case 1: rewind + fgets, then key/current +$file->rewind(); +$file->fgets(); +echo "After rewind+fgets: key=" . $file->key() . " current=" . trim($file->current()) . "\n"; + +// Case 2: multiple fgets +$file->rewind(); +$file->fgets(); +$file->fgets(); +echo "After rewind+fgets+fgets: key=" . $file->key() . " current=" . trim($file->current()) . "\n"; + +// Case 3: current then fgets +$file->rewind(); +$file->current(); +$file->fgets(); +echo "After current+fgets: key=" . $file->key() . " current=" . trim($file->current()) . "\n"; +?> +--EXPECT-- +After rewind+fgets: key=1 current=line 1 +After rewind+fgets+fgets: key=2 current=line 2 +After current+fgets: key=1 current=line 1 diff --git a/ext/spl/tests/SplFileObject/gh8563.phpt b/ext/spl/tests/SplFileObject/gh8563.phpt new file mode 100644 index 000000000000..03891750f8bf --- /dev/null +++ b/ext/spl/tests/SplFileObject/gh8563.phpt @@ -0,0 +1,29 @@ +--TEST-- +GH-8563 (Different results for seek() on SplFileObject and SplTempFileObject) +--FILE-- +fwrite("line {$i}" . PHP_EOL); + $file_02->fwrite("line {$i}" . PHP_EOL); +} + +$file_01->rewind(); +$file_02->rewind(); + +$file_01->seek(10); +$file_02->seek(10); + +echo 'SplFileObject: ' . $file_01->key() . "\n"; +echo 'SplTempFileObject: ' . $file_02->key() . "\n"; +?> +--CLEAN-- + +--EXPECT-- +SplFileObject: 5 +SplTempFileObject: 5 diff --git a/ext/spl/tests/SplFileObject/gh8564.phpt b/ext/spl/tests/SplFileObject/gh8564.phpt new file mode 100644 index 000000000000..ff16893c4c6b --- /dev/null +++ b/ext/spl/tests/SplFileObject/gh8564.phpt @@ -0,0 +1,20 @@ +--TEST-- +GH-8564 (SplFileObject: next() moves to nonexistent indexes) +--FILE-- +fwrite("line {$i}" . PHP_EOL); +} + +$file->rewind(); +for ($i = 0; $i < 10; $file->next(), $i++); +echo "next() 10x: key=" . $file->key() . " valid=" . var_export($file->valid(), true) . "\n"; + +$file->rewind(); +$file->seek(10); +echo "seek(10): key=" . $file->key() . " valid=" . var_export($file->valid(), true) . "\n"; +?> +--EXPECT-- +next() 10x: key=5 valid=false +seek(10): key=5 valid=false diff --git a/ext/spl/tests/gh13685.phpt b/ext/spl/tests/gh13685.phpt index 0f679d0e93fc..2bdddec4584e 100644 --- a/ext/spl/tests/gh13685.phpt +++ b/ext/spl/tests/gh13685.phpt @@ -44,9 +44,9 @@ try { string(14) ""A", "B", "C" " string(13) ""D", "E", "F"" -Cannot read from file php://temp +string(0) "" --- Use csv control --- string(14) ""A", "B", "C" " string(13) ""D", "E", "F"" -Cannot read from file php://temp +string(0) "" diff --git a/ext/spl/tests/gh8562.phpt b/ext/spl/tests/gh8562.phpt new file mode 100644 index 000000000000..40b2554f5794 --- /dev/null +++ b/ext/spl/tests/gh8562.phpt @@ -0,0 +1,27 @@ +--TEST-- +GH-8562 (SplFileObject::current() returns wrong result after call to next()) +--FILE-- +fwrite("line {$i}" . PHP_EOL); +} + +$file->rewind(); +$file->next(); +echo "After rewind+next: key=" . $file->key() . " current=" . trim($file->current()) . "\n"; + +$file->rewind(); +$file->next(); +$file->next(); +echo "After rewind+next+next: key=" . $file->key() . " current=" . trim($file->current()) . "\n"; + +$file->rewind(); +$file->current(); +$file->next(); +echo "After current+next: key=" . $file->key() . " current=" . trim($file->current()) . "\n"; +?> +--EXPECT-- +After rewind+next: key=1 current=line 1 +After rewind+next+next: key=2 current=line 2 +After current+next: key=1 current=line 1 From 159b4ee08602774fa64671e86e8bb4381ca74fbb Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Mon, 13 Apr 2026 11:37:59 +0100 Subject: [PATCH 04/16] Add NEWS entry for SplFileObject iterator fixes --- NEWS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/NEWS b/NEWS index a7ad6778875b..f5c9cfa75502 100644 --- a/NEWS +++ b/NEWS @@ -133,6 +133,8 @@ PHP NEWS - SPL: . DirectoryIterator key can now work better with filesystem supporting larger directory indexing. (David Carlier) + . Fix bugs GH-8561, GH-8562, GH-8563, and GH-8564 (Fixing various + SplFileObject iterator desync bugs). (iliaal) - Sqlite3: . Fix NUL byte truncation in sqlite3 TEXT column handling. (ndossche) From d0167e73e9a8d808b85b3b6aba00d16216459b1f Mon Sep 17 00:00:00 2001 From: Pratik Bhujel Date: Mon, 13 Apr 2026 17:32:23 +0545 Subject: [PATCH 05/16] ext/snmp: rename argument and variables to be more consistent and informative (#21723) --- ext/snmp/snmp.c | 137 +++++++++++++++++++++++++----------------------- 1 file changed, 71 insertions(+), 66 deletions(-) diff --git a/ext/snmp/snmp.c b/ext/snmp/snmp.c index 9b520bce902c..ecea48883d52 100644 --- a/ext/snmp/snmp.c +++ b/ext/snmp/snmp.c @@ -654,7 +654,7 @@ static void php_free_objid_query(struct objid_query *objid_query, HashTable* oid static bool php_snmp_parse_oid( zval *object, int st, struct objid_query *objid_query, zend_string *oid_str, HashTable *oid_ht, zend_string *type_str, HashTable *type_ht, zend_string *value_str, HashTable *value_ht, - uint32_t oid_argument_offset, uint32_t type_argument_offset, uint32_t value_argument_offset + uint32_t oid_arg_num, uint32_t type_arg_num, uint32_t value_arg_num ) { char *pptr; uint32_t idx_type = 0, idx_value = 0; @@ -681,7 +681,7 @@ static bool php_snmp_parse_oid( ZEND_ASSERT(type_str && value_str); if (ZSTR_LEN(type_str) != 1) { - zend_argument_value_error(type_argument_offset, "must be a single character"); + zend_argument_value_error(type_arg_num, "must be a single character"); efree(objid_query->vars); return false; } @@ -692,7 +692,7 @@ static bool php_snmp_parse_oid( objid_query->count++; } else if (oid_ht) { /* we got objid array */ if (zend_hash_num_elements(oid_ht) == 0) { - zend_argument_value_error(oid_argument_offset, "must not be empty when passed as an array"); + zend_argument_value_error(oid_arg_num, "must not be empty when passed as an array"); return false; } objid_query->vars = (snmpobjarg *)safe_emalloc(sizeof(snmpobjarg), zend_hash_num_elements(oid_ht), 0); @@ -737,14 +737,14 @@ static bool php_snmp_parse_oid( char ptype = *ZSTR_VAL(type); zend_string_release(type); if (len != 1) { - zend_argument_value_error(type_argument_offset, "must be a single character"); + zend_argument_value_error(type_arg_num, "must be a single character"); php_free_objid_query(objid_query, oid_ht, value_ht, st); return false; } objid_query->vars[objid_query->count].type = ptype; idx_type++; } else { - zend_argument_value_error(type_argument_offset, "must contain a type for object ID '%s'", ZSTR_VAL(tmp)); + zend_argument_value_error(type_arg_num, "must contain a type for object ID '%s'", ZSTR_VAL(tmp)); php_free_objid_query(objid_query, oid_ht, value_ht, st); return false; } @@ -779,7 +779,7 @@ static bool php_snmp_parse_oid( objid_query->vars[objid_query->count].value = ZSTR_VAL(tmp); idx_value++; } else { - zend_argument_value_error(value_argument_offset, "must contain a value for object ID '%s'", ZSTR_VAL(tmp)); + zend_argument_value_error(value_arg_num, "must contain a value for object ID '%s'", ZSTR_VAL(tmp)); php_free_objid_query(objid_query, oid_ht, value_ht, st); return false; } @@ -826,7 +826,7 @@ static bool php_snmp_parse_oid( /* {{{ snmp_session_init allocates memory for session and session->peername, caller should free it manually using snmp_session_free() and efree() */ -static bool snmp_session_init(php_snmp_session **session_p, int version, zend_string *hostname, zend_string *community, zend_long timeout, zend_long retries, int hostname_argument_offset, int timeout_argument_offset) +static bool snmp_session_init(php_snmp_session **session_p, int version, zend_string *hostname, zend_string *community, zend_long timeout, zend_long retries, uint32_t hostname_arg_num, uint32_t timeout_arg_num) { php_snmp_session *session; char *pptr, *host_ptr; @@ -841,23 +841,23 @@ static bool snmp_session_init(php_snmp_session **session_p, int version, zend_st ZEND_ASSERT(community != NULL); if (ZSTR_LEN(hostname) >= MAX_NAME_LEN) { - zend_argument_value_error(hostname_argument_offset, "length must be lower than %d", MAX_NAME_LEN); + zend_argument_value_error(hostname_arg_num, "length must be lower than %d", MAX_NAME_LEN); return false; } if (ZSTR_LEN(community) == 0) { - zend_argument_must_not_be_empty_error(hostname_argument_offset + 1); + zend_argument_must_not_be_empty_error(hostname_arg_num + 1); return false; } - if (timeout_argument_offset != -1) { + if (timeout_arg_num != 0) { if (timeout < -1 || timeout > LONG_MAX) { - zend_argument_value_error(timeout_argument_offset, "must be between -1 and %ld", LONG_MAX); + zend_argument_value_error(timeout_arg_num, "must be between -1 and %ld", LONG_MAX); return false; } if (retries < -1 || retries > INT_MAX) { - zend_argument_value_error(timeout_argument_offset + 1, "must be between -1 and %d", INT_MAX); + zend_argument_value_error(timeout_arg_num + 1, "must be between -1 and %d", INT_MAX); return false; } } @@ -888,14 +888,14 @@ static bool snmp_session_init(php_snmp_session **session_p, int version, zend_st char *pport = pptr + 2; tmp_port = atoi(pport); if (tmp_port < 0 || tmp_port > USHRT_MAX) { - zend_argument_value_error(hostname_argument_offset, "remote port must be between 0 and %u", USHRT_MAX); + zend_argument_value_error(hostname_arg_num, "remote port must be between 0 and %u", USHRT_MAX); return false; } remote_port = (unsigned short)tmp_port; } *pptr = '\0'; } else { - zend_argument_value_error(hostname_argument_offset, "has a malformed IPv6 address, closing square bracket missing"); + zend_argument_value_error(hostname_arg_num, "has a malformed IPv6 address, closing square bracket missing"); return false; } } else { /* IPv4 address */ @@ -903,7 +903,7 @@ static bool snmp_session_init(php_snmp_session **session_p, int version, zend_st char *pport = pptr + 1; tmp_port = atoi(pport); if (tmp_port < 0 || tmp_port > USHRT_MAX) { - zend_argument_value_error(hostname_argument_offset, "remote port must be between 0 and %u", USHRT_MAX); + zend_argument_value_error(hostname_arg_num, "remote port must be between 0 and %u", USHRT_MAX); return false; } remote_port = (unsigned short)tmp_port; @@ -1112,13 +1112,13 @@ static ZEND_ATTRIBUTE_NONNULL bool snmp_session_gen_sec_key(struct snmp_session /* }}} */ /* {{{ Set context Engine Id in the snmpv3 session */ -static bool snmp_session_set_contextEngineID(struct snmp_session *s, zend_string * contextEngineID, uint32_t contextEngineID_argument_offset) +static bool snmp_session_set_contextEngineID(struct snmp_session *s, zend_string *contextEngineID, uint32_t context_engine_id_arg_num) { size_t ebuf_len = 32, eout_len = 0; uint8_t *ebuf = (uint8_t *) emalloc(ebuf_len); if (!snmp_hex_to_binary(&ebuf, &ebuf_len, &eout_len, 1, ZSTR_VAL(contextEngineID))) { - zend_argument_value_error(contextEngineID_argument_offset, "must be a valid context engine ID"); + zend_argument_value_error(context_engine_id_arg_num, "must be a valid context engine ID"); efree(ebuf); return false; } @@ -1134,13 +1134,13 @@ static bool snmp_session_set_contextEngineID(struct snmp_session *s, zend_string /* }}} */ /* {{{ Set all snmpv3-related security options - * auth_protocol_argnum and contextEngineID_argument_offset are the userland + * auth_protocol_arg_num and context_engine_id_arg_num are the userland * argument numbers used for error reporting. */ static ZEND_ATTRIBUTE_NONNULL_ARGS(2) bool snmp_session_set_security(struct snmp_session *session, zend_string *sec_level, zend_string *auth_protocol, zend_string *auth_passphrase, zend_string *priv_protocol, zend_string *priv_passphrase, zend_string *contextName, zend_string *contextEngineID, - uint32_t auth_protocol_argnum, uint32_t contextEngineID_argument_offset) + uint32_t auth_protocol_arg_num, uint32_t context_engine_id_arg_num) { /* Setting the security level. */ @@ -1152,7 +1152,7 @@ static ZEND_ATTRIBUTE_NONNULL_ARGS(2) bool snmp_session_set_security(struct snmp if (session->securityLevel == SNMP_SEC_LEVEL_AUTHNOPRIV || session->securityLevel == SNMP_SEC_LEVEL_AUTHPRIV) { if (!auth_protocol) { - zend_argument_value_error(auth_protocol_argnum, "cannot be null when security level is \"authNoPriv\" or \"authPriv\""); + zend_argument_value_error(auth_protocol_arg_num, "cannot be null when security level is \"authNoPriv\" or \"authPriv\""); return false; } @@ -1163,7 +1163,7 @@ static ZEND_ATTRIBUTE_NONNULL_ARGS(2) bool snmp_session_set_security(struct snmp } if (!auth_passphrase) { - zend_argument_value_error(auth_protocol_argnum + 1, "cannot be null when security level is \"authNoPriv\" or \"authPriv\""); + zend_argument_value_error(auth_protocol_arg_num + 1, "cannot be null when security level is \"authNoPriv\" or \"authPriv\""); return false; } @@ -1176,7 +1176,7 @@ static ZEND_ATTRIBUTE_NONNULL_ARGS(2) bool snmp_session_set_security(struct snmp if (session->securityLevel == SNMP_SEC_LEVEL_AUTHPRIV) { if (!priv_protocol) { - zend_argument_value_error(auth_protocol_argnum + 2, "cannot be null when security level is \"authPriv\""); + zend_argument_value_error(auth_protocol_arg_num + 2, "cannot be null when security level is \"authPriv\""); return false; } @@ -1187,7 +1187,7 @@ static ZEND_ATTRIBUTE_NONNULL_ARGS(2) bool snmp_session_set_security(struct snmp } if (!priv_passphrase) { - zend_argument_value_error(auth_protocol_argnum + 3, "cannot be null when security level is \"authPriv\""); + zend_argument_value_error(auth_protocol_arg_num + 3, "cannot be null when security level is \"authPriv\""); return false; } @@ -1206,7 +1206,7 @@ static ZEND_ATTRIBUTE_NONNULL_ARGS(2) bool snmp_session_set_security(struct snmp } /* Setting contextEngineIS if specified */ - if (contextEngineID && ZSTR_LEN(contextEngineID) && !snmp_session_set_contextEngineID(session, contextEngineID, contextEngineID_argument_offset)) { + if (contextEngineID && ZSTR_LEN(contextEngineID) && !snmp_session_set_contextEngineID(session, contextEngineID, context_engine_id_arg_num)) { /* Warning message sent already, just bail out */ return false; } @@ -1226,15 +1226,17 @@ static void php_snmp(INTERNAL_FUNCTION_PARAMETERS, int st, int version) { zend_string *oid_str, *type_str = NULL, *value_str = NULL; HashTable *oid_ht, *type_ht = NULL, *value_ht = NULL; - zend_string *a1 = NULL, *a2 = NULL, *a3 = NULL, *a4 = NULL, *a5 = NULL, *a6 = NULL, *a7 = NULL; + zend_string *hostname = NULL, *community_or_security_name = NULL; + zend_string *security_level = NULL, *auth_protocol = NULL, *auth_passphrase = NULL; + zend_string *privacy_protocol = NULL, *privacy_passphrase = NULL; bool use_orignames = 0, suffix_keys = 0; zend_long timeout = SNMP_DEFAULT_TIMEOUT; zend_long retries = SNMP_DEFAULT_RETRIES; struct objid_query objid_query; php_snmp_session *session; int session_less_mode = (getThis() == NULL); - int timeout_argument_offset = -1; - uint32_t oid_argument_offset = 1, type_argument_offset = 0, value_argument_offset = 0; + uint32_t timeout_arg_num = 0; + uint32_t oid_arg_num = 1, type_arg_num = 0, value_arg_num = 0; php_snmp_object *snmp_object; php_snmp_object glob_snmp_object; @@ -1247,13 +1249,13 @@ static void php_snmp(INTERNAL_FUNCTION_PARAMETERS, int st, int version) if (version == SNMP_VERSION_3) { if (st & SNMP_CMD_SET) { ZEND_PARSE_PARAMETERS_START(10, 12) - Z_PARAM_PATH_STR(a1) - Z_PARAM_PATH_STR(a2) - Z_PARAM_STR(a3) - Z_PARAM_STR(a4) - Z_PARAM_STR(a5) - Z_PARAM_STR(a6) - Z_PARAM_STR(a7) + Z_PARAM_PATH_STR(hostname) + Z_PARAM_PATH_STR(community_or_security_name) + Z_PARAM_STR(security_level) + Z_PARAM_STR(auth_protocol) + Z_PARAM_STR(auth_passphrase) + Z_PARAM_STR(privacy_protocol) + Z_PARAM_STR(privacy_passphrase) Z_PARAM_ARRAY_HT_OR_STR(oid_ht, oid_str) Z_PARAM_ARRAY_HT_OR_STR(type_ht, type_str) Z_PARAM_ARRAY_HT_OR_STR(value_ht, value_str) @@ -1262,37 +1264,37 @@ static void php_snmp(INTERNAL_FUNCTION_PARAMETERS, int st, int version) Z_PARAM_LONG(retries) ZEND_PARSE_PARAMETERS_END(); - timeout_argument_offset = 10; - oid_argument_offset = 8; - type_argument_offset = 9; - value_argument_offset = 10; + timeout_arg_num = 10; + oid_arg_num = 8; + type_arg_num = 9; + value_arg_num = 10; } else { /* SNMP_CMD_GET * SNMP_CMD_GETNEXT * SNMP_CMD_WALK */ ZEND_PARSE_PARAMETERS_START(8, 10) - Z_PARAM_PATH_STR(a1) - Z_PARAM_PATH_STR(a2) - Z_PARAM_STR(a3) - Z_PARAM_STR(a4) - Z_PARAM_STR(a5) - Z_PARAM_STR(a6) - Z_PARAM_STR(a7) + Z_PARAM_PATH_STR(hostname) + Z_PARAM_PATH_STR(community_or_security_name) + Z_PARAM_STR(security_level) + Z_PARAM_STR(auth_protocol) + Z_PARAM_STR(auth_passphrase) + Z_PARAM_STR(privacy_protocol) + Z_PARAM_STR(privacy_passphrase) Z_PARAM_ARRAY_HT_OR_STR(oid_ht, oid_str) Z_PARAM_OPTIONAL Z_PARAM_LONG(timeout) Z_PARAM_LONG(retries) ZEND_PARSE_PARAMETERS_END(); - timeout_argument_offset = 9; - oid_argument_offset = 8; + timeout_arg_num = 9; + oid_arg_num = 8; } } else { if (st & SNMP_CMD_SET) { ZEND_PARSE_PARAMETERS_START(5, 7) - Z_PARAM_PATH_STR(a1) - Z_PARAM_PATH_STR(a2) + Z_PARAM_PATH_STR(hostname) + Z_PARAM_PATH_STR(community_or_security_name) Z_PARAM_ARRAY_HT_OR_STR(oid_ht, oid_str) Z_PARAM_ARRAY_HT_OR_STR(type_ht, type_str) Z_PARAM_ARRAY_HT_OR_STR(value_ht, value_str) @@ -1301,26 +1303,26 @@ static void php_snmp(INTERNAL_FUNCTION_PARAMETERS, int st, int version) Z_PARAM_LONG(retries) ZEND_PARSE_PARAMETERS_END(); - timeout_argument_offset = 6; - oid_argument_offset = 3; - type_argument_offset = 4; - value_argument_offset = 5; + timeout_arg_num = 6; + oid_arg_num = 3; + type_arg_num = 4; + value_arg_num = 5; } else { /* SNMP_CMD_GET * SNMP_CMD_GETNEXT * SNMP_CMD_WALK */ ZEND_PARSE_PARAMETERS_START(3, 5) - Z_PARAM_PATH_STR(a1) - Z_PARAM_PATH_STR(a2) + Z_PARAM_PATH_STR(hostname) + Z_PARAM_PATH_STR(community_or_security_name) Z_PARAM_ARRAY_HT_OR_STR(oid_ht, oid_str) Z_PARAM_OPTIONAL Z_PARAM_LONG(timeout) Z_PARAM_LONG(retries) ZEND_PARSE_PARAMETERS_END(); - timeout_argument_offset = 4; - oid_argument_offset = 3; + timeout_arg_num = 4; + oid_arg_num = 3; } } } else { @@ -1330,8 +1332,8 @@ static void php_snmp(INTERNAL_FUNCTION_PARAMETERS, int st, int version) Z_PARAM_ARRAY_HT_OR_STR(type_ht, type_str) Z_PARAM_ARRAY_HT_OR_STR(value_ht, value_str) ZEND_PARSE_PARAMETERS_END(); - type_argument_offset = 2; - value_argument_offset = 3; + type_arg_num = 2; + value_arg_num = 3; } else if (st & SNMP_CMD_WALK) { ZEND_PARSE_PARAMETERS_START(1, 4) Z_PARAM_ARRAY_HT_OR_STR(oid_ht, oid_str) @@ -1362,17 +1364,17 @@ static void php_snmp(INTERNAL_FUNCTION_PARAMETERS, int st, int version) } if (!php_snmp_parse_oid(getThis(), st, &objid_query, oid_str, oid_ht, type_str, type_ht, value_str, value_ht, - oid_argument_offset, type_argument_offset, value_argument_offset)) { + oid_arg_num, type_arg_num, value_arg_num)) { RETURN_FALSE; } if (session_less_mode) { - if (!snmp_session_init(&session, version, a1, a2, timeout, retries, 1, timeout_argument_offset)) { + if (!snmp_session_init(&session, version, hostname, community_or_security_name, timeout, retries, 1, timeout_arg_num)) { php_free_objid_query(&objid_query, oid_ht, value_ht, st); snmp_session_free(&session); RETURN_FALSE; } - if (version == SNMP_VERSION_3 && !snmp_session_set_security(session, a3, a4, a5, a6, a7, NULL, NULL, 4, 0)) { + if (version == SNMP_VERSION_3 && !snmp_session_set_security(session, security_level, auth_protocol, auth_passphrase, privacy_protocol, privacy_passphrase, NULL, NULL, 4, 0)) { php_free_objid_query(&objid_query, oid_ht, value_ht, st); snmp_session_free(&session); /* An error has already been emitted, just bail out. */ @@ -1729,7 +1731,11 @@ PHP_METHOD(SNMP, setSecurity) { php_snmp_object *snmp_object; zval *object = ZEND_THIS; - zend_string *a1 = NULL, *a2 = NULL, *a3 = NULL, *a4 = NULL, *a5 = NULL, *a6 = NULL, *a7 = NULL; + zend_string *security_level = NULL, *auth_protocol = NULL, *auth_passphrase = NULL; + zend_string *privacy_protocol = NULL, *privacy_passphrase = NULL; + zend_string *context_name = NULL, *context_engine_id = NULL; + uint32_t auth_protocol_arg_num = 2; + uint32_t context_engine_id_arg_num = 7; snmp_object = Z_SNMP_P(object); if (!snmp_object->session) { @@ -1737,12 +1743,11 @@ PHP_METHOD(SNMP, setSecurity) RETURN_THROWS(); } - if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|SSSSSS", &a1, &a2, &a3, &a4,&a5, &a6, &a7) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|SSSSSS", &security_level, &auth_protocol, &auth_passphrase, &privacy_protocol, &privacy_passphrase, &context_name, &context_engine_id) == FAILURE) { RETURN_THROWS(); } - /* authProtocol is argument #2 and contextEngineId is argument #7. */ - if (!snmp_session_set_security(snmp_object->session, a1, a2, a3, a4, a5, a6, a7, 2, 7)) { + if (!snmp_session_set_security(snmp_object->session, security_level, auth_protocol, auth_passphrase, privacy_protocol, privacy_passphrase, context_name, context_engine_id, auth_protocol_arg_num, context_engine_id_arg_num)) { /* An error has already been emitted, just bail out. */ RETURN_FALSE; } From d1670fb7e1958abe74b934470ffc01d775aa6725 Mon Sep 17 00:00:00 2001 From: "Hans Krentel (hakre)" Date: Sat, 11 Apr 2026 23:55:41 +0200 Subject: [PATCH 06/16] Add date.timezone=UTC to the INI overwrites in run-tests.php Supersedes GH-21665 Closes GH-21729 --- run-tests.php | 1 + 1 file changed, 1 insertion(+) diff --git a/run-tests.php b/run-tests.php index 195d17fa0a03..e4a4563f93fc 100755 --- a/run-tests.php +++ b/run-tests.php @@ -304,6 +304,7 @@ function main(): void 'zend.exception_ignore_args=0', 'zend.exception_string_param_max_len=15', 'short_open_tag=0', + 'date.timezone=UTC', ]; $no_file_cache = '-d opcache.file_cache= -d opcache.file_cache_only=0'; From 91b0aebae7ad16c7e0cc71deb0effe02e10d751a Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Mon, 13 Apr 2026 15:01:56 +0100 Subject: [PATCH 07/16] Remove charsets plugin (#21714) --- UPGRADING.INTERNALS | 1 + ext/mysqlnd/mysqlnd_charset.c | 34 ---------------------------------- ext/mysqlnd/mysqlnd_charset.h | 14 -------------- 3 files changed, 1 insertion(+), 48 deletions(-) diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS index 5da8d205be74..3a24fcce4772 100644 --- a/UPGRADING.INTERNALS +++ b/UPGRADING.INTERNALS @@ -133,6 +133,7 @@ PHP 8.6 INTERNALS UPGRADE NOTES . Dropped session_options parameter from all methods in mysqlnd_auth. The same information is present in conn->options and should be used instead. + . Removed charsets plugin. - ext/session: . php_session_flush() now returns a bool rather than a zend_result. diff --git a/ext/mysqlnd/mysqlnd_charset.c b/ext/mysqlnd/mysqlnd_charset.c index b9ba0577c84a..eacf74240fd1 100644 --- a/ext/mysqlnd/mysqlnd_charset.c +++ b/ext/mysqlnd/mysqlnd_charset.c @@ -967,40 +967,6 @@ PHPAPI zend_ulong mysqlnd_cset_escape_slashes(const MYSQLND_CHARSET * const cset /* }}} */ -static struct st_mysqlnd_plugin_charsets mysqlnd_plugin_charsets_plugin = -{ - { - MYSQLND_PLUGIN_API_VERSION, - "charsets", - MYSQLND_VERSION_ID, - PHP_MYSQLND_VERSION, - "Modified BSD License (BSD-3-Clause)", - "Andrey Hristov , Ulf Wendel , Georg Richter ", - { - NULL, /* no statistics , will be filled later if there are some */ - NULL, /* no statistics */ - }, - { - NULL /* plugin shutdown */ - } - }, - {/* methods */ - mysqlnd_find_charset_nr, - mysqlnd_find_charset_name, - mysqlnd_cset_escape_quotes, - mysqlnd_cset_escape_slashes - } -}; - - -/* {{{ mysqlnd_charsets_plugin_register */ -void -mysqlnd_charsets_plugin_register(void) -{ - mysqlnd_plugin_register_ex((struct st_mysqlnd_plugin_header *) &mysqlnd_plugin_charsets_plugin); -} -/* }}} */ - #if MYSQLND_CHARSETS_SANITY_CHECK void mysqlnd_charsets_sanity_check(void) { diff --git a/ext/mysqlnd/mysqlnd_charset.h b/ext/mysqlnd/mysqlnd_charset.h index 401d6d98cec8..d5e621e38eb1 100644 --- a/ext/mysqlnd/mysqlnd_charset.h +++ b/ext/mysqlnd/mysqlnd_charset.h @@ -26,18 +26,4 @@ PHPAPI zend_ulong mysqlnd_cset_escape_quotes(const MYSQLND_CHARSET * const chars PHPAPI zend_ulong mysqlnd_cset_escape_slashes(const MYSQLND_CHARSET * const cset, char * newstr, const char * escapestr, const size_t escapestr_len); -struct st_mysqlnd_plugin_charsets -{ - const struct st_mysqlnd_plugin_header plugin_header; - struct - { - const MYSQLND_CHARSET * (*const find_charset_by_nr)(unsigned int charsetnr); - const MYSQLND_CHARSET * (*const find_charset_by_name)(const char * const name); - zend_ulong (*const escape_quotes)(const MYSQLND_CHARSET * const cset, char * newstr, const char * escapestr, const size_t escapestr_len); - zend_ulong (*const escape_slashes)(const MYSQLND_CHARSET * const cset, char * newstr, const char * escapestr, const size_t escapestr_len); - } methods; -}; - -void mysqlnd_charsets_plugin_register(void); - #endif /* MYSQLND_CHARSET_H */ From 9b6f83e1bb61c226bc4dc5a2c35b83ba563f8343 Mon Sep 17 00:00:00 2001 From: Calvin Buckley Date: Mon, 13 Apr 2026 12:44:04 -0400 Subject: [PATCH 08/16] ext/pdo_odbc: Require non-empty string when building string buffer (#21652) A buggy driver could do this and get PDO_ODBC stuck in this loop. Require a non-empty string, so an empty one breaks like the SQL_NO_DATA case. Fixes GH-21534 --- ext/pdo_odbc/odbc_stmt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/pdo_odbc/odbc_stmt.c b/ext/pdo_odbc/odbc_stmt.c index ea9d5c788f57..c114f721a7a7 100644 --- a/ext/pdo_odbc/odbc_stmt.c +++ b/ext/pdo_odbc/odbc_stmt.c @@ -710,7 +710,7 @@ static int odbc_stmt_get_col(pdo_stmt_t *stmt, int colno, zval *result, enum pdo str = zend_string_realloc(str, used + 256, 0); memcpy(ZSTR_VAL(str) + used, buf2, 256); used = used + 255; - } else if (rc==SQL_SUCCESS) { + } else if (rc == SQL_SUCCESS && C->fetched_len != 0) { str = zend_string_realloc(str, used + C->fetched_len, 0); memcpy(ZSTR_VAL(str) + used, buf2, C->fetched_len); used = used + C->fetched_len; From 9d30bd57251147c3af70fe6ee6001558bef6bc10 Mon Sep 17 00:00:00 2001 From: Calvin Buckley Date: Mon, 13 Apr 2026 12:48:24 -0400 Subject: [PATCH 09/16] Finish deprecation of $row < 1 (#21053) odbc_fetch_row was changed to have $row be nullable and null by default instead of using 0, but still accepted 0 due to old code being explicit. Use ValueError for non-null $row < 1 instead. --- ext/odbc/php_odbc.c | 11 +++++------ ext/odbc/tests/odbc_fetch_array_001.phpt | 2 +- ext/odbc/tests/odbc_fetch_into_001.phpt | 2 +- ext/odbc/tests/odbc_fetch_object_001.phpt | 2 +- ext/odbc/tests/odbc_fetch_row_001.phpt | 11 +++++++---- 5 files changed, 15 insertions(+), 13 deletions(-) diff --git a/ext/odbc/php_odbc.c b/ext/odbc/php_odbc.c index 96e1b8796140..95c872c293f1 100644 --- a/ext/odbc/php_odbc.c +++ b/ext/odbc/php_odbc.c @@ -1340,12 +1340,11 @@ static void php_odbc_fetch(INTERNAL_FUNCTION_PARAMETERS, bool return_array, php_ result = Z_ODBC_RESULT_P(pv_res); CHECK_ODBC_RESULT(result); - /* TODO deprecate $row argument values less than 1 after PHP 8.4 - * for functions other than odbc_fetch_row (see GH-13910) - */ - if (!result_type && !pv_row_is_null && pv_row < 1) { - php_error_docref(NULL, E_WARNING, "Argument #3 ($row) must be greater than or equal to 1"); - RETURN_FALSE; + if (!pv_row_is_null && pv_row < 1) { + /* row arg no differs between callers */ + zend_argument_value_error(pv_res_arr == return_value ? 2 : 3, + "must be greater than or equal to 1"); + RETURN_THROWS(); } if (result->numcols == 0) { diff --git a/ext/odbc/tests/odbc_fetch_array_001.phpt b/ext/odbc/tests/odbc_fetch_array_001.phpt index bf13ed25e4d6..e7d4ccf328b6 100644 --- a/ext/odbc/tests/odbc_fetch_array_001.phpt +++ b/ext/odbc/tests/odbc_fetch_array_001.phpt @@ -17,7 +17,7 @@ odbc_exec($conn, 'INSERT INTO fetch_array VALUES (1), (2)'); $res = odbc_exec($conn, 'SELECT * FROM fetch_array'); var_dump(odbc_fetch_array($res)); -var_dump(odbc_fetch_array($res, 0)); +var_dump(odbc_fetch_array($res, null)); var_dump(odbc_fetch_array($res, 2)); var_dump(odbc_fetch_array($res, 4)); diff --git a/ext/odbc/tests/odbc_fetch_into_001.phpt b/ext/odbc/tests/odbc_fetch_into_001.phpt index 19f7f79268c5..e420475f02cc 100644 --- a/ext/odbc/tests/odbc_fetch_into_001.phpt +++ b/ext/odbc/tests/odbc_fetch_into_001.phpt @@ -20,7 +20,7 @@ $arr = []; var_dump(odbc_fetch_into($res, $arr)); var_dump($arr); $arr = []; -var_dump(odbc_fetch_into($res, $arr, 0)); +var_dump(odbc_fetch_into($res, $arr, null)); var_dump($arr); $arr = []; var_dump(odbc_fetch_into($res, $arr, 2)); diff --git a/ext/odbc/tests/odbc_fetch_object_001.phpt b/ext/odbc/tests/odbc_fetch_object_001.phpt index 62a8fc3b2c7e..eb553409639f 100644 --- a/ext/odbc/tests/odbc_fetch_object_001.phpt +++ b/ext/odbc/tests/odbc_fetch_object_001.phpt @@ -17,7 +17,7 @@ odbc_exec($conn, 'INSERT INTO fetch_object VALUES (1), (2)'); $res = odbc_exec($conn, 'SELECT * FROM fetch_object'); var_dump(odbc_fetch_object($res)); -var_dump(odbc_fetch_object($res, 0)); +var_dump(odbc_fetch_object($res, null)); var_dump(odbc_fetch_object($res, 2)); var_dump(odbc_fetch_object($res, 4)); diff --git a/ext/odbc/tests/odbc_fetch_row_001.phpt b/ext/odbc/tests/odbc_fetch_row_001.phpt index 576bb15414ce..fbadc8272590 100644 --- a/ext/odbc/tests/odbc_fetch_row_001.phpt +++ b/ext/odbc/tests/odbc_fetch_row_001.phpt @@ -17,7 +17,11 @@ odbc_exec($conn, 'INSERT INTO fetch_row VALUES (1), (2)'); $res = odbc_exec($conn, 'SELECT * FROM fetch_row'); -var_dump(odbc_fetch_row($res, 0)); +try { + var_dump(odbc_fetch_row($res, 0)); +} catch (\ValueError $e) { + echo $e->getMessage() . \PHP_EOL; +} var_dump(odbc_fetch_row($res, null)); var_dump(odbc_result($res, 'test')); @@ -39,9 +43,8 @@ require 'config.inc'; $conn = odbc_connect($dsn, $user, $pass); odbc_exec($conn, 'DROP TABLE fetch_row'); ?> ---EXPECTF-- -Warning: odbc_fetch_row(): Argument #3 ($row) must be greater than or equal to 1 in %s on line %d -bool(false) +--EXPECT-- +odbc_fetch_row(): Argument #2 ($row) must be greater than or equal to 1 bool(true) string(1) "1" bool(true) From 72c12ea01a404085fd637d2f750dee38be42c3d3 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Mon, 13 Apr 2026 05:53:49 +0100 Subject: [PATCH 10/16] Add myself to DOM/XML/SOAP/SimpleXML/XMLReader/Writer and XSL. close GH-21741 --- .github/CODEOWNERS | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 3b6d79ae8a4e..91f207e0c66c 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -20,11 +20,13 @@ /ext/curl @adoy /ext/date @derickr /ext/dba @Girgias +/ext/dom @devnexen /ext/ffi @dstogov /ext/gd @devnexen /ext/gettext @devnexen /ext/gmp @Girgias /ext/intl @devnexen +/ext/libxml @devnexen /ext/json @bukka /ext/mbstring @alexdowad @youkidearitai /ext/mysqli @bukka @kamil-tekiela @@ -44,9 +46,15 @@ /ext/random @TimWolla @zeriyoshi /ext/reflection @DanielEScherzer /ext/session @Girgias +/ext/simplexml @devnexen +/ext/soap @devnexen /ext/sockets @devnexen /ext/spl @Girgias /ext/standard @bukka +/ext/xml @devnexen +/ext/xmlreader @devnexen +/ext/xmlwriter @devnexen +/ext/xsl @devnexen /main @bukka /sapi/fpm @bukka /Zend/Optimizer @dstogov From ebb6e4f5f8d6e10c853b533da423eaf86e0e7a1d Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Thu, 2 Apr 2026 17:09:36 +0100 Subject: [PATCH 11/16] Zend/zend_execute.c: add const qualifiers --- Zend/zend_execute.c | 82 +++++++++++++++++++++++++++------------------ Zend/zend_execute.h | 6 ++-- 2 files changed, 52 insertions(+), 36 deletions(-) diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index a4871bc3bebd..8b688c4adc7b 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -646,7 +646,7 @@ static zend_never_inline ZEND_COLD void zend_throw_access_uninit_prop_by_ref_err } /* this should modify object only if it's empty */ -static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_throw_non_object_error(const zval *object, zval *property OPLINE_DC EXECUTE_DATA_DC) +static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_throw_non_object_error(const zval *object, const zval *property OPLINE_DC EXECUTE_DATA_DC) { zend_string *tmp_property_name; zend_string *property_name = zval_get_tmp_string(property, &tmp_property_name); @@ -1709,7 +1709,7 @@ static zend_never_inline void zend_binary_assign_op_typed_prop(const zend_proper } } -static zend_never_inline zend_long zend_check_string_offset(zval *dim, int type EXECUTE_DATA_DC) +static zend_never_inline zend_long zend_check_string_offset(const zval *dim, int type EXECUTE_DATA_DC) { zend_long offset; @@ -2184,7 +2184,7 @@ static zend_property_info *zend_get_prop_not_accepting_double(zend_reference *re return NULL; } -static ZEND_COLD zend_long zend_throw_incdec_ref_error(zend_property_info *error_prop OPLINE_DC) +static ZEND_COLD zend_long zend_throw_incdec_ref_error(const zend_property_info *error_prop OPLINE_DC) { zend_string *type_str = zend_type_to_string(error_prop->type); if (ZEND_IS_INCREMENT(opline->opcode)) { @@ -2206,7 +2206,7 @@ static ZEND_COLD zend_long zend_throw_incdec_ref_error(zend_property_info *error } } -static ZEND_COLD zend_long zend_throw_incdec_prop_error(zend_property_info *prop OPLINE_DC) { +static ZEND_COLD zend_long zend_throw_incdec_prop_error(const zend_property_info *prop OPLINE_DC) { zend_string *type_str = zend_type_to_string(prop->type); if (ZEND_IS_INCREMENT(opline->opcode)) { zend_type_error("Cannot increment property %s::$%s of type %s past its maximal value", @@ -2257,7 +2257,7 @@ static void zend_incdec_typed_ref(zend_reference *ref, zval *copy OPLINE_DC EXEC } } -static void zend_incdec_typed_prop(zend_property_info *prop_info, zval *var_ptr, zval *copy OPLINE_DC EXECUTE_DATA_DC) +static void zend_incdec_typed_prop(const zend_property_info *prop_info, zval *var_ptr, zval *copy OPLINE_DC EXECUTE_DATA_DC) { zval tmp; @@ -2287,7 +2287,7 @@ static void zend_incdec_typed_prop(zend_property_info *prop_info, zval *var_ptr, } } -static void zend_pre_incdec_property_zval(zval *prop, zend_property_info *prop_info OPLINE_DC EXECUTE_DATA_DC) +static void zend_pre_incdec_property_zval(zval *prop, const zend_property_info *prop_info OPLINE_DC EXECUTE_DATA_DC) { if (EXPECTED(Z_TYPE_P(prop) == IS_LONG)) { if (ZEND_IS_INCREMENT(opline->opcode)) { @@ -2325,7 +2325,7 @@ static void zend_pre_incdec_property_zval(zval *prop, zend_property_info *prop_i } } -static void zend_post_incdec_property_zval(zval *prop, zend_property_info *prop_info OPLINE_DC EXECUTE_DATA_DC) +static void zend_post_incdec_property_zval(zval *prop, const zend_property_info *prop_info OPLINE_DC EXECUTE_DATA_DC) { if (EXPECTED(Z_TYPE_P(prop) == IS_LONG)) { ZVAL_LONG(EX_VAR(opline->result.var), Z_LVAL_P(prop)); @@ -2553,7 +2553,7 @@ ZEND_API zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_undefined_method(co zend_throw_error(NULL, "Call to undefined method %s::%s()", ZSTR_VAL(ce->name), ZSTR_VAL(method)); } -static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_invalid_method_call(zval *object, zval *function_name) +static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_invalid_method_call(const zval *object, const zval *function_name) { zend_throw_error(NULL, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_zval_value_name(object)); @@ -2617,7 +2617,7 @@ ZEND_API zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_call_stack_size_err } #endif /* ZEND_CHECK_STACK_LIMIT */ -static ZEND_COLD void zend_binary_assign_op_dim_slow(zval *container, zval *dim OPLINE_DC EXECUTE_DATA_DC) +static ZEND_COLD void zend_binary_assign_op_dim_slow(const zval *container, const zval *dim OPLINE_DC EXECUTE_DATA_DC) { if (UNEXPECTED(Z_TYPE_P(container) == IS_STRING)) { if (opline->op2_type == IS_UNUSED) { @@ -3051,7 +3051,7 @@ static zend_never_inline void ZEND_FASTCALL zend_fetch_dimension_address_UNSET(z zend_fetch_dimension_address(result, container_ptr, dim, dim_type, BP_VAR_UNSET EXECUTE_DATA_CC); } -static zend_always_inline void zend_fetch_dimension_address_read(zval *result, zval *container, zval *dim, int dim_type, int type, bool is_list, bool slow EXECUTE_DATA_DC) +static zend_always_inline void zend_fetch_dimension_address_read(zval *result, const zval *container, zval *dim, int dim_type, int type, bool is_list, bool slow EXECUTE_DATA_DC) { zval *retval; @@ -3205,36 +3205,36 @@ static zend_always_inline void zend_fetch_dimension_address_read(zval *result, z } } -static zend_never_inline void ZEND_FASTCALL zend_fetch_dimension_address_read_R(zval *container, zval *dim, int dim_type OPLINE_DC EXECUTE_DATA_DC) +static zend_never_inline void ZEND_FASTCALL zend_fetch_dimension_address_read_R(const zval *container, zval *dim, int dim_type OPLINE_DC EXECUTE_DATA_DC) { zval *result = EX_VAR(opline->result.var); zend_fetch_dimension_address_read(result, container, dim, dim_type, BP_VAR_R, 0, 0 EXECUTE_DATA_CC); } -static zend_never_inline void zend_fetch_dimension_address_read_R_slow(zval *container, zval *dim OPLINE_DC EXECUTE_DATA_DC) +static zend_never_inline void zend_fetch_dimension_address_read_R_slow(const zval *container, zval *dim OPLINE_DC EXECUTE_DATA_DC) { zval *result = EX_VAR(opline->result.var); zend_fetch_dimension_address_read(result, container, dim, IS_CV, BP_VAR_R, 0, 1 EXECUTE_DATA_CC); } -static zend_never_inline void ZEND_FASTCALL zend_fetch_dimension_address_read_IS(zval *container, zval *dim, int dim_type OPLINE_DC EXECUTE_DATA_DC) +static zend_never_inline void ZEND_FASTCALL zend_fetch_dimension_address_read_IS(const zval *container, zval *dim, int dim_type OPLINE_DC EXECUTE_DATA_DC) { zval *result = EX_VAR(opline->result.var); zend_fetch_dimension_address_read(result, container, dim, dim_type, BP_VAR_IS, 0, 0 EXECUTE_DATA_CC); } -static zend_never_inline void ZEND_FASTCALL zend_fetch_dimension_address_LIST_r(zval *container, zval *dim, int dim_type OPLINE_DC EXECUTE_DATA_DC) +static zend_never_inline void ZEND_FASTCALL zend_fetch_dimension_address_LIST_r(const zval *container, zval *dim, int dim_type OPLINE_DC EXECUTE_DATA_DC) { zval *result = EX_VAR(opline->result.var); zend_fetch_dimension_address_read(result, container, dim, dim_type, BP_VAR_R, 1, 0 EXECUTE_DATA_CC); } -ZEND_API void zend_fetch_dimension_const(zval *result, zval *container, zval *dim, int type) +ZEND_API void zend_fetch_dimension_const(zval *result, const zval *container, zval *dim, int type) { zend_fetch_dimension_address_read(result, container, dim, IS_TMP_VAR, type, 0, 0 NO_EXECUTE_DATA_CC); } -static zend_never_inline zval* ZEND_FASTCALL zend_find_array_dim_slow(HashTable *ht, zval *offset EXECUTE_DATA_DC) +static zend_never_inline zval* ZEND_FASTCALL zend_find_array_dim_slow(HashTable *ht, const zval *offset EXECUTE_DATA_DC) { zend_ulong hval; @@ -3289,7 +3289,7 @@ static zend_never_inline zval* ZEND_FASTCALL zend_find_array_dim_slow(HashTable } } -static zend_never_inline bool ZEND_FASTCALL zend_isset_dim_slow(zval *container, zval *offset EXECUTE_DATA_DC) +static zend_never_inline bool ZEND_FASTCALL zend_isset_dim_slow(const zval *container, zval *offset EXECUTE_DATA_DC) { if (/*OP2_TYPE == IS_CV &&*/ UNEXPECTED(Z_TYPE_P(offset) == IS_UNDEF)) { offset = ZVAL_UNDEFINED_OP2(); @@ -3328,7 +3328,7 @@ static zend_never_inline bool ZEND_FASTCALL zend_isset_dim_slow(zval *container, } } -static zend_never_inline bool ZEND_FASTCALL zend_isempty_dim_slow(zval *container, zval *offset EXECUTE_DATA_DC) +static zend_never_inline bool ZEND_FASTCALL zend_isempty_dim_slow(const zval *container, zval *offset EXECUTE_DATA_DC) { if (/*OP2_TYPE == IS_CV &&*/ UNEXPECTED(Z_TYPE_P(offset) == IS_UNDEF)) { offset = ZVAL_UNDEFINED_OP2(); @@ -3367,7 +3367,7 @@ static zend_never_inline bool ZEND_FASTCALL zend_isempty_dim_slow(zval *containe } } -static zend_never_inline bool ZEND_FASTCALL zend_array_key_exists_fast(HashTable *ht, zval *key OPLINE_DC EXECUTE_DATA_DC) +static zend_never_inline bool ZEND_FASTCALL zend_array_key_exists_fast(HashTable *ht, const zval *key OPLINE_DC EXECUTE_DATA_DC) { zend_string *str; zend_ulong hval; @@ -3426,7 +3426,7 @@ static zend_never_inline bool ZEND_FASTCALL zend_array_key_exists_fast(HashTable } static ZEND_COLD void ZEND_FASTCALL zend_array_key_exists_error( - zval *subject, zval *key OPLINE_DC EXECUTE_DATA_DC) + const zval *subject, const zval *key OPLINE_DC EXECUTE_DATA_DC) { if (Z_TYPE_P(key) == IS_UNDEF) { ZVAL_UNDEFINED_OP1(); @@ -3440,7 +3440,7 @@ static ZEND_COLD void ZEND_FASTCALL zend_array_key_exists_error( } } -static zend_always_inline bool promotes_to_array(zval *val) { +static zend_always_inline bool promotes_to_array(const zval *val) { return Z_TYPE_P(val) <= IS_FALSE || (Z_ISREF_P(val) && Z_TYPE_P(Z_REFVAL_P(val)) <= IS_FALSE); } @@ -3504,8 +3504,18 @@ static zend_never_inline bool zend_handle_fetch_obj_flags( return 1; } -static zend_always_inline void zend_fetch_property_address(zval *result, zval *container, uint32_t container_op_type, zval *prop_ptr, uint32_t prop_op_type, void **cache_slot, int type, uint32_t flags, zend_property_info **prop_info_p OPLINE_DC EXECUTE_DATA_DC) -{ +static zend_always_inline void zend_fetch_property_address( + zval *result, + const zval *container, + uint32_t container_op_type, + const zval *prop_ptr, + uint32_t prop_op_type, + void **cache_slot, + int type, + uint32_t flags, + zend_property_info **prop_info_p + OPLINE_DC EXECUTE_DATA_DC +) { zval *ptr; zend_object *zobj; zend_string *name, *tmp_name; @@ -3650,8 +3660,14 @@ static zend_always_inline void zend_fetch_property_address(zval *result, zval *c } } -static zend_always_inline void zend_assign_to_property_reference(zval *container, uint32_t container_op_type, zval *prop_ptr, uint32_t prop_op_type, zval *value_ptr OPLINE_DC EXECUTE_DATA_DC) -{ +static zend_always_inline void zend_assign_to_property_reference( + const zval *container, + uint32_t container_op_type, + const zval *prop_ptr, + uint32_t prop_op_type, + zval *value_ptr + OPLINE_DC EXECUTE_DATA_DC +) { zval variable, *variable_ptr = &variable; void **cache_addr = (prop_op_type == IS_CONST) ? CACHE_ADDR(opline->extended_value & ~ZEND_RETURNS_FUNCTION) : NULL; zend_refcounted *garbage = NULL; @@ -3689,25 +3705,25 @@ static zend_always_inline void zend_assign_to_property_reference(zval *container } } -static zend_never_inline void zend_assign_to_property_reference_this_const(zval *container, zval *prop_ptr, zval *value_ptr OPLINE_DC EXECUTE_DATA_DC) +static zend_never_inline void zend_assign_to_property_reference_this_const(const zval *container, const zval *prop_ptr, zval *value_ptr OPLINE_DC EXECUTE_DATA_DC) { zend_assign_to_property_reference(container, IS_UNUSED, prop_ptr, IS_CONST, value_ptr OPLINE_CC EXECUTE_DATA_CC); } -static zend_never_inline void zend_assign_to_property_reference_var_const(zval *container, zval *prop_ptr, zval *value_ptr OPLINE_DC EXECUTE_DATA_DC) +static zend_never_inline void zend_assign_to_property_reference_var_const(const zval *container, const zval *prop_ptr, zval *value_ptr OPLINE_DC EXECUTE_DATA_DC) { zend_assign_to_property_reference(container, IS_VAR, prop_ptr, IS_CONST, value_ptr OPLINE_CC EXECUTE_DATA_CC); } -static zend_never_inline void zend_assign_to_property_reference_this_var(zval *container, zval *prop_ptr, zval *value_ptr OPLINE_DC EXECUTE_DATA_DC) +static zend_never_inline void zend_assign_to_property_reference_this_var(const zval *container, const zval *prop_ptr, zval *value_ptr OPLINE_DC EXECUTE_DATA_DC) { zend_assign_to_property_reference(container, IS_UNUSED, prop_ptr, IS_VAR, value_ptr OPLINE_CC EXECUTE_DATA_CC); } -static zend_never_inline void zend_assign_to_property_reference_var_var(zval *container, zval *prop_ptr, zval *value_ptr OPLINE_DC EXECUTE_DATA_DC) +static zend_never_inline void zend_assign_to_property_reference_var_var(const zval *container, const zval *prop_ptr, zval *value_ptr OPLINE_DC EXECUTE_DATA_DC) { zend_assign_to_property_reference(container, IS_VAR, prop_ptr, IS_VAR, value_ptr OPLINE_CC EXECUTE_DATA_CC); @@ -4480,7 +4496,7 @@ ZEND_API zend_function * ZEND_FASTCALL zend_fetch_function(zend_string *name) /* ZEND_API zend_function * ZEND_FASTCALL zend_fetch_function_str(const char *name, size_t len) /* {{{ */ { - zval *zv = zend_hash_str_find(EG(function_table), name, len); + const zval *zv = zend_hash_str_find(EG(function_table), name, len); if (EXPECTED(zv != NULL)) { zend_function *fbc = Z_FUNC_P(zv); @@ -4904,7 +4920,7 @@ static void cleanup_live_vars(zend_execute_data *execute_data, uint32_t op_num, /* Handle the split range for loop vars */ if (catch_op_num) { - zend_op *final_op = EX(func)->op_array.opcodes + range->end; + const zend_op *final_op = EX(func)->op_array.opcodes + range->end; if (final_op->extended_value & ZEND_FREE_ON_RETURN && (final_op->opcode == ZEND_FE_FREE || final_op->opcode == ZEND_FREE)) { if (catch_op_num < range->end + final_op->op2.num) { continue; @@ -5192,7 +5208,7 @@ static zend_never_inline zend_execute_data *zend_init_dynamic_call_object(zend_o } /* }}} */ -static zend_never_inline zend_execute_data *zend_init_dynamic_call_array(zend_array *function, uint32_t num_args) /* {{{ */ +static zend_never_inline zend_execute_data *zend_init_dynamic_call_array(const zend_array *function, uint32_t num_args) /* {{{ */ { zend_function *fbc; void *object_or_called_scope; @@ -5283,7 +5299,7 @@ static zend_never_inline zend_execute_data *zend_init_dynamic_call_array(zend_ar #define ZEND_FAKE_OP_ARRAY ((zend_op_array*)(intptr_t)-1) -static zend_never_inline zend_op_array* ZEND_FASTCALL zend_include_or_eval(zval *inc_filename_zv, int type) /* {{{ */ +static zend_never_inline zend_op_array* ZEND_FASTCALL zend_include_or_eval(const zval *inc_filename_zv, int type) /* {{{ */ { zend_op_array *new_op_array = NULL; zend_string *tmp_inc_filename; diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index cb2c9e144801..92ce8a0dcbb2 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -134,7 +134,7 @@ ZEND_API void ZEND_FASTCALL zend_ref_del_type_source(zend_property_info_source_l ZEND_API zval* zend_assign_to_typed_ref(zval *variable_ptr, zval *value, uint8_t value_type, bool strict); ZEND_API zval* zend_assign_to_typed_ref_ex(zval *variable_ptr, zval *value, uint8_t value_type, bool strict, zend_refcounted **garbage_ptr); -static zend_always_inline void zend_copy_to_variable(zval *variable_ptr, zval *value, uint8_t value_type) +static zend_always_inline void zend_copy_to_variable(zval *variable_ptr, const zval *value, uint8_t value_type) { zend_refcounted *ref = NULL; @@ -210,7 +210,7 @@ static zend_always_inline zval* zend_assign_to_variable_ex(zval *variable_ptr, z return variable_ptr; } -static zend_always_inline void zend_safe_assign_to_variable_noref(zval *variable_ptr, zval *value) { +static zend_always_inline void zend_safe_assign_to_variable_noref(zval *variable_ptr, const zval *value) { if (Z_REFCOUNTED_P(variable_ptr)) { ZEND_ASSERT(Z_TYPE_P(variable_ptr) != IS_REFERENCE); zend_refcounted *ref = Z_COUNTED_P(variable_ptr); @@ -484,7 +484,7 @@ ZEND_API zend_function * ZEND_FASTCALL zend_fetch_function(zend_string *name); ZEND_API zend_function * ZEND_FASTCALL zend_fetch_function_str(const char *name, size_t len); ZEND_API void ZEND_FASTCALL zend_init_func_run_time_cache(zend_op_array *op_array); -ZEND_API void zend_fetch_dimension_const(zval *result, zval *container, zval *dim, int type); +ZEND_API void zend_fetch_dimension_const(zval *result, const zval *container, zval *dim, int type); ZEND_API zval* zend_get_compiled_variable_value(const zend_execute_data *execute_data_ptr, uint32_t var); From f4db0d08bfbb741e7da1dd719b4b1301aea400b7 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Mon, 6 Apr 2026 18:32:24 +0100 Subject: [PATCH 12/16] Zend/zend_execute.c: use zend_never_inline ZEND_COLD rather than ZEND_COLD zend_never_inline to align the coding style with the rest of the file --- Zend/zend_execute.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 8b688c4adc7b..fb9c1587e7b4 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -835,7 +835,7 @@ ZEND_API bool zend_verify_scalar_type_hint(uint32_t type_mask, zval *arg, bool s return zend_verify_weak_scalar_type_hint(type_mask, arg); } -ZEND_COLD zend_never_inline void zend_verify_class_constant_type_error(const zend_class_constant *c, const zend_string *name, const zval *constant) +zend_never_inline ZEND_COLD void zend_verify_class_constant_type_error(const zend_class_constant *c, const zend_string *name, const zval *constant) { zend_string *type_str = zend_type_to_string(c->type); @@ -845,7 +845,7 @@ ZEND_COLD zend_never_inline void zend_verify_class_constant_type_error(const zen zend_string_release(type_str); } -ZEND_COLD zend_never_inline void zend_verify_property_type_error(const zend_property_info *info, const zval *property) +zend_never_inline ZEND_COLD void zend_verify_property_type_error(const zend_property_info *info, const zval *property) { zend_string *type_str; @@ -863,7 +863,7 @@ ZEND_COLD zend_never_inline void zend_verify_property_type_error(const zend_prop zend_string_release(type_str); } -ZEND_COLD zend_never_inline void zend_magic_get_property_type_inconsistency_error(const zend_property_info *info, const zval *property) +zend_never_inline ZEND_COLD void zend_magic_get_property_type_inconsistency_error(const zend_property_info *info, const zval *property) { /* we _may_ land here in case reading already errored and runtime cache thus has not been updated (i.e. it contains a valid but unrelated info) */ if (EG(exception)) { From 933ae15c0a9e1968aaa258f5c4f2832008ec17bb Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Thu, 2 Apr 2026 17:14:44 +0100 Subject: [PATCH 13/16] Zend/zend_execute.c: mark some error functions as static Those are never used outside of zend_execute.c so no reason to export them in a header --- Zend/zend_execute.c | 8 ++++---- Zend/zend_execute.h | 3 --- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index fb9c1587e7b4..c575fc4c738c 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -835,7 +835,7 @@ ZEND_API bool zend_verify_scalar_type_hint(uint32_t type_mask, zval *arg, bool s return zend_verify_weak_scalar_type_hint(type_mask, arg); } -zend_never_inline ZEND_COLD void zend_verify_class_constant_type_error(const zend_class_constant *c, const zend_string *name, const zval *constant) +static zend_never_inline ZEND_COLD void zend_verify_class_constant_type_error(const zend_class_constant *c, const zend_string *name, const zval *constant) { zend_string *type_str = zend_type_to_string(c->type); @@ -845,7 +845,7 @@ zend_never_inline ZEND_COLD void zend_verify_class_constant_type_error(const zen zend_string_release(type_str); } -zend_never_inline ZEND_COLD void zend_verify_property_type_error(const zend_property_info *info, const zval *property) +static zend_never_inline ZEND_COLD void zend_verify_property_type_error(const zend_property_info *info, const zval *property) { zend_string *type_str; @@ -863,7 +863,7 @@ zend_never_inline ZEND_COLD void zend_verify_property_type_error(const zend_prop zend_string_release(type_str); } -zend_never_inline ZEND_COLD void zend_magic_get_property_type_inconsistency_error(const zend_property_info *info, const zval *property) +static zend_never_inline ZEND_COLD void zend_magic_get_property_type_inconsistency_error(const zend_property_info *info, const zval *property) { /* we _may_ land here in case reading already errored and runtime cache thus has not been updated (i.e. it contains a valid but unrelated info) */ if (EG(exception)) { @@ -3921,7 +3921,7 @@ ZEND_API ZEND_COLD void zend_throw_ref_type_error_zval(const zend_property_info zend_string_release(type_str); } -ZEND_API ZEND_COLD void zend_throw_conflicting_coercion_error(const zend_property_info *prop1, const zend_property_info *prop2, const zval *zv) { +static ZEND_COLD void zend_throw_conflicting_coercion_error(const zend_property_info *prop1, const zend_property_info *prop2, const zval *zv) { zend_string *type1_str = zend_type_to_string(prop1->type); zend_string *type2_str = zend_type_to_string(prop2->type); zend_type_error("Cannot assign %s to reference held by property %s::$%s of type %s and property %s::$%s of type %s, as this would result in an inconsistent type conversion", diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index 92ce8a0dcbb2..c724ac78e1f3 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -585,11 +585,8 @@ ZEND_API zend_result ZEND_FASTCALL zend_handle_undef_args(zend_execute_data *cal ZEND_API bool zend_verify_class_constant_type(const zend_class_constant *c, const zend_string *name, zval *constant); -ZEND_COLD void zend_verify_class_constant_type_error(const zend_class_constant *c, const zend_string *name, const zval *constant); ZEND_API bool zend_verify_property_type(const zend_property_info *info, zval *property, bool strict); -ZEND_COLD void zend_verify_property_type_error(const zend_property_info *info, const zval *property); -ZEND_COLD void zend_magic_get_property_type_inconsistency_error(const zend_property_info *info, const zval *property); #define ZEND_REF_ADD_TYPE_SOURCE(ref, source) \ zend_ref_add_type_source(&ZEND_REF_TYPE_SOURCES(ref), source) From 6b159ca83cfd5cb09726925cd7d6c10179034726 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Thu, 2 Apr 2026 17:11:35 +0100 Subject: [PATCH 14/16] Zend/zend_execute.c: mark error functions as zend_never_inline For consistency with other functions --- Zend/zend_execute.c | 48 ++++++++++++++++++++++----------------------- Zend/zend_execute.h | 34 ++++++++++++++++---------------- 2 files changed, 41 insertions(+), 41 deletions(-) diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index c575fc4c738c..21d2280d48fe 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -604,7 +604,7 @@ static zend_never_inline ZEND_COLD zval *zend_wrong_assign_to_variable_reference return zend_assign_to_variable_ex(variable_ptr, value_ptr, IS_TMP_VAR, EX_USES_STRICT_TYPES(), garbage_ptr); } -ZEND_API ZEND_COLD void ZEND_FASTCALL zend_cannot_pass_by_reference(uint32_t arg_num) +ZEND_API zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_cannot_pass_by_reference(uint32_t arg_num) { const zend_execute_data *execute_data = EG(current_execute_data); zend_string *func_name = get_function_or_method_name(EX(call)->func); @@ -680,7 +680,7 @@ static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_throw_non_object_erro } } -static ZEND_COLD void zend_verify_type_error_common( +static zend_never_inline ZEND_COLD void zend_verify_type_error_common( const zend_function *zf, const zend_arg_info *arg_info, const zval *value, const char **fname, const char **fsep, const char **fclass, zend_string **need_msg, const char **given_kind) @@ -703,7 +703,7 @@ static ZEND_COLD void zend_verify_type_error_common( } } -ZEND_API ZEND_COLD void zend_verify_arg_error( +ZEND_API zend_never_inline ZEND_COLD void zend_verify_arg_error( const zend_function *zf, const zend_arg_info *arg_info, uint32_t arg_num, const zval *value) { const zend_execute_data *ptr = EG(current_execute_data)->prev_execute_data; @@ -880,7 +880,7 @@ static zend_never_inline ZEND_COLD void zend_magic_get_property_type_inconsisten zend_string_release(type_str); } -ZEND_COLD void zend_match_unhandled_error(const zval *value) +zend_never_inline ZEND_COLD void zend_match_unhandled_error(const zval *value) { zend_long max_len = EG(exception_string_param_max_len); smart_str msg = {0}; @@ -900,35 +900,35 @@ ZEND_COLD void zend_match_unhandled_error(const zval *value) smart_str_free(&msg); } -ZEND_API ZEND_COLD void ZEND_FASTCALL zend_readonly_property_modification_error( +ZEND_API zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_readonly_property_modification_error( const zend_property_info *info) { zend_readonly_property_modification_error_ex( ZSTR_VAL(info->ce->name), zend_get_unmangled_property_name(info->name)); } -ZEND_API ZEND_COLD void ZEND_FASTCALL zend_readonly_property_modification_error_ex( +ZEND_API zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_readonly_property_modification_error_ex( const char *class_name, const char *prop_name) { zend_throw_error(NULL, "Cannot modify readonly property %s::$%s", class_name, prop_name); } -ZEND_API ZEND_COLD void ZEND_FASTCALL zend_readonly_property_indirect_modification_error(const zend_property_info *info) +ZEND_API zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_readonly_property_indirect_modification_error(const zend_property_info *info) { zend_throw_error(NULL, "Cannot indirectly modify readonly property %s::$%s", ZSTR_VAL(info->ce->name), zend_get_unmangled_property_name(info->name)); } -ZEND_API ZEND_COLD void ZEND_FASTCALL zend_invalid_class_constant_type_error(const uint8_t type) +ZEND_API zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_invalid_class_constant_type_error(const uint8_t type) { zend_type_error("Cannot use value of type %s as class constant name", zend_get_type_by_const(type)); } -ZEND_API ZEND_COLD void ZEND_FASTCALL zend_object_released_while_assigning_to_property_error(const zend_property_info *info) +ZEND_API zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_object_released_while_assigning_to_property_error(const zend_property_info *info) { zend_throw_error(NULL, "Object was released while assigning to property %s::$%s", ZSTR_VAL(info->ce->name), zend_get_unmangled_property_name(info->name)); } -ZEND_API ZEND_COLD void ZEND_FASTCALL zend_asymmetric_visibility_property_modification_error( +ZEND_API zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_asymmetric_visibility_property_modification_error( const zend_property_info *prop_info, const char *operation ) { const zend_class_entry *scope; @@ -1321,7 +1321,7 @@ ZEND_API bool zend_internal_call_should_throw(const zend_function *fbc, zend_exe return 0; } -ZEND_API ZEND_COLD void zend_internal_call_arginfo_violation(const zend_function *fbc) +ZEND_API zend_never_inline ZEND_COLD void zend_internal_call_arginfo_violation(const zend_function *fbc) { zend_error_noreturn(E_ERROR, "Arginfo / zpp mismatch during call of %s%s%s()", fbc->common.scope ? ZSTR_VAL(fbc->common.scope->name) : "", @@ -1392,7 +1392,7 @@ static void zend_verify_internal_func_info(const zend_function *fn, const zval * } #endif -ZEND_API ZEND_COLD void ZEND_FASTCALL zend_missing_arg_error(const zend_execute_data *execute_data) +ZEND_API zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_missing_arg_error(const zend_execute_data *execute_data) { const zend_execute_data *ptr = EX(prev_execute_data); @@ -1417,7 +1417,7 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_missing_arg_error(const zend_execute_ } } -ZEND_API ZEND_COLD void zend_verify_return_error(const zend_function *zf, const zval *value) +ZEND_API zend_never_inline ZEND_COLD void zend_verify_return_error(const zend_function *zf, const zval *value) { const zend_arg_info *arg_info = &zf->common.arg_info[-1]; const char *fname, *fsep, *fclass; @@ -1433,7 +1433,7 @@ ZEND_API ZEND_COLD void zend_verify_return_error(const zend_function *zf, const zend_string_release(need_msg); } -ZEND_API ZEND_COLD void zend_verify_never_error(const zend_function *zf) +ZEND_API zend_never_inline ZEND_COLD void zend_verify_never_error(const zend_function *zf) { zend_string *func_name = get_function_or_method_name(zf); @@ -1444,7 +1444,7 @@ ZEND_API ZEND_COLD void zend_verify_never_error(const zend_function *zf) } #if ZEND_DEBUG -static ZEND_COLD void zend_verify_internal_return_error(const zend_function *zf, const zval *value) +static zend_never_inline ZEND_COLD void zend_verify_internal_return_error(const zend_function *zf, const zval *value) { const zend_arg_info *arg_info = &zf->common.arg_info[-1]; const char *fname, *fsep, *fclass; @@ -1458,7 +1458,7 @@ static ZEND_COLD void zend_verify_internal_return_error(const zend_function *zf, fclass, fsep, fname, ZSTR_VAL(need_msg), given_msg); } -static ZEND_COLD void zend_verify_void_return_error(const zend_function *zf, const char *returned_msg, const char *returned_kind) +static zend_never_inline ZEND_COLD void zend_verify_void_return_error(const zend_function *zf, const char *returned_msg, const char *returned_kind) { const char *fname = ZSTR_VAL(zf->common.function_name); const char *fsep; @@ -1497,7 +1497,7 @@ ZEND_API bool zend_verify_internal_return_type(const zend_function *zf, zval *re } #endif -static ZEND_COLD void zend_verify_missing_return_type(const zend_function *zf) +static zend_never_inline ZEND_COLD void zend_verify_missing_return_type(const zend_function *zf) { /* VERIFY_RETURN_TYPE is not emitted for "void" functions, so this is always an error. */ zend_verify_return_error(zf, NULL); @@ -1754,7 +1754,7 @@ static zend_never_inline zend_long zend_check_string_offset(const zval *dim, int return zval_get_long_func(dim, /* is_strict */ false); } -ZEND_API ZEND_COLD void zend_wrong_string_offset_error(void) +ZEND_API zend_never_inline ZEND_COLD void zend_wrong_string_offset_error(void) { const char *msg = NULL; const zend_execute_data *execute_data = EG(current_execute_data); @@ -2184,7 +2184,7 @@ static zend_property_info *zend_get_prop_not_accepting_double(zend_reference *re return NULL; } -static ZEND_COLD zend_long zend_throw_incdec_ref_error(const zend_property_info *error_prop OPLINE_DC) +static zend_never_inline ZEND_COLD zend_long zend_throw_incdec_ref_error(const zend_property_info *error_prop OPLINE_DC) { zend_string *type_str = zend_type_to_string(error_prop->type); if (ZEND_IS_INCREMENT(opline->opcode)) { @@ -2206,7 +2206,7 @@ static ZEND_COLD zend_long zend_throw_incdec_ref_error(const zend_property_info } } -static ZEND_COLD zend_long zend_throw_incdec_prop_error(const zend_property_info *prop OPLINE_DC) { +static zend_never_inline ZEND_COLD zend_long zend_throw_incdec_prop_error(const zend_property_info *prop OPLINE_DC) { zend_string *type_str = zend_type_to_string(prop->type); if (ZEND_IS_INCREMENT(opline->opcode)) { zend_type_error("Cannot increment property %s::$%s of type %s past its maximal value", @@ -3425,7 +3425,7 @@ static zend_never_inline bool ZEND_FASTCALL zend_array_key_exists_fast(HashTable } } -static ZEND_COLD void ZEND_FASTCALL zend_array_key_exists_error( +static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_array_key_exists_error( const zval *subject, const zval *key OPLINE_DC EXECUTE_DATA_DC) { if (Z_TYPE_P(key) == IS_UNDEF) { @@ -3894,7 +3894,7 @@ ZEND_API zval* ZEND_FASTCALL zend_fetch_static_property(zend_execute_data *ex, i return result; } -ZEND_API ZEND_COLD void zend_throw_ref_type_error_type(const zend_property_info *prop1, const zend_property_info *prop2, const zval *zv) { +ZEND_API zend_never_inline ZEND_COLD void zend_throw_ref_type_error_type(const zend_property_info *prop1, const zend_property_info *prop2, const zval *zv) { zend_string *type1_str = zend_type_to_string(prop1->type); zend_string *type2_str = zend_type_to_string(prop2->type); zend_type_error("Reference with value of type %s held by property %s::$%s of type %s is not compatible with property %s::$%s of type %s", @@ -3910,7 +3910,7 @@ ZEND_API ZEND_COLD void zend_throw_ref_type_error_type(const zend_property_info zend_string_release(type2_str); } -ZEND_API ZEND_COLD void zend_throw_ref_type_error_zval(const zend_property_info *prop, const zval *zv) { +ZEND_API zend_never_inline ZEND_COLD void zend_throw_ref_type_error_zval(const zend_property_info *prop, const zval *zv) { zend_string *type_str = zend_type_to_string(prop->type); zend_type_error("Cannot assign %s to reference held by property %s::$%s of type %s", zend_zval_value_name(zv), @@ -3921,7 +3921,7 @@ ZEND_API ZEND_COLD void zend_throw_ref_type_error_zval(const zend_property_info zend_string_release(type_str); } -static ZEND_COLD void zend_throw_conflicting_coercion_error(const zend_property_info *prop1, const zend_property_info *prop2, const zval *zv) { +static zend_never_inline ZEND_COLD void zend_throw_conflicting_coercion_error(const zend_property_info *prop1, const zend_property_info *prop2, const zval *zv) { zend_string *type1_str = zend_type_to_string(prop1->type); zend_string *type2_str = zend_type_to_string(prop2->type); zend_type_error("Cannot assign %s to reference held by property %s::$%s of type %s and property %s::$%s of type %s, as this would result in an inconsistent type conversion", diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index c724ac78e1f3..8f6b8804298b 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -60,7 +60,7 @@ ZEND_API zend_result zend_eval_stringl_ex(const char *str, size_t str_len, zval /* export zend_pass_function to allow comparisons against it */ extern ZEND_API const zend_internal_function zend_pass_function; -ZEND_API ZEND_COLD void ZEND_FASTCALL zend_missing_arg_error(const zend_execute_data *execute_data); +ZEND_API zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_missing_arg_error(const zend_execute_data *execute_data); ZEND_API ZEND_COLD void ZEND_FASTCALL zend_deprecated_function(const zend_function *fbc); ZEND_API ZEND_COLD void ZEND_FASTCALL zend_nodiscard_function(const zend_function *fbc); ZEND_API ZEND_COLD void ZEND_FASTCALL zend_deprecated_class_constant(const zend_class_constant *c, const zend_string *constant_name); @@ -80,31 +80,31 @@ typedef enum { ZEND_API bool ZEND_FASTCALL zend_verify_prop_assignable_by_ref_ex(const zend_property_info *prop_info, zval *orig_val, bool strict, zend_verify_prop_assignable_by_ref_context context); ZEND_API bool ZEND_FASTCALL zend_verify_prop_assignable_by_ref(const zend_property_info *prop_info, zval *orig_val, bool strict); -ZEND_API ZEND_COLD void zend_throw_ref_type_error_zval(const zend_property_info *prop, const zval *zv); -ZEND_API ZEND_COLD void zend_throw_ref_type_error_type(const zend_property_info *prop1, const zend_property_info *prop2, const zval *zv); +ZEND_API zend_never_inline ZEND_COLD void zend_throw_ref_type_error_zval(const zend_property_info *prop, const zval *zv); +ZEND_API zend_never_inline ZEND_COLD void zend_throw_ref_type_error_type(const zend_property_info *prop1, const zend_property_info *prop2, const zval *zv); ZEND_API ZEND_COLD zval* ZEND_FASTCALL zend_undefined_offset_write(HashTable *ht, zend_long lval); ZEND_API ZEND_COLD zval* ZEND_FASTCALL zend_undefined_index_write(HashTable *ht, zend_string *offset); -ZEND_API ZEND_COLD void zend_wrong_string_offset_error(void); +ZEND_API zend_never_inline ZEND_COLD void zend_wrong_string_offset_error(void); -ZEND_API ZEND_COLD void ZEND_FASTCALL zend_readonly_property_modification_error(const zend_property_info *info); -ZEND_API ZEND_COLD void ZEND_FASTCALL zend_readonly_property_modification_error_ex(const char *class_name, const char *prop_name); -ZEND_API ZEND_COLD void ZEND_FASTCALL zend_readonly_property_indirect_modification_error(const zend_property_info *info); +ZEND_API zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_readonly_property_modification_error(const zend_property_info *info); +ZEND_API zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_readonly_property_modification_error_ex(const char *class_name, const char *prop_name); +ZEND_API zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_readonly_property_indirect_modification_error(const zend_property_info *info); -ZEND_API ZEND_COLD void ZEND_FASTCALL zend_invalid_class_constant_type_error(uint8_t type); +ZEND_API zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_invalid_class_constant_type_error(uint8_t type); -ZEND_API ZEND_COLD void ZEND_FASTCALL zend_object_released_while_assigning_to_property_error(const zend_property_info *info); +ZEND_API zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_object_released_while_assigning_to_property_error(const zend_property_info *info); -ZEND_API ZEND_COLD void ZEND_FASTCALL zend_cannot_add_element(void); +ZEND_API zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_cannot_add_element(void); ZEND_API bool ZEND_FASTCALL zend_asymmetric_property_has_set_access(const zend_property_info *prop_info); -ZEND_API ZEND_COLD void ZEND_FASTCALL zend_asymmetric_visibility_property_modification_error(const zend_property_info *prop_info, const char *operation); +ZEND_API zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_asymmetric_visibility_property_modification_error(const zend_property_info *prop_info, const char *operation); ZEND_API bool zend_verify_scalar_type_hint(uint32_t type_mask, zval *arg, bool strict, bool is_internal_arg); -ZEND_API ZEND_COLD void zend_verify_arg_error( +ZEND_API zend_never_inline ZEND_COLD void zend_verify_arg_error( const zend_function *zf, const zend_arg_info *arg_info, uint32_t arg_num, const zval *value); -ZEND_API ZEND_COLD void zend_verify_return_error( +ZEND_API zend_never_inline ZEND_COLD void zend_verify_return_error( const zend_function *zf, const zval *value); -ZEND_API ZEND_COLD void zend_verify_never_error( +ZEND_API zend_never_inline ZEND_COLD void zend_verify_never_error( const zend_function *zf); ZEND_API bool zend_verify_ref_array_assignable(zend_reference *ref); ZEND_API bool zend_check_user_type_slow( @@ -112,7 +112,7 @@ ZEND_API bool zend_check_user_type_slow( #if ZEND_DEBUG ZEND_API bool zend_internal_call_should_throw(const zend_function *fbc, zend_execute_data *call); -ZEND_API ZEND_COLD void zend_internal_call_arginfo_violation(const zend_function *fbc); +ZEND_API zend_never_inline ZEND_COLD void zend_internal_call_arginfo_violation(const zend_function *fbc); ZEND_API bool zend_verify_internal_return_type(const zend_function *zf, zval *ret); #endif @@ -471,7 +471,7 @@ ZEND_API zend_string *zend_get_executed_filename_ex(void); ZEND_API uint32_t zend_get_executed_lineno(void); ZEND_API zend_class_entry *zend_get_executed_scope(void); ZEND_API bool zend_is_executing(void); -ZEND_API ZEND_COLD void ZEND_FASTCALL zend_cannot_pass_by_reference(uint32_t arg_num); +ZEND_API zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_cannot_pass_by_reference(uint32_t arg_num); ZEND_API void zend_set_timeout(zend_long seconds, bool reset_signals); ZEND_API void zend_unset_timeout(void); @@ -615,7 +615,7 @@ ZEND_API bool zend_verify_property_type(const zend_property_info *info, zval *pr } \ } while (0) -ZEND_COLD void zend_match_unhandled_error(const zval *value); +zend_never_inline ZEND_COLD void zend_match_unhandled_error(const zval *value); /* Call this to handle the timeout or the interrupt function. It will set * EG(vm_interrupt) to false. From bc42a8744fbeb85faec1d7f0e7e37a5830bcc403 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Thu, 2 Apr 2026 17:27:42 +0100 Subject: [PATCH 15/16] Zend/zend_execute.c: mark zend_non_static_method_call() as ZEND_COLD zend_never_inline For consistency with other functions --- Zend/zend_execute.c | 2 +- Zend/zend_execute.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 21d2280d48fe..474e8a826e14 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -2559,7 +2559,7 @@ static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_invalid_method_call(c Z_STRVAL_P(function_name), zend_zval_value_name(object)); } -ZEND_API void ZEND_FASTCALL zend_non_static_method_call(const zend_function *fbc) +ZEND_API zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_non_static_method_call(const zend_function *fbc) { zend_throw_error( zend_ce_error, diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index 8f6b8804298b..ba48b19bcfe1 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -511,7 +511,7 @@ ZEND_API ZEND_ATTRIBUTE_DEPRECATED HashTable *zend_unfinished_execution_gc(zend_ ZEND_API HashTable *zend_unfinished_execution_gc_ex(zend_execute_data *execute_data, zend_execute_data *call, zend_get_gc_buffer *gc_buffer, bool suspended_by_yield); ZEND_API zval* ZEND_FASTCALL zend_fetch_static_property(zend_execute_data *ex, int fetch_type); ZEND_API zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_undefined_method(const zend_class_entry *ce, const zend_string *method); -ZEND_API void ZEND_FASTCALL zend_non_static_method_call(const zend_function *fbc); +ZEND_API zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_non_static_method_call(const zend_function *fbc); ZEND_API void zend_frameless_observed_call(zend_execute_data *execute_data); From d648cc1087efa03ba412b66562bc20b971849037 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Thu, 2 Apr 2026 17:38:10 +0100 Subject: [PATCH 16/16] Zend/zend_execute.c: use uint32_t type instead of int type --- Zend/zend_execute.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 474e8a826e14..85461eaa1569 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -4905,9 +4905,7 @@ static void cleanup_unfinished_calls(zend_execute_data *execute_data, uint32_t o static void cleanup_live_vars(zend_execute_data *execute_data, uint32_t op_num, uint32_t catch_op_num) /* {{{ */ { - int i; - - for (i = 0; i < EX(func)->op_array.last_live_range; i++) { + for (uint32_t i = 0; i < EX(func)->op_array.last_live_range; i++) { const zend_live_range *range = &EX(func)->op_array.live_range[i]; if (range->start > op_num) { /* further blocks will not be relevant... */