Description
A YAML string with too many backslash escapes can trigger a PREG_BACKTRACK_LIMIT_ERROR
error in the Yaml parser.
Steps to reproduce:
Run the following unit test:
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Component\Yaml\Yaml;
class YamlParserBacktrackLimitTest extends WebTestCase
{
public function testYamlQuotedString() {
$foo = str_repeat("x\r\n\\\"x\"x", 1000);
$yamlString = Yaml::dump(["foo" => $foo]);
$arrayFromYaml = Yaml::parse($yamlString);
$this->assertEquals($foo, $arrayFromYaml['foo']);
}
}
Observed behaviour
This test will pass if you reduce the "1000" constant to "100", and fail as-is.
The reported exception is:
Malformed inline YAML string ("x\r\n\\\ ...
at n/a
in ...\vendor\symfony\symfony\src\Symfony\Component\Yaml\Inline.php line 344
The relevant source is here:
const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'([^\']*(?:\'\'[^\']*)*)\')';
...
if (!preg_match('/'.self::REGEX_QUOTED_STRING.'/Au', substr($scalar, $i), $match)) {
throw new ParseException(sprintf('Malformed inline YAML string: %s.', substr($scalar, $i)));
}
Expected behaviour
-
The test should pass, i.e. the YAML should be parseable, since it fits in memory and is well formed.
-
The exception thrown by Symfony if the
preg_match
fails due toPREG_BACKTRACK_LIMIT_ERROR
should indicate that the op failed due to resource exhaustion and not incorrectly blame invalid YAML.
Suggested fix
I suspect that changing the REGEX_QUOTED_STRING
regex to use possessive qualifiers will probably fix bug 1 above without otherwise changing the YAML parser's behaviour.
Fixing bug 2 above needs a call to preg_last_error()
after each "preg_match
" call in Symfony code, which will be tedious.