Skip to content
Closed
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
2 changes: 2 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,8 @@ PHP NEWS
. Fixed bug GH-24988 (Incorrect opcode range check causes bugs with exceptions in
function JIT). (ndossche, Jorg Sowa)
. Fix opcache phar check. (ndossche)
. Fixed memory leak in JIT ASSIGN_DIM when the assignment fails.
(jorgsowa)

- OpenSSL:
. Fixed build and test compatibility with OpenSSL 4.0 and 4.1.
Expand Down
25 changes: 14 additions & 11 deletions ext/opcache/jit/zend_jit_helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -922,10 +922,6 @@ static zval* ZEND_FASTCALL zend_jit_fetch_dim_w_helper(zend_array *ht, zval *dim
ZVAL_NULL(EX_VAR(opline->result.var));
}
}
if (opline->opcode == ZEND_ASSIGN_DIM
&& ((opline+1)->op1_type & (IS_VAR | IS_TMP_VAR))) {
zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var));
}
return NULL;
}
ZEND_FALLTHROUGH;
Expand Down Expand Up @@ -1003,13 +999,6 @@ static zval* ZEND_FASTCALL zend_jit_fetch_dim_w_helper(zend_array *ht, zval *dim
default:
zend_illegal_container_offset(ZSTR_KNOWN(ZEND_STR_ARRAY), dim, BP_VAR_R);
undef_result_after_exception();
if (EG(opline_before_exception)
&& (EG(opline_before_exception)+1)->opcode == ZEND_OP_DATA
&& ((EG(opline_before_exception)+1)->op1_type & (IS_VAR|IS_TMP_VAR))) {
zend_execute_data *execute_data = EG(current_execute_data);

zval_ptr_dtor_nogc(EX_VAR((EG(opline_before_exception)+1)->op1.var));
}
return NULL;
}

Expand Down Expand Up @@ -1472,6 +1461,20 @@ static void ZEND_FASTCALL zend_jit_fetch_dim_obj_rw_helper(zval *object_ptr, zva
// zend_jit_fetch_dim_obj_helper(object_ptr, dim, result, BP_VAR_UNSET);
//}

static zval* ZEND_FASTCALL zend_jit_assign_dim_fetch_w_helper(zend_array *ht, zval *dim)
{
zval *retval = zend_jit_fetch_dim_w_helper(ht, dim);

if (UNEXPECTED(!retval)) {
zend_execute_data *execute_data = EG(current_execute_data);
/* Throwing replaces EX(opline) with HANDLE_EXCEPTION */
const zend_op *opline = EG(exception) ? EG(opline_before_exception) : EX(opline);

zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var));
}
return retval;
}

static void ZEND_FASTCALL zend_jit_assign_dim_helper(zval *object_ptr, zval *dim, zval *value, zval *result)
{
if (EXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) {
Expand Down
8 changes: 7 additions & 1 deletion ext/opcache/jit/zend_jit_ir.c
Original file line number Diff line number Diff line change
Expand Up @@ -3139,6 +3139,7 @@ static void zend_jit_setup_disasm(void)
REGISTER_HELPER(zend_jit_fetch_dim_isset_helper);
REGISTER_HELPER(zend_jit_fetch_dim_rw_helper);
REGISTER_HELPER(zend_jit_fetch_dim_w_helper);
REGISTER_HELPER(zend_jit_assign_dim_fetch_w_helper);
REGISTER_HELPER(zend_jit_fetch_dim_str_offset_r_helper);
REGISTER_HELPER(zend_jit_fetch_dim_str_r_helper);
REGISTER_HELPER(zend_jit_fetch_dim_str_is_helper);
Expand Down Expand Up @@ -12437,7 +12438,11 @@ static int zend_jit_fetch_dimension_address_inner(zend_jit_ctx *jit,
ir_END_list(*end_inputs);
break;
case BP_VAR_W:
ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_dim_w_helper), ht_ref, ref);
if (opline->opcode == ZEND_ASSIGN_DIM && ((opline+1)->op1_type & (IS_VAR|IS_TMP_VAR))) {
ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_assign_dim_fetch_w_helper), ht_ref, ref);
} else {
ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_dim_w_helper), ht_ref, ref);
}
if_found = ir_IF(ref);
ir_IF_TRUE(if_found);
ir_refs_add(found_inputs, ir_END());
Expand Down Expand Up @@ -13373,6 +13378,7 @@ static int zend_jit_assign_dim(zend_jit_ctx *jit,
// JIT: zend_throw_error(NULL, "Cannot add element to the array as the next element is already occupied");
jit_SET_EX_OPLINE(jit, opline);
ir_CALL(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_cannot_add_element, IR_FASTCALL_FUNC));
jit_FREE_OP(jit, (opline+1)->op1_type, (opline+1)->op1, val_info, NULL);

ir_END_list(end_inputs);

Expand Down
31 changes: 31 additions & 0 deletions ext/opcache/tests/jit/assign_dim_018.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
--TEST--
JIT ASSIGN_DIM: OP_DATA is freed when appending to a full array fails
--INI--
opcache.enable=1
opcache.enable_cli=1
opcache.file_update_protection=0
opcache.jit=function
--EXTENSIONS--
opcache
--FILE--
<?php
class D {
function __destruct() {
echo "dtor\n";
}
}

function test() {
$a = [PHP_INT_MAX => 1];
$a[] = new D;
}

