Skip to content
This repository was archived by the owner on Jul 7, 2018. It is now read-only.

Commit 4d6b82a

Browse files
committed
Fix wron behavior when reference get deleted durin notifier call
1 parent 1e912ed commit 4d6b82a

File tree

4 files changed

+70
-6
lines changed

4 files changed

+70
-6
lines changed

php_ref_reference.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,12 +122,14 @@ static void php_ref_call_notifiers(HashTable *references, zval *exceptions, zval
122122
}
123123

124124
if (IS_NULL == Z_TYPE(reference->notifier)) {
125-
/* no notifier set*/
125+
/* notifier is not set */
126126
break;
127127
}
128128

129-
/* callback notifier */
129+
/* WeakRef could be destroyed during notifier call, so we need to increment decrement refcount to survive */
130+
Z_ADDREF(reference->this_ptr);
130131
php_ref_reference_call_notifier(&reference->this_ptr, &reference->notifier);
132+
Z_DELREF(reference->this_ptr);
131133

132134
if (EG(exception)) {
133135
php_ref_store_exceptions(exceptions, tmp);

tests/002-WeakReference-clone.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ object(Ref\WeakReference)#5 (2) refcount(3){
9797

9898
Weak references reported with cloned reference: ok
9999

100-
Notified: object(Ref\WeakReference)#5 (2) refcount(6){
100+
Notified: object(Ref\WeakReference)#5 (2) refcount(7){
101101
["referent":"Ref\AbstractReference":private]=>
102102
NULL
103103
["notifier":"Ref\AbstractReference":private]=>
@@ -115,7 +115,7 @@ Notified: object(Ref\WeakReference)#5 (2) refcount(6){
115115
}
116116
}
117117
}
118-
Notified: object(Ref\WeakReference)#4 (2) refcount(6){
118+
Notified: object(Ref\WeakReference)#4 (2) refcount(7){
119119
["referent":"Ref\AbstractReference":private]=>
120120
NULL
121121
["notifier":"Ref\AbstractReference":private]=>
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
--TEST--
2+
Ref\WeakReference - reference deleted during notifier call
3+
--SKIPIF--
4+
<?php if (!extension_loaded("ref")) print "skip"; ?>
5+
--FILE--
6+
<?php
7+
8+
use Ref\WeakReference;
9+
10+
class Test
11+
{
12+
public $storage = [];
13+
14+
public function put($key, $value, string $hash)
15+
{
16+
$key = new WeakReference($key, function () use ($hash) {
17+
echo __METHOD__, PHP_EOL;
18+
var_dump($this);
19+
unset($this->storage[$hash]);
20+
var_dump($this);
21+
});
22+
23+
$this->storage[$hash] = $key;
24+
}
25+
}
26+
27+
$map = new Test();
28+
29+
$key_1 = new stdClass();
30+
$value_1 = new stdClass();
31+
32+
$map->put($key_1, $value_1, 'test');
33+
34+
$key_1 = null;
35+
?>
36+
--EXPECT--
37+
{closure}
38+
object(Test)#1 (1) {
39+
["storage"]=>
40+
array(1) {
41+
["test"]=>
42+
object(Ref\WeakReference)#4 (2) {
43+
["referent":"Ref\AbstractReference":private]=>
44+
NULL
45+
["notifier":"Ref\AbstractReference":private]=>
46+
object(Closure)#5 (2) {
47+
["static"]=>
48+
array(1) {
49+
["hash"]=>
50+
string(4) "test"
51+
}
52+
["this"]=>
53+
*RECURSION*
54+
}
55+
}
56+
}
57+
}
58+
object(Test)#1 (1) {
59+
["storage"]=>
60+
array(0) {
61+
}
62+
}

tests/004-SoftReference-clone.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ object(Ref\SoftReference)#5 (2) refcount(3){
9797

9898
Soft references reported with cloned reference: ok
9999

100-
Notified: object(Ref\SoftReference)#5 (2) refcount(6){
100+
Notified: object(Ref\SoftReference)#5 (2) refcount(7){
101101
["referent":"Ref\AbstractReference":private]=>
102102
object(stdClass)#2 (0) refcount(2){
103103
}
@@ -116,7 +116,7 @@ Notified: object(Ref\SoftReference)#5 (2) refcount(6){
116116
}
117117
}
118118
}
119-
Notified: object(Ref\SoftReference)#4 (2) refcount(6){
119+
Notified: object(Ref\SoftReference)#4 (2) refcount(7){
120120
["referent":"Ref\AbstractReference":private]=>
121121
object(stdClass)#2 (0) refcount(2){
122122
}

0 commit comments

Comments
 (0)