From 2ef8771ad7a90366b31e24f986d23e686bc1ef41 Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Sat, 4 Jan 2020 19:57:41 +0100 Subject: [PATCH 01/10] [Security\Guard] Fix missing typehints --- .../Security/Guard/Firewall/GuardAuthenticationListener.php | 2 +- .../Security/Guard/Provider/GuardAuthenticationProvider.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Security/Guard/Firewall/GuardAuthenticationListener.php b/src/Symfony/Component/Security/Guard/Firewall/GuardAuthenticationListener.php index 25de3ce440..94a1efb469 100644 --- a/src/Symfony/Component/Security/Guard/Firewall/GuardAuthenticationListener.php +++ b/src/Symfony/Component/Security/Guard/Firewall/GuardAuthenticationListener.php @@ -51,7 +51,7 @@ class GuardAuthenticationListener implements ListenerInterface * @param iterable|AuthenticatorInterface[] $guardAuthenticators The authenticators, with keys that match what's passed to GuardAuthenticationProvider * @param LoggerInterface $logger A LoggerInterface instance */ - public function __construct(GuardAuthenticatorHandler $guardHandler, AuthenticationManagerInterface $authenticationManager, string $providerKey, $guardAuthenticators, LoggerInterface $logger = null) + public function __construct(GuardAuthenticatorHandler $guardHandler, AuthenticationManagerInterface $authenticationManager, string $providerKey, iterable $guardAuthenticators, LoggerInterface $logger = null) { if (empty($providerKey)) { throw new \InvalidArgumentException('$providerKey must not be empty.'); diff --git a/src/Symfony/Component/Security/Guard/Provider/GuardAuthenticationProvider.php b/src/Symfony/Component/Security/Guard/Provider/GuardAuthenticationProvider.php index 625ac5e6fe..d4d23dfb0d 100644 --- a/src/Symfony/Component/Security/Guard/Provider/GuardAuthenticationProvider.php +++ b/src/Symfony/Component/Security/Guard/Provider/GuardAuthenticationProvider.php @@ -45,7 +45,7 @@ class GuardAuthenticationProvider implements AuthenticationProviderInterface * @param UserProviderInterface $userProvider The user provider * @param string $providerKey The provider (i.e. firewall) key */ - public function __construct($guardAuthenticators, UserProviderInterface $userProvider, string $providerKey, UserCheckerInterface $userChecker) + public function __construct(iterable $guardAuthenticators, UserProviderInterface $userProvider, string $providerKey, UserCheckerInterface $userChecker) { $this->guardAuthenticators = $guardAuthenticators; $this->userProvider = $userProvider; From 87212e41b395921d4fac8692009947cc53d3922e Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Thu, 2 Jan 2020 12:21:52 +0100 Subject: [PATCH 02/10] [FrameworkBundle][TranslationUpdateCommand] Do not output positive feedback on stderr --- .../Command/TranslationUpdateCommand.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php index 7375450d5d..fcf145cc46 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php @@ -200,12 +200,12 @@ EOF } } - $errorIo->title('Translation Messages Extractor and Dumper'); - $errorIo->comment(sprintf('Generating "%s" translation files for "%s"', $input->getArgument('locale'), $currentName)); + $io->title('Translation Messages Extractor and Dumper'); + $io->comment(sprintf('Generating "%s" translation files for "%s"', $input->getArgument('locale'), $currentName)); // load any messages from templates $extractedCatalogue = new MessageCatalogue($input->getArgument('locale')); - $errorIo->comment('Parsing templates...'); + $io->comment('Parsing templates...'); $prefix = $input->getOption('prefix'); // @deprecated since version 3.4, to be removed in 4.0 along with the --no-prefix option if ($input->getOption('no-prefix')) { @@ -221,7 +221,7 @@ EOF // load any existing messages from the translation files $currentCatalogue = new MessageCatalogue($input->getArgument('locale')); - $errorIo->comment('Loading translation files...'); + $io->comment('Loading translation files...'); foreach ($transPaths as $path) { if (is_dir($path)) { $this->reader->read($path, $currentCatalogue); @@ -274,7 +274,7 @@ EOF } if ('xlf' == $input->getOption('output-format')) { - $errorIo->comment('Xliff output version is 1.2'); + $io->comment('Xliff output version is 1.2'); } $resultMessage = sprintf('%d message%s successfully extracted', $extractedMessagesCount, $extractedMessagesCount > 1 ? 's were' : ' was'); @@ -286,7 +286,7 @@ EOF // save the files if (true === $input->getOption('force')) { - $errorIo->comment('Writing files...'); + $io->comment('Writing files...'); $bundleTransPath = false; foreach ($transPaths as $path) { @@ -306,7 +306,7 @@ EOF } } - $errorIo->success($resultMessage.'.'); + $io->success($resultMessage.'.'); return null; } From 9b711b87fe0552df4dbb3023f3643a5499c19aef Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Mon, 6 Jan 2020 22:25:08 +0100 Subject: [PATCH 03/10] [Security] Prevent canceled remember-me cookie from being accepted --- .../Tests/Functional/ClearRememberMeTest.php | 2 +- src/Symfony/Bundle/SecurityBundle/composer.json | 2 +- .../Http/RememberMe/AbstractRememberMeServices.php | 4 ++++ .../RememberMe/AbstractRememberMeServicesTest.php | 11 +++++++++++ 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/ClearRememberMeTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/ClearRememberMeTest.php index 3a1046b0c4..51f56c220d 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/ClearRememberMeTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/ClearRememberMeTest.php @@ -33,7 +33,7 @@ class ClearRememberMeTest extends AbstractWebTestCase $this->assertNotNull($cookieJar->get('REMEMBERME')); $client->request('GET', '/foo'); - $this->assertSame(200, $client->getResponse()->getStatusCode()); + $this->assertRedirect($client->getResponse(), '/login'); $this->assertNull($cookieJar->get('REMEMBERME')); } } diff --git a/src/Symfony/Bundle/SecurityBundle/composer.json b/src/Symfony/Bundle/SecurityBundle/composer.json index 1a8057b6fb..f0e35c7f3d 100644 --- a/src/Symfony/Bundle/SecurityBundle/composer.json +++ b/src/Symfony/Bundle/SecurityBundle/composer.json @@ -19,7 +19,7 @@ "php": "^5.5.9|>=7.0.8", "ext-xml": "*", "symfony/config": "~3.4|~4.0", - "symfony/security": "~3.4.36|~4.3.9|^4.4.1", + "symfony/security": "~3.4.37|~4.3.10|^4.4.3", "symfony/dependency-injection": "^3.4.3|^4.0.3", "symfony/http-kernel": "~3.4|~4.0", "symfony/polyfill-php70": "~1.0" diff --git a/src/Symfony/Component/Security/Http/RememberMe/AbstractRememberMeServices.php b/src/Symfony/Component/Security/Http/RememberMe/AbstractRememberMeServices.php index 8dacdafb57..bf69f3012b 100644 --- a/src/Symfony/Component/Security/Http/RememberMe/AbstractRememberMeServices.php +++ b/src/Symfony/Component/Security/Http/RememberMe/AbstractRememberMeServices.php @@ -99,6 +99,10 @@ abstract class AbstractRememberMeServices implements RememberMeServicesInterface */ final public function autoLogin(Request $request) { + if (($cookie = $request->attributes->get(self::COOKIE_ATTR_NAME)) && null === $cookie->getValue()) { + return null; + } + if (null === $cookie = $request->cookies->get($this->options['name'])) { return null; } diff --git a/src/Symfony/Component/Security/Http/Tests/RememberMe/AbstractRememberMeServicesTest.php b/src/Symfony/Component/Security/Http/Tests/RememberMe/AbstractRememberMeServicesTest.php index 8dc2042f12..cf70ed4cb1 100644 --- a/src/Symfony/Component/Security/Http/Tests/RememberMe/AbstractRememberMeServicesTest.php +++ b/src/Symfony/Component/Security/Http/Tests/RememberMe/AbstractRememberMeServicesTest.php @@ -39,6 +39,17 @@ class AbstractRememberMeServicesTest extends TestCase $this->assertNull($service->autoLogin(new Request())); } + public function testAutoLoginReturnsNullAfterLoginFail() + { + $service = $this->getService(null, ['name' => 'foo', 'path' => null, 'domain' => null]); + + $request = new Request(); + $request->cookies->set('foo', 'foo'); + + $service->loginFail($request); + $this->assertNull($service->autoLogin($request)); + } + /** * @group legacy */ From c2bdc4c4d36acdb5c7e3e1a27a4827976df0d188 Mon Sep 17 00:00:00 2001 From: Toni Rudolf Date: Mon, 30 Dec 2019 19:18:34 +0100 Subject: [PATCH 04/10] [Messenger] Added check if json_encode succeeded --- .../Tests/Transport/RedisExt/ConnectionTest.php | 11 +++++++++++ .../Messenger/Transport/RedisExt/Connection.php | 13 ++++++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Messenger/Tests/Transport/RedisExt/ConnectionTest.php b/src/Symfony/Component/Messenger/Tests/Transport/RedisExt/ConnectionTest.php index 81baaac8d9..5d9f68a982 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/RedisExt/ConnectionTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/RedisExt/ConnectionTest.php @@ -177,6 +177,17 @@ class ConnectionTest extends TestCase $redis->del('messenger-getnonblocking'); } + public function testJsonError() + { + $redis = new \Redis(); + $connection = Connection::fromDsn('redis://localhost/json-error', [], $redis); + try { + $connection->add("\xB1\x31", []); + } catch (TransportException $e) { + } + $this->assertSame('Malformed UTF-8 characters, possibly incorrectly encoded', $e->getMessage()); + } + public function testLastErrorGetsCleared() { $redis = $this->getMockBuilder(\Redis::class)->disableOriginalConstructor()->getMock(); diff --git a/src/Symfony/Component/Messenger/Transport/RedisExt/Connection.php b/src/Symfony/Component/Messenger/Transport/RedisExt/Connection.php index 6ded724ca5..b9515e7ad0 100644 --- a/src/Symfony/Component/Messenger/Transport/RedisExt/Connection.php +++ b/src/Symfony/Component/Messenger/Transport/RedisExt/Connection.php @@ -185,9 +185,16 @@ class Connection } try { - $added = $this->connection->xadd($this->stream, '*', ['message' => json_encode( - ['body' => $body, 'headers' => $headers] - )]); + $message = json_encode([ + 'body' => $body, + 'headers' => $headers, + ]); + + if (false === $message) { + throw new TransportException(json_last_error_msg()); + } + + $added = $this->connection->xadd($this->stream, '*', ['message' => $message]); } catch (\RedisException $e) { throw new TransportException($e->getMessage(), 0, $e); } From 25c805ed5612c125be7239f0ae8527b93a972dc5 Mon Sep 17 00:00:00 2001 From: Oleg Andreyev Date: Tue, 7 Jan 2020 00:31:32 +0200 Subject: [PATCH 05/10] [PhpUnitBridge] When using phpenv + phpenv-composer plugin, composer executable is wrapped into a bash script --- src/Symfony/Bridge/PhpUnit/bin/simple-phpunit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit index 262fdd9dea..da99873a93 100755 --- a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit +++ b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit @@ -60,7 +60,7 @@ foreach ($defaultEnvs as $envName => $envValue) { $COMPOSER = file_exists($COMPOSER = $oldPwd.'/composer.phar') || ($COMPOSER = rtrim('\\' === DIRECTORY_SEPARATOR ? preg_replace('/[\r\n].*/', '', `where.exe composer.phar`) : `which composer.phar 2> /dev/null`)) || ($COMPOSER = rtrim('\\' === DIRECTORY_SEPARATOR ? preg_replace('/[\r\n].*/', '', `where.exe composer`) : `which composer 2> /dev/null`)) - ? $PHP.' '.escapeshellarg($COMPOSER) + ? (file_get_contents($COMPOSER, null, 0, 18) === '#!/usr/bin/env php' ? $PHP : '').' '.escapeshellarg($COMPOSER) // detect shell wrappers by looking at the shebang : 'composer'; if (false === $SYMFONY_PHPUNIT_REMOVE = getenv('SYMFONY_PHPUNIT_REMOVE')) { From 2a5d9cb75a4388cef7a68f6be256d0554f96eac7 Mon Sep 17 00:00:00 2001 From: Stephen Lewis Date: Fri, 3 Jan 2020 11:56:12 +0000 Subject: [PATCH 06/10] [TwigBridge] button_widget now has its title attr translated even if its label = null or false --- .../Twig/Resources/views/Form/form_div_layout.html.twig | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig index ad4477cba5..cee716eb47 100644 --- a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig +++ b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig @@ -222,13 +222,11 @@ '%name%': name, '%id%': id, }) %} - {%- elseif label is same as(false) -%} - {% set translation_domain = false %} - {%- else -%} + {%- elseif label is not same as(false) -%} {% set label = name|humanize %} {%- endif -%} {%- endif -%} - + {%- endblock button_widget -%} {%- block submit_widget -%} From 08c1481b88a00c2a2d8c3f6f0c44e3306dc7c576 Mon Sep 17 00:00:00 2001 From: Igor Tarasov Date: Tue, 7 Jan 2020 23:22:51 +0300 Subject: [PATCH 07/10] [HttpClient] Added missing sprintf It was supposed to be there. --- src/Symfony/Component/HttpClient/Response/ResponseTrait.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpClient/Response/ResponseTrait.php b/src/Symfony/Component/HttpClient/Response/ResponseTrait.php index d249d63048..c747f373a0 100644 --- a/src/Symfony/Component/HttpClient/Response/ResponseTrait.php +++ b/src/Symfony/Component/HttpClient/Response/ResponseTrait.php @@ -323,7 +323,7 @@ trait ResponseTrait } if ('' !== $chunk && null !== $response->content && \strlen($chunk) !== fwrite($response->content, $chunk)) { - $multi->handlesActivity[$j] = [null, new TransportException('Failed writing %d bytes to the response buffer.', \strlen($chunk))]; + $multi->handlesActivity[$j] = [null, new TransportException(sprintf('Failed writing %d bytes to the response buffer.', \strlen($chunk)))]; continue; } From eb69e135b2768d74544cced5b62152b6ba4c81b8 Mon Sep 17 00:00:00 2001 From: naitsirch Date: Tue, 7 Jan 2020 21:29:45 +0100 Subject: [PATCH 08/10] [Dotenv] Fixed infinite loop with missing quote followed by quoted value If there's a quote missing to end a value and in the next line there's again a quoted value Dotenv will run into an infinite loop. An .env file with the following content will result in this error: ``` FOO="foo BAR="bar" ``` See #34642 for more details. --- src/Symfony/Component/Dotenv/Dotenv.php | 5 ++++- src/Symfony/Component/Dotenv/Tests/DotenvTest.php | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Dotenv/Dotenv.php b/src/Symfony/Component/Dotenv/Dotenv.php index 84e66b1d0b..63424e165d 100644 --- a/src/Symfony/Component/Dotenv/Dotenv.php +++ b/src/Symfony/Component/Dotenv/Dotenv.php @@ -203,7 +203,10 @@ final class Dotenv $this->cursor += 1 + $len; } elseif ('"' === $this->data[$this->cursor]) { $value = ''; - ++$this->cursor; + + if (++$this->cursor === $this->end) { + throw $this->createFormatException('Missing quote to end the value'); + } while ('"' !== $this->data[$this->cursor] || ('\\' === $this->data[$this->cursor - 1] && '\\' !== $this->data[$this->cursor - 2])) { $value .= $this->data[$this->cursor]; diff --git a/src/Symfony/Component/Dotenv/Tests/DotenvTest.php b/src/Symfony/Component/Dotenv/Tests/DotenvTest.php index 43607d3555..fa53029c67 100644 --- a/src/Symfony/Component/Dotenv/Tests/DotenvTest.php +++ b/src/Symfony/Component/Dotenv/Tests/DotenvTest.php @@ -40,6 +40,7 @@ class DotenvTest extends TestCase ['FOO', "Missing = in the environment variable declaration in \".env\" at line 1.\n...FOO...\n ^ line 1 offset 3"], ['FOO="foo', "Missing quote to end the value in \".env\" at line 1.\n...FOO=\"foo...\n ^ line 1 offset 8"], ['FOO=\'foo', "Missing quote to end the value in \".env\" at line 1.\n...FOO='foo...\n ^ line 1 offset 8"], + ["FOO=\"foo\nBAR=\"bar\"", "Missing quote to end the value in \".env\" at line 1.\n...FOO=\"foo\\nBAR=\"bar\"...\n ^ line 1 offset 18"], ['FOO=\'foo'."\n", "Missing quote to end the value in \".env\" at line 1.\n...FOO='foo\\n...\n ^ line 1 offset 9"], ['export FOO', "Unable to unset an environment variable in \".env\" at line 1.\n...export FOO...\n ^ line 1 offset 10"], ['FOO=${FOO', "Unclosed braces on variable expansion in \".env\" at line 1.\n...FOO=\${FOO...\n ^ line 1 offset 9"], From 3a840a9796ffdc59f9f3d87d9cbf86b6d3db92e9 Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Wed, 8 Jan 2020 15:00:15 +0100 Subject: [PATCH 09/10] [Routing] Fix using a custom matcher & generator dumper class --- src/Symfony/Component/Routing/Router.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/Routing/Router.php b/src/Symfony/Component/Routing/Router.php index 003bdc3e29..3f91cd64b2 100644 --- a/src/Symfony/Component/Routing/Router.php +++ b/src/Symfony/Component/Routing/Router.php @@ -291,7 +291,7 @@ class Router implements RouterInterface, RequestMatcherInterface return $this->matcher; } - $compiled = is_a($this->options['matcher_class'], CompiledUrlMatcher::class, true) && (UrlMatcher::class === $this->options['matcher_base_class'] || RedirectableUrlMatcher::class === $this->options['matcher_base_class']); + $compiled = is_a($this->options['matcher_class'], CompiledUrlMatcher::class, true) && (UrlMatcher::class === $this->options['matcher_base_class'] || RedirectableUrlMatcher::class === $this->options['matcher_base_class']) && is_a($this->options['matcher_dumper_class'], CompiledUrlMatcherDumper::class, true); if (null === $this->options['cache_dir'] || null === $this->options['matcher_cache_class']) { $routes = $this->getRouteCollection(); @@ -348,7 +348,7 @@ class Router implements RouterInterface, RequestMatcherInterface return $this->generator; } - $compiled = is_a($this->options['generator_class'], CompiledUrlGenerator::class, true) && UrlGenerator::class === $this->options['generator_base_class']; + $compiled = is_a($this->options['generator_class'], CompiledUrlGenerator::class, true) && UrlGenerator::class === $this->options['generator_base_class'] && is_a($this->options['generator_dumper_class'], CompiledUrlGeneratorDumper::class, true); if (null === $this->options['cache_dir'] || null === $this->options['generator_cache_class']) { $routes = $this->getRouteCollection(); @@ -398,8 +398,8 @@ class Router implements RouterInterface, RequestMatcherInterface */ protected function getGeneratorDumperInstance() { - // For BC, fallback to PhpGeneratorDumper if the UrlGenerator and UrlGeneratorDumper are not consistent with each other - if (is_a($this->options['generator_class'], CompiledUrlGenerator::class, true) !== is_a($this->options['generator_dumper_class'], CompiledUrlGeneratorDumper::class, true)) { + // For BC, fallback to PhpGeneratorDumper (which is the old default value) if the old UrlGenerator is used with the new default CompiledUrlGeneratorDumper + if (!is_a($this->options['generator_class'], CompiledUrlGenerator::class, true) && is_a($this->options['generator_dumper_class'], CompiledUrlGeneratorDumper::class, true)) { return new PhpGeneratorDumper($this->getRouteCollection()); } @@ -411,8 +411,8 @@ class Router implements RouterInterface, RequestMatcherInterface */ protected function getMatcherDumperInstance() { - // For BC, fallback to PhpMatcherDumper if the UrlMatcher and UrlMatcherDumper are not consistent with each other - if (is_a($this->options['matcher_class'], CompiledUrlMatcher::class, true) !== is_a($this->options['matcher_dumper_class'], CompiledUrlMatcherDumper::class, true)) { + // For BC, fallback to PhpMatcherDumper (which is the old default value) if the old UrlMatcher is used with the new default CompiledUrlMatcherDumper + if (!is_a($this->options['matcher_class'], CompiledUrlMatcher::class, true) && is_a($this->options['matcher_dumper_class'], CompiledUrlMatcherDumper::class, true)) { return new PhpMatcherDumper($this->getRouteCollection()); } From 0c320febe1547e6db30c59390ea5e86a4dd7d487 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 8 Jan 2020 17:32:40 +0100 Subject: [PATCH 10/10] [Debug] fix ClassNotFoundFatalErrorHandler --- .../Debug/Tests/Exception/FlattenExceptionTest.php | 12 ++++++++++++ .../ClassNotFoundFatalErrorHandlerTest.php | 4 ++++ 2 files changed, 16 insertions(+) diff --git a/src/Symfony/Component/Debug/Tests/Exception/FlattenExceptionTest.php b/src/Symfony/Component/Debug/Tests/Exception/FlattenExceptionTest.php index 0290b05bad..3d163eec77 100644 --- a/src/Symfony/Component/Debug/Tests/Exception/FlattenExceptionTest.php +++ b/src/Symfony/Component/Debug/Tests/Exception/FlattenExceptionTest.php @@ -199,6 +199,10 @@ class FlattenExceptionTest extends TestCase public function testArguments() { + if (\PHP_VERSION_ID >= 70400) { + $this->markTestSkipped('PHP 7.4 removes arguments from exception traces.'); + } + $dh = opendir(__DIR__); $fh = tmpfile(); @@ -261,6 +265,10 @@ class FlattenExceptionTest extends TestCase public function testRecursionInArguments() { + if (\PHP_VERSION_ID >= 70400) { + $this->markTestSkipped('PHP 7.4 removes arguments from exception traces.'); + } + $a = null; $a = ['foo', [2, &$a]]; $exception = $this->createException($a); @@ -272,6 +280,10 @@ class FlattenExceptionTest extends TestCase public function testTooBigArray() { + if (\PHP_VERSION_ID >= 70400) { + $this->markTestSkipped('PHP 7.4 removes arguments from exception traces.'); + } + $a = []; for ($i = 0; $i < 20; ++$i) { for ($j = 0; $j < 50; ++$j) { diff --git a/src/Symfony/Component/Debug/Tests/FatalErrorHandler/ClassNotFoundFatalErrorHandlerTest.php b/src/Symfony/Component/Debug/Tests/FatalErrorHandler/ClassNotFoundFatalErrorHandlerTest.php index 9a56b3b4ec..f356476201 100644 --- a/src/Symfony/Component/Debug/Tests/FatalErrorHandler/ClassNotFoundFatalErrorHandlerTest.php +++ b/src/Symfony/Component/Debug/Tests/FatalErrorHandler/ClassNotFoundFatalErrorHandlerTest.php @@ -29,6 +29,10 @@ class ClassNotFoundFatalErrorHandlerTest extends TestCase // get class loaders wrapped by DebugClassLoader if ($function[0] instanceof DebugClassLoader) { $function = $function[0]->getClassLoader(); + + if (!\is_array($function)) { + continue; + } } if ($function[0] instanceof ComposerClassLoader) {