Fix Composer autoloader being hijackable by script/plugin event handlers (#11955)
parent
d4396a85bf
commit
bcab1c4b8e
|
@ -180,11 +180,6 @@ parameters:
|
|||
count: 2
|
||||
path: ../src/Composer/Util/Hg.php
|
||||
|
||||
-
|
||||
message: "#^Only booleans are allowed in &&, int\\<0, 2097152\\> given on the right side\\.$#"
|
||||
count: 1
|
||||
path: ../src/Composer/Util/Http/CurlDownloader.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$multi_handle of function curl_multi_add_handle expects CurlMultiHandle, resource\\|null given\\.$#"
|
||||
count: 1
|
||||
|
|
|
@ -332,7 +332,7 @@ parameters:
|
|||
|
||||
-
|
||||
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
|
||||
count: 4
|
||||
count: 3
|
||||
path: ../src/Composer/Command/DiagnoseCommand.php
|
||||
|
||||
-
|
||||
|
@ -1850,6 +1850,11 @@ parameters:
|
|||
count: 1
|
||||
path: ../src/Composer/Downloader/ZipDownloader.php
|
||||
|
||||
-
|
||||
message: "#^Argument of an invalid type array\\<int, callable\\>\\|false supplied for foreach, only iterables are supported\\.$#"
|
||||
count: 2
|
||||
path: ../src/Composer/EventDispatcher/EventDispatcher.php
|
||||
|
||||
-
|
||||
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
|
||||
count: 1
|
||||
|
@ -4000,7 +4005,7 @@ parameters:
|
|||
|
||||
-
|
||||
message: "#^Cannot access offset 'features' on array\\|false\\.$#"
|
||||
count: 2
|
||||
count: 1
|
||||
path: ../src/Composer/Util/Http/CurlDownloader.php
|
||||
|
||||
-
|
||||
|
@ -4010,11 +4015,6 @@ parameters:
|
|||
|
||||
-
|
||||
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
|
||||
count: 3
|
||||
path: ../src/Composer/Util/Http/CurlDownloader.php
|
||||
|
||||
-
|
||||
message: "#^Only booleans are allowed in &&, int given on the right side\\.$#"
|
||||
count: 1
|
||||
path: ../src/Composer/Util/Http/CurlDownloader.php
|
||||
|
||||
|
@ -4188,11 +4188,6 @@ parameters:
|
|||
count: 1
|
||||
path: ../src/Composer/Util/Http/CurlDownloader.php
|
||||
|
||||
-
|
||||
message: "#^Method Composer\\\\Util\\\\Http\\\\RequestProxy::getCurlOptions\\(\\) should return array\\<int, int\\|string\\> but returns array\\<int\\|string, int\\|string\\>.$#"
|
||||
count: 1
|
||||
path: ../src/Composer/Util/Http/RequestProxy.php
|
||||
|
||||
-
|
||||
message: "#^Constant CURLOPT_PROXY_CAINFO not found\\.$#"
|
||||
count: 1
|
||||
|
@ -4203,6 +4198,11 @@ parameters:
|
|||
count: 1
|
||||
path: ../src/Composer/Util/Http/RequestProxy.php
|
||||
|
||||
-
|
||||
message: "#^Method Composer\\\\Util\\\\Http\\\\RequestProxy\\:\\:getCurlOptions\\(\\) should return array\\<int, int\\|string\\> but returns array\\<int\\|string, int\\|string\\>\\.$#"
|
||||
count: 1
|
||||
path: ../src/Composer/Util/Http/RequestProxy.php
|
||||
|
||||
-
|
||||
message: "#^Cannot call method abortRequest\\(\\) on Composer\\\\Util\\\\Http\\\\CurlDownloader\\|null\\.$#"
|
||||
count: 1
|
||||
|
@ -4618,11 +4618,6 @@ parameters:
|
|||
count: 1
|
||||
path: ../src/Composer/Util/StreamContextFactory.php
|
||||
|
||||
-
|
||||
message: "#^Only booleans are allowed in an if condition, array given\\.$#"
|
||||
count: 1
|
||||
path: ../src/Composer/Util/StreamContextFactory.php
|
||||
|
||||
-
|
||||
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
|
||||
count: 2
|
||||
|
|
|
@ -194,6 +194,8 @@ class EventDispatcher
|
|||
|
||||
$this->pushEvent($event);
|
||||
|
||||
$autoloadersBefore = spl_autoload_functions();
|
||||
|
||||
try {
|
||||
$returnMax = 0;
|
||||
foreach ($listeners as $callable) {
|
||||
|
@ -411,6 +413,26 @@ class EventDispatcher
|
|||
}
|
||||
} finally {
|
||||
$this->popEvent();
|
||||
|
||||
$knownIdentifiers = [];
|
||||
foreach ($autoloadersBefore as $key => $cb) {
|
||||
$knownIdentifiers[$this->getCallbackIdentifier($cb)] = ['key' => $key, 'callback' => $cb];
|
||||
}
|
||||
foreach (spl_autoload_functions() as $cb) {
|
||||
// once we get to the first known autoloader, we can leave any appended autoloader without problems
|
||||
if (isset($knownIdentifiers[$this->getCallbackIdentifier($cb)]) && $knownIdentifiers[$this->getCallbackIdentifier($cb)]['key'] === 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
// other newly appeared prepended autoloaders should be appended instead to ensure Composer loads its classes first
|
||||
if ($cb instanceof ClassLoader) {
|
||||
$cb->unregister();
|
||||
$cb->register(false);
|
||||
} else {
|
||||
spl_autoload_unregister($cb);
|
||||
spl_autoload_register($cb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $returnMax;
|
||||
|
@ -638,4 +660,20 @@ class EventDispatcher
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function getCallbackIdentifier(callable $cb): string
|
||||
{
|
||||
if (is_string($cb)) {
|
||||
return 'fn:'.$cb;
|
||||
}
|
||||
if (is_object($cb)) {
|
||||
return 'obj:'.spl_object_hash($cb);
|
||||
}
|
||||
if (is_array($cb)) {
|
||||
return 'array:'.(is_string($cb[0]) ? $cb[0] : get_class($cb[0]) .'#'.spl_object_hash($cb[0])).'::'.$cb[1];
|
||||
}
|
||||
|
||||
// not great but also do not want to break everything here
|
||||
return 'unsupported';
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue