Skip to content

Commit 71998e9

Browse files
committed
Add dedicated StreamBucket class
1 parent 11d3ded commit 71998e9

7 files changed

+87
-29
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: 10 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,13 @@ 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+
}
2433
Done

ext/standard/user_filters.c

Lines changed: 24 additions & 18 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,16 @@ 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);
358+
object_init_ex(return_value, stream_bucket_class_entry);
359359
add_property_zval(return_value, "bucket", &zbucket);
360360
/* add_property_zval increments the refcount which is unwanted here */
361361
zval_ptr_dtor(&zbucket);
362362
add_property_stringl(return_value, "data", bucket->buf, bucket->buflen);
363363
add_property_long(return_value, "datalen", bucket->buflen);
364+
} else {
365+
ZVAL_NULL(return_value);
364366
}
365367
}
366368
/* }}} */
@@ -369,38 +371,42 @@ PHP_FUNCTION(stream_bucket_make_writeable)
369371
static void php_stream_bucket_attach(int append, INTERNAL_FUNCTION_PARAMETERS)
370372
{
371373
zval *zbrigade, *zobject;
372-
zval *pzbucket, *pzdata;
374+
zval *pzbucket, *pzdata, rv;
373375
php_stream_bucket_brigade *brigade;
374376
php_stream_bucket *bucket;
375377

376378
ZEND_PARSE_PARAMETERS_START(2, 2)
377379
Z_PARAM_RESOURCE(zbrigade)
378-
Z_PARAM_OBJECT(zobject)
380+
Z_PARAM_OBJECT_OF_CLASS(zobject, stream_bucket_class_entry)
379381
ZEND_PARSE_PARAMETERS_END();
380382

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");
383+
if ((brigade = (php_stream_bucket_brigade*)zend_fetch_resource(
384+
Z_RES_P(zbrigade), PHP_STREAM_BRIGADE_RES_NAME, le_bucket_brigade)) == NULL) {
383385
RETURN_THROWS();
384386
}
385387

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

391394
if ((bucket = (php_stream_bucket *)zend_fetch_resource_ex(pzbucket, PHP_STREAM_BUCKET_RES_NAME, le_bucket)) == NULL) {
392395
RETURN_THROWS();
393396
}
394397

395-
if (NULL != (pzdata = zend_hash_str_find_deref(Z_OBJPROP_P(zobject), "data", sizeof("data")-1)) && Z_TYPE_P(pzdata) == IS_STRING) {
396-
if (!bucket->own_buf) {
397-
bucket = php_stream_bucket_make_writeable(bucket);
398-
}
399-
if (bucket->buflen != Z_STRLEN_P(pzdata)) {
400-
bucket->buf = perealloc(bucket->buf, Z_STRLEN_P(pzdata), bucket->is_persistent);
401-
bucket->buflen = Z_STRLEN_P(pzdata);
398+
if (NULL != (pzdata = zend_read_property(NULL, Z_OBJ_P(zobject), "data", sizeof("data")-1, false, &rv))) {
399+
ZVAL_DEREF(pzdata);
400+
if (Z_TYPE_P(pzdata) == IS_STRING) {
401+
if (!bucket->own_buf) {
402+
bucket = php_stream_bucket_make_writeable(bucket);
403+
}
404+
if (bucket->buflen != Z_STRLEN_P(pzdata)) {
405+
bucket->buf = perealloc(bucket->buf, Z_STRLEN_P(pzdata), bucket->is_persistent);
406+
bucket->buflen = Z_STRLEN_P(pzdata);
407+
}
408+
memcpy(bucket->buf, Z_STRVAL_P(pzdata), bucket->buflen);
402409
}
403-
memcpy(bucket->buf, Z_STRVAL_P(pzdata), bucket->buflen);
404410
}
405411

406412
if (append) {
@@ -454,7 +460,7 @@ PHP_FUNCTION(stream_bucket_new)
454460
bucket = php_stream_bucket_new(stream, pbuffer, buffer_len, 1, php_stream_is_persistent(stream));
455461

456462
ZVAL_RES(&zbucket, zend_register_resource(bucket, le_bucket));
457-
object_init(return_value);
463+
object_init_ex(return_value, stream_bucket_class_entry);
458464
add_property_zval(return_value, "bucket", &zbucket);
459465
/* add_property_zval increments the refcount which is unwanted here */
460466
zval_ptr_dtor(&zbucket);

ext/standard/user_filters.stub.php

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

ext/standard/user_filters_arginfo.h

Lines changed: 34 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)