Skip to content

Commit

Permalink
Fix for endless loop detection
Browse files Browse the repository at this point in the history
  • Loading branch information
herndlm authored and ondrejmirtes committed Nov 11, 2024
1 parent d6412b8 commit fd6a0f2
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 2 deletions.
5 changes: 3 additions & 2 deletions src/Analyser/NodeScopeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -1369,7 +1369,10 @@ private function processStmtNode(
}

$bodyScope = $bodyScope->mergeWith($initScope);

$alwaysIterates = TrinaryLogic::createFromBoolean($context->isTopLevel());
if ($lastCondExpr !== null) {
$alwaysIterates = $alwaysIterates->and($bodyScope->getType($lastCondExpr)->toBoolean()->isTrue());
$bodyScope = $this->processExprNode($stmt, $lastCondExpr, $bodyScope, $nodeCallback, ExpressionContext::createDeep())->getTruthyScope();
}

Expand All @@ -1385,9 +1388,7 @@ private function processStmtNode(
}
$finalScope = $finalScope->generalizeWith($loopScope);

$alwaysIterates = TrinaryLogic::createFromBoolean($context->isTopLevel());
if ($lastCondExpr !== null) {
$alwaysIterates = $alwaysIterates->and($finalScope->getType($lastCondExpr)->toBoolean()->isTrue());
$finalScope = $finalScope->filterByFalseyValue($lastCondExpr);
}

Expand Down
8 changes: 8 additions & 0 deletions tests/PHPStan/Analyser/StatementResultTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,14 @@ public function dataIsAlwaysTerminating(): array
'for (; "a", "";) { }',
false,
],
[
'for ($c = (0x80 | 0x40); $c & 0x80; $c = $c << 1) { }',
false,
],
[
'for ($i = 0; $i < 10; $i++) { $i = 5; }',
true,
],
[
'do { } while (doFoo());',
false,
Expand Down
6 changes: 6 additions & 0 deletions tests/PHPStan/Rules/DeadCode/UnreachableStatementRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -224,4 +224,10 @@ public function testBug11179(): void
$this->analyse([__DIR__ . '/data/bug-11179.php'], []);
}

public function testBug11992(): void
{
$this->treatPhpDocTypesAsCertain = false;
$this->analyse([__DIR__ . '/data/bug-11992.php'], []);
}

}
37 changes: 37 additions & 0 deletions tests/PHPStan/Rules/DeadCode/data/bug-11992.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php declare(strict_types = 1);

namespace Bug11992;

// valid
function exampleA(): void {
$bc = 0;
for ($i = 0; $i < 3; ++$i) {
$bc++;
}
printf("bc: %d\n", $bc);
}

// not valid? Why? this is deterministic even from a static standpoint
function exampleB(): void {
$bc = 0;
for ($c = (0x80 | 0x40); $c & 0x80; $c = $c << 1) {
$bc++;
}
printf("bc: %d\n", $bc);
}

// invalid because valid() is theoretically infinite?
function exampleC(): void {
for (
$it = new \DirectoryIterator('/tmp');
$it->valid();
$it->next()
) {
printf("name: %s\n", $it->getFilename());
}
printf("done\n");
}

exampleA();
exampleB();
exampleC();

0 comments on commit fd6a0f2

Please sign in to comment.