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 @@ -94,6 +94,8 @@ PHP NEWS
. Fixed a memory leak in array_merge_recursive() when the recursive merge of
an object converted to an array fails. (David Carlier)
. Fixed read buffer compaction in php_stream_filter_flush(). (crystarm)
. Fixed leaked buckets when a stream filter appends output and then returns
PSFS_FEED_ME or PSFS_ERR_FATAL. (Ilia Alshanetsky)

- SimpleXML:
. Fixed writing to a dimension of the object returned by attributes() not
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
--TEST--
php_stream_filter_flush() discards buckets a filter left behind on PSFS_FEED_ME / PSFS_ERR_FATAL
--FILE--
<?php
class feed_filter extends php_user_filter
{
public function filter($in, $out, &$consumed, $closing): int
{
while ($bucket = stream_bucket_make_writeable($in)) {
$consumed += strlen($bucket->data);
}
stream_bucket_append($out, stream_bucket_new($this->stream, 'abandoned'));
return PSFS_FEED_ME;
}
}

class fatal_filter extends php_user_filter
{
public function filter($in, $out, &$consumed, $closing): int
{
stream_bucket_append($out, stream_bucket_new($this->stream, 'abandoned'));
return PSFS_ERR_FATAL;
}
}

stream_filter_register('feed', feed_filter::class);
stream_filter_register('fatal', fatal_filter::class);

foreach (['feed', 'fatal'] as $name) {
$fp = fopen('php://memory', 'w+');
$filter = stream_filter_append($fp, $name, STREAM_FILTER_WRITE);
var_dump(stream_filter_remove($filter));
fclose($fp);
}

echo "done\n";
?>
--EXPECTF--
bool(true)

Warning: stream_filter_remove(): Unable to flush filter, not removing in %s on line %d
bool(false)
done
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
--TEST--
php_stream_write_filtered() discards output buckets a filter left behind on PSFS_FEED_ME
--FILE--
<?php
class feed_filter extends php_user_filter
{
public function filter($in, $out, &$consumed, $closing): int
{
while ($bucket = stream_bucket_make_writeable($in)) {
$consumed += strlen($bucket->data);
}
stream_bucket_append($out, stream_bucket_new($this->stream, 'abandoned'));
return PSFS_FEED_ME;
}
}

stream_filter_register('feed', feed_filter::class);

$fp = fopen('php://memory', 'w+');
stream_filter_append($fp, 'feed', STREAM_FILTER_WRITE);
var_dump(fwrite($fp, 'one'));
fclose($fp);

echo "done\n";
?>
--EXPECT--
int(3)
done
10 changes: 10 additions & 0 deletions main/streams/filter.c
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,16 @@ PHPAPI int _php_stream_filter_flush(php_stream_filter *filter, int finish)
php_stream_filter_status_t status;

status = current->fops->filter(stream, current, inp, outp, NULL, flags);
if (status == PSFS_FEED_ME || status == PSFS_ERR_FATAL) {
while ((bucket = inp->head)) {
php_stream_bucket_unlink(bucket);
php_stream_bucket_delref(bucket);
}
while ((bucket = outp->head)) {
php_stream_bucket_unlink(bucket);
php_stream_bucket_delref(bucket);
}
}
if (status == PSFS_FEED_ME) {
/* We've flushed the data far enough */
return SUCCESS;
Expand Down
5 changes: 5 additions & 0 deletions main/streams/streams.c
Original file line number Diff line number Diff line change
Expand Up @@ -1306,6 +1306,11 @@ static ssize_t _php_stream_write_filtered(php_stream *stream, const char *buf, s
php_stream_bucket_unlink(bucket);
php_stream_bucket_delref(bucket);
}
while (brig_outp->head) {
bucket = brig_outp->head;
php_stream_bucket_unlink(bucket);
php_stream_bucket_delref(bucket);
}
break;
}

Expand Down
Loading