try {
test();
} catch (Throwable $e) {
echo $e::class, ": ", $e->getMessage(), "\n";
}
?>
--EXPECT--
dtor
Error: Cannot add element to the array as the next element is already occupied
34 changes: 34 additions & 0 deletions ext/opcache/tests/jit/assign_dim_019.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
--TEST--
JIT ASSIGN_DIM: OP_DATA is freed when a float key conversion throws
--INI--
opcache.enable=1
opcache.enable_cli=1
opcache.file_update_protection=0
opcache.jit=function
--EXTENSIONS--
opcache
--FILE--
<?php
class D {
function __destruct() {
echo "dtor\n";
}
}

set_error_handler(function ($errno, $errstr) {
throw new Exception($errstr);
});

function test() {
$a[1.5] = new D;
}

try {
test();
} catch (Throwable $e) {
echo $e::class, ": ", $e->getMessage(), "\n";
}
?>
--EXPECT--
dtor
Exception: Implicit conversion from float 1.5 to int loses precision
34 changes: 34 additions & 0 deletions ext/opcache/tests/jit/assign_dim_020.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
--TEST--
JIT ASSIGN_DIM: OP_DATA is freed when a resource key conversion throws
--INI--
opcache.enable=1
opcache.enable_cli=1
opcache.file_update_protection=0
opcache.jit=function
--EXTENSIONS--
opcache
--FILE--
<?php
class D {
function __destruct() {
echo "dtor\n";
}
}

set_error_handler(function ($errno, $errstr) {
throw new Exception($errstr);
});

function test() {
$a[STDIN] = new D;
}

try {
test();
} catch (Throwable $e) {
echo $e::class, ": ", $e->getMessage(), "\n";
}
?>
--EXPECTF--
dtor
Exception: Resource ID#%d used as offset, casting to integer (%d)
42 changes: 42 additions & 0 deletions ext/opcache/tests/jit/assign_dim_021.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
--TEST--
JIT ASSIGN_DIM: OP_DATA is freed once when a float key conversion throws on a false container
--INI--
opcache.enable=1
opcache.enable_cli=1
opcache.file_update_protection=0
opcache.jit=function
zend.exception_ignore_args=1
--EXTENSIONS--
opcache
--FILE--
<?php
class D {
function __destruct() {
echo "dtor\n";
}
}

set_error_handler(function ($errno, $errstr) {
if (!str_starts_with($errstr, "Automatic conversion of false")) {
throw new Exception($errstr);
}
});

function id($x) {
return $x;
}

function test($o) {
$a = false;
$a[1.5] = id($o);
}

try {
test(new D);
} catch (Exception $e) {
echo $e::class, ": ", $e->getMessage(), "\n";
}
?>
--EXPECT--
dtor
Exception: Implicit conversion from float 1.5 to int loses precision
42 changes: 42 additions & 0 deletions ext/opcache/tests/jit/assign_dim_022.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
--TEST--
JIT ASSIGN_DIM: OP_DATA is freed once when a resource key conversion throws on a false container
--INI--
opcache.enable=1
opcache.enable_cli=1
opcache.file_update_protection=0
opcache.jit=function
zend.exception_ignore_args=1
--EXTENSIONS--
opcache
--FILE--
<?php
class D {
function __destruct() {
echo "dtor\n";
}
}

set_error_handler(function ($errno, $errstr) {
if (!str_starts_with($errstr, "Automatic conversion of false")) {
throw new Exception($errstr);
}
});

function id($x) {
return $x;
}

function test($o) {
$a = false;
$a[STDIN] = id($o);
}

try {
test(new D);
} catch (Exception $e) {
echo $e::class, ": ", $e->getMessage(), "\n";
}
?>
--EXPECTF--
dtor
Exception: Resource ID#%d used as offset, casting to integer (%d)
30 changes: 30 additions & 0 deletions ext/opcache/tests/jit/assign_dim_023.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
--TEST--
JIT ASSIGN_DIM: OP_DATA is freed when the key is an illegal offset
--INI--
opcache.enable=1
opcache.enable_cli=1
opcache.file_update_protection=0
opcache.jit=function
--EXTENSIONS--
opcache
--FILE--
<?php
class D {
function __destruct() {
echo "dtor\n";
}
}

function test() {
$a[[]] = new D;
}

try {
test();
} catch (Throwable $e) {
echo $e::class, ": ", $e->getMessage(), "\n";
}
?>
--EXPECT--
dtor
TypeError: Cannot access offset of type array on array
34 changes: 34 additions & 0 deletions ext/opcache/tests/jit/assign_dim_024.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
--TEST--
JIT ASSIGN_DIM: OP_DATA is freed when an undefined key warning throws
--INI--
opcache.enable=1
opcache.enable_cli=1
opcache.file_update_protection=0
opcache.jit=function
--EXTENSIONS--
opcache
--FILE--
<?php
class D {
function __destruct() {
echo "dtor\n";
}
}

set_error_handler(function ($errno, $errstr) {
throw new Exception($errstr);
});

function test() {
$a[$k] = new D;
}

try {
test();
} catch (Throwable $e) {
echo $e::class, ": ", $e->getMessage(), "\n";
}
?>
--EXPECT--
dtor
Exception: Undefined variable $k
34 changes: 34 additions & 0 deletions ext/opcache/tests/jit/assign_dim_025.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
--TEST--
JIT ASSIGN_DIM: OP_DATA is freed when the array is destroyed by a float key notice
--INI--
opcache.enable=1
opcache.enable_cli=1
opcache.file_update_protection=0
opcache.jit=function
--EXTENSIONS--
opcache
--FILE--
<?php
class D {
function __destruct() {
echo "dtor\n";
}
}

set_error_handler(function () {
$GLOBALS["a"] = null;
return true;
});

function test() {
$GLOBALS["a"] = [];
$a = &$GLOBALS["a"];
$a[1.5] = new D;
var_dump($a);
}

test();
?>
--EXPECT--
dtor
NULL
Loading
Loading