Fix use after free when WeakMap is modified during field write

(When a value's destructor triggers a resizing or rehashing of the WeakMap)

Closes GH-7671
This commit is contained in:
Tyson Andre 2021-11-20 15:20:52 -05:00
parent 2f8407f185
commit 241bd3f454
2 changed files with 121 additions and 1 deletions

View File

@ -0,0 +1,116 @@
--TEST--
WeakReference overwriting existing value
--FILE--
<?php
class HasDtor {
public function __destruct() {
echo "In destruct\n";
global $w, $all;
for ($i = 0; $i < 10; $i++) {
$v = new stdClass();
$all[] = $v;
$w[$v] = $i;
}
}
}
$all = [];
$w = new WeakMap();
$o = new stdClass();
$w[$o] = new HasDtor();
$w[$o] = 123;
var_dump($w);
?>
--EXPECT--
In destruct
object(WeakMap)#1 (11) {
[0]=>
array(2) {
["key"]=>
object(stdClass)#2 (0) {
}
["value"]=>
int(123)
}
[1]=>
array(2) {
["key"]=>
object(stdClass)#4 (0) {
}
["value"]=>
int(0)
}
[2]=>
array(2) {
["key"]=>
object(stdClass)#5 (0) {
}
["value"]=>
int(1)
}
[3]=>
array(2) {
["key"]=>
object(stdClass)#6 (0) {
}
["value"]=>
int(2)
}
[4]=>
array(2) {
["key"]=>
object(stdClass)#7 (0) {
}
["value"]=>
int(3)
}
[5]=>
array(2) {
["key"]=>
object(stdClass)#8 (0) {
}
["value"]=>
int(4)
}
[6]=>
array(2) {
["key"]=>
object(stdClass)#9 (0) {
}
["value"]=>
int(5)
}
[7]=>
array(2) {
["key"]=>
object(stdClass)#10 (0) {
}
["value"]=>
int(6)
}
[8]=>
array(2) {
["key"]=>
object(stdClass)#11 (0) {
}
["value"]=>
int(7)
}
[9]=>
array(2) {
["key"]=>
object(stdClass)#12 (0) {
}
["value"]=>
int(8)
}
[10]=>
array(2) {
["key"]=>
object(stdClass)#13 (0) {
}
["value"]=>
int(9)
}
}

View File

@ -351,8 +351,12 @@ static void zend_weakmap_write_dimension(zend_object *object, zval *offset, zval
zval *zv = zend_hash_index_find(&wm->ht, (zend_ulong) obj_key);
if (zv) {
zval_ptr_dtor(zv);
/* Because the destructors can have side effects such as resizing or rehashing the WeakMap storage,
* free the zval only after overwriting the original value. */
zval zv_orig;
ZVAL_COPY_VALUE(&zv_orig, zv);
ZVAL_COPY_VALUE(zv, value);
zval_ptr_dtor(&zv_orig);
return;
}