Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Untrapped Divide by Zero Error #5157

Closed
rivets opened this issue Feb 5, 2021 · 11 comments · Fixed by #5182
Closed

Untrapped Divide by Zero Error #5157

rivets opened this issue Feb 5, 2021 · 11 comments · Fixed by #5182
Labels

Comments

@rivets
Copy link

rivets commented Feb 5, 2021

I'm afraid all I have is a stack trace. I'm using PHP 8.0.1

Uncaught Exception: Division by zero
Stack trace in the forked worker:
#0FWStan/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOp/NonDivArithmeticOpAnalyzer.php(181): Psalm\Internal\Analyzer\Statements\Expression\BinaryOp\NonDivArithmeticOpAnalyzer::analyzeNonDivOperands(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(Psalm\Codebase), Object(Psalm\Config), Object(Psalm\Context), Object(PhpParser\Node\Scalar\LNumber), Object(PhpParser\Node\Scalar\LNumber), Object(PhpParser\Node\Expr\BinaryOp\Div), Object(Psalm\Type\Atomic\TLiteralInt), Object(Psalm\Type\Atomic\TLiteralInt), Array, Array, false, false, false, NULL)
#1 FWStan/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOp/NonComparisonOpAnalyzer.php(121): Psalm\Internal\Analyzer\Statements\Expression\BinaryOp\NonDivArithmeticOpAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(Psalm\Internal\Provider\NodeDataProvider), Object(PhpParser\Node\Scalar\LNumber), Object(PhpParser\Node\Scalar\LNumber), Object(PhpParser\Node\Expr\BinaryOp\Div), NULL, Object(Psalm\Context))
#2 FWStan/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOpAnalyzer.php(325): Psalm\Internal\Analyzer\Statements\Expression\BinaryOp\NonComparisonOpAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\BinaryOp\Div), Object(Psalm\Context))
#3 FWStan/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php(231): Psalm\Internal\Analyzer\Statements\Expression\BinaryOpAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\BinaryOp\Div), Object(Psalm\Context), 0, true)
#4 FWStan/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php(39): Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer::handleExpression(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\BinaryOp\Div), Object(Psalm\Context), false, Object(Psalm\Context), true)
#5 FWStan/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php(519): Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\BinaryOp\Div), Object(Psalm\Context), false, Object(Psalm\Context), true)
#6 FWStan/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php(168): Psalm\Internal\Analyzer\StatementsAnalyzer::analyzeStatement(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Stmt\Expression), Object(Psalm\Context), Object(Psalm\Context))
#7 FWStan/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php(654): Psalm\Internal\Analyzer\StatementsAnalyzer->analyze(Array, Object(Psalm\Context), Object(Psalm\Context), true)
#8 FWStan/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ClassAnalyzer.php(1968): Psalm\Internal\Analyzer\FunctionLikeAnalyzer->analyze(Object(Psalm\Context), Object(Psalm\Internal\Provider\NodeDataProvider), Object(Psalm\Context))
#9 FWStan/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ClassAnalyzer.php(745): Psalm\Internal\Analyzer\ClassAnalyzer->analyzeClassMethod(Object(PhpParser\Node\Stmt\ClassMethod), Object(Psalm\Storage\ClassLikeStorage), Object(Psalm\Internal\Analyzer\ClassAnalyzer), Object(Psalm\Context), Object(Psalm\Context))
#10 FWStan/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/FileAnalyzer.php(211): Psalm\Internal\Analyzer\ClassAnalyzer->analyze(Object(Psalm\Context), Object(Psalm\Context))
#11FWStan/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Analyzer.php(340): Psalm\Internal\Analyzer\FileAnalyzer->analyze(NULL)
#12 FWStan/vendor/vimeo/psalm/src/Psalm/Internal/Fork/Pool.php(193): Psalm\Internal\Codebase\Analyzer->Psalm\Internal\Codebase{closure}(19, '/Users/nlfm/Lib...')
#13 FWStan/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Analyzer.php(406): Psalm\Internal\Fork\Pool->__construct(Array, Object(Closure), Object(Closure), Object(Closure), Object(Closure))
#14 FWStan/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Analyzer.php(269): Psalm\Internal\Codebase\Analyzer->doAnalysis(Object(Psalm\Internal\Analyzer\ProjectAnalyzer), 3)
#15 FWStan/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php(639): Psalm\Internal\Codebase\Analyzer->analyzeFiles(Object(Psalm\Internal\Analyzer\ProjectAnalyzer), 3, false, true)
#16 FWStan/vendor/vimeo/psalm/src/psalm.php(676): Psalm\Internal\Analyzer\ProjectAnalyzer->check('/Users/nlfm/Lib...', false)
#17 FWStan/vendor/vimeo/psalm/psalm(2): require_once('/Users/nlfm/Lib...')
#18 {main} in FWStan/vendor/vimeo/psalm/src/Psalm/Internal/Fork/Pool.php:358
Stack trace:
#0 FWStan/vendor/vimeo/psalm/src/Psalm/Internal/Fork/Pool.php(390): Psalm\Internal\Fork\Pool->readResultsFromChildren()
#1 FWStan/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Analyzer.php(473): Psalm\Internal\Fork\Pool->wait()
#2 FWStan/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Analyzer.php(269): Psalm\Internal\Codebase\Analyzer->doAnalysis(Object(Psalm\Internal\Analyzer\ProjectAnalyzer), 3)
#3 FWStan/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php(639): Psalm\Internal\Codebase\Analyzer->analyzeFiles(Object(Psalm\Internal\Analyzer\ProjectAnalyzer), 3, false, true)
#4 FWStan/vendor/vimeo/psalm/src/psalm.php(676): Psalm\Internal\Analyzer\ProjectAnalyzer->check('/Users/nlfm/Lib...', false)
#5 FWStan/vendor/vimeo/psalm/psalm(2): require_once('/Users/nlfm/Lib...')
#6 {main}
(Psalm 4.2.1@ea9cb72143b77e7520c52fa37290bd8d8bc88fd9 crashed due to an uncaught Throwable)

@psalm-github-bot
Copy link

Hey @rivets, can you reproduce the issue on https://psalm.dev ?

@rivets
Copy link
Author

rivets commented Feb 5, 2021

I'm running psalm 4.4.1 and it fails

@orklah
Copy link
Collaborator

orklah commented Feb 5, 2021

Can you give the stack trace for Psalm 4.4.1? The stack above seems to come from 4.2.1

@weirdan weirdan added the bug label Feb 5, 2021
@orklah
Copy link
Collaborator

orklah commented Feb 5, 2021

It really seems like Psalm does the division by zero because after it found a literal division by zero in your code. Judging from the parameters, you have a ??? / 0 expression in your code

Please run psalm with the --debug-by-line option and search for that expression in the last file it outputs?

@rivets
Copy link
Author

rivets commented Feb 5, 2021

Sorry - I forgot I had downgraded to see if it went away :-)

Uncaught Exception: Division by zero
Stack trace in the forked worker:
#0 FWStan/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOp/NonDivArithmeticOpAnalyzer.php(183): Psalm\Internal\Analyzer\Statements\Expression\BinaryOp\NonDivArithmeticOpAnalyzer::analyzeNonDivOperands(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(Psalm\Codebase), Object(Psalm\Config), Object(Psalm\Context), Object(PhpParser\Node\Scalar\LNumber), Object(PhpParser\Node\Scalar\LNumber), Object(PhpParser\Node\Expr\BinaryOp\Div), Object(Psalm\Type\Atomic\TLiteralInt), Object(Psalm\Type\Atomic\TLiteralInt), Array, Array, false, false, false, NULL)
#1 FWStan/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOp/NonComparisonOpAnalyzer.php(119): Psalm\Internal\Analyzer\Statements\Expression\BinaryOp\NonDivArithmeticOpAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(Psalm\Internal\Provider\NodeDataProvider), Object(PhpParser\Node\Scalar\LNumber), Object(PhpParser\Node\Scalar\LNumber), Object(PhpParser\Node\Expr\BinaryOp\Div), NULL, Object(Psalm\Context))
#2 FWStan/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOpAnalyzer.php(334): Psalm\Internal\Analyzer\Statements\Expression\BinaryOp\NonComparisonOpAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\BinaryOp\Div), Object(Psalm\Context))
#3 FWStan/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php(228): Psalm\Internal\Analyzer\Statements\Expression\BinaryOpAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\BinaryOp\Div), Object(Psalm\Context), 0, true)
#4 FWStan/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php(40): Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer::handleExpression(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\BinaryOp\Div), Object(Psalm\Context), false, Object(Psalm\Context), true)
#5 FWStan/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php(530): Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\BinaryOp\Div), Object(Psalm\Context), false, Object(Psalm\Context), true)
#6 FWStan/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php(172): Psalm\Internal\Analyzer\StatementsAnalyzer::analyzeStatement(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Stmt\Expression), Object(Psalm\Context), Object(Psalm\Context))
#7 FWStan/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php(421): Psalm\Internal\Analyzer\StatementsAnalyzer->analyze(Array, Object(Psalm\Context), Object(Psalm\Context), true)
#8 FWStan/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ClassAnalyzer.php(1639): Psalm\Internal\Analyzer\FunctionLikeAnalyzer->analyze(Object(Psalm\Context), Object(Psalm\Internal\Provider\NodeDataProvider), Object(Psalm\Context))
#9 FWStan/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ClassAnalyzer.php(387): Psalm\Internal\Analyzer\ClassAnalyzer->analyzeClassMethod(Object(PhpParser\Node\Stmt\ClassMethod), Object(Psalm\Storage\ClassLikeStorage), Object(Psalm\Internal\Analyzer\ClassAnalyzer), Object(Psalm\Context), Object(Psalm\Context))
#10 FWStan/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/FileAnalyzer.php(213): Psalm\Internal\Analyzer\ClassAnalyzer->analyze(Object(Psalm\Context), Object(Psalm\Context))
#11 FWStan/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Analyzer.php(340): Psalm\Internal\Analyzer\FileAnalyzer->analyze(NULL)
#12 FWStan/vendor/vimeo/psalm/src/Psalm/Internal/Fork/Pool.php(193): Psalm\Internal\Codebase\Analyzer->Psalm\Internal\Codebase{closure}(19, '/Users/nlfm/Lib...')
#13 FWStan/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Analyzer.php(406): Psalm\Internal\Fork\Pool->__construct(Array, Object(Closure), Object(Closure), Object(Closure), Object(Closure))
#14 FWStan/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Analyzer.php(269): Psalm\Internal\Codebase\Analyzer->doAnalysis(Object(Psalm\Internal\Analyzer\ProjectAnalyzer), 3)
#15 FWStan/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php(635): Psalm\Internal\Codebase\Analyzer->analyzeFiles(Object(Psalm\Internal\Analyzer\ProjectAnalyzer), 3, false, true)
#16 FWStan/vendor/vimeo/psalm/src/psalm.php(676): Psalm\Internal\Analyzer\ProjectAnalyzer->check('/Users/nlfm/Lib...', false)
#17 FWStan/vendor/vimeo/psalm/psalm(2): require_once('/Users/nlfm/Lib...')
#18 {main} in FWStan/vendor/vimeo/psalm/src/Psalm/Internal/Fork/Pool.php:357
Stack trace:
#0 FWStan/vendor/vimeo/psalm/src/Psalm/Internal/Fork/Pool.php(389): Psalm\Internal\Fork\Pool->readResultsFromChildren()
#1 FWStan/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Analyzer.php(473): Psalm\Internal\Fork\Pool->wait()
#2 FWStan/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Analyzer.php(269): Psalm\Internal\Codebase\Analyzer->doAnalysis(Object(Psalm\Internal\Analyzer\ProjectAnalyzer), 3)
#3 FWStan/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php(635): Psalm\Internal\Codebase\Analyzer->analyzeFiles(Object(Psalm\Internal\Analyzer\ProjectAnalyzer), 3, false, true)
#4 FWStan/vendor/vimeo/psalm/src/psalm.php(676): Psalm\Internal\Analyzer\ProjectAnalyzer->check('/Users/nlfm/Lib...', false)
#5 FWStan/vendor/vimeo/psalm/psalm(2): require_once('/Users/nlfm/Lib...')
#6 {main}
(Psalm 4.4.1@9fd7a7d885b3a216cff8dec9d8c21a132f275224 crashed due to an uncaught Throwable)

