8000 prevent hash collisions caused by reused object hashes · symfony/symfony@9c81f2a · GitHub
[go: up one dir, main page]

Skip to content

Commit 9c81f2a

Browse files
committed
prevent hash collisions caused by reused object hashes
1 parent 9645fa3 commit 9c81f2a

File tree

4 files changed

+41
-18
lines changed

4 files changed

+41
-18
lines changed

src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
class FormValidator extends ConstraintValidator
2626
{
2727
private $resolvedGroups;
28-
private $fieldFormConstraints;
2928

3029
/**
3130
* {@inheritdoc}
@@ -68,7 +67,6 @@ public function validate($form, Constraint $formConstraint)
6867

6968
if ($hasChildren && $form->isRoot()) {
7069
$this->resolvedGroups = new \SplObjectStorage();
71-
$this->fieldFormConstraints = [];
7270
}
7371

7472
if ($groups instanceof GroupSequence) {
@@ -93,7 +91,6 @@ public function validate($form, Constraint $formConstraint)
9391
$this->resolvedGroups[$field] = (array) $group;
9492
$fieldFormConstraint = new Form();
9593
$fieldFormConstraint->groups = $group;
96-
$this->fieldFormConstraints[] = $fieldFormConstraint;
9794
$this->context->setNode($this->context->getValue(), $field, $this->context->getMetadata(), $this->context->getPropertyPath());
9895
$validator->atPath(sprintf('children[%s]', $field->getName()))->validate($field, $fieldFormConstraint, $group);
9996
}
@@ -139,18 +136,15 @@ public function validate($form, Constraint $formConstraint)
139136
foreach ($form->all() as $field) {
140137
if ($field->isSubmitted()) {
141138
$this->resolvedGroups[$field] = $groups;
142-
$fieldFormConstraint = new Form();
143-
$this->fieldFormConstraints[] = $fieldFormConstraint;
144139
$this->context->setNode($this->context->getValue(), $field, $this->context->getMetadata(), $this->context->getPropertyPath());
145-
$validator->atPath(sprintf('children[%s]', $field->getName()))->validate($field, $fieldFormConstraint);
140+
$validator->atPath(sprintf('children[%s]', $field->getName()))->validate($field, $formConstraint);
146141
}
147142
}
148143
}
149144

150145
if ($hasChildren && $form->isRoot()) {
151146
// destroy storage to avoid memory leaks
152147
$this->resolvedGroups = new \SplObjectStorage();
153-
$this->fieldFormConstraints = [];
154148
}
155149
} elseif (!$form->isSynchronized()) {
156150
$childrenSynchronized = true;
@@ -159,11 +153,8 @@ public function validate($form, Constraint $formConstraint)
159153
foreach ($form as $child) {
160154
if (!$child->isSynchronized()) {
161155
$childrenSynchronized = false;
162-
163-
$fieldFormConstraint = new Form();
164-
$this->fieldFormConstraints[] = $fieldFormConstraint;
165156
$this->context->setNode($this->context->getValue(), $child, $this->context->getMetadata(), $this->context->getPropertyPath());
166-
$validator->atPath(sprintf('children[%s]', $child->getName()))->validate($child, $fieldFormConstraint);
157+
$validator->atPath(sprintf('children[%s]', $child->getName()))->validate($child, $formConstraint);
167158
}
168159
}
169160

src/Symfony/Component/Form/composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
},
2828
"require-dev": {
2929
"doctrine/collections": "~1.0",
30-
"symfony/validator": "^3.4.44|^4.3.4|^5.0",
30+
"symfony/validator": "^3.4.46|^4.4.16|^5.0",
3131
"symfony/dependency-injection": "^3.4|^4.0|^5.0",
3232
"symfony/expression-language": "^3.4|^4.0|^5.0",
3333
"symfony/config": "^3.4|^4.0|^5.0",

src/Symfony/Component/Validator/Context/ExecutionContext.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ class ExecutionContext implements ExecutionContextInterface
129129
* @var array
130130
*/
131131
private $initializedObjects;
132+
private $cachedObjectsRefs;
132133

133134
/**
134135
* Creates a new execution context.
@@ -153,6 +154,7 @@ public function __construct(ValidatorInterface $validator, $root, $translator, s
153154
$this->translator = $translator;
154155
$this->translationDomain = $translationDomain;
155156
$this->violations = new ConstraintViolationList();
157+
$this->cachedObjectsRefs = new \SplObjectStorage();
156158
}
157159

158160
/**
@@ -358,4 +360,20 @@ public function isObjectInitialized($cacheKey): bool
358360
{
359361
return isset($this->initializedObjects[$cacheKey]);
360362
}
363+
364+
/**
365+
* @internal
366+
*
367+
* @param object $object
368+
*
369+
* @return string
370+
*/
371+
public function generateCacheKey($object)
372+
{
373+
if (!isset($this->cachedObjectsRefs[$object])) {
374+
$this->cachedObjectsRefs[$object] = spl_object_hash($object);
375+
}
376+
377+
return $this->cachedObjectsRefs[$object];
378+
}
361379
}

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

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ public function validate($value, $constraints = null, $groups = null)
108108
$this->validateGenericNode(
109109
$value,
110110
$previousObject,
111-
\is_object($value) ? spl_object_hash($value) : null,
111+
\is_object($value) ? $this->generateCacheKey($value) : null,
112112
$metadata,
113113
$this->defaultPropertyPath,
114114
$groups,
@@ -176,7 +176,7 @@ public function validateProperty($object, $propertyName, $groups = null)
176176

177177
$propertyMetadatas = $classMetadata->getPropertyMetadata($propertyName);
178178
$groups = $groups ? $this->normalizeGroups($groups) : $this->defaultGroups;
179-
$cacheKey = spl_object_hash($object);
179+
$cacheKey = $this->generateCacheKey($object);
180180
$propertyPath = PropertyPath::append($this->defaultPropertyPath, $propertyName);
181181

182182
$previousValue = $this->context->getValue();
@@ -224,7 +224,7 @@ public function validatePropertyValue($objectOrClass, $propertyName, $value, $gr
224224
if (\is_object($objectOrClass)) {
225225
$object = $objectOrClass;
226226
$class = \get_class($object);
227-
$cacheKey = spl_object_hash($objectOrClass);
227+
$cacheKey = $this->generateCacheKey($objectOrClass);
228228
$propertyPath = PropertyPath::append($this->defaultPropertyPath, $propertyName);
229229
} else {
230230
// $objectOrClass contains a class name
@@ -313,7 +313,7 @@ private function validateObject($object, string $propertyPath, array $groups, in
313313

314314
$this->validateClassNode(
315315
$object,
316-
spl_object_hash($object),
316+
$this->generateCacheKey($object),
317317
$classMetadata,
318318
$propertyPath,
319319
$groups,
@@ -429,7 +429,7 @@ private function validateClassNode($object, ?string $cacheKey, ClassMetadataInte
429429
$defaultOverridden = false;
430430

431431
// Use the object hash for group sequences
432-
$groupHash = \is_object($group) ? spl_object_hash($group) : $group;
432+
$groupHash = \is_object($group) ? $this->generateCacheKey($group) : $group;
433433

434434
if ($context->isGroupValidated($cacheKey, $groupHash)) {
435435
// Skip this group when validating the properties and when
@@ -740,7 +740,7 @@ private function validateInGroup($value, ?string $cacheKey, MetadataInterface $m
740740
// Prevent duplicate validation of constraints, in the case
741741
// that constraints belong to multiple validated groups
742742
if (null !== $cacheKey) {
743-
$constraintHash = spl_object_hash($constraint);
743+
$constraintHash = $this->generateCacheKey($constraint);
744744
// instanceof Valid: In case of using a Valid constraint with many groups
745745
// it makes a reference object get validated by each group
746746
if ($constraint instanceof Composite || $constraint instanceof Valid) {
@@ -772,4 +772,18 @@ private function validateInGroup($value, ?string $cacheKey, MetadataInterface $m
772772
}
773773
}
774774
}
775+
776+
/**
777+
* @param object $object
778+
*
779+
* @return string
780+
*/
781+
private function generateCacheKey($object)
782+
{
783+
if ($this->context instanceof ExecutionContext) {
784+
return $this->context->generateCacheKey($object);
785+
}
786+
787+
return spl_object_hash($object);
788+
}
775789
}

0 commit comments

Comments
 (0)
0