diff --git a/Zend/tests/first_class_callable/constexpr/gh22782.inc b/Zend/tests/first_class_callable/constexpr/gh22782.inc new file mode 100644 index 000000000000..d67ba4eab14e --- /dev/null +++ b/Zend/tests/first_class_callable/constexpr/gh22782.inc @@ -0,0 +1,18 @@ + +--FILE-- +getAttributes(A::class)[0]->newInstance()->fn)('hello')); +echo "# Method attr\n"; +var_dump((new ReflectionMethod(C::class, 'f')->getAttributes(A::class)[0]->newInstance()->fn)('hello')); +echo "# Method default value\n"; +var_dump((new C()->f())('hello')); + +?> +--EXPECT-- +# Class const +int(5) +# Class attr +int(5) +# Method attr +int(5) +# Method default value +int(5) diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c index adcb62a51d1f..1b293c832c91 100644 --- a/Zend/zend_ast.c +++ b/Zend/zend_ast.c @@ -1139,6 +1139,12 @@ static zend_result ZEND_FASTCALL zend_ast_evaluate_inner( case ZEND_AST_CALL: case ZEND_AST_STATIC_CALL: { + // Preloading will attempt to resolve constants but objects can't be stored in shm + // Aborting here to store the const AST instead + if (CG(in_compilation)) { + return FAILURE; + } + zend_function *fptr; zend_class_entry *called_scope = NULL; diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index bb24d73fb240..6a677e71a6b6 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -12037,8 +12037,6 @@ static void zend_compile_const_expr_fcc(zend_ast **ast_ptr) zend_error_noreturn(E_COMPILE_ERROR, "Constant expression contains invalid operations"); } - ZEND_MAP_PTR_NEW(((zend_ast_fcc *)*args_ast)->fptr); - switch ((*ast_ptr)->kind) { case ZEND_AST_CALL: { zend_ast *name_ast = (*ast_ptr)->child[0]; diff --git a/ext/dom/element.c b/ext/dom/element.c index 71fa39b59b5a..2a0aa3a4d0e7 100644 --- a/ext/dom/element.c +++ b/ext/dom/element.c @@ -720,6 +720,8 @@ static void dom_element_set_attribute_node_common(INTERNAL_FUNCTION_PARAMETERS, nsp = attrp->ns; if (use_ns && nsp != NULL) { existattrp = xmlHasNsProp(nodep, attrp->name, nsp->href); + } else if (nsp == NULL) { + existattrp = xmlHasNsProp(nodep, attrp->name, NULL); } else { existattrp = xmlHasProp(nodep, attrp->name); } diff --git a/ext/dom/node.c b/ext/dom/node.c index 4cfc6c5af0d2..e0af66227014 100644 --- a/ext/dom/node.c +++ b/ext/dom/node.c @@ -970,7 +970,7 @@ static void dom_node_insert_before_legacy(zval *return_value, zval *ref, dom_obj xmlAttrPtr lastattr; if (child->ns == NULL) - lastattr = xmlHasProp(refp->parent, child->name); + lastattr = xmlHasNsProp(refp->parent, child->name, NULL); else lastattr = xmlHasNsProp(refp->parent, child->name, child->ns->href); if (lastattr != NULL && lastattr->type != XML_ATTRIBUTE_DECL) { @@ -1017,7 +1017,7 @@ static void dom_node_insert_before_legacy(zval *return_value, zval *ref, dom_obj xmlAttrPtr lastattr; if (child->ns == NULL) - lastattr = xmlHasProp(parentp, child->name); + lastattr = xmlHasNsProp(parentp, child->name, NULL); else lastattr = xmlHasNsProp(parentp, child->name, child->ns->href); if (lastattr != NULL && lastattr->type != XML_ATTRIBUTE_DECL) { @@ -1379,7 +1379,7 @@ static void dom_node_append_child_legacy(zval *return_value, dom_object *intern, xmlAttrPtr lastattr; if (child->ns == NULL) - lastattr = xmlHasProp(nodep, child->name); + lastattr = xmlHasNsProp(nodep, child->name, NULL); else lastattr = xmlHasNsProp(nodep, child->name, child->ns->href); if (lastattr != NULL && lastattr->type != XML_ATTRIBUTE_DECL) { diff --git a/ext/dom/tests/gh22447.phpt b/ext/dom/tests/gh22447.phpt new file mode 100644 index 000000000000..396a0ff1ee1c --- /dev/null +++ b/ext/dom/tests/gh22447.phpt @@ -0,0 +1,25 @@ +--TEST-- +GH-22447 (UAF at dom_objects_free_storage when setAttributeNode collides with a namespaced attribute of the same local name) +--EXTENSIONS-- +dom +--FILE-- +createAttribute("my-attribute"); +$container = $dom->appendChild($dom->createElement("container")); +$attribute2 = $dom->createAttribute("my-attribute"); +$attribute4 = $dom->createAttributeNS("urn:a", "my-attribute"); + +$container->setAttributeNode($attribute1); +$container->setAttributeNode($attribute4); + +var_dump($container->setAttributeNode($attribute2) === $attribute1); +var_dump($container->setAttributeNode($attribute1) === $attribute2); + +echo $dom->saveXml($container), PHP_EOL; +?> +--EXPECT-- +bool(true) +bool(true) + diff --git a/ext/opcache/jit/zend_jit_ir.c b/ext/opcache/jit/zend_jit_ir.c index f3dbcc84c124..8f6804cb8915 100644 --- a/ext/opcache/jit/zend_jit_ir.c +++ b/ext/opcache/jit/zend_jit_ir.c @@ -858,12 +858,14 @@ void *zend_jit_snapshot_handler(ir_ctx *ctx, ir_ref snapshot_ref, ir_insn *snaps t->stack_map[t->exit_info[exit_point].stack_offset + var].flags = ZREG_TYPE_ONLY; } else { if ((exit_flags & ZEND_JIT_EXIT_FIXED) - && t->stack_map[t->exit_info[exit_point].stack_offset + var].reg != IR_REG_NUM(reg)) { + && (t->stack_map[t->exit_info[exit_point].stack_offset + var].reg != IR_REG_NUM(reg) + || (t->stack_map[t->exit_info[exit_point].stack_offset + var].flags & ~(ZREG_LOAD|ZREG_STORE|ZREG_LAST_USE)))) { exit_point = zend_jit_duplicate_exit_point(ctx, t, exit_point, snapshot_ref); addr = (void*)zend_jit_trace_get_exit_addr(exit_point); exit_flags &= ~ZEND_JIT_EXIT_FIXED; } t->stack_map[t->exit_info[exit_point].stack_offset + var].reg = IR_REG_NUM(reg); + t->stack_map[t->exit_info[exit_point].stack_offset + var].flags &= (ZREG_LOAD|ZREG_STORE|ZREG_LAST_USE); } } else { if ((exit_flags & ZEND_JIT_EXIT_FIXED) diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c index 77bfaa03473a..505427890129 100644 --- a/ext/opcache/jit/zend_jit_trace.c +++ b/ext/opcache/jit/zend_jit_trace.c @@ -3571,6 +3571,8 @@ static int zend_jit_trace_deoptimization( } } } else if (STACK_FLAGS(parent_stack, i) == ZREG_TYPE_ONLY) { + ZEND_ASSERT(reg == ZREG_NONE); + uint8_t type = STACK_TYPE(parent_stack, i); if (!zend_jit_store_type(jit, i, type)) { diff --git a/ext/opcache/tests/jit/gh22763.phpt b/ext/opcache/tests/jit/gh22763.phpt new file mode 100644 index 000000000000..67d7caa308ed --- /dev/null +++ b/ext/opcache/tests/jit/gh22763.phpt @@ -0,0 +1,58 @@ +--TEST-- +GH-22763: JIT fails to clear ZREG_TYPE_ONLY after setting reg +--FILE-- += -$d && $kf <= $d && $vf[$offset + $kf] + $vb[$offset + $k] >= $n) { + return [$n - $x, $m - $y, $n - $xs, $m - $ys]; + } + } + } + + return []; +} + +$from = [3,2,1]; +$to = [1,99,3]; +findMiddleSnake($from, 0, count($from), $to, 0, count($to)); +?> +--EXPECTF-- +int(0) + +Warning: Undefined array key 3 in %s on line %d diff --git a/ext/opcache/zend_file_cache.c b/ext/opcache/zend_file_cache.c index af59b9b2c34a..265d5de41476 100644 --- a/ext/opcache/zend_file_cache.c +++ b/ext/opcache/zend_file_cache.c @@ -1308,7 +1308,9 @@ static void zend_file_cache_unserialize_ast(zend_ast *ast, zend_ast_get_op_array(ast)->op_array = Z_PTR(z); } else if (ast->kind == ZEND_AST_CALLABLE_CONVERT) { zend_ast_fcc *fcc = (zend_ast_fcc*)ast; - ZEND_MAP_PTR_NEW(fcc->fptr); + if (!script->corrupted) { + ZEND_MAP_PTR_NEW(fcc->fptr); + } if (!IS_UNSERIALIZED(fcc->args)) { UNSERIALIZE_PTR(fcc->args); zend_file_cache_unserialize_ast(fcc->args, script, buf); diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c index c06452e6acf2..d3e719dbed70 100644 --- a/ext/opcache/zend_persist.c +++ b/ext/opcache/zend_persist.c @@ -195,6 +195,9 @@ static zend_ast *zend_persist_ast(zend_ast *ast) node = (zend_ast *) copy; } else if (ast->kind == ZEND_AST_CALLABLE_CONVERT) { zend_ast_fcc *copy = zend_shared_memdup(ast, sizeof(zend_ast_fcc)); + if (!ZCG(current_persistent_script)->corrupted) { + ZEND_MAP_PTR_NEW(copy->fptr); + } copy->args = zend_persist_ast(copy->args); node = (zend_ast *) copy; } else if (zend_ast_is_decl(ast)) {