Skip to content

Commit c838191

Browse files
address Arnaud's comment
1 parent 3d5358f commit c838191

File tree

2 files changed

+53
-15
lines changed

2 files changed

+53
-15
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
--TEST--
2+
GH-20370 (User filters should handle private stream property correctly)
3+
--FILE--
4+
<?php
5+
6+
class pass_filter
7+
{
8+
public $filtername;
9+
public $params;
10+
private $stream;
11+
12+
function filter($in, $out, &$consumed, $closing): int
13+
{
14+
while ($bucket = stream_bucket_make_writeable($in)) {
15+
$consumed += $bucket->datalen;
16+
stream_bucket_append($out, $bucket);
17+
}
18+
return PSFS_PASS_ON;
19+
}
20+
21+
function onClose()
22+
{
23+
var_dump($this->stream); // should be null
24+
}
25+
}
26+
27+
stream_filter_register("pass", "pass_filter");
28+
$fp = fopen("php://memory", "w");
29+
stream_filter_append($fp, "pass", STREAM_FILTER_WRITE);
30+
31+
fwrite($fp, "data");
32+
rewind($fp);
33+
echo fread($fp, 1024) . "\n";
34+
35+
?>
36+
--EXPECT--
37+
data
38+
NULL

ext/standard/user_filters.c

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,6 @@ php_stream_filter_status_t userfilter_filter(
169169
return PSFS_ERR_FATAL;
170170
}
171171
}
172-
zend_string_release(stream_name);
173172

174173
EG(fake_scope) = old_scope;
175174

@@ -213,22 +212,23 @@ php_stream_filter_status_t userfilter_filter(
213212

214213
/* filter resources are cleaned up by the stream destructor,
215214
* keeping a reference to the stream resource here would prevent it
216-
* from being destroyed properly */
217-
zend_property_info *prop_info = zend_hash_str_find_ptr(&Z_OBJCE_P(obj)->properties_info, "stream", sizeof("stream")-1);
218-
zval *stream_prop = zend_hash_str_find(Z_OBJPROP_P(obj), "stream", sizeof("stream")-1);
219-
220-
if (stream_prop) {
221-
if (prop_info) {
222-
/* Declared property: set to UNDEF to make it uninitialized */
223-
zval_ptr_dtor(stream_prop);
224-
ZVAL_UNDEF(stream_prop);
225-
} else {
226-
/* Dynamic property: set to null */
227-
zval_ptr_dtor(stream_prop);
228-
ZVAL_NULL(stream_prop);
229-
}
215+
* from being destroyed properly.
216+
* Since the property accepted a resource assignment above, it must have
217+
* no type hint or be typed as mixed, so we can safely assign null.
218+
*/
219+
old_scope = EG(fake_scope);
220+
EG(fake_scope) = Z_OBJCE_P(obj);
221+
222+
if (Z_OBJ_HT_P(obj)->has_property(Z_OBJ_P(obj), stream_name, ZEND_PROPERTY_EXISTS, NULL)) {
223+
zval null_zval;
224+
ZVAL_NULL(&null_zval);
225+
zend_update_property_ex(Z_OBJCE_P(obj), Z_OBJ_P(obj), stream_name, &null_zval);
230226
}
231227

228+
EG(fake_scope) = old_scope;
229+
230+
zend_string_release(stream_name);
231+
232232
zval_ptr_dtor(&args[3]);
233233
zval_ptr_dtor(&args[2]);
234234
zval_ptr_dtor(&args[1]);

0 commit comments

Comments
 (0)