@orklah
Copy link
Collaborator

orklah commented Feb 5, 2021

Well, the fix is pretty simple but I have mixed feelings about this. It's way too specific to create a new Issue and if we don't, Psalm expect the returned type of the division by zero.

I tried putting the empty type but it's not very well supported by psalm (it doesn't produce errors on usage) and I don't want to return an int or a float.

I'd advise finding the expression and fixing it because it make no sense (it will always throw an error)

For reference, the issue is there:

$value = $left_type_part->value / $right_type_part->value;

Psalm sees a division with literal params and does the division by itself to infer the literal result

@rivets
Copy link
Author

rivets commented Feb 9, 2021

I'll check the code (there is very little division) but there isn't anything that would be a literal division by 0. This didn't happen in earlier versions and I haven't (conciously) added any code using division since I changed to the latest version.

@orklah
Copy link
Collaborator

orklah commented Feb 9, 2021

You should be able to find the file quickly with --debug-by-line. It's probably some code that was already there before.

@rivets
Copy link
Author

rivets commented Feb 9, 2021

I've added --debug-by-line but how do I identify which file is causing the error? The error output appears in different places every run. BTW the failure leaves a dead process that you have to kill every time.

@rivets
Copy link
Author

rivets commented Feb 9, 2021

I've found it! It's a piece of code that has always been there as it exists to test my unhandled exception handling code - so it does a division by 0. This didn't break the version of psalm I was using before so you must have added this test more recently. Is there anyway of telling psalm not to check the line? I don't want to not check the file as psalm really helps keep things in shape.

@orklah
Copy link
Collaborator

orklah commented Feb 9, 2021

Well, this looks like a legitimate use case so I proposed a PR to fix the issue. Let's see what @muglug say about the way I tried to fix it.

You could maybe try to avoid having literals on both side of the divison in the meantime. I think something like

$a = 1;
$a/0;

should be ok because it's not a literal

And yeah, Psalm indeed extended its analysis to such cases in #2132

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants