From 7d0b08409ac5b9567819442e71ec2059a99003fd Mon Sep 17 00:00:00 2001 From: Simon Praetorius Date: Mon, 30 Oct 2023 22:48:21 +0100 Subject: [PATCH] [BUGFIX] Prevent infinite loop in BooleanParser (#821) This change prevents an infinite loop if single or double quotes in boolean expressions are not properly closed. Resolves: #667 --- src/Core/Parser/BooleanParser.php | 4 +++ tests/Unit/Core/Parser/BooleanParserTest.php | 28 ++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/src/Core/Parser/BooleanParser.php b/src/Core/Parser/BooleanParser.php index 6af1ed291..7e66a7ce3 100644 --- a/src/Core/Parser/BooleanParser.php +++ b/src/Core/Parser/BooleanParser.php @@ -288,6 +288,10 @@ protected function parseStringToken() while (trim($t = $this->peek(true)) !== $stringIdentifier) { $this->consume($t); $string .= $t; + + if ($t === '') { + throw new Exception(sprintf('Closing string token expected in boolean expression "%s".', $this->expression), 1697479462); + } } $this->consume($stringIdentifier); $string .= $stringIdentifier; diff --git a/tests/Unit/Core/Parser/BooleanParserTest.php b/tests/Unit/Core/Parser/BooleanParserTest.php index d63f47b64..33f291c5e 100644 --- a/tests/Unit/Core/Parser/BooleanParserTest.php +++ b/tests/Unit/Core/Parser/BooleanParserTest.php @@ -10,6 +10,7 @@ namespace TYPO3Fluid\Fluid\Tests\Unit\Core\Parser; use TYPO3Fluid\Fluid\Core\Parser\BooleanParser; +use TYPO3Fluid\Fluid\Core\Parser\Exception; use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\BooleanNode; use TYPO3Fluid\Fluid\Core\Rendering\RenderingContext; use TYPO3Fluid\Fluid\Tests\UnitTestCase; @@ -120,4 +121,31 @@ public function testSomeEvaluations(string $comparison, bool $expected, array $v eval('function ' . $functionName . '($context) {return ' . $compiledEvaluation . ';}'); self::assertEquals($expected, BooleanNode::convertToBoolean($functionName($variables), $renderingContext), 'compiled Expression: ' . $compiledEvaluation); } + + public static function invalidEvaluationsDataProvider(): array + { + return [ + ['{pageClass} == "myClass', ['pageClass' => 'myClass']], + ['{pageClass} == \'myClass', ['pageClass' => 'myClass']], + ['\'string1\' == \'string2', []], + ]; + } + + /** + * @test + * @dataProvider invalidEvaluationsDataProvider + */ + public function invalidEvaluations(string $comparison, array $variables = []): void + { + $this->expectException(Exception::class); + $this->expectExceptionCode(1697479462); + + $renderingContext = new RenderingContext(); + $parser = new BooleanParser(); + BooleanNode::convertToBoolean($parser->evaluate($comparison, $variables), $renderingContext); + $compiledEvaluation = $parser->compile($comparison); + $functionName = 'expression_' . md5($comparison . rand(0, 100000)); + eval('function ' . $functionName . '($context) {return ' . $compiledEvaluation . ';}'); + BooleanNode::convertToBoolean($functionName($variables), $renderingContext); + } }