From 6fe34822f88528a1bad8dd6b874cc1d699c20517 Mon Sep 17 00:00:00 2001 From: Weilin Du Date: Mon, 20 Jul 2026 22:25:46 +0800 Subject: [PATCH 01/11] Fix GH-22759: Keep Io\Poll watcher registry in sync (#22760) Fixed #22759 by removing the watcher from the Context registry when it is explicitly removed, and rolling back the backend registration on failure. --- ext/standard/io_poll.c | 40 ++++++++++++++++++---------- ext/standard/tests/poll/gh22759.phpt | 38 ++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 14 deletions(-) create mode 100644 ext/standard/tests/poll/gh22759.phpt diff --git a/ext/standard/io_poll.c b/ext/standard/io_poll.c index 837470a9f753..ca363c7b37d9 100644 --- a/ext/standard/io_poll.c +++ b/ext/standard/io_poll.c @@ -44,6 +44,8 @@ static zend_object_handlers php_io_poll_context_object_handlers; static zend_object_handlers php_io_poll_watcher_object_handlers; static zend_object_handlers php_io_poll_handle_object_handlers; +typedef struct php_io_poll_context_object php_io_poll_context_object; + /* Watcher object structure */ typedef struct php_io_poll_watcher_object { php_poll_handle_object *handle; @@ -51,16 +53,16 @@ typedef struct php_io_poll_watcher_object { uint32_t triggered_events; zval data; bool active; - php_poll_ctx *poll_ctx; /* Back reference to poll context */ + php_io_poll_context_object *context; /* Back reference to Context object */ zend_object std; } php_io_poll_watcher_object; /* Context object structure */ -typedef struct php_io_poll_context_object { +struct php_io_poll_context_object { php_poll_ctx *ctx; HashTable *watchers; /* Maps handle pointer -> watcher object */ zend_object std; -} php_io_poll_context_object; +}; /* Stream poll handle specific data */ typedef struct php_stream_poll_handle_data { @@ -251,7 +253,7 @@ static zend_object *php_io_poll_watcher_create_object(zend_class_entry *ce) intern->watched_events = 0; intern->triggered_events = 0; intern->active = false; - intern->poll_ctx = NULL; + intern->context = NULL; ZVAL_NULL(&intern->data); return &intern->std; @@ -293,7 +295,7 @@ static void php_io_poll_context_free_object(zend_object *obj) ZEND_HASH_FOREACH_VAL(intern->watchers, zval *zv) { php_io_poll_watcher_object *watcher = PHP_POLL_WATCHER_OBJ_FROM_ZOBJ(Z_OBJ_P(zv)); watcher->active = false; - watcher->poll_ctx = NULL; + watcher->context = NULL; } ZEND_HASH_FOREACH_END(); } @@ -349,7 +351,7 @@ static zend_always_inline zend_ulong php_io_poll_compute_ptr_key(void *ptr) static zend_result php_io_poll_watcher_modify_events( php_io_poll_watcher_object *watcher, uint32_t events) { - if (!watcher->active || !watcher->poll_ctx) { + if (!watcher->active || !watcher->context) { zend_throw_exception( php_io_poll_inactive_watcher_class_entry, "Cannot modify inactive watcher", 0); return FAILURE; @@ -363,8 +365,9 @@ static zend_result php_io_poll_watcher_modify_events( } /* Modify in poll context */ - if (php_poll_modify(watcher->poll_ctx, (int) fd, events, watcher) != SUCCESS) { - php_poll_error err = php_poll_get_error(watcher->poll_ctx); + php_poll_ctx *poll_ctx = watcher->context->ctx; + if (php_poll_modify(poll_ctx, (int) fd, events, watcher) != SUCCESS) { + php_poll_error err = php_poll_get_error(poll_ctx); php_io_poll_throw_failed_operation(php_io_poll_failed_watcher_mod_class_entry, "Failed to modify watcher in polling system", err); return FAILURE; @@ -632,19 +635,27 @@ PHP_METHOD(Io_Poll_Watcher, remove) php_io_poll_watcher_object *intern = PHP_POLL_WATCHER_OBJ_FROM_ZV(getThis()); - if (!intern->active || !intern->poll_ctx) { + if (!intern->active || !intern->context) { zend_throw_exception( php_io_poll_inactive_watcher_class_entry, "Cannot remove inactive watcher", 0); RETURN_THROWS(); } + php_io_poll_context_object *context = intern->context; + php_poll_ctx *poll_ctx = context->ctx; + HashTable *watchers = context->watchers; + zend_ulong hash_key = php_io_poll_compute_ptr_key(intern->handle); php_socket_t fd = php_poll_handle_get_fd(intern->handle); if (fd != SOCK_ERR) { - php_poll_remove(intern->poll_ctx, (int) fd); + php_poll_remove(poll_ctx, (int) fd); } intern->active = false; - intern->poll_ctx = NULL; + intern->context = NULL; + + if (watchers) { + zend_hash_index_del(watchers, hash_key); + } } PHP_METHOD(Io_Poll_Context, __construct) @@ -727,8 +738,6 @@ PHP_METHOD(Io_Poll_Context, add) watcher->handle = handle; watcher->watched_events = events; watcher->triggered_events = 0; - watcher->active = true; - watcher->poll_ctx = intern->ctx; GC_ADDREF(&handle->std); @@ -757,7 +766,10 @@ PHP_METHOD(Io_Poll_Context, add) GC_ADDREF(&watcher->std); zend_ulong hash_key = php_io_poll_compute_ptr_key(handle); - zend_hash_index_add(intern->watchers, hash_key, &watcher_zv); + zend_hash_index_add_new(intern->watchers, hash_key, &watcher_zv); + + watcher->active = true; + watcher->context = intern; } PHP_METHOD(Io_Poll_Context, wait) diff --git a/ext/standard/tests/poll/gh22759.phpt b/ext/standard/tests/poll/gh22759.phpt new file mode 100644 index 000000000000..3df68c4f1314 --- /dev/null +++ b/ext/standard/tests/poll/gh22759.phpt @@ -0,0 +1,38 @@ +--TEST-- +GH-22759 (Io\Poll: re-adding a removed handle keeps the new watcher tracked) +--FILE-- +add($handle, [Io\Poll\Event::Read]); +$first->remove(); + +$ref = WeakReference::create($first); +unset($first); +gc_collect_cycles(); +var_dump($ref->get()); + +$second = $context->add($handle, [Io\Poll\Event::Read]); + +unset($context); +gc_collect_cycles(); + +var_dump($second->isActive()); + +try { + $second->remove(); +} catch (Io\Poll\InactiveWatcherException $e) { + echo $e->getMessage(), "\n"; +} + +echo "done\n"; +?> +--EXPECT-- +NULL +bool(false) +Cannot remove inactive watcher +done From 61a987b5a1927dd3fe39b4744bba20de7ca73d33 Mon Sep 17 00:00:00 2001 From: Ilia Alshanetsky Date: Mon, 20 Jul 2026 10:58:59 -0400 Subject: [PATCH 02/11] Fix crash when a partial skips a param with a constant default (#22804) Const exprs represent a constant fetch that could not be evaluated at compile time as ZEND_AST_CONSTANT, which zend_compile_expr_inner() had no case for, so compiling such a default into a partial's forwarding call hit ZEND_ASSERT(0). Compile it to ZEND_FETCH_CONSTANT using the name already resolved by zend_compile_const_expr_const(). zp_compile_forwarding_call() also dropped the reference it took on a constant-expression default value. Closes GH-22804 --- .../default_const_expr.phpt | 116 ++++++++++++++++++ Zend/zend_compile.c | 43 ++++--- Zend/zend_partial.c | 1 + 3 files changed, 145 insertions(+), 15 deletions(-) create mode 100644 Zend/tests/partial_application/default_const_expr.phpt diff --git a/Zend/tests/partial_application/default_const_expr.phpt b/Zend/tests/partial_application/default_const_expr.phpt new file mode 100644 index 000000000000..12d25adedeff --- /dev/null +++ b/Zend/tests/partial_application/default_const_expr.phpt @@ -0,0 +1,116 @@ +--TEST-- +PFA: constant-expression default for a skipped optional parameter +--FILE-- +name, $c]; +} + +$p = f(a: 10, c: ?); +var_dump($p(99)); + +$v = variadic(a: 10, c: ?, foo: 1); +var_dump($v(99)); + +$q = C::m(a: 1, c: ?); +var_dump($q(9)); + +$r = g(a: 1, c: ?); +var_dump($r(9)); + +$l = late(a: 1, c: ?); +define('App\LATE', 'defined after the partial was created'); +var_dump($l(9)); + +define('GLOBAL_ONLY', 'global fallback'); +$s = fallback(a: 1, c: ?); +var_dump($s(9)); + +?> +--EXPECT-- +array(3) { + [0]=> + int(10) + [1]=> + int(7) + [2]=> + int(99) +} +array(4) { + [0]=> + int(10) + [1]=> + int(7) + [2]=> + int(99) + [3]=> + array(1) { + ["foo"]=> + int(1) + } +} +array(3) { + [0]=> + int(1) + [1]=> + int(42) + [2]=> + int(9) +} +array(3) { + [0]=> + int(1) + [1]=> + string(1) "A" + [2]=> + int(9) +} +array(3) { + [0]=> + int(1) + [1]=> + string(37) "defined after the partial was created" + [2]=> + int(9) +} +array(3) { + [0]=> + int(1) + [1]=> + string(15) "global fallback" + [2]=> + int(9) +} diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index f44784239533..bb24d73fb240 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -11519,12 +11519,25 @@ static void zend_compile_array(znode *result, zend_ast *ast) /* {{{ */ } /* }}} */ +static void zend_emit_fetch_constant(znode *result, zend_string *resolved_name, bool unqualified_in_namespace) +{ + zend_op *opline = zend_emit_op_tmp(result, ZEND_FETCH_CONSTANT, NULL, NULL); + opline->op2_type = IS_CONST; + + if (unqualified_in_namespace) { + opline->op1.num = IS_CONSTANT_UNQUALIFIED_IN_NAMESPACE; + opline->op2.constant = zend_add_const_name_literal(resolved_name, true); + } else { + opline->op1.num = 0; + opline->op2.constant = zend_add_const_name_literal(resolved_name, false); + } + opline->extended_value = zend_alloc_cache_slot(); +} + static void zend_compile_const(znode *result, const zend_ast *ast) /* {{{ */ { zend_ast *name_ast = ast->child[0]; - zend_op *opline; - bool is_fully_qualified; zend_string *orig_name = zend_ast_get_str(name_ast); zend_string *resolved_name = zend_resolve_const_name(orig_name, name_ast->attr, &is_fully_qualified); @@ -11553,22 +11566,19 @@ static void zend_compile_const(znode *result, const zend_ast *ast) /* {{{ */ return; } - opline = zend_emit_op_tmp(result, ZEND_FETCH_CONSTANT, NULL, NULL); - opline->op2_type = IS_CONST; - - if (is_fully_qualified || !FC(current_namespace)) { - opline->op1.num = 0; - opline->op2.constant = zend_add_const_name_literal( - resolved_name, false); - } else { - opline->op1.num = IS_CONSTANT_UNQUALIFIED_IN_NAMESPACE; - opline->op2.constant = zend_add_const_name_literal( - resolved_name, true); - } - opline->extended_value = zend_alloc_cache_slot(); + zend_emit_fetch_constant(result, resolved_name, + !is_fully_qualified && FC(current_namespace)); } /* }}} */ +static void zend_compile_constant(znode *result, zend_ast *ast) +{ + zend_string *name = zend_ast_get_constant_name(ast); + + zend_emit_fetch_constant(result, zend_string_copy(name), + (ast->attr & IS_CONSTANT_UNQUALIFIED_IN_NAMESPACE) != 0); +} + static void zend_compile_class_const(znode *result, zend_ast *ast) /* {{{ */ { zend_ast *class_ast; @@ -12436,6 +12446,9 @@ static void zend_compile_expr_inner(znode *result, zend_ast *ast) /* {{{ */ case ZEND_AST_CONST: zend_compile_const(result, ast); return; + case ZEND_AST_CONSTANT: + zend_compile_constant(result, ast); + return; case ZEND_AST_CLASS_CONST: zend_compile_class_const(result, ast); return; diff --git a/Zend/zend_partial.c b/Zend/zend_partial.c index ef335cd805c3..e7a3e1c92b58 100644 --- a/Zend/zend_partial.c +++ b/Zend/zend_partial.c @@ -588,6 +588,7 @@ static zend_ast *zp_compile_forwarding_call( if (Z_TYPE(default_value) == IS_CONSTANT_AST) { /* Must dup AST because we are going to destroy it */ default_value_ast = zend_ast_dup(Z_ASTVAL(default_value)); + zval_ptr_dtor_nogc(&default_value); } else { default_value_ast = zend_ast_create_zval(&default_value); } From b82fc3c0e04b77d88fe6202fdb6f98bb3375e862 Mon Sep 17 00:00:00 2001 From: Nora Dossche <7771979+ndossche@users.noreply.github.com> Date: Mon, 20 Jul 2026 18:09:42 +0200 Subject: [PATCH 03/11] Fix unchecked sqlite3_column_text() calls (#22715) This is the pdo equivalent of GH-22045. Notably it does not include a change for the blob call because ZVAL_STRINGL_FAST already takes care of that implicitly. --- ext/pdo_sqlite/sqlite_statement.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/ext/pdo_sqlite/sqlite_statement.c b/ext/pdo_sqlite/sqlite_statement.c index ca82b1b09322..25c9e6917e43 100644 --- a/ext/pdo_sqlite/sqlite_statement.c +++ b/ext/pdo_sqlite/sqlite_statement.c @@ -276,8 +276,13 @@ static int pdo_sqlite_stmt_get_col( int64_t i = sqlite3_column_int64(S->stmt, colno); #if SIZEOF_ZEND_LONG < 8 if (i > ZEND_LONG_MAX || i < ZEND_LONG_MIN) { + const char *text = (const char *) sqlite3_column_text(S->stmt, colno); + if (UNEXPECTED(!text)) { + pdo_sqlite_error_stmt(stmt); + return 0; + } ZVAL_STRINGL(result, - (char *) sqlite3_column_text(S->stmt, colno), + text, sqlite3_column_bytes(S->stmt, colno)); return 1; } @@ -295,10 +300,15 @@ static int pdo_sqlite_stmt_get_col( sqlite3_column_blob(S->stmt, colno), sqlite3_column_bytes(S->stmt, colno)); return 1; - default: - ZVAL_STRINGL_FAST(result, - (char *) sqlite3_column_text(S->stmt, colno), sqlite3_column_bytes(S->stmt, colno)); + default: { + const char *text = (const char *) sqlite3_column_text(S->stmt, colno); + if (UNEXPECTED(!text)) { + pdo_sqlite_error_stmt(stmt); + return 0; + } + ZVAL_STRINGL_FAST(result, text, sqlite3_column_bytes(S->stmt, colno)); return 1; + } } } From 19af2e43f36015b26415e5f01c39422c3a897b26 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Sun, 19 Jul 2026 05:04:44 +0100 Subject: [PATCH 04/11] ext/opcache: zend_jit_resolve_tsrm_ls_cache_offsets() TEXTREL from bare __tls_get_addr call. Fix GH-22693 The x86_64 General Dynamic TLS sequence called __tls_get_addr without @PLT, which could emit a PC-relative relocation against the external symbol landing in read-only .text, producing a DT_TEXTREL and a linker warning about a possible runtime segfault. Routing the call through the PLT matches the x86-64 TLS ABI canonical sequence and the already correct i386 variant, without changing the emitted instruction bytes. Close GH-22801 --- NEWS | 4 ++++ ext/opcache/jit/tls/zend_jit_tls_x86_64.c | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 2b0cdc5e039f..78f23b882421 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,10 @@ PHP NEWS - Date: . Fixed leak on double DatePeriod::__construct() call. (ilutov) +- Opcache: + . Fixed GH-22693 (DT_TEXTREL in JIT-generated TLS access on x86_64). + (David Carlier) + - Sockets: . Fixed socket_set_option() validation error messages for UDP_SEGMENT and SO_LINGER options. (Weilin Du) diff --git a/ext/opcache/jit/tls/zend_jit_tls_x86_64.c b/ext/opcache/jit/tls/zend_jit_tls_x86_64.c index 11ffe495fcbb..bea2968ffd21 100644 --- a/ext/opcache/jit/tls/zend_jit_tls_x86_64.c +++ b/ext/opcache/jit/tls/zend_jit_tls_x86_64.c @@ -102,7 +102,7 @@ zend_result zend_jit_resolve_tsrm_ls_cache_offsets( "leaq _tsrm_ls_cache@tlsgd(%%rip), %%rdi\n" ".word 0x6666\n" "rex64\n" - "call __tls_get_addr\n" + "call __tls_get_addr@PLT\n" /* Load thread pointer address */ "movq %%fs:0, %%rsi\n" : "=a" (addr), "=b" (code), "=S" (thread_pointer) From 145e8c26d4ce147fcb8f2c83f48d920e4d3a37a1 Mon Sep 17 00:00:00 2001 From: Ilia Alshanetsky Date: Mon, 20 Jul 2026 08:29:57 -0400 Subject: [PATCH 05/11] Fix GH-22825: DOM attribute methods on a DTD default attribute xmlHasNsProp() falls back to the internal subset, so the legacy ext/dom attribute methods can receive a DTD attribute declaration instead of an attribute node. setAttribute() and dom_remove_attribute() enumerated only XML_ATTRIBUTE_NODE and XML_NAMESPACE_DECL, so a defaulted attribute asserted on debug builds and ran into __builtin_unreachable() on release builds, and setAttributeNode() skipped the declaration when unlinking the old attribute but still returned it, throwing after the tree was already modified. setAttribute() now creates the attribute as it did before 8.4, matching setAttributeNS(); removeAttribute() reports that nothing was removed, since the declaration lives in the DTD and not on the element; setAttributeNode() returns null; and toggleAttribute() derives its result from the removal instead of assuming it succeeded, so the returned value keeps agreeing with hasAttribute(). getAttribute() and hasAttribute() already handled the declaration, and the Dom\Element methods are unaffected because the spec-compliant lookup never consults the DTD. Fixes GH-22825 Closes GH-22830 --- NEWS | 4 ++ ext/dom/element.c | 13 +++-- ext/dom/tests/gh22825.phpt | 98 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 112 insertions(+), 3 deletions(-) create mode 100644 ext/dom/tests/gh22825.phpt diff --git a/NEWS b/NEWS index ccae29155dbd..cfb82c4f0ca2 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,10 @@ PHP NEWS - Date: . Fixed leak on double DatePeriod::__construct() call. (ilutov) +- DOM: + . Fixed bug GH-22825 (DOMElement::setAttribute() fails silently when the DTD + declares a default value for the attribute). (iliaal) + - Sockets: . Fixed various memory related issues in ext/sockets. (David Carlier) diff --git a/ext/dom/element.c b/ext/dom/element.c index e25805df53eb..b2564428db9c 100644 --- a/ext/dom/element.c +++ b/ext/dom/element.c @@ -468,6 +468,8 @@ PHP_METHOD(DOMElement, setAttribute) break; case XML_NAMESPACE_DECL: RETURN_FALSE; + case XML_ATTRIBUTE_DECL: + break; EMPTY_SWITCH_DEFAULT_CASE(); } } @@ -595,6 +597,8 @@ static bool dom_remove_attribute(xmlNodePtr thisp, xmlNodePtr attrp) break; } + case XML_ATTRIBUTE_DECL: + return false; EMPTY_SWITCH_DEFAULT_CASE(); } return true; @@ -726,7 +730,11 @@ static void dom_element_set_attribute_node_common(INTERNAL_FUNCTION_PARAMETERS, existattrp = xmlHasProp(nodep, attrp->name); } - if (existattrp != NULL && existattrp->type != XML_ATTRIBUTE_DECL) { + if (existattrp != NULL && existattrp->type == XML_ATTRIBUTE_DECL) { + existattrp = NULL; + } + + if (existattrp != NULL) { if ((oldobj = php_dom_object_get_data((xmlNodePtr) existattrp)) != NULL && ((php_libxml_node_ptr *)oldobj->ptr)->node == (xmlNodePtr) attrp) { @@ -1788,8 +1796,7 @@ PHP_METHOD(DOMElement, toggleAttribute) /* Step 5 */ if (force_is_null || !force) { - dom_remove_attribute(thisp, attribute); - retval = false; + retval = !dom_remove_attribute(thisp, attribute); goto out; } diff --git a/ext/dom/tests/gh22825.phpt b/ext/dom/tests/gh22825.phpt new file mode 100644 index 000000000000..987ed57a1454 --- /dev/null +++ b/ext/dom/tests/gh22825.phpt @@ -0,0 +1,98 @@ +--TEST-- +GH-22825 (DOMElement::setAttribute() reaches EMPTY_SWITCH_DEFAULT_CASE() with DTD #FIXED default attributes) +--EXTENSIONS-- +dom +--FILE-- +', '', 'A'], + ['', '', 'A'], + ['', '', 'p:A'], +]; + +function element(string $attlist, string $root): DOMElement { + $doc = new DOMDocument(); + $doc->loadXML("$root"); + return $doc->documentElement; +} + +foreach ($cases as [$attlist, $root, $name]) { + echo "--- $attlist ---\n"; + + $el = element($attlist, $root); + echo "hasAttribute: "; + var_dump($el->hasAttribute($name)); + echo "getAttribute: "; + var_dump($el->getAttribute($name)); + + $el = element($attlist, $root); + $result = $el->setAttribute($name, 'v'); + echo "setAttribute: ", is_object($result) ? $result::class : var_export($result, true), "\n"; + echo "after setAttribute: ", trim($el->ownerDocument->saveXML($el)), "\n"; + + $el = element($attlist, $root); + echo "removeAttribute: "; + var_dump($el->removeAttribute($name)); + echo "still present after removeAttribute: "; + var_dump($el->hasAttribute($name)); + + $el = element($attlist, $root); + echo "toggleAttribute(false): "; + var_dump($el->toggleAttribute($name, false)); + echo "still present after toggleAttribute(false): "; + var_dump($el->hasAttribute($name)); + + $el = element($attlist, $root); + echo "toggleAttribute(true): "; + var_dump($el->toggleAttribute($name, true)); + echo "still present after toggleAttribute(true): "; + var_dump($el->hasAttribute($name)); + + $el = element($attlist, $root); + $attr = $el->ownerDocument->createAttribute($name); + $attr->value = 'z'; + echo "setAttributeNode: "; + var_dump($el->setAttributeNode($attr)); + echo "after setAttributeNode: ", trim($el->ownerDocument->saveXML($el)), "\n"; +} +?> +--EXPECT-- +--- --- +hasAttribute: bool(true) +getAttribute: string(1) "d" +setAttribute: DOMAttr +after setAttribute: +removeAttribute: bool(false) +still present after removeAttribute: bool(true) +toggleAttribute(false): bool(true) +still present after toggleAttribute(false): bool(true) +toggleAttribute(true): bool(true) +still present after toggleAttribute(true): bool(true) +setAttributeNode: NULL +after setAttributeNode: +--- --- +hasAttribute: bool(true) +getAttribute: string(1) "d" +setAttribute: DOMAttr +after setAttribute: +removeAttribute: bool(false) +still present after removeAttribute: bool(true) +toggleAttribute(false): bool(true) +still present after toggleAttribute(false): bool(true) +toggleAttribute(true): bool(true) +still present after toggleAttribute(true): bool(true) +setAttributeNode: NULL +after setAttributeNode: +--- --- +hasAttribute: bool(true) +getAttribute: string(1) "d" +setAttribute: DOMAttr +after setAttribute: +removeAttribute: bool(false) +still present after removeAttribute: bool(true) +toggleAttribute(false): bool(true) +still present after toggleAttribute(false): bool(true) +toggleAttribute(true): bool(true) +still present after toggleAttribute(true): bool(true) +setAttributeNode: NULL +after setAttributeNode: From 6c988e0abb0b341c5f21ef799437728b4b58f75f Mon Sep 17 00:00:00 2001 From: Calvin Buckley Date: Mon, 20 Jul 2026 16:15:14 -0300 Subject: [PATCH 06/11] main: Add AIX to PHP_OS_FAMILY (#22834) There are two OSes in this family: AIX itself, and IBM i PASE, which provides an AIX syscall emulation environment. uname is different between them (AIX/OS400). --- UPGRADING | 2 ++ main/php.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/UPGRADING b/UPGRADING index 1b7cda4b8612..e1976941ddf1 100644 --- a/UPGRADING +++ b/UPGRADING @@ -566,6 +566,8 @@ PHP 8.6 UPGRADE NOTES - Core: . In case of a hard OOM PHP now calls abort() instead of exit(1), changing the exit code to 134 and possibly creating a core dump. + . The PHP_OS_FAMILY constant has an AIX value for when running on AIX or + IBM i via PASE. ======================================== 14. Performance Improvements diff --git a/main/php.h b/main/php.h index c7516bca3124..a0c639810b8f 100644 --- a/main/php.h +++ b/main/php.h @@ -42,6 +42,8 @@ # define PHP_OS_FAMILY "Darwin" #elif defined(__sun__) # define PHP_OS_FAMILY "Solaris" +#elif defined(_AIX) +# define PHP_OS_FAMILY "AIX" #elif defined(__linux__) # define PHP_OS_FAMILY "Linux" #else From ab99a29383d7434fb6a8d7eac7fe3c16013e6fd9 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Sat, 27 Jun 2026 05:12:03 +0100 Subject: [PATCH 07/11] Zend: reset typed property default on every unserialize failure path. GH-22263 follow-up Close GH-22481 --- NEWS | 2 + ...serialize_typed_prop_reset_on_failure.phpt | 37 +++++++++++++++++++ ext/standard/var_unserializer.re | 6 +-- 3 files changed, 40 insertions(+), 5 deletions(-) create mode 100644 Zend/tests/unserialize_typed_prop_reset_on_failure.phpt diff --git a/NEWS b/NEWS index 7a00f15c2ba4..de11135f0d3b 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,8 @@ PHP NEWS - Core: . Implemented partial function application RFC. (Arnaud) + . Fixed bug GH-22263 (reset typed property default on every unserialize + failure path). (David Carlier) - DOM: . Fixed bug GH-22825 (DOMElement::setAttribute() fails silently when the DTD diff --git a/Zend/tests/unserialize_typed_prop_reset_on_failure.phpt b/Zend/tests/unserialize_typed_prop_reset_on_failure.phpt new file mode 100644 index 000000000000..2380c8e5550e --- /dev/null +++ b/Zend/tests/unserialize_typed_prop_reset_on_failure.phpt @@ -0,0 +1,37 @@ +--TEST-- +unserialize() resets a typed property to its default on every failure path +--FILE-- +getPrevious()) { + printf("%s: %s\n", $e::class, $e->getMessage()); + } +} + +/* By-ref type violation: the slot is reset to its default. */ +class C { public array $a; } +try { + var_dump(unserialize('O:1:"C":1:{s:1:"a";R:1;}')); +} catch (\Throwable $e) { + printf("%s: %s\n", $e::class, $e->getMessage()); +} +echo "OK\n"; +?> +--EXPECTF-- +Warning: unserialize(): Error at offset %d of %d bytes in %s on line %d +TypeError: %s +OK diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re index 4a9b278c116c..a9f1f96f366f 100644 --- a/ext/standard/var_unserializer.re +++ b/ext/standard/var_unserializer.re @@ -689,11 +689,7 @@ second_try: if (!php_var_unserialize_internal(data, p, max, var_hash)) { if (info) { - if (Z_ISREF_P(data)) { - ZEND_REF_ADD_TYPE_SOURCE(Z_REF_P(data), info); - } else { - var_restore_prop_default(var_hash, obj, info, data); - } + var_restore_prop_default(var_hash, obj, info, data); } goto failure; } From 06411654ff1825bc0e0dc4342cf2441d8420bb90 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 20 Jul 2026 21:36:50 +0200 Subject: [PATCH 08/11] Skip __get() when __isset() materialised the property (GH-22181) After __isset() returns true on ?? or empty(), re-check the property table before calling __get(). When __isset() materialised the property (a pattern used by lazy proxies), its value is returned directly. isset() itself is unchanged. Fixes GH-12695 --- UPGRADING | 5 ++ Zend/tests/magic_methods/gh12695.phpt | 65 +++++++++++++++++++ Zend/tests/magic_methods/gh12695_empty.phpt | 55 ++++++++++++++++ .../gh12695_no_materialization.phpt | 65 +++++++++++++++++++ .../gh12695_object_released_in_isset.phpt | 28 ++++++++ Zend/zend_object_handlers.c | 44 ++++++++++++- 6 files changed, 261 insertions(+), 1 deletion(-) create mode 100644 Zend/tests/magic_methods/gh12695.phpt create mode 100644 Zend/tests/magic_methods/gh12695_empty.phpt create mode 100644 Zend/tests/magic_methods/gh12695_no_materialization.phpt create mode 100644 Zend/tests/magic_methods/gh12695_object_released_in_isset.phpt diff --git a/UPGRADING b/UPGRADING index e1976941ddf1..077a7faf6562 100644 --- a/UPGRADING +++ b/UPGRADING @@ -19,6 +19,11 @@ PHP 8.6 UPGRADE NOTES 1. Backward Incompatible Changes ======================================== +- Core: + . ??/empty() on a magic property no longer call __get() when __isset() + has materialised the property by writing into the property table. + The freshly-written value is returned directly. isset() is unaffected. + - COM . It is no longer possible to clone variant objects, this is because the cloning behaviour was ill defined. diff --git a/Zend/tests/magic_methods/gh12695.phpt b/Zend/tests/magic_methods/gh12695.phpt new file mode 100644 index 000000000000..957f474fb6a1 --- /dev/null +++ b/Zend/tests/magic_methods/gh12695.phpt @@ -0,0 +1,65 @@ +--TEST-- +GH-12695: ?? on unset property does not call __get() when __isset() materialized the property +--FILE-- +$n = 123; + return true; + } +} + +echo "Dynamic property materialised in __isset, then `??`:\n"; +$a = new A; +var_dump($a->foo ?? 'fallback'); + +echo "\nSame on a declared (unset) property:\n"; +class B { + public int $x = 99; + public function __get($n) { + throw new Exception("__get must not be called when __isset materialised the property"); + } + public function __isset($n) { + echo " __isset($n)\n"; + $this->$n = 7; + return true; + } +} +$b = new B; +unset($b->x); +var_dump($b->x ?? 'fallback'); + +echo "\nWhen __isset() materialises the property to null, `??` falls back:\n"; +#[AllowDynamicProperties] +class D { + public function __get($n) { + throw new Exception("__get must not be called when __isset materialised the property"); + } + public function __isset($n) { + echo " __isset($n)\n"; + $this->$n = null; + return true; + } +} +$d = new D; +var_dump($d->foo ?? 'fallback'); + +?> +--EXPECT-- +Dynamic property materialised in __isset, then `??`: + __isset(foo) +int(123) + +Same on a declared (unset) property: + __isset(x) +int(7) + +When __isset() materialises the property to null, `??` falls back: + __isset(foo) +string(8) "fallback" diff --git a/Zend/tests/magic_methods/gh12695_empty.phpt b/Zend/tests/magic_methods/gh12695_empty.phpt new file mode 100644 index 000000000000..99806820cc6f --- /dev/null +++ b/Zend/tests/magic_methods/gh12695_empty.phpt @@ -0,0 +1,55 @@ +--TEST-- +GH-12695: empty() on unset property does not call __get() when __isset() materialized the property +--FILE-- +$n = $GLOBALS['next_value']; + return true; + } +} + +echo "empty() when __isset materialised a truthy value: __get is not called, empty=false:\n"; +$GLOBALS['next_value'] = 7; +$a = new A; +var_dump(empty($a->foo)); + +echo "\nempty() when __isset materialised a falsy value: __get is not called, empty=true:\n"; +$GLOBALS['next_value'] = 0; +$a = new A; +var_dump(empty($a->bar)); + +echo "\nempty() with no materialization: __get is still called (legacy path preserved):\n"; +class B { + public function __get($n) { + echo " __get($n)\n"; + return 'value'; + } + public function __isset($n) { + echo " __isset($n)\n"; + return true; + } +} +$b = new B; +var_dump(empty($b->any)); + +?> +--EXPECT-- +empty() when __isset materialised a truthy value: __get is not called, empty=false: + __isset(foo) +bool(false) + +empty() when __isset materialised a falsy value: __get is not called, empty=true: + __isset(bar) +bool(true) + +empty() with no materialization: __get is still called (legacy path preserved): + __isset(any) + __get(any) +bool(false) diff --git a/Zend/tests/magic_methods/gh12695_no_materialization.phpt b/Zend/tests/magic_methods/gh12695_no_materialization.phpt new file mode 100644 index 000000000000..700b605e2984 --- /dev/null +++ b/Zend/tests/magic_methods/gh12695_no_materialization.phpt @@ -0,0 +1,65 @@ +--TEST-- +GH-12695: __get() invocation is based on __isset()'s return value +--FILE-- +any ?? 'fallback'); + +echo "\n`??` when __isset=true and __get returns null: __get is called and fallback is used:\n"; +class D { + public function __get($n) { + echo " __get($n)\n"; + return null; + } + public function __isset($n) { + echo " __isset($n)\n"; + return true; + } +} +$d = new D; +var_dump($d->any ?? 'fallback'); + +echo "\n`??` when __isset returns false: __get is not called:\n"; +class E { + public function __get($n) { + throw new Exception("__get must not be called when __isset returned false"); + } + public function __isset($n) { + echo " __isset($n)\n"; + return false; + } +} +$e = new E; +var_dump($e->any ?? 'fallback'); + +?> +--EXPECT-- +`??` when __isset=true and __get returns a value: __get is called: + __isset(any) + __get(any) +string(8) "from-get" + +`??` when __isset=true and __get returns null: __get is called and fallback is used: + __isset(any) + __get(any) +string(8) "fallback" + +`??` when __isset returns false: __get is not called: + __isset(any) +string(8) "fallback" diff --git a/Zend/tests/magic_methods/gh12695_object_released_in_isset.phpt b/Zend/tests/magic_methods/gh12695_object_released_in_isset.phpt new file mode 100644 index 000000000000..911ffde637a9 --- /dev/null +++ b/Zend/tests/magic_methods/gh12695_object_released_in_isset.phpt @@ -0,0 +1,28 @@ +--TEST-- +GH-12695: Object freed by __isset() during materialization +--FILE-- +prop = 'materialised'; + return true; + } +} + +$obj = new C(); +unset($obj->prop); +var_dump($obj->prop ?? 'fb'); + +?> +--EXPECT-- +string(12) "materialised" diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 7ccd9f26190a..313113d7dc28 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -934,6 +934,35 @@ ZEND_API zval *zend_std_read_property(zend_object *zobj, zend_string *name, int } zval_ptr_dtor(&tmp_result); + + /* __isset() may have materialised the property by writing into + * the property table. Re-check it before deferring to __get(), + * so the freshly-written value is returned directly without a + * redundant __get() call (GH-12695). The value is copied into + * `rv` because the property table can be freed by the OBJ_RELEASE + * below (e.g. when __isset() drops the last external reference + * to the object). */ + if (IS_VALID_PROPERTY_OFFSET(property_offset)) { + retval = OBJ_PROP(zobj, property_offset); + if (Z_TYPE_P(retval) != IS_UNDEF) { + ZVAL_COPY(rv, retval); + retval = rv; + OBJ_RELEASE(zobj); + goto exit; + } + } else if (IS_DYNAMIC_PROPERTY_OFFSET(property_offset)) { + if (zobj->properties != NULL) { + retval = zend_hash_find(zobj->properties, name); + if (retval) { + ZVAL_COPY(rv, retval); + retval = rv; + OBJ_RELEASE(zobj); + goto exit; + } + } + } + retval = &EG(uninitialized_zval); + if (zobj->ce->__get && !((*guard) & IN_GET)) { goto call_getter; } @@ -2498,7 +2527,20 @@ ZEND_API int zend_std_has_property(zend_object *zobj, zend_string *name, int has result = zend_is_true(&rv); zval_ptr_dtor(&rv); if (has_set_exists == ZEND_PROPERTY_NOT_EMPTY && result) { - if (EXPECTED(!EG(exception)) && zobj->ce->__get && !((*guard) & IN_GET)) { + /* GH-12695, see above. */ + zval *prop = NULL; + if (IS_VALID_PROPERTY_OFFSET(property_offset)) { + prop = OBJ_PROP(zobj, property_offset); + if (Z_TYPE_P(prop) == IS_UNDEF) { + prop = NULL; + } + } else if (IS_DYNAMIC_PROPERTY_OFFSET(property_offset) + && zobj->properties != NULL) { + prop = zend_hash_find(zobj->properties, name); + } + if (prop) { + result = i_zend_is_true(prop); + } else if (EXPECTED(!EG(exception)) && zobj->ce->__get && !((*guard) & IN_GET)) { (*guard) |= IN_GET; zend_std_call_getter(zobj, name, &rv); (*guard) &= ~IN_GET; From 85fc5768d6dbfe29baa4e9f921df26d3ae0d7458 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Mon, 20 Jul 2026 19:15:41 +0100 Subject: [PATCH 09/11] streams: remove parameters that always passed NULL or unused --- main/streams/stream_errors.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/main/streams/stream_errors.c b/main/streams/stream_errors.c index 2fa2cc646636..b7663fe56f5d 100644 --- a/main/streams/stream_errors.c +++ b/main/streams/stream_errors.c @@ -326,7 +326,7 @@ PHPAPI php_stream_error_operation *php_stream_error_operation_begin(void) } static void php_stream_error_add(zend_enum_StreamErrorCode code, const char *wrapper_name, - zend_string *message, const char *docref, char *param, int severity, bool terminating) + zend_string *message, const char *docref, int severity, bool terminating) { php_stream_error_operation *op = FG(stream_error_state).current_operation; ZEND_ASSERT(op != NULL); @@ -335,7 +335,7 @@ static void php_stream_error_add(zend_enum_StreamErrorCode code, const char *wra entry->message = message; entry->code = code; entry->wrapper_name = wrapper_name ? estrdup(wrapper_name) : NULL; - entry->param = param; + entry->param = NULL; entry->docref = docref ? estrdup(docref) : NULL; entry->severity = severity; entry->terminating = terminating; @@ -575,15 +575,15 @@ PHPAPI void php_stream_error_operation_abort(void) /* Wrapper error reporting */ static void php_stream_wrapper_error_internal(const char *wrapper_name, php_stream_context *context, - const char *docref, int options, int severity, bool terminating, - zend_enum_StreamErrorCode code, char *param, zend_string *message) + const char *docref, int severity, bool terminating, + zend_enum_StreamErrorCode code, zend_string *message) { bool implicit_operation = (FG(stream_error_state).current_operation == NULL); if (implicit_operation) { php_stream_error_operation_begin(); } - php_stream_error_add(code, wrapper_name, message, docref, param, severity, terminating); + php_stream_error_add(code, wrapper_name, message, docref, severity, terminating); if (implicit_operation) { php_stream_error_operation_end(context); @@ -604,7 +604,7 @@ PHPAPI void php_stream_wrapper_error_with_name(const char *wrapper_name, va_end(args); php_stream_wrapper_error_internal( - wrapper_name, context, docref, options, severity, terminating, code, NULL, message); + wrapper_name, context, docref, severity, terminating, code, message); } PHPAPI void php_stream_wrapper_error(php_stream_wrapper *wrapper, php_stream_context *context, @@ -623,7 +623,7 @@ PHPAPI void php_stream_wrapper_error(php_stream_wrapper *wrapper, php_stream_con const char *wrapper_name = PHP_STREAM_ERROR_WRAPPER_NAME(wrapper); php_stream_wrapper_error_internal( - wrapper_name, context, docref, options, severity, terminating, code, NULL, message); + wrapper_name, context, docref, severity, terminating, code, message); } /* Stream error reporting */ @@ -641,8 +641,8 @@ PHPAPI void php_stream_error(php_stream *stream, const char *docref, int severit php_stream_context *context = PHP_STREAM_CONTEXT(stream); - php_stream_wrapper_error_internal(wrapper_name, context, docref, REPORT_ERRORS, severity, - terminating, code, NULL, message); + php_stream_wrapper_error_internal(wrapper_name, context, docref, severity, + terminating, code, message); } /* Legacy wrapper error logging */ @@ -705,7 +705,7 @@ PHPAPI void php_stream_wrapper_log_error(const php_stream_wrapper *wrapper, if (options & REPORT_ERRORS) { php_stream_wrapper_error_internal( - wrapper_name, context, NULL, options, severity, terminating, code, NULL, message); + wrapper_name, context, NULL, severity, terminating, code, message); } else { php_stream_wrapper_log_store_error( message, code, wrapper_name, severity, terminating); @@ -784,8 +784,8 @@ PHPAPI void php_stream_display_wrapper_name_errors(const char *wrapper_name, zend_string *message = strpprintf(0, "%s: %s", caption, msg); - php_stream_wrapper_error_internal(wrapper_name, context, NULL, REPORT_ERRORS, E_WARNING, true, - code, NULL, message); + php_stream_wrapper_error_internal(wrapper_name, context, NULL, E_WARNING, true, + code, message); if (free_msg) { efree(msg); From 0cf29ab0589cd9ab3b6d3d3972e2222e57eced3f Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Mon, 20 Jul 2026 19:18:16 +0100 Subject: [PATCH 10/11] streams: remove param field of php_stream_error_entry It is always assigned NULL --- main/streams/php_stream_errors.h | 1 - main/streams/stream_errors.c | 22 ++++------------------ 2 files changed, 4 insertions(+), 19 deletions(-) diff --git a/main/streams/php_stream_errors.h b/main/streams/php_stream_errors.h index b21f47505248..67112c8932b7 100644 --- a/main/streams/php_stream_errors.h +++ b/main/streams/php_stream_errors.h @@ -73,7 +73,6 @@ typedef struct _php_stream_error_entry { zend_string *message; zend_enum_StreamErrorCode code; char *wrapper_name; - char *param; char *docref; int severity; bool terminating; diff --git a/main/streams/stream_errors.c b/main/streams/stream_errors.c index b7663fe56f5d..5cb4d3df4026 100644 --- a/main/streams/stream_errors.c +++ b/main/streams/stream_errors.c @@ -67,12 +67,8 @@ static void php_stream_error_create_object(zval *zv, php_stream_error_entry *ent zend_update_property_bool( php_ce_stream_error, Z_OBJ_P(zv), ZEND_STRL("terminating"), entry->terminating); - if (entry->param) { - zend_update_property_string( - php_ce_stream_error, Z_OBJ_P(zv), ZEND_STRL("param"), entry->param); - } else { - zend_update_property_null(php_ce_stream_error, Z_OBJ_P(zv), ZEND_STRL("param")); - } + /* TODO: Remove property */ + zend_update_property_null(php_ce_stream_error, Z_OBJ_P(zv), ZEND_STRL("param")); } /* Create array of StreamError objects from error chain */ @@ -213,7 +209,6 @@ static void php_stream_error_entry_free(php_stream_error_entry *entry) php_stream_error_entry *next = entry->next; zend_string_release(entry->message); efree(entry->wrapper_name); - efree(entry->param); efree(entry->docref); efree(entry); entry = next; @@ -335,7 +330,6 @@ static void php_stream_error_add(zend_enum_StreamErrorCode code, const char *wra entry->message = message; entry->code = code; entry->wrapper_name = wrapper_name ? estrdup(wrapper_name) : NULL; - entry->param = NULL; entry->docref = docref ? estrdup(docref) : NULL; entry->severity = severity; entry->terminating = terminating; @@ -399,15 +393,9 @@ static void php_stream_report_errors(php_stream_context *context, php_stream_err { switch (error_mode) { case PHP_STREAM_ERROR_MODE_ERROR: { - php_stream_error_entry *entry = op->first_error; + const php_stream_error_entry *entry = op->first_error; while (entry) { - if (entry->param) { - php_error_docref1(entry->docref, entry->param, entry->severity, "%s", - ZSTR_VAL(entry->message)); - } else { - php_error_docref( - entry->docref, entry->severity, "%s", ZSTR_VAL(entry->message)); - } + php_error_docref(entry->docref, entry->severity, "%s", ZSTR_VAL(entry->message)); entry = entry->next; } break; @@ -652,7 +640,6 @@ static void php_stream_error_entry_dtor_legacy(void *error) php_stream_error_entry *entry = *(php_stream_error_entry **) error; zend_string_release(entry->message); efree(entry->wrapper_name); - efree(entry->param); efree(entry->docref); efree(entry); } @@ -671,7 +658,6 @@ static void php_stream_wrapper_log_store_error(zend_string *message, zend_enum_S entry->message = message; entry->code = code; entry->wrapper_name = wrapper_name ? estrdup(wrapper_name) : NULL; - entry->param = NULL; entry->severity = severity; entry->terminating = terminating; From 36d854783b5c505fd4feebd1f88f3aabf2979c2e Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Mon, 20 Jul 2026 19:20:13 +0100 Subject: [PATCH 11/11] streams: remove StreamError::$param property It is always null --- main/streams/stream_errors.c | 3 --- main/streams/stream_errors.stub.php | 1 - main/streams/stream_errors_arginfo.h | 8 +------- main/streams/stream_errors_decl.h | 8 ++++---- 4 files changed, 5 insertions(+), 15 deletions(-) diff --git a/main/streams/stream_errors.c b/main/streams/stream_errors.c index 5cb4d3df4026..b2dfdbb217ad 100644 --- a/main/streams/stream_errors.c +++ b/main/streams/stream_errors.c @@ -66,9 +66,6 @@ static void php_stream_error_create_object(zval *zv, php_stream_error_entry *ent zend_update_property_bool( php_ce_stream_error, Z_OBJ_P(zv), ZEND_STRL("terminating"), entry->terminating); - - /* TODO: Remove property */ - zend_update_property_null(php_ce_stream_error, Z_OBJ_P(zv), ZEND_STRL("param")); } /* Create array of StreamError objects from error chain */ diff --git a/main/streams/stream_errors.stub.php b/main/streams/stream_errors.stub.php index 255c92beb89e..28fb381df24d 100644 --- a/main/streams/stream_errors.stub.php +++ b/main/streams/stream_errors.stub.php @@ -132,7 +132,6 @@ enum StreamErrorStore public string $wrapperName; public int $severity; public bool $terminating; - public ?string $param; } class StreamException extends Exception diff --git a/main/streams/stream_errors_arginfo.h b/main/streams/stream_errors_arginfo.h index 89df622beb05..4558f64b77f5 100644 --- a/main/streams/stream_errors_arginfo.h +++ b/main/streams/stream_errors_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit stream_errors.stub.php instead. - * Stub hash: 4cddf758cc9f2041802d8cbbaaa45593022a5db1 + * Stub hash: d3087b608996f81bf0dd19c25792feec9744e768 * Has decl header: yes */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_StreamException_getErrors, 0, 0, IS_ARRAY, 0) @@ -237,12 +237,6 @@ static zend_class_entry *register_class_StreamError(void) zend_declare_typed_property(class_entry, property_terminating_name, &property_terminating_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL)); zend_string_release_ex(property_terminating_name, true); - zval property_param_default_value; - ZVAL_UNDEF(&property_param_default_value); - zend_string *property_param_name = zend_string_init("param", sizeof("param") - 1, true); - zend_declare_typed_property(class_entry, property_param_name, &property_param_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING|MAY_BE_NULL)); - zend_string_release_ex(property_param_name, true); - return class_entry; } diff --git a/main/streams/stream_errors_decl.h b/main/streams/stream_errors_decl.h index 69fe96252b4c..3a18055b9e74 100644 --- a/main/streams/stream_errors_decl.h +++ b/main/streams/stream_errors_decl.h @@ -1,8 +1,8 @@ /* This is a generated file, edit stream_errors.stub.php instead. - * Stub hash: 4cddf758cc9f2041802d8cbbaaa45593022a5db1 */ + * Stub hash: d3087b608996f81bf0dd19c25792feec9744e768 */ -#ifndef ZEND_STREAM_ERRORS_DECL_4cddf758cc9f2041802d8cbbaaa45593022a5db1_H -#define ZEND_STREAM_ERRORS_DECL_4cddf758cc9f2041802d8cbbaaa45593022a5db1_H +#ifndef ZEND_STREAM_ERRORS_DECL_d3087b608996f81bf0dd19c25792feec9744e768_H +#define ZEND_STREAM_ERRORS_DECL_d3087b608996f81bf0dd19c25792feec9744e768_H typedef enum zend_enum_StreamErrorCode { ZEND_ENUM_StreamErrorCode_None = 1, @@ -184,4 +184,4 @@ typedef enum zend_enum_StreamErrorStore { ZEND_ENUM_StreamErrorStore_All = 5, } zend_enum_StreamErrorStore; -#endif /* ZEND_STREAM_ERRORS_DECL_4cddf758cc9f2041802d8cbbaaa45593022a5db1_H */ +#endif /* ZEND_STREAM_ERRORS_DECL_d3087b608996f81bf0dd19c25792feec9744e768_H */