]> granicus.if.org Git - php/commitdiff
fix #39551 (Segfault with stream_bucket_new in user filter)
authorAntony Dovgal <tony2001@php.net>
Tue, 21 Nov 2006 15:47:44 +0000 (15:47 +0000)
committerAntony Dovgal <tony2001@php.net>
Tue, 21 Nov 2006 15:47:44 +0000 (15:47 +0000)
also fixes several segfaults and leaks
add test

ext/standard/tests/file/bug39551.phpt [new file with mode: 0644]
ext/standard/user_filters.c
main/streams/filter.c

diff --git a/ext/standard/tests/file/bug39551.phpt b/ext/standard/tests/file/bug39551.phpt
new file mode 100644 (file)
index 0000000..67dc7e7
--- /dev/null
@@ -0,0 +1,28 @@
+--TEST--
+Bug #39551 (Segfault with stream_bucket_new in user filter)
+--FILE--
+<?php
+
+$bucket = stream_bucket_new(fopen('php://temp', 'w+'), '');
+
+class bucketFilter {
+       public function filter($in, $out, &$consumed, $closing ){
+
+               $bucket = stream_bucket_new(fopen('php://temp', 'w+'), '');
+               stream_bucket_append($out, $bucket);
+               return PSFS_PASS_ON;
+       }
+}
+
+stream_filter_register('bucketfault', 'bucketFilter');
+stream_filter_append($s = fopen('php://temp', 'r+'), 'bucketfault');
+stream_get_contents($s);
+
+echo "Done\n";
+?>
+--EXPECTF--    
+Done
+--UEXPECTF--
+Done
+
+Notice: Unknown: 0 character unicode buffer downcoded for binary stream runtime_encoding in Unknown on line 0
index fe324972503699b62104332c9e3b685608a7ccac..886362d32b58ab42358a234d6776368979792599 100644 (file)
@@ -79,6 +79,15 @@ static zend_function_entry user_filter_class_funcs[] = {
 
 static zend_class_entry user_filter_class_entry;
 
+static ZEND_RSRC_DTOR_FUNC(php_bucket_dtor)
+{
+       php_stream_bucket *bucket = (php_stream_bucket *)rsrc->ptr;
+       if (bucket) {
+               php_stream_bucket_delref(bucket TSRMLS_CC);
+               bucket = NULL;
+       }
+}
+
 PHP_MINIT_FUNCTION(user_filters)
 {
        zend_class_entry *php_user_filter;
@@ -101,7 +110,7 @@ PHP_MINIT_FUNCTION(user_filters)
        /* Filters will dispose of their brigades */
        le_bucket_brigade = zend_register_list_destructors_ex(NULL, NULL, PHP_STREAM_BRIGADE_RES_NAME, module_number);
        /* Brigades will dispose of their buckets */
-       le_bucket = zend_register_list_destructors_ex(NULL, NULL, PHP_STREAM_BUCKET_RES_NAME, module_number);
+       le_bucket = zend_register_list_destructors_ex(php_bucket_dtor, NULL, PHP_STREAM_BUCKET_RES_NAME, module_number);
        
        if (le_bucket_brigade == FAILURE) {
                return FAILURE;
@@ -466,6 +475,13 @@ static void php_stream_bucket_attach(int append, INTERNAL_FUNCTION_PARAMETERS)
        } else {
                php_stream_bucket_prepend(brigade, bucket TSRMLS_CC);
        }
+       
+       /* This is a hack necessary to accomodate situations where bucket is appended to the stream
+        *      * multiple times. See bug35916.phpt for reference.
+        *           */
+       if (bucket->refcount == 1) {
+               bucket->refcount++;
+       }
 }
 /* }}} */
 
@@ -502,14 +518,19 @@ PHP_FUNCTION(stream_bucket_new)
 
        object_init(return_value);
        if (Z_TYPE_P(buffer) == IS_UNICODE) {
-               bucket = php_stream_bucket_new_unicode(stream, Z_USTRVAL_P(buffer), Z_USTRLEN_P(buffer), 0, php_stream_is_persistent(stream) TSRMLS_CC);
+               UChar *pbuffer = peumalloc(Z_USTRLEN_P(buffer), php_stream_is_persistent(stream));
+               memcpy(pbuffer, buffer, UBYTES(Z_USTRLEN_P(buffer)));
+
+               bucket = php_stream_bucket_new_unicode(stream, pbuffer, Z_USTRLEN_P(buffer), 1, php_stream_is_persistent(stream) TSRMLS_CC);
 
-               ZVAL_ADDREF(buffer);
                add_property_zval(return_value, "data", buffer);
                add_property_long(return_value, "datalen", Z_USTRLEN_P(buffer));
        } else {
+               char *pbuffer = peumalloc(Z_STRLEN_P(buffer), php_stream_is_persistent(stream));
+               memcpy(pbuffer, buffer, Z_STRLEN_P(buffer));
+
                convert_to_string(buffer);
-               bucket = php_stream_bucket_new(stream, Z_STRVAL_P(buffer), Z_STRLEN_P(buffer), 0, php_stream_is_persistent(stream) TSRMLS_CC);
+               bucket = php_stream_bucket_new(stream, pbuffer, Z_STRLEN_P(buffer), 1, php_stream_is_persistent(stream) TSRMLS_CC);
  
                add_property_zval(return_value, "data", buffer);
                add_property_long(return_value, "datalen", Z_STRLEN_P(buffer));
index 214bdd38d0da4a86576565a05e7af42e3bdfb78a..4b414cbe274655f1837b15525634bcb9bf246ad9 100644 (file)
@@ -103,6 +103,7 @@ PHPAPI php_stream_bucket *php_stream_bucket_new(php_stream *stream, char *buf, s
        bucket->buf_type = IS_STRING;
        bucket->is_persistent = is_persistent;
        bucket->refcount = 1;
+       bucket->brigade = NULL;
 
        return bucket;
 }
@@ -140,6 +141,7 @@ PHPAPI php_stream_bucket *php_stream_bucket_new_unicode(php_stream *stream, UCha
        bucket->buf_type = IS_UNICODE;
        bucket->is_persistent = is_persistent;
        bucket->refcount = 1;
+       bucket->brigade = NULL;
 
        return bucket;
 }