68 lines
4.7 KiB
Diff
68 lines
4.7 KiB
Diff
# UNDF: UNDF-2026-000000038
|
|
diff --git a/src/Composer/Repository/InstalledRepository.php b/src/Composer/Repository/InstalledRepository.php
|
|
index 3520fde..3cbe917 100644
|
|
--- a/src/Composer/Repository/InstalledRepository.php
|
|
+++ b/src/Composer/Repository/InstalledRepository.php
|
|
@@ -86,7 +86,7 @@ public function findPackagesWithReplacersAndProviders(string $name, $constraint
|
|
* @return array[] An associative array of arrays as described above.
|
|
* @phpstan-return array<array{0: PackageInterface, 1: Link, 2: array<mixed>|false}>
|
|
*/
|
|
- public function getDependents($needle, ?ConstraintInterface $constraint = null, bool $invert = false, bool $recurse = true, ?array $packagesFound = null): array
|
|
+ public function getDependents($needle, ?ConstraintInterface $constraint = null, bool $invert = false, bool $recurse = true, ?array $packagesFound = null, ?array $packagesFoundSet = null): array
|
|
{
|
|
$needles = array_map('strtolower', (array) $needle);
|
|
$results = [];
|
|
@@ -96,6 +96,13 @@ public function getDependents($needle, ?ConstraintInterface $constraint = null,
|
|
$packagesFound = $needles;
|
|
}
|
|
|
|
+ // CWE-407 fix: build a parallel hash set for O(1) in_array() replacement.
|
|
+ // $packagesFoundSet mirrors $packagesFound as an associative array keyed by
|
|
+ // package name string so isset() is O(1) instead of in_array() O(n).
|
|
+ if (null === $packagesFoundSet) {
|
|
+ $packagesFoundSet = array_fill_keys($packagesFound, true);
|
|
+ }
|
|
+
|
|
// locate root package for use below
|
|
$rootPackage = null;
|
|
foreach ($this->getPackages() as $package) {
|
|
@@ -112,6 +119,7 @@ public function getDependents($needle, ?ConstraintInterface $constraint = null,
|
|
// each loop needs its own "tree" as we want to show the complete dependent set of every needle
|
|
// without warning all the time about finding circular deps
|
|
$packagesInTree = $packagesFound;
|
|
+ $packagesInTreeSet = $packagesFoundSet;
|
|
|
|
// Replacements are considered valid reasons for a package to be installed during forward resolution
|
|
if (!$invert) {
|
|
@@ -125,12 +133,13 @@ public function getDependents($needle, ?ConstraintInterface $constraint = null,
|
|
if ($link->getSource() === $needle) {
|
|
if ($constraint === null || ($link->getConstraint()->matches($constraint) === true)) {
|
|
// already displayed this node's dependencies, cutting short
|
|
- if (in_array($link->getTarget(), $packagesInTree)) {
|
|
+ if (isset($packagesInTreeSet[$link->getTarget()])) {
|
|
$results[] = [$package, $link, false];
|
|
continue;
|
|
}
|
|
+ $packagesInTreeSet[$link->getTarget()] = true;
|
|
$packagesInTree[] = $link->getTarget();
|
|
- $dependents = $recurse ? $this->getDependents($link->getTarget(), null, false, true, $packagesInTree) : [];
|
|
+ $dependents = $recurse ? $this->getDependents($link->getTarget(), null, false, true, $packagesInTree, $packagesInTreeSet) : [];
|
|
$results[] = [$package, $link, $dependents];
|
|
$needles[] = $link->getTarget();
|
|
}
|
|
@@ -151,12 +160,13 @@ public function getDependents($needle, ?ConstraintInterface $constraint = null,
|
|
if ($link->getTarget() === $needle) {
|
|
if ($constraint === null || ($link->getConstraint()->matches($constraint) === !$invert)) {
|
|
// already displayed this node's dependencies, cutting short
|
|
- if (in_array($link->getSource(), $packagesInTree)) {
|
|
+ if (isset($packagesInTreeSet[$link->getSource()])) {
|
|
$results[] = [$package, $link, false];
|
|
continue;
|
|
}
|
|
+ $packagesInTreeSet[$link->getSource()] = true;
|
|
$packagesInTree[] = $link->getSource();
|
|
- $dependents = $recurse ? $this->getDependents($link->getSource(), null, false, true, $packagesInTree) : [];
|
|
+ $dependents = $recurse ? $this->getDependents($link->getSource(), null, false, true, $packagesInTree, $packagesInTreeSet) : [];
|
|
$results[] = [$package, $link, $dependents];
|
|
}
|
|
}
|