Skip to content

[Config] Always protected ClassExistenceResource against bad parents #23041

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

Merged
merged 1 commit into from
Jun 2, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 18 additions & 22 deletions src/Symfony/Component/Config/Resource/ClassExistenceResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,21 @@
*/
class ClassExistenceResource implements SelfCheckingResourceInterface, \Serializable
{
const EXISTS_OK = 1;
const EXISTS_KO = 0;
const EXISTS_KO_WITH_THROWING_AUTOLOADER = -1;

private $resource;
private $existsStatus;
private $exists;

private static $autoloadLevel = 0;
private static $existsCache = array();

/**
* @param string $resource The fully-qualified class name
* @param int|null $existsStatus One of the self::EXISTS_* const if the existency check has already been done
* @param string $resource The fully-qualified class name
* @param bool|null $exists Boolean when the existency check has already been done
*/
public function __construct($resource, $existsStatus = null)
public function __construct($resource, $exists = null)
{
$this->resource = $resource;
if (null !== $existsStatus) {
$this->existsStatus = (int) $existsStatus;
if (null !== $exists) {
$this->exists = (bool) $exists;
}
}

Expand All @@ -64,11 +60,13 @@ public function getResource()
*/
public function isFresh($timestamp)
{
$loaded = class_exists($this->resource, false) || interface_exists($this->resource, false) || trait_exists($this->resource, false);

if (null !== $exists = &self::$existsCache[$this->resource]) {
$exists = $exists || class_exists($this->resource, false) || interface_exists($this->resource, false) || trait_exists($this->resource, false);
} elseif (self::EXISTS_KO_WITH_THROWING_AUTOLOADER === $this->existsStatus) {
$exists = $exists || $loaded;
} elseif (!$exists = $loaded) {
if (!self::$autoloadLevel++) {
spl_autoload_register('Symfony\Component\Config\Resource\ClassExistenceResource::throwOnRequiredClass');
spl_autoload_register(__CLASS__.'::throwOnRequiredClass');
}

try {
Expand All @@ -77,38 +75,36 @@ public function isFresh($timestamp)
$exists = false;
} finally {
if (!--self::$autoloadLevel) {
spl_autoload_unregister('Symfony\Component\Config\Resource\ClassExistenceResource::throwOnRequiredClass');
spl_autoload_unregister(__CLASS__.'::throwOnRequiredClass');
}
}
} else {
$exists = class_exists($this->resource) || interface_exists($this->resource, false) || trait_exists($this->resource, false);
}

if (null === $this->existsStatus) {
$this->existsStatus = $exists ? self::EXISTS_OK : self::EXISTS_KO;
if (null === $this->exists) {
$this->exists = $exists;
}

return self::EXISTS_OK === $this->existsStatus xor !$exists;
return $this->exists xor !$exists;
}

/**
* {@inheritdoc}
*/
public function serialize()
{
if (null === $this->existsStatus) {
if (null === $this->exists) {
$this->isFresh(0);
}

return serialize(array($this->resource, $this->existsStatus));
return serialize(array($this->resource, $this->exists));
}

/**
* {@inheritdoc}
*/
public function unserialize($serialized)
{
list($this->resource, $this->existsStatus) = unserialize($serialized);
list($this->resource, $this->exists) = unserialize($serialized);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public function testExistsKo()

$loadedClass = 123;

$res = new ClassExistenceResource('MissingFooClass', ClassExistenceResource::EXISTS_KO);
$res = new ClassExistenceResource('MissingFooClass', false);

$this->assertSame(123, $loadedClass);
} finally {
Expand All @@ -76,7 +76,7 @@ public function testExistsKo()

public function testConditionalClass()
{
$res = new ClassExistenceResource(ConditionalClass::class, ClassExistenceResource::EXISTS_KO_WITH_THROWING_AUTOLOADER);
$res = new ClassExistenceResource(ConditionalClass::class, false);

$this->assertFalse($res->isFresh(0));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ private function populateAvailableType($id, Definition $definition)
unset($this->ambiguousServiceTypes[$type]);
}

if ($definition->isDeprecated() || !$reflectionClass = $this->container->getReflectionClass($definition->getClass(), true)) {
if ($definition->isDeprecated() || !$reflectionClass = $this->container->getReflectionClass($definition->getClass())) {
return;
}

Expand Down Expand Up @@ -444,7 +444,7 @@ private function set($type, $id)
*/
private function createAutowiredDefinition($type)
{
if (!($typeHint = $this->container->getReflectionClass($type, true)) || !$typeHint->isInstantiable()) {
if (!($typeHint = $this->container->getReflectionClass($type)) || !$typeHint->isInstantiable()) {
return;
}

Expand Down Expand Up @@ -478,7 +478,7 @@ private function createAutowiredDefinition($type)

private function createTypeNotFoundMessage(TypedReference $reference, $label)
{
if (!$r = $this->container->getReflectionClass($type = $reference->getType(), true)) {
if (!$r = $this->container->getReflectionClass($type = $reference->getType())) {
$message = sprintf('has type "%s" but this class does not exist.', $type);
} else {
$message = $this->container->has($type) ? 'this service is abstract' : 'no such service exists';
Expand Down
12 changes: 4 additions & 8 deletions src/Symfony/Component/DependencyInjection/ContainerBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -337,13 +337,12 @@ public function addClassResource(\ReflectionClass $class)
* Retrieves the requested reflection class and registers it for resource tracking.
*
* @param string $class
* @param bool $koWithThrowingAutoloader Whether autoload should be protected against bad parents or not
*
* @return \ReflectionClass|null
*
* @final
*/
public function getReflectionClass($class, $koWithThrowingAutoloader = false)
public function getReflectionClass($class)
{
if (!$class = $this->getParameterBag()->resolveValue($class)) {
return;
Expand All @@ -353,20 +352,17 @@ public function getReflectionClass($class, $koWithThrowingAutoloader = false)
try {
if (isset($this->classReflectors[$class])) {
$classReflector = $this->classReflectors[$class];
} elseif ($koWithThrowingAutoloader) {
$resource = new ClassExistenceResource($class, ClassExistenceResource::EXISTS_KO_WITH_THROWING_AUTOLOADER);

$classReflector = $resource->isFresh(0) ? false : new \ReflectionClass($class);
} else {
$classReflector = new \ReflectionClass($class);
$resource = new ClassExistenceResource($class, false);
$classReflector = $resource->isFresh(0) ? false : new \ReflectionClass($class);
}
} catch (\ReflectionException $e) {
$classReflector = false;
}

if ($this->trackResources) {
if (!$classReflector) {
$this->addResource($resource ?: new ClassExistenceResource($class, ClassExistenceResource::EXISTS_KO));
$this->addResource($resource ?: new ClassExistenceResource($class, false));
} elseif (!$classReflector->isInternal()) {
$path = $classReflector->getFileName();

Expand Down
2 changes: 1 addition & 1 deletion src/Symfony/Component/DependencyInjection/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"symfony/proxy-manager-bridge": "Generate service proxies to lazy load them"
},
"conflict": {
"symfony/config": "<3.3",
"symfony/config": "<3.3.1",
"symfony/finder": "<3.3",
"symfony/yaml": "<3.3"
},
Expand Down