-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Fix stream double free in phar #18953
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
--TEST-- | ||
Phar: Stream double free | ||
--EXTENSIONS-- | ||
phar | ||
--INI-- | ||
phar.readonly=0 | ||
--ENV-- | ||
USE_ZEND_ALLOC=0 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Drop this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
--FILE-- | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
require __DIR__ . '/gh18953/autoload.inc'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You don't need all this autoloading stuff, nor the classes at the bottom. Executing the test without these things, with ASAN+USE_ZEND_ALLOC=0, reliably reproduces the bug. |
||
|
||
// cleaning | ||
@unlink("gh18953.phar"); | ||
@unlink("gh18953.phar.gz"); | ||
Comment on lines
+16
to
+18
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This shouldn't be needed because of the CLEAN section There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If last test failed without cleaning, this test will never success. So I unlink them here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A CLEAN section always runs, if it doesn't there are bigger problems with the test runner. Please remove it as asked previously. |
||
|
||
// create a phar | ||
$phar = new Phar("gh18953.phar"); | ||
$phar->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-- | ||
<?php | ||
@unlink("gh18953.phar"); | ||
@unlink("gh18953.phar.gz"); | ||
?> | ||
--EXPECT-- | ||
Done |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<?php | ||
|
||
spl_autoload_register(function ($class) { | ||
$base_dir = __DIR__ . '/src/'; | ||
|
||
$file = $base_dir . str_replace('\\', '/', $class) . '.inc'; | ||
if (file_exists($file)) { | ||
require $file; | ||
} | ||
}); | ||
Comment on lines
+3
to
+10
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you not move this into the base test file? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace NS1; | ||
|
||
use NS2\Interface1; | ||
|
||
class Class1 implements Interface1 | ||
{ | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace NS2; | ||
|
||
interface Interface1 | ||
{ | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like the wrong solution. You're resetting the file pointer but
phar_copy_file_contents
already used it.I believe the right solution is to:
phar_copy_file_contents
/* save for potential restore on error */
block that moves the file pointers as this recovery mechanism isn't implemented as far as I see.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's hard for me to understand why phar codes use
cfp
, so I use this strange solution to avoid break other features.Also, there are many memcpys (like newentry <- entry here), dont know why, so I chose to not modify
phar_copy_file_contents