staabm / phpstan-todo-by

Todo comments with expiration
https://staabm.github.io/2023/12/17/phpstan-todo-by-published.html
MIT License
173 stars 4 forks source link

TodoByPackageVersionRule: backtrack limit error #44

Closed staabm closed 8 months ago

staabm commented 8 months ago

the comment

// TODO: minimumApiClientVersion:2.0 This can be removed once all API consumers use client version 2.0 or higher

Uncaught RuntimeException: Error in PCRE: Backtrack limit exhausted in /Users/staabm/workspace/phpstan-todo-by/src/utils/CommentMatcher.php:43
#0 /Users/staabm/workspace/phpstan-todo-by/src/TodoByPackageVersionRule.php(71): staabm\PHPStanTodoBy\utils\CommentMatcher::matchComments(Object(PhpParser\Node\Stmt\Nop), '{\n    @?TODO # ...')
#1 phar:///Users/staabm/workspace/phpstan-todo-by/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/FileAnalyser.php(107): staabm\PHPStanTodoBy\TodoByPackageVersionRule->processNode(Object(PhpParser\Node\Stmt\Nop), Object(PHPStan\Analyser\MutatingScope))
#2 phar:///Users/staabm/workspace/phpstan-todo-by/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScopeResolver.php(459): PHPStan\Analyser\FileAnalyser->PHPStan\Analyser\{closure}(Object(PhpParser\Node\Stmt\Nop), Object(PHPStan\Analyser\MutatingScope))
#3 phar:///Users/staabm/workspace/phpstan-todo-by/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScopeResolver.php(402): PHPStan\Analyser\NodeScopeResolver->processStmtNode(Object(PhpParser\Node\Stmt\Nop), Object(PHPStan\Analyser\MutatingScope), Object(Closure), Object(PHPStan\Analyser\StatementContext))
#4 phar:///Users/staabm/workspace/phpstan-todo-by/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScopeResolver.php(641): PHPStan\Analyser\NodeScopeResolver->processStmtNodes(Object(PhpParser\Node\Stmt\Namespace_), Array, Object(PHPStan\Analyser\MutatingScope), Object(Closure), Object(PHPStan\Analyser\StatementContext))
#5 phar:///Users/staabm/workspace/phpstan-todo-by/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScopeResolver.php(371): PHPStan\Analyser\NodeScopeResolver->processStmtNode(Object(PhpParser\Node\Stmt\Namespace_), Object(PHPStan\Analyser\MutatingScope), Object(Closure), Object(PHPStan\Analyser\StatementContext))
#6 phar:///Users/staabm/workspace/phpstan-todo-by/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/FileAnalyser.php(166): PHPStan\Analyser\NodeScopeResolver->processNodes(Array, Object(PHPStan\Analyser\MutatingScope), Object(Closure))
#7 phar:///Users/staabm/workspace/phpstan-todo-by/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/Analyser.php(72): PHPStan\Analyser\FileAnalyser->analyseFile('/Users/staabm/w...', Array, Object(PHPStan\Rules\LazyRegistry), Object(PHPStan\Collectors\Registry), NULL)
#8 phar:///Users/staabm/workspace/phpstan-todo-by/vendor/phpstan/phpstan/phpstan.phar/src/Command/AnalyserRunner.php(62): PHPStan\Analyser\Analyser->analyse(Array, Object(Closure), NULL, true, Array)
#9 phar:///Users/staabm/workspace/phpstan-todo-by/vendor/phpstan/phpstan/phpstan.phar/src/Command/AnalyseApplication.php(209): PHPStan\Command\AnalyserRunner->runAnalyser(Array, Array, Object(Closure), NULL, true, true, '/Users/staabm/w...', Object(_PHPStan_39fe102d2\Symfony\Component\Console\Input\ArgvInput))
#10 phar:///Users/staabm/workspace/phpstan-todo-by/vendor/phpstan/phpstan/phpstan.phar/src/Command/AnalyseApplication.php(101): PHPStan\Command\AnalyseApplication->runAnalyser(Array, Array, true, '/Users/staabm/w...', Object(PHPStan\Command\Symfony\SymfonyOutput), Object(PHPStan\Command\Symfony\SymfonyOutput), Object(_PHPStan_39fe102d2\Symfony\Component\Console\Input\ArgvInput))
#11 phar:///Users/staabm/workspace/phpstan-todo-by/vendor/phpstan/phpstan/phpstan.phar/src/Command/AnalyseCommand.php(198): PHPStan\Command\AnalyseApplication->analyse(Array, true, Object(PHPStan\Command\Symfony\SymfonyOutput), Object(PHPStan\Command\Symfony\SymfonyOutput), false, true, '/Users/staabm/w...', Array, Object(_PHPStan_39fe102d2\Symfony\Component\Console\Input\ArgvInput))
#12 phar:///Users/staabm/workspace/phpstan-todo-by/vendor/phpstan/phpstan/phpstan.phar/vendor/symfony/console/Command/Command.php(259): PHPStan\Command\AnalyseCommand->execute(Object(_PHPStan_39fe102d2\Symfony\Component\Console\Input\ArgvInput), Object(_PHPStan_39fe102d2\Symfony\Component\Console\Output\ConsoleOutput))
#13 phar:///Users/staabm/workspace/phpstan-todo-by/vendor/phpstan/phpstan/phpstan.phar/vendor/symfony/console/Application.php(870): _PHPStan_39fe102d2\Symfony\Component\Console\Command\Command->run(Object(_PHPStan_39fe102d2\Symfony\Component\Console\Input\ArgvInput), Object(_PHPStan_39fe102d2\Symfony\Component\Console\Output\ConsoleOutput))
#14 phar:///Users/staabm/workspace/phpstan-todo-by/vendor/phpstan/phpstan/phpstan.phar/vendor/symfony/console/Application.php(261): _PHPStan_39fe102d2\Symfony\Component\Console\Application->doRunCommand(Object(PHPStan\Command\AnalyseCommand), Object(_PHPStan_39fe102d2\Symfony\Component\Console\Input\ArgvInput), Object(_PHPStan_39fe102d2\Symfony\Component\Console\Output\ConsoleOutput))
#15 phar:///Users/staabm/workspace/phpstan-todo-by/vendor/phpstan/phpstan/phpstan.phar/vendor/symfony/console/Application.php(157): _PHPStan_39fe102d2\Symfony\Component\Console\Application->doRun(Object(_PHPStan_39fe102d2\Symfony\Component\Console\Input\ArgvInput), Object(_PHPStan_39fe102d2\Symfony\Component\Console\Output\ConsoleOutput))
#16 phar:///Users/staabm/workspace/phpstan-todo-by/vendor/phpstan/phpstan/phpstan.phar/bin/phpstan(124): _PHPStan_39fe102d2\Symfony\Component\Console\Application->run()
#17 phar:///Users/staabm/workspace/phpstan-todo-by/vendor/phpstan/phpstan/phpstan.phar/bin/phpstan(125): _PHPStan_39fe102d2\{closure}()
#18 /Users/staabm/workspace/phpstan-todo-by/vendor/phpstan/phpstan/phpstan(8): require('phar:///Users/s...')
#19 /Users/staabm/workspace/phpstan-todo-by/vendor/bin/phpstan(119): include('/Users/staabm/w...')
#20 {main}

triggers a PCRE backtrack limit error

staabm commented 8 months ago

@glaubinix do you have a idea why the example you gave runs into backtrack limits on this regex pattern?

staabm commented 8 months ago

or maybe @seldaek has an idea?

glaubinix commented 8 months ago

If I saw this correct, then you used the regex used by Composer/Packagist.org to validate a package name? If the package name part is one long string without / then the PCRE backtrack limit can be reached. One solution is to use possessive greedy quantifiers ++ + instead of + and . Just be aware that this can cause that certain package names doesn't get matched by the regex but we haven't seen any name like that out there.

So the package name part of your regex would then look like (?:(?P<package>(php|[a-z0-9]([_.-]?[a-z0-9]++)*+/[a-z0-9](([_.]|-{1,2})?[a-z0-9]++)*+)):) # "php" or a composer package name, followed by ":"

staabm commented 8 months ago

If I saw this correct, then you used the regex used by Composer/Packagist.org to validate a package name?

rights, its from the website.

One solution is to use the greedy quantifiers ++ + instead of + and .

oohh wow.. never seen this regex syntax before

github-actions[bot] commented 7 months ago

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.