Skip to content

Commit 7ca6a2e

Browse files
committed
Fix escape analysis for objects implementing ArrayAccess
Objects that implement ArrayAccess can run arbitrayr code on isset(), dimensions accesses etc. SCCP can then run on stale property values that were manipulated by such ArrayAccess handlers. We also take into accuont that we don't know the interfaces yet of unlinked classes.
1 parent 026bb4e commit 7ca6a2e

2 files changed

Lines changed: 54 additions & 0 deletions

File tree

‎Zend/Optimizer/escape_analysis.c‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,9 @@ static bool is_allocation_def(zend_op_array *op_array, zend_ssa *ssa, int def, i
175175
&& !ce->__set
176176
&& !ce->__isset
177177
&& !ce->num_hooked_props
178+
/* ArrayAccess methods receive the object, interfaces of unlinked classes are unknown */
179+
&& !ce->arrayaccess_funcs_ptr
180+
&& ((ce->ce_flags & ZEND_ACC_LINKED) || !ce->num_interfaces)
178181
&& !(ce->ce_flags & forbidden_flags)
179182
&& (ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) {
180183
return 1;
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
--TEST--
2+
Escape analysis: objects implementing ArrayAccess escape through dimension accesses
3+
--INI--
4+
opcache.enable=1
5+
opcache.enable_cli=1
6+
opcache.optimization_level=-1
7+
--EXTENSIONS--
8+
opcache
9+
--FILE--
10+
<?php
11+
#[AllowDynamicProperties]
12+
class AA implements ArrayAccess {
13+
function offsetExists($o): bool { $this->x = 3; return true; }
14+
function offsetGet($o): mixed { $this->x = 2; return 42; }
15+
function offsetSet($o, $v): void { $this->x = 4; }
16+
function offsetUnset($o): void {}
17+
18+
static function fetch() {
19+
$o = new self;
20+
$o->x = 1;
21+
$o[0];
22+
return $o->x;
23+
}
24+
25+
static function isset() {
26+
$o = new self;
27+
$o->x = 1;
28+
return [isset($o[0]), $o->x];
29+
}
30+
31+
static function assign() {
32+
$o = new self;
33+
$o->x = 1;
34+
$o[0] = 1;
35+
return $o->x;
36+
}
37+
}
38+
39+
var_dump(AA::fetch());
40+
var_dump(AA::isset());
41+
var_dump(AA::assign());
42+
?>
43+
--EXPECT--
44+
int(2)
45+
array(2) {
46+
[0]=>
47+
bool(true)
48+
[1]=>
49+
int(3)
50+
}
51+
int(4)

0 commit comments

Comments
 (0)