1
0
Fork 0

Detect infinite script call recursion

pull/4592/head
Giorgio Premi 2015-11-09 13:05:16 +01:00
parent a25492d1b9
commit fd0026b542
2 changed files with 65 additions and 0 deletions

View File

@ -45,6 +45,7 @@ class EventDispatcher
protected $loader;
protected $process;
protected $listeners;
private $eventStack;
/**
* Constructor.
@ -58,6 +59,7 @@ class EventDispatcher
$this->composer = $composer;
$this->io = $io;
$this->process = $process ?: new ProcessExecutor($io);
$this->eventStack = array();
}
/**
@ -145,6 +147,8 @@ class EventDispatcher
{
$listeners = $this->getListeners($event);
$this->pushEvent($event);
$return = 0;
foreach ($listeners as $callable) {
if (!is_string($callable) && is_callable($callable)) {
@ -198,6 +202,8 @@ class EventDispatcher
}
}
$this->popEvent();
return $return;
}
@ -381,4 +387,31 @@ class EventDispatcher
{
return '@' === substr($callable, 0, 1);
}
/**
* Push an event to the stack of active event
*
* @param Event $event
* @throws \RuntimeException
* @return number
*/
protected function pushEvent(Event $event)
{
$eventName = $event->getName();
if (in_array($eventName, $this->eventStack)) {
throw new \RuntimeException(sprintf("Recursive call to '%s' detected", $eventName));
}
return array_push($this->eventStack, $eventName);
}
/**
* Pops the active event from the stack
*
* @return mixed
*/
protected function popEvent()
{
return array_pop($this->eventStack);
}
}

View File

@ -201,6 +201,38 @@ class EventDispatcherTest extends TestCase
$dispatcher->dispatch('root', new CommandEvent('root', $composer, $io));
}
/**
* @expectedException RuntimeException
*/
public function testDispatcherDetectInfiniteRecursion()
{
$process = $this->getMock('Composer\Util\ProcessExecutor');
$dispatcher = $this->getMockBuilder('Composer\EventDispatcher\EventDispatcher')
->setConstructorArgs(array(
$composer = $this->getMock('Composer\Composer'),
$io = $this->getMock('Composer\IO\IOInterface'),
$process,
))
->setMethods(array(
'getListeners',
))
->getMock();
$dispatcher->expects($this->atLeastOnce())
->method('getListeners')
->will($this->returnCallback(function (Event $event) {
if ($event->getName() === 'root') {
return array('@recurse');
} elseif ($event->getName() === 'recurse') {
return array('@root');
}
return array();
}));
$dispatcher->dispatch('root', new CommandEvent('root', $composer, $io));
}
private function getDispatcherStubForListenersTest($listeners, $io)
{
$dispatcher = $this->getMockBuilder('Composer\EventDispatcher\EventDispatcher')