Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit f8cea76

Browse files
committed
[Validator][RecursiveContextualValidator] Prevent validated hash collisions
1 parent 932a4f8 commit f8cea76

File tree

2 files changed

+56
-1
lines changed

2 files changed

+56
-1
lines changed

src/Symfony/Component/Validator/Tests/Validator/RecursiveValidatorTest.php

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,16 @@
1212
namespace Symfony\Component\Validator\Tests\Validator;
1313

1414
use Symfony\Component\Translation\IdentityTranslator;
15+
use Symfony\Component\Validator\Constraint;
1516
use Symfony\Component\Validator\Constraints\All;
1617
use Symfony\Component\Validator\Constraints\Collection;
1718
use Symfony\Component\Validator\Constraints\GroupSequence;
19+
use Symfony\Component\Validator\Constraints\IsFalse;
1820
use Symfony\Component\Validator\Constraints\IsTrue;
1921
use Symfony\Component\Validator\Constraints\Length;
2022
use Symfony\Component\Validator\Constraints\NotBlank;
2123
use Symfony\Component\Validator\Constraints\NotNull;
24+
use Symfony\Component\Validator\ConstraintValidator;
2225
use Symfony\Component\Validator\ConstraintValidatorFactory;
2326
use Symfony\Component\Validator\Context\ExecutionContextFactory;
2427
use Symfony\Component\Validator\Mapping\ClassMetadata;
@@ -157,4 +160,36 @@ public function testAllConstraintValidateAllGroupsForNestedConstraints()
157160
$this->assertInstanceOf(NotBlank::class, $violations->get(0)->getConstraint());
158161
$this->assertInstanceOf(Length::class, $violations->get(1)->getConstraint());
159162
}
163+
164+
public function testValidatedConstraintsHashesDontCollide()
165+
{
166+
$entity = new Entity();
167+
$entity->data = new \stdClass();
168+
169+
$this->assertSame(1, $this->validator->validate($entity, new TestConstraintHashesDontCollide())->count());
170+
}
171+
}
172+
173+
final class TestConstraintHashesDontCollide extends Constraint
174+
{
175+
}
176+
177+
final class TestConstraintHashesDontCollideValidator extends ConstraintValidator
178+
{
179+
/**
180+
* {@inheritdoc}
181+
*/
182+
public function validate($value, Constraint $constraint)
183+
{
184+
if (!$value instanceof Entity) {
185+
throw new \LogicException();
186+
}
187+
188+
$this->context->getValidator()
189+
->inContext($this->context)
190+
->atPath('data')
191+
->validate($value, new NotNull())
192+
->validate($value, new NotNull())
193+
->validate($value, new IsFalse());
194+
}
160195
}

src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ class RecursiveContextualValidator implements ContextualValidatorInterface
4848
private $validatorFactory;
4949
private $objectInitializers;
5050

51+
private $validatedObjectsReferences = [];
52+
private $validatedConstraintsReferences = [];
53+
private $initializedObjectsReferences = [];
54+
5155
/**
5256
* Creates a validator for the given context.
5357
*
@@ -442,6 +446,10 @@ private function validateClassNode($object, $cacheKey, ClassMetadataInterface $m
442446
{
443447
$context->setNode($object, $object, $metadata, $propertyPath);
444448

449+
if (!isset($this->initializedObjectsReferences[$cacheKey])) {
450+
$this->initializedObjectsReferences[$cacheKey] = $object;
451+
}
452+
445453
if (!$context->isObjectInitialized($cacheKey)) {
446454
foreach ($this->objectInitializers as $initializer) {
447455
$initializer->initialize($object);
@@ -457,7 +465,15 @@ private function validateClassNode($object, $cacheKey, ClassMetadataInterface $m
457465
$defaultOverridden = false;
458466

459467
// Use the object hash for group sequences
460-
$groupHash = \is_object($group) ? spl_object_hash($group) : $group;
468+
if (\is_object($group)) {
469+
$groupHash = spl_object_hash($group);
470+
471+
if (!isset($this->validatedObjectsReferences[$groupHash])) {
472+
$this->validatedObjectsReferences[$groupHash] = $group;
473+
}
474+
} else {
475+
$groupHash = $group;
476+
}
461477

462478
if ($context->isGroupValidated($cacheKey, $groupHash)) {
463479
// Skip this group when validating the properties and when
@@ -790,6 +806,10 @@ private function validateInGroup($value, $cacheKey, MetadataInterface $metadata,
790806
// that constraints belong to multiple validated groups
791807
if (null !== $cacheKey) {
792808
$constraintHash = spl_object_hash($constraint);
809+
if (!isset($this->validatedConstraintsReferences[$constraintHash])) {
810+
$this->validatedConstraintsReferences[$constraintHash] = $constraint;
811+
}
812+
793813
// instanceof Valid: In case of using a Valid constraint with many groups
794814
// it makes a reference object get validated by each group
795815
if ($constraint instanceof Composite || $constraint instanceof Valid) {

0 commit comments

Comments
 (0)