From 10a51be63942ea7fba73c38b1aafbc3a045e4beb Mon Sep 17 00:00:00 2001 From: Alexander Hofbauer Date: Tue, 12 Dec 2023 12:19:33 +0100 Subject: [PATCH] [ErrorHandler] Don't format binary strings Calling var_export on a binary string easily causes memory exhaustion if it's called with even a small image. Fixes #53005 --- .../Bridge/Twig/Extension/CodeExtension.php | 4 +- .../ErrorRenderer/HtmlErrorRenderer.php | 2 + .../ErrorRenderer/HtmlErrorRendererTest.php | 41 ++++++++++++++++++ .../ErrorHandler/Tests/Fixtures/pixel.png | Bin 0 -> 69 bytes 4 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Component/ErrorHandler/Tests/Fixtures/pixel.png diff --git a/src/Symfony/Bridge/Twig/Extension/CodeExtension.php b/src/Symfony/Bridge/Twig/Extension/CodeExtension.php index 353bd84f3f6f7..fe2246e68b21a 100644 --- a/src/Symfony/Bridge/Twig/Extension/CodeExtension.php +++ b/src/Symfony/Bridge/Twig/Extension/CodeExtension.php @@ -97,8 +97,10 @@ public function formatArgs(array $args): string $formattedValue = ''.strtolower(htmlspecialchars(var_export($item[1], true), \ENT_COMPAT | \ENT_SUBSTITUTE, $this->charset)).''; } elseif ('resource' === $item[0]) { $formattedValue = 'resource'; + } elseif (preg_match('/[^\x07-\x0D\x1B\x20-\xFF]/', $item[1])) { + $formattedValue = 'binary string'; } else { - $formattedValue = str_replace("\n", '', htmlspecialchars(var_export($item[1], true), \ENT_COMPAT | \ENT_SUBSTITUTE, $this->charset)); + $formattedValue = str_replace("\n", '', $this->escape(var_export($item[1], true))); } $result[] = \is_int($key) ? $formattedValue : sprintf("'%s' => %s", htmlspecialchars($key, \ENT_COMPAT | \ENT_SUBSTITUTE, $this->charset), $formattedValue); diff --git a/src/Symfony/Component/ErrorHandler/ErrorRenderer/HtmlErrorRenderer.php b/src/Symfony/Component/ErrorHandler/ErrorRenderer/HtmlErrorRenderer.php index 92434b8e94506..08685fa21e867 100644 --- a/src/Symfony/Component/ErrorHandler/ErrorRenderer/HtmlErrorRenderer.php +++ b/src/Symfony/Component/ErrorHandler/ErrorRenderer/HtmlErrorRenderer.php @@ -173,6 +173,8 @@ private function formatArgs(array $args): string $formattedValue = ''.strtolower(var_export($item[1], true)).''; } elseif ('resource' === $item[0]) { $formattedValue = 'resource'; + } elseif (preg_match('/[^\x07-\x0D\x1B\x20-\xFF]/', $item[1])) { + $formattedValue = 'binary string'; } else { $formattedValue = str_replace("\n", '', $this->escape(var_export($item[1], true))); } diff --git a/src/Symfony/Component/ErrorHandler/Tests/ErrorRenderer/HtmlErrorRendererTest.php b/src/Symfony/Component/ErrorHandler/Tests/ErrorRenderer/HtmlErrorRendererTest.php index 6680b95a0cc3d..4ab602337159b 100644 --- a/src/Symfony/Component/ErrorHandler/Tests/ErrorRenderer/HtmlErrorRendererTest.php +++ b/src/Symfony/Component/ErrorHandler/Tests/ErrorRenderer/HtmlErrorRendererTest.php @@ -54,4 +54,45 @@ public static function getRenderData(): iterable $expectedNonDebug, ]; } + + public function testRendersStackWithoutBinaryStrings() + { + if (\PHP_VERSION_ID >= 70400) { + // make sure method arguments are available in stack traces (see https://www.php.net/manual/en/ini.core.php) + ini_set('zend.exception_ignore_args', false); + } + + $binaryData = file_get_contents(__DIR__ . '/../Fixtures/pixel.png'); + $exception = $this->getRuntimeException($binaryData); + + $rendered = (new HtmlErrorRenderer(true))->render($exception)->getAsString(); + + $this->assertStringContainsString( + "buildRuntimeException('FooException')", + $rendered, + '->render() contains the method call with "FooException"' + ); + + $this->assertStringContainsString( + 'getRuntimeException(binary string)', + $rendered, + '->render() contains the method call with "binary string" replacement' + ); + + $this->assertStringContainsString( + 'binary string', + $rendered, + '->render() returns the HTML content with "binary string" replacement' + ); + } + + private function getRuntimeException(string $unusedArgument): \RuntimeException + { + return $this->buildRuntimeException('FooException'); + } + + private function buildRuntimeException(string $message): \RuntimeException + { + return new \RuntimeException($message); + } } diff --git a/src/Symfony/Component/ErrorHandler/Tests/Fixtures/pixel.png b/src/Symfony/Component/ErrorHandler/Tests/Fixtures/pixel.png new file mode 100644 index 0000000000000000000000000000000000000000..35269f61fcde4c9802d0648f1bddf24f745bb842 GIT binary patch literal 69 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx1SBVv2j2ryJf1F&Asp9}BQ6_>Gcd1ZJU8uO RWdu;1!PC{xWt~$(69Bs855E8a literal 0 HcmV?d00001