Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions Zend/tests/first_class_callable/constexpr/gh22782.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

#[Attribute]
class A {
function __construct(public mixed $fn) {}
}

#[A(strlen(...))]
class C {
const CC = strlen(...);

#[A(strlen(...))]
function f($arg = strlen(...)) {
return $arg;
}
}

const CC = strlen(...);
35 changes: 35 additions & 0 deletions Zend/tests/first_class_callable/constexpr/gh22782.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
--TEST--
GH-22782: FCC preloading
--EXTENSIONS--
opcache
--INI--
opcache.enable=1
opcache.enable_cli=1
opcache.optimization_level=-1
opcache.preload={PWD}/gh22782.inc
--SKIPIF--
<?php
if (PHP_OS_FAMILY == 'Windows') die('skip Preloading is not supported on Windows');
?>
--FILE--
<?php

echo "# Class const\n";
var_dump((C::CC)('hello'));
echo "# Class attr\n";
var_dump((new ReflectionClass(C::class)->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)
6 changes: 6 additions & 0 deletions Zend/zend_ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
2 changes: 0 additions & 2 deletions Zend/zend_compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down
2 changes: 2 additions & 0 deletions ext/dom/element.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
6 changes: 3 additions & 3 deletions ext/dom/node.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down
25 changes: 25 additions & 0 deletions ext/dom/tests/gh22447.phpt
Original file line number Diff line number Diff line change
@@ -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--
<?php
$dom = Dom\HTMLDocument::createEmpty();

$attribute1 = $dom->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)
<container xmlns="http://www.w3.org/1999/xhtml" xmlns:ns1="urn:a" ns1:my-attribute="" my-attribute=""></container>
4 changes: 3 additions & 1 deletion ext/opcache/jit/zend_jit_ir.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 2 additions & 0 deletions ext/opcache/jit/zend_jit_trace.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down
58 changes: 58 additions & 0 deletions ext/opcache/tests/jit/gh22763.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
--TEST--
GH-22763: JIT fails to clear ZREG_TYPE_ONLY after setting reg
--FILE--
<?php

function findMiddleSnake(array $a, int $aLo, int $aHi, array $b, int $bLo, int $bHi): array
{
$n = $aHi - $aLo;
$m = $bHi - $bLo;
$delta = $n - $m;
$deltaIsOdd = ($delta & 1) !== 0;
$offset = 4;
$size = 2 * 3 + 2;
$vf = array_fill(0, $size, 0);
$vb = array_fill(0, $size, 0);

$d = 2;
$x = 0;

for ($k = -$d; $k <= $d; $k += 2) {
if ($k === -$d || ($k !== $d && $vb[$offset + $k - 1] < $vb[$offset + $k + 1])) {
$x = $vb[$offset + $k + 1];
var_dump($x);
} else {
$x = $vb[$offset + $k - 1] + 1;
}

$y = $x - $k;
$xs = $x;
$ys = $y;

while ($x < $n && $y < $m && $a[$aLo + $n - 1 - $x] === $b[$bLo + $m - 1 - $y]) {
$x++;
$y++;
}

$vb[$offset + $k] = $x;

if (!$deltaIsOdd) {
$kf = $delta - $k;

if ($kf >= -$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
4 changes: 3 additions & 1 deletion ext/opcache/zend_file_cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
3 changes: 3 additions & 0 deletions ext/opcache/zend_persist.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down