Skip to content

Commit be2f454

Browse files
authored
Add dedicated StreamBucket class (#13111)
RFC: https://wiki.php.net/rfc/dedicated_stream_bucket
1 parent bc62b41 commit be2f454

7 files changed

+101
-28
lines changed

ext/reflection/tests/ReflectionExtension_getClassNames_basic.phpt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@ $standard = new ReflectionExtension('standard');
88
var_dump($standard->getClassNames());
99
?>
1010
--EXPECT--
11-
array(4) {
11+
array(5) {
1212
[0]=>
1313
string(22) "__PHP_Incomplete_Class"
1414
[1]=>
1515
string(14) "AssertionError"
1616
[2]=>
1717
string(15) "php_user_filter"
1818
[3]=>
19+
string(12) "StreamBucket"
20+
[4]=>
1921
string(9) "Directory"
2022
}

ext/standard/basic_functions.stub.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3744,19 +3744,19 @@ function get_headers(string $url, bool $associative = false, $context = null): a
37443744
* @param resource $brigade
37453745
* @refcount 1
37463746
*/
3747-
function stream_bucket_make_writeable($brigade): ?object {}
3747+
function stream_bucket_make_writeable($brigade): ?StreamBucket {}
37483748

37493749
/** @param resource $brigade */
3750-
function stream_bucket_prepend($brigade, object $bucket): void {}
3750+
function stream_bucket_prepend($brigade, StreamBucket $bucket): void {}
37513751

37523752
/** @param resource $brigade */
3753-
function stream_bucket_append($brigade, object $bucket): void {}
3753+
function stream_bucket_append($brigade, StreamBucket $bucket): void {}
37543754

37553755
/**
37563756
* @param resource $stream
37573757
* @refcount 1
37583758
*/
3759-
function stream_bucket_new($stream, string $buffer): object {}
3759+
function stream_bucket_new($stream, string $buffer): StreamBucket {}
37603760

37613761
/**
37623762
* @return array<int, string>

ext/standard/basic_functions_arginfo.h

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ext/standard/tests/file/bug39551.phpt

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ Bug #39551 (Segfault with stream_bucket_new in user filter)
44
<?php
55

66
$bucket = stream_bucket_new(fopen('php://temp', 'w+'), '');
7+
var_dump($bucket);
78

89
class bucketFilter extends php_user_filter {
910
public function filter($in, $out, &$consumed, $closing ): int {
@@ -20,5 +21,15 @@ stream_get_contents($s);
2021

2122
echo "Done\n";
2223
?>
23-
--EXPECT--
24+
--EXPECTF--
25+
object(StreamBucket)#%d (%d) {
26+
["bucket"]=>
27+
resource(%d) of type (userfilter.bucket)
28+
["data"]=>
29+
string(0) ""
30+
["datalen"]=>
31+
int(0)
32+
["dataLength"]=>
33+
int(0)
34+
}
2435
Done

ext/standard/user_filters.c

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ PHP_METHOD(php_user_filter, onClose)
6161
}
6262

6363
static zend_class_entry *user_filter_class_entry;
64+
static zend_class_entry *stream_bucket_class_entry;
6465

6566
static ZEND_RSRC_DTOR_FUNC(php_bucket_dtor)
6667
{
@@ -75,6 +76,7 @@ PHP_MINIT_FUNCTION(user_filters)
7576
{
7677
/* init the filter class ancestor */
7778
user_filter_class_entry = register_class_php_user_filter();
79+
stream_bucket_class_entry = register_class_StreamBucket();
7880

7981
/* Filters will dispose of their brigades */
8082
le_bucket_brigade = zend_register_list_destructors_ex(NULL, NULL, PHP_STREAM_BRIGADE_RES_NAME, module_number);
@@ -351,16 +353,17 @@ PHP_FUNCTION(stream_bucket_make_writeable)
351353
RETURN_THROWS();
352354
}
353355

354-
ZVAL_NULL(return_value);
355-
356356
if (brigade->head && (bucket = php_stream_bucket_make_writeable(brigade->head))) {
357357
ZVAL_RES(&zbucket, zend_register_resource(bucket, le_bucket));
358-
object_init(return_value);
359-
add_property_zval(return_value, "bucket", &zbucket);
358+
object_init_ex(return_value, stream_bucket_class_entry);
359+
zend_update_property(Z_OBJCE_P(return_value), Z_OBJ_P(return_value), ZEND_STRL("bucket"), &zbucket);
360360
/* add_property_zval increments the refcount which is unwanted here */
361361
zval_ptr_dtor(&zbucket);
362-
add_property_stringl(return_value, "data", bucket->buf, bucket->buflen);
363-
add_property_long(return_value, "datalen", bucket->buflen);
362+
zend_update_property_stringl(Z_OBJCE_P(return_value), Z_OBJ_P(return_value), ZEND_STRL("data"), bucket->buf, bucket->buflen);
363+
zend_update_property_long(Z_OBJCE_P(return_value), Z_OBJ_P(return_value), ZEND_STRL("datalen"), bucket->buflen);
364+
zend_update_property_long(Z_OBJCE_P(return_value), Z_OBJ_P(return_value), ZEND_STRL("dataLength"), bucket->buflen);
365+
} else {
366+
ZVAL_NULL(return_value);
364367
}
365368
}
366369
/* }}} */
@@ -369,30 +372,32 @@ PHP_FUNCTION(stream_bucket_make_writeable)
369372
static void php_stream_bucket_attach(int append, INTERNAL_FUNCTION_PARAMETERS)
370373
{
371374
zval *zbrigade, *zobject;
372-
zval *pzbucket, *pzdata;
375+
zval *pzbucket, *pzdata, rv;
373376
php_stream_bucket_brigade *brigade;
374377
php_stream_bucket *bucket;
375378

376379
ZEND_PARSE_PARAMETERS_START(2, 2)
377380
Z_PARAM_RESOURCE(zbrigade)
378-
Z_PARAM_OBJECT(zobject)
381+
Z_PARAM_OBJECT_OF_CLASS(zobject, stream_bucket_class_entry)
379382
ZEND_PARSE_PARAMETERS_END();
380383

381-
if (NULL == (pzbucket = zend_hash_str_find_deref(Z_OBJPROP_P(zobject), "bucket", sizeof("bucket")-1))) {
382-
zend_argument_value_error(2, "must be an object that has a \"bucket\" property");
384+
if ((brigade = (php_stream_bucket_brigade*)zend_fetch_resource(
385+
Z_RES_P(zbrigade), PHP_STREAM_BRIGADE_RES_NAME, le_bucket_brigade)) == NULL) {
383386
RETURN_THROWS();
384387
}
385388

386-
if ((brigade = (php_stream_bucket_brigade*)zend_fetch_resource(
387-
Z_RES_P(zbrigade), PHP_STREAM_BRIGADE_RES_NAME, le_bucket_brigade)) == NULL) {
389+
if (NULL == (pzbucket = zend_read_property(NULL, Z_OBJ_P(zobject), "bucket", sizeof("bucket")-1, false, &rv))) {
390+
zend_argument_value_error(2, "must be an object that has a \"bucket\" property");
388391
RETURN_THROWS();
389392
}
393+
ZVAL_DEREF(pzbucket);
390394

391395
if ((bucket = (php_stream_bucket *)zend_fetch_resource_ex(pzbucket, PHP_STREAM_BUCKET_RES_NAME, le_bucket)) == NULL) {
392396
RETURN_THROWS();
393397
}
394398

395-
if (NULL != (pzdata = zend_hash_str_find_deref(Z_OBJPROP_P(zobject), "data", sizeof("data")-1)) && Z_TYPE_P(pzdata) == IS_STRING) {
399+
if (NULL != (pzdata = zend_read_property(NULL, Z_OBJ_P(zobject), "data", sizeof("data")-1, false, &rv))) {
400+
ZVAL_DEREF(pzdata);
396401
if (!bucket->own_buf) {
397402
bucket = php_stream_bucket_make_writeable(bucket);
398403
}
@@ -454,12 +459,13 @@ PHP_FUNCTION(stream_bucket_new)
454459
bucket = php_stream_bucket_new(stream, pbuffer, buffer_len, 1, php_stream_is_persistent(stream));
455460

456461
ZVAL_RES(&zbucket, zend_register_resource(bucket, le_bucket));
457-
object_init(return_value);
458-
add_property_zval(return_value, "bucket", &zbucket);
462+
object_init_ex(return_value, stream_bucket_class_entry);
463+
zend_update_property(Z_OBJCE_P(return_value), Z_OBJ_P(return_value), ZEND_STRL("bucket"), &zbucket);
459464
/* add_property_zval increments the refcount which is unwanted here */
460465
zval_ptr_dtor(&zbucket);
461-
add_property_stringl(return_value, "data", bucket->buf, bucket->buflen);
462-
add_property_long(return_value, "datalen", bucket->buflen);
466+
zend_update_property_stringl(Z_OBJCE_P(return_value), Z_OBJ_P(return_value), ZEND_STRL("data"), bucket->buf, bucket->buflen);
467+
zend_update_property_long(Z_OBJCE_P(return_value), Z_OBJ_P(return_value), ZEND_STRL("datalen"), bucket->buflen);
468+
zend_update_property_long(Z_OBJCE_P(return_value), Z_OBJ_P(return_value), ZEND_STRL("dataLength"), bucket->buflen);
463469
}
464470
/* }}} */
465471

ext/standard/user_filters.stub.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,18 @@ public function onCreate(): bool {}
5555
/** @tentative-return-type */
5656
public function onClose(): void {}
5757
}
58+
59+
final class StreamBucket
60+
{
61+
/**
62+
* @var resource
63+
* @readonly
64+
*/
65+
public $bucket;
66+
/** @readonly */
67+
public string $data;
68+
/** @readonly */
69+
public int $datalen;
70+
/** @readonly */
71+
public int $dataLength;
72+
}

ext/standard/user_filters_arginfo.h

Lines changed: 40 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)