Skip to content
Open
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 @@ -30,6 +30,8 @@ PHP NEWS
for grouping. (Klaas Skelte van der Werf)
. Fixed bug GH-24265 (Unwind/GracefulExit discarded in
zend_fiber_execute()). (David Carlier)
. Fixed bug GH-24712 (Use-after-free in foreach by reference when destructor
modifies the loop variable). (Lazizbek Ergashev)

- Date:
. Fixed bug GH-20503 (Assertion failure with ext/date DateInterval property
Expand Down
15 changes: 15 additions & 0 deletions Zend/tests/gh24712.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
--TEST--
GH-24712 (Use-after-free in foreach by reference when destructor modifies the loop variable)
--FILE--
<?php
class C {
function __destruct() {
$GLOBALS['a'] = null;
}
}
$a = new C;
foreach ([1] as &$a);
var_dump($a);
?>
--EXPECT--
NULL
27 changes: 27 additions & 0 deletions Zend/tests/gh24712_2.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
--TEST--
GH-24712 (Use-after-free in static variable binding when destructor modifies the variable)
--FILE--
<?php
class C {
function __construct(public string $var) {}
function __destruct() {
$GLOBALS[$this->var] = null;
}
}
function init() {
return 1;
}
$a = new C('a');
static $a;
var_dump($a);

for ($i = 0; $i < 2; $i++) {
unset($b);
$b = $i ? new C('b') : 0;
static $b = init();
}
var_dump($b);
?>
--EXPECT--
NULL
NULL
19 changes: 14 additions & 5 deletions Zend/zend_vm_def.h
Original file line number Diff line number Diff line change
Expand Up @@ -7402,11 +7402,13 @@ ZEND_VM_C_LABEL(fe_fetch_w_exit):
zval *variable_ptr = EX_VAR(opline->op2.var);
if (EXPECTED(variable_ptr != value)) {
zend_reference *ref;
zval garbage;

ref = Z_REF_P(value);
GC_ADDREF(ref);
i_zval_ptr_dtor(variable_ptr);
ZVAL_COPY_VALUE(&garbage, variable_ptr);
ZVAL_REF(variable_ptr, ref);
i_zval_ptr_dtor(&garbage);
}
} else {
Z_ADDREF_P(value);
Expand Down Expand Up @@ -9056,6 +9058,7 @@ ZEND_VM_HANDLER(183, ZEND_BIND_STATIC, CV, ANY, REF)
HashTable *ht;
zval *value;
zval *variable_ptr;
zval garbage;

variable_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_W);

Expand Down Expand Up @@ -9085,19 +9088,22 @@ ZEND_VM_HANDLER(183, ZEND_BIND_STATIC, CV, ANY, REF)
ref->sources.ptr = NULL;
Z_REF_P(value) = ref;
Z_TYPE_INFO_P(value) = IS_REFERENCE_EX;
i_zval_ptr_dtor(variable_ptr);
ZVAL_COPY_VALUE(&garbage, variable_ptr);
ZVAL_REF(variable_ptr, ref);
i_zval_ptr_dtor(&garbage);
} else {
Z_ADDREF_P(value);
i_zval_ptr_dtor(variable_ptr);
ZVAL_COPY_VALUE(&garbage, variable_ptr);
ZVAL_REF(variable_ptr, Z_REF_P(value));
i_zval_ptr_dtor(&garbage);
if (OP2_TYPE != IS_UNUSED) {
FREE_OP2();
}
}
} else {
i_zval_ptr_dtor(variable_ptr);
ZVAL_COPY_VALUE(&garbage, variable_ptr);
ZVAL_COPY(variable_ptr, value);
i_zval_ptr_dtor(&garbage);
}

ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
Expand All @@ -9122,11 +9128,14 @@ ZEND_VM_HANDLER(203, ZEND_BIND_INIT_STATIC_OR_JMP, CV, JMP_ADDR)
if (Z_TYPE_P(value) == IS_NULL) {
ZEND_VM_NEXT_OPCODE();
} else {
zval garbage;

SAVE_OPLINE();
zval_ptr_dtor(variable_ptr);
ZEND_ASSERT(Z_TYPE_P(value) == IS_REFERENCE);
Z_ADDREF_P(value);
ZVAL_COPY_VALUE(&garbage, variable_ptr);
ZVAL_REF(variable_ptr, Z_REF_P(value));
zval_ptr_dtor(&garbage);
ZEND_VM_JMP_EX(OP_JMP_ADDR(opline, opline->op2), 1);
}
}
Expand Down
19 changes: 14 additions & 5 deletions Zend/zend_vm_execute.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading