Skip to content

Commit

Permalink
Add maximum depth to serializer to prevent infinite recursion (#167) (#…
Browse files Browse the repository at this point in the history
…171)

Co-authored-by: Ilario Pierbattista <[email protected]>
  • Loading branch information
mhvis and ilario-pierbattista authored Dec 7, 2024
1 parent 2b12512 commit 9432814
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 6 deletions.
17 changes: 11 additions & 6 deletions src/DataCollector/MongoQuerySerializer.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ public static function serialize(Query $query): void
*
* @return mixed[]
*/
private static function prepareUnserializableData($data): array
private static function prepareUnserializableData($data, int $maxDepth = 256): array
{
if ($data instanceof Serializable) {
$data = $data->bsonSerialize();
}

$newData = [];
foreach ($data as $key => $item) {
$newData[$key] = self::prepareItemData($item);
$newData[$key] = self::prepareItemData($item, $maxDepth - 1);
}

return $newData;
Expand All @@ -43,19 +43,24 @@ private static function prepareUnserializableData($data): array
*
* @return mixed
*/
public static function prepareItemData($item)
public static function prepareItemData($item, int $maxDepth = 256)
{
// Prevent infinite recursion
if ($maxDepth < 0) {
return null;
}

if (\is_scalar($item)) {
return $item;
}

if (\is_array($item)) {
return self::prepareUnserializableData($item);
return self::prepareUnserializableData($item, $maxDepth);
}

if (\is_object($item)) {
if (method_exists($item, 'getArrayCopy')) {
return self::prepareUnserializableData($item->getArrayCopy());
return self::prepareUnserializableData($item->getArrayCopy(), $maxDepth);
}

if (method_exists($item, 'toDateTime')) {
Expand All @@ -70,7 +75,7 @@ public static function prepareItemData($item)
return $item->bsonSerialize();
}

return self::prepareUnserializableData((array) $item);
return self::prepareUnserializableData((array) $item, $maxDepth);
}

return $item;
Expand Down
23 changes: 23 additions & 0 deletions tests/Unit/DataCollector/MongoQuerySerializerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,29 @@ public function unserializedDataProvider(): array
];
}

public function test_serializer_terminating(): void
{
// tests that the serializer terminates when serializing an object which references itself
$selfReferencingObject = new class {
public $self;

public function __construct(
) {
$this->self = $this;
}
};
$data = ['test' => $selfReferencingObject];

$query = new Query();
$query->setFilters($data);
$query->setData($data);
$query->setOptions($data);

MongoQuerySerializer::serialize($query);

$this->expectNotToPerformAssertions();
}

public function test_serializer_regression_with_replaceOne(): void
{
$stdClass = new \stdClass();
Expand Down

0 comments on commit 9432814

Please sign in to comment.