Skip to content

Commit 4913a88

Browse files
committed
Add dedicated StreamBucket class
1 parent 807524d commit 4913a88

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);
@@ -366,16 +368,16 @@ PHP_FUNCTION(stream_bucket_make_writeable)
366368
RETURN_THROWS();
367369
}
368370

369-
ZVAL_NULL(return_value);
370-
371371
if (brigade->head && (bucket = php_stream_bucket_make_writeable(brigade->head))) {
372372
ZVAL_RES(&zbucket, zend_register_resource(bucket, le_bucket));
373-
object_init(return_value);
373+
object_init_ex(return_value, stream_bucket_class_entry);
374374
add_property_zval(return_value, "bucket", &zbucket);
375375
/* add_property_zval increments the refcount which is unwanted here */
376376
zval_ptr_dtor(&zbucket);
377377
add_property_stringl(return_value, "data", bucket->buf, bucket->buflen);
378378
add_property_long(return_value, "datalen", bucket->buflen);
379+
} else {
380+
ZVAL_NULL(return_value);
379381
}
380382
}
381383
/* }}} */
@@ -384,38 +386,42 @@ PHP_FUNCTION(stream_bucket_make_writeable)
384386
static void php_stream_bucket_attach(int append, INTERNAL_FUNCTION_PARAMETERS)
385387
{
386388
zval *zbrigade, *zobject;
387-
zval *pzbucket, *pzdata;
389+
zval *pzbucket, *pzdata, rv;
388390
php_stream_bucket_brigade *brigade;
389391
php_stream_bucket *bucket;
390392

391393
ZEND_PARSE_PARAMETERS_START(2, 2)
392394
Z_PARAM_RESOURCE(zbrigade)
393-
Z_PARAM_OBJECT(zobject)
395+
Z_PARAM_OBJECT_OF_CLASS(zobject, stream_bucket_class_entry)
394396
ZEND_PARSE_PARAMETERS_END();
395397

396-
if (NULL == (pzbucket = zend_hash_str_find_deref(Z_OBJPROP_P(zobject), "bucket", sizeof("bucket")-1))) {
397-
zend_argument_value_error(2, "must be an object that has a \"bucket\" property");
398+
if ((brigade = (php_stream_bucket_brigade*)zend_fetch_resource(
399+
Z_RES_P(zbrigade), PHP_STREAM_BRIGADE_RES_NAME, le_bucket_brigade)) == NULL) {
398400
RETURN_THROWS();
399401
}
400402

401-
if ((brigade = (php_stream_bucket_brigade*)zend_fetch_resource(
402-
Z_RES_P(zbrigade), PHP_STREAM_BRIGADE_RES_NAME, le_bucket_brigade)) == NULL) {
403+
if (NULL == (pzbucket = zend_read_property(NULL, Z_OBJ_P(zobject), "bucket", sizeof("bucket")-1, false, &rv))) {
404+
zend_argument_value_error(2, "must be an object that has a \"bucket\" property");
403405
RETURN_THROWS();
404406
}
407+
ZVAL_DEREF(pzbucket);
405408

406409
if ((bucket = (php_stream_bucket *)zend_fetch_resource_ex(pzbucket, PHP_STREAM_BUCKET_RES_NAME, le_bucket)) == NULL) {
407410
RETURN_THROWS();
408411
}
409412

410-
if (NULL != (pzdata = zend_hash_str_find_deref(Z_OBJPROP_P(zobject), "data", sizeof("data")-1)) && Z_TYPE_P(pzdata) == IS_STRING) {
411-
if (!bucket->own_buf) {
412-
bucket = php_stream_bucket_make_writeable(bucket);
413-
}
414-
if (bucket->buflen != Z_STRLEN_P(pzdata)) {
415-
bucket->buf = perealloc(bucket->buf, Z_STRLEN_P(pzdata), bucket->is_persistent);
416-
bucket->buflen = Z_STRLEN_P(pzdata);
413+
if (NULL != (pzdata = zend_read_property(NULL, Z_OBJ_P(zobject), "data", sizeof("data")-1, false, &rv))) {
414+
ZVAL_DEREF(pzdata);
415+
if (Z_TYPE_P(pzdata) == IS_STRING) {
416+
if (!bucket->own_buf) {
417+
bucket = php_stream_bucket_make_writeable(bucket);
418+
}
419+
if (bucket->buflen != Z_STRLEN_P(pzdata)) {
420+
bucket->buf = perealloc(bucket->buf, Z_STRLEN_P(pzdata), bucket->is_persistent);
421+
bucket->buflen = Z_STRLEN_P(pzdata);
422+
}
423+
memcpy(bucket->buf, Z_STRVAL_P(pzdata), bucket->buflen);
417424
}
418-
memcpy(bucket->buf, Z_STRVAL_P(pzdata), bucket->buflen);
419425
}
420426

421427
if (append) {
@@ -469,7 +475,7 @@ PHP_FUNCTION(stream_bucket_new)
469475
bucket = php_stream_bucket_new(stream, pbuffer, buffer_len, 1, php_stream_is_persistent(stream));
470476

471477
ZVAL_RES(&zbucket, zend_register_resource(bucket, le_bucket));
472-
object_init(return_value);
478+
object_init_ex(return_value, stream_bucket_class_entry);
473479
add_property_zval(return_value, "bucket", &zbucket);
474480
/* add_property_zval increments the refcount which is unwanted here */
475481
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)