Skip to content

Commit ae7117b

Browse files
committed
Merge branch 'PHP-8.3' into PHP-8.4
* PHP-8.3: Fix phpGH-20302: Freeing a phar alias may invalidate PharFileInfo objects
2 parents 0929f73 + 6fe40de commit ae7117b

File tree

3 files changed

+55
-11
lines changed

3 files changed

+55
-11
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ PHP NEWS
7373
. Fix file descriptor leak in phar_zip_flush() on failure. (nielsdos)
7474
. Fix memory leak when opening temp file fails while trying to open
7575
gzip-compressed archive. (nielsdos)
76+
. Fixed bug GH-20302 (Freeing a phar alias may invalidate
77+
PharFileInfo objects). (nielsdos)
7678

7779
- Random:
7880
. Fix Randomizer::__serialize() w.r.t. INDIRECTs. (nielsdos)

ext/phar/phar_object.c

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4520,6 +4520,9 @@ PHP_METHOD(PharFileInfo, __construct)
45204520
entry_obj->entry = entry_info;
45214521
if (!entry_info->is_persistent && !entry_info->is_temp_dir) {
45224522
++entry_info->fp_refcount;
4523+
/* The phar data must exist to keep the alias locked. */
4524+
ZEND_ASSERT(!phar_data->is_persistent);
4525+
++phar_data->refcount;
45234526
}
45244527

45254528
ZVAL_STRINGL(&arg1, fname, fname_len);
@@ -4550,23 +4553,26 @@ PHP_METHOD(PharFileInfo, __destruct)
45504553
RETURN_THROWS();
45514554
}
45524555

4553-
if (!entry_obj->entry) {
4556+
phar_entry_info *entry = entry_obj->entry;
4557+
if (!entry) {
45544558
return;
45554559
}
45564560

4557-
if (entry_obj->entry->is_temp_dir) {
4558-
if (entry_obj->entry->filename) {
4559-
efree(entry_obj->entry->filename);
4560-
entry_obj->entry->filename = NULL;
4561+
if (entry->is_temp_dir) {
4562+
if (entry->filename) {
4563+
efree(entry->filename);
4564+
entry->filename = NULL;
45614565
}
45624566

4563-
efree(entry_obj->entry);
4564-
} else if (!entry_obj->entry->is_persistent) {
4565-
--entry_obj->entry->fp_refcount;
4566-
/* It is necessarily still in the manifest, which will ultimately free this. */
4567+
efree(entry);
4568+
entry_obj->entry = NULL;
4569+
} else if (!entry->is_persistent) {
4570+
--entry->fp_refcount;
4571+
/* The entry itself still lives in the manifest,
4572+
* which will either be freed here if the file info was the last reference; or freed later. */
4573+
entry_obj->entry = NULL;
4574+
phar_archive_delref(entry->phar);
45674575
}
4568-
4569-
entry_obj->entry = NULL;
45704576
}
45714577
/* }}} */
45724578

ext/phar/tests/gh20302.phpt

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
--TEST--
2+
GH-20302 (Freeing a phar alias may invalidate PharFileInfo objects)
3+
--EXTENSIONS--
4+
phar
5+
--INI--
6+
phar.require_hash=0
7+
--FILE--
8+
<?php
9+
$fname = __DIR__.'/gh20302.phar';
10+
$pname = 'phar://' . $fname;
11+
$file = "<?php
12+
__HALT_COMPILER(); ?>";
13+
$files = array();
14+
$files['here'] = 'a';
15+
include __DIR__.'/files/phar_test.inc';
16+
$b = new PharFileInfo($pname . '/here');
17+
18+
// Create new phar with same alias and open it
19+
@mkdir(__DIR__.'/gh20302');
20+
$fname = __DIR__.'/gh20302/gh20302.phar';
21+
$pname = 'phar://' . $fname;
22+
include __DIR__.'/files/phar_test.inc';
23+
try {
24+
new Phar($fname);
25+
} catch (UnexpectedValueException $e) {
26+
echo $e->getMessage(), "\n";
27+
}
28+
?>
29+
--CLEAN--
30+
<?php
31+
@unlink(__DIR__.'/gh20302/gh20302.phar');
32+
@unlink(__DIR__.'/gh20302.phar');
33+
@rmdir(__DIR__.'/gh20302');
34+
?>
35+
--EXPECTF--
36+
Cannot open archive "%sgh20302.phar", alias is already in use by existing archive

0 commit comments

Comments
 (0)