diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index 723339a431ee2..22d97dcc573d8 100644 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -2306,6 +2306,13 @@ static zend_object *phar_convert_to_other(phar_archive_data *source, int convert /* exception already thrown */ return NULL; } + + if (newentry.fp == NULL) { + /* entry->fp may be moved to cfp in phar_copy_file_contents + * and be free'd later in phar_flush_ex + * If so, zero fp to avoid double free in rshutdown. */ + entry->fp = NULL; + } no_copy: newentry.filename = zend_string_copy(newentry.filename); diff --git a/ext/phar/tests/gh18953.phpt b/ext/phar/tests/gh18953.phpt new file mode 100644 index 0000000000000..53860edfa3a52 --- /dev/null +++ b/ext/phar/tests/gh18953.phpt @@ -0,0 +1,45 @@ +--TEST-- +Phar: Stream double free +--EXTENSIONS-- +phar +--INI-- +phar.readonly=0 +--ENV-- +USE_ZEND_ALLOC=0 +--FILE-- +startBuffering(); +// add any dir +$phar->addEmptyDir("dir"); +$phar->stopBuffering(); +// compress +$phar->compress(Phar::GZ); + +// this increases the chance of reproducing the problem +// even with this, it's not always reproducible +$obj1 = new NS1\Class1(); +$obj2 = new NS1\Class1(); +$obj2 = new NS1\Class1(); +$obj2 = new NS1\Class1(); +$obj2 = new NS1\Class1(); + +echo "Done" . PHP_EOL; +?> +--CLEAN-- + +--EXPECT-- +Done diff --git a/ext/phar/tests/gh18953/autoload.inc b/ext/phar/tests/gh18953/autoload.inc new file mode 100644 index 0000000000000..bf00622767c1e --- /dev/null +++ b/ext/phar/tests/gh18953/autoload.inc @@ -0,0 +1,10 @@ +