Skip to content

[Config] ResourceCheckerConfigCache produces PHP unserialization warning for longer class/property names #61806

@aboks

Description

@aboks

Symfony version(s) affected

7.2.0 and up

Description

The logic for generating the JSON metadata file in ResourceCheckerConfigCache generates a PHP unserialization warning if $metadata contains an object that has a property where the class name plus property name combined are more than around 100 characters in length.

This is due to incorrect mangling of the serialized representation in

$ser = preg_replace_callback('/s:(\d+):"\0[^\0]++\0/', static fn ($m) => 's:'.($m[1] - \strlen($m[0]) + 6).':"', $ser);
This line aims to remove the class name (and surrounding nullbytes) from the serialized representation of a property. The magic constant 6 is probably some ugly micro-optimization to prevent capturing the matched class name. It seems that the 6 is based on an assumption of 6 'non-removed' characters in the matched string: the s, :, two characters for the serialized string length, another : and a ". However, when the length of the serialized property id (class name surrounded with nullbytes plus property name) exceeds 100, the assumption of two characters for the serialized string length does not hold anymore.

This causes the logic to generate an invalid serialized representation like s:3:"prop", where the indicated string length does not match the actual length of the property name string, and thus causes unserialize() to fail.

How to reproduce

The following script suffices in a project where symfony/config is installed via composer:

<?php
declare(strict_types=1);

require_once "vendor/autoload.php";

class MyResourceWithAVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongName implements \Symfony\Component\Config\Resource\ResourceInterface {
	public function __construct(
		private readonly string $prop,
	) {}

	public function __toString(): string {
		return "myresource";
	}
}


$file = __DIR__ . "/my_cache.php";
$configCache = new \Symfony\Component\Config\ResourceCheckerConfigCache($file);

$metadata = [
	new MyResourceWithAVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongName("bar"),
];
$configCache->write("foo", $metadata);

Note that the issue disappears when you remove one 'Very' from the class name, bringing the total length back under 100.

Possible Solution

Replace the + 6 by + 4 + \strlen($m[1]), or just capture the removed classname and use its length for the adjustment.

Additional Context

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions