From 8373efc9b95d1ebc08763a2ab1d227ecd04210d0 Mon Sep 17 00:00:00 2001 From: Antony Dovgal Date: Tue, 21 Nov 2006 15:47:44 +0000 Subject: [PATCH] fix #39551 (Segfault with stream_bucket_new in user filter) also fixes several segfaults and leaks add test --- ext/standard/tests/file/bug39551.phpt | 28 ++++++++++++++++++++++++++ ext/standard/user_filters.c | 29 +++++++++++++++++++++++---- main/streams/filter.c | 2 ++ 3 files changed, 55 insertions(+), 4 deletions(-) create mode 100644 ext/standard/tests/file/bug39551.phpt diff --git a/ext/standard/tests/file/bug39551.phpt b/ext/standard/tests/file/bug39551.phpt new file mode 100644 index 0000000000..67dc7e7b23 --- /dev/null +++ b/ext/standard/tests/file/bug39551.phpt @@ -0,0 +1,28 @@ +--TEST-- +Bug #39551 (Segfault with stream_bucket_new in user filter) +--FILE-- + +--EXPECTF-- +Done +--UEXPECTF-- +Done + +Notice: Unknown: 0 character unicode buffer downcoded for binary stream runtime_encoding in Unknown on line 0 diff --git a/ext/standard/user_filters.c b/ext/standard/user_filters.c index fe32497250..886362d32b 100644 --- a/ext/standard/user_filters.c +++ b/ext/standard/user_filters.c @@ -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)); diff --git a/main/streams/filter.c b/main/streams/filter.c index 214bdd38d0..4b414cbe27 100644 --- a/main/streams/filter.c +++ b/main/streams/filter.c @@ -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; } -- 2.50.1