diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index 155a3fca67bf2..acd9aa0cff655 100644 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -4391,6 +4391,9 @@ PHP_METHOD(PharFileInfo, __construct) entry_obj->entry = entry_info; if (!entry_info->is_persistent && !entry_info->is_temp_dir) { ++entry_info->fp_refcount; + /* The phar data must exist to keep the alias locked. */ + ZEND_ASSERT(!phar_data->is_persistent); + ++phar_data->refcount; } ZVAL_STRINGL(&arg1, fname, fname_len); @@ -4421,19 +4424,23 @@ PHP_METHOD(PharFileInfo, __destruct) PHAR_ENTRY_OBJECT_EX(false); - if (entry_obj->entry->is_temp_dir) { - if (entry_obj->entry->filename) { - zend_string_efree(entry_obj->entry->filename); - entry_obj->entry->filename = NULL; + phar_entry_info *entry = entry_obj->entry; + + if (entry->is_temp_dir) { + if (entry->filename) { + zend_string_release_ex(entry->filename, false); + entry->filename = NULL; } - efree(entry_obj->entry); - } else if (!entry_obj->entry->is_persistent) { - --entry_obj->entry->fp_refcount; - /* It is necessarily still in the manifest, which will ultimately free this. */ + efree(entry); + entry_obj->entry = NULL; + } else if (!entry->is_persistent) { + --entry->fp_refcount; + /* The entry itself still lives in the manifest, + * which will either be freed here if the file info was the last reference; or freed later. */ + entry_obj->entry = NULL; + phar_archive_delref(entry->phar); } - - entry_obj->entry = NULL; } /* }}} */ diff --git a/ext/phar/tests/gh20302.phpt b/ext/phar/tests/gh20302.phpt new file mode 100644 index 0000000000000..0cbd253d54fc3 --- /dev/null +++ b/ext/phar/tests/gh20302.phpt @@ -0,0 +1,36 @@ +--TEST-- +GH-20302 (Freeing a phar alias may invalidate PharFileInfo objects) +--EXTENSIONS-- +phar +--INI-- +phar.require_hash=0 +--FILE-- +"; +$files = array(); +$files['here'] = 'a'; +include __DIR__.'/files/phar_test.inc'; +$b = new PharFileInfo($pname . '/here'); + +// Create new phar with same alias and open it +@mkdir(__DIR__.'/gh20302'); +$fname = __DIR__.'/gh20302/gh20302.phar'; +$pname = 'phar://' . $fname; +include __DIR__.'/files/phar_test.inc'; +try { + new Phar($fname); +} catch (UnexpectedValueException $e) { + echo $e->getMessage(), "\n"; +} +?> +--CLEAN-- + +--EXPECTF-- +Cannot open archive "%sgh20302.phar", alias is already in use by existing archive