diff --git a/src/applications/phid/query/PhabricatorObjectQuery.php b/src/applications/phid/query/PhabricatorObjectQuery.php index 49d238c6a9..fbec78b29b 100644 --- a/src/applications/phid/query/PhabricatorObjectQuery.php +++ b/src/applications/phid/query/PhabricatorObjectQuery.php @@ -104,6 +104,16 @@ final class PhabricatorObjectQuery } private function loadObjectsByPHID(array $types, array $phids) { + // Don't try to load PHIDs which are already "in flight"; this prevents us + // from recursing indefinitely if policy checks or edges form a loop. We + // will decline to load the corresponding objects. + $in_flight = $this->getPHIDsInFlight(); + foreach ($phids as $key => $phid) { + if (isset($in_flight[$phid])) { + unset($phids[$key]); + } + } + $results = array(); $workspace = $this->getObjectsFromWorkspace($phids); @@ -119,6 +129,8 @@ final class PhabricatorObjectQuery return $results; } + $this->putPHIDsInFlight($phids); + $groups = array(); foreach ($phids as $phid) { $type = phid_get_type($phid); diff --git a/src/infrastructure/query/policy/PhabricatorPolicyAwareQuery.php b/src/infrastructure/query/policy/PhabricatorPolicyAwareQuery.php index 1f353d7dfb..e1b2028a19 100644 --- a/src/infrastructure/query/policy/PhabricatorPolicyAwareQuery.php +++ b/src/infrastructure/query/policy/PhabricatorPolicyAwareQuery.php @@ -33,6 +33,7 @@ abstract class PhabricatorPolicyAwareQuery extends PhabricatorOffsetPagedQuery { private $rawResultLimit; private $capabilities; private $workspace = array(); + private $inFlightPHIDs = array(); private $policyFilteredPHIDs = array(); private $canUseApplication; @@ -468,6 +469,39 @@ abstract class PhabricatorPolicyAwareQuery extends PhabricatorOffsetPagedQuery { } + /** + * Mark PHIDs as in flight. + * + * PHIDs which are "in flight" are actively being queried for. Using this + * list can prevent infinite query loops by aborting queries which cycle. + * + * @param list List of PHIDs which are now in flight. + * @return this + */ + public function putPHIDsInFlight(array $phids) { + foreach ($phids as $phid) { + $this->inFlightPHIDs[$phid] = $phid; + } + return $this; + } + + + /** + * Get PHIDs which are currently in flight. + * + * PHIDs which are "in flight" are actively being queried for. + * + * @return map PHIDs currently in flight. + */ + public function getPHIDsInFlight() { + $results = $this->inFlightPHIDs; + if ($this->getParentQuery()) { + $results += $this->getParentQuery()->getPHIDsInFlight(); + } + return $results; + } + + /* -( Policy Query Implementation )---------------------------------------- */