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

Constexpr evaluator underflow / overflow handling for + and - #5921

Closed
BafS opened this issue Jun 11, 2021 · 6 comments · Fixed by #5924
Closed

Constexpr evaluator underflow / overflow handling for + and - #5921

BafS opened this issue Jun 11, 2021 · 6 comments · Fixed by #5924
Labels
bug causes crash easy problems Issues that can be fixed without background knowledge of Psalm

Comments

@BafS
Copy link
Contributor

BafS commented Jun 11, 2021

I have a type error bug (similar to #5505) when using binary shifts

Psalm version: v4.7.3

Error

Uncaught TypeError: Argument 2 passed to Psalm\Type::getInt() must be of the type int or null, float given, called in phar:///.../vendor/psalm/phar/psalm.phar/src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOp/NonDivArithmeticOpAnalyzer.php on line 162 and defined in phar:///.../vendor/psalm/phar/psalm.phar/src/Psalm/Type.php:129

psalm.xml

<?xml version="1.0"?>
<psalm
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="https://getpsalm.org/schema/config"
    xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
    xmlns:xi="http://www.w3.org/2001/XInclude"
>
    <projectFiles>
        <file name="bug-psalm.php" />
    </projectFiles>
</psalm>

bug-psalm.php

<?php

const MASK = (1 << 63) - (1 << 20);
@psalm-github-bot
Copy link

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

@BafS
Copy link
Contributor Author

BafS commented Jun 11, 2021

Yes, https://psalm.dev/r/b5c187cf0c

@psalm-github-bot
Copy link

I found these snippets:

https://psalm.dev/r/b5c187cf0c
<?php

const MASK = (1 << 63) - (1 << 20);
Psalm encountered an internal error:

/vendor/vimeo/psalm/src/Psalm/Type.php: Argument 2 passed to Psalm\Type::getInt() must be of the type int or null, float given, called in /vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOp/NonDivArithmeticOpAnalyzer.php on line 314

@weirdan weirdan added the bug label Jun 11, 2021
@weirdan
Copy link
Collaborator

weirdan commented Jun 11, 2021

The code handling Plus and Minus should be fixed to handle float results, the way it's already done for Pow and Mul:

if ($parent instanceof PhpParser\Node\Expr\BinaryOp\Plus) {
$calculated_type = Type::getInt(false, $left_type_part->value + $right_type_part->value);
} elseif ($parent instanceof PhpParser\Node\Expr\BinaryOp\Minus) {
$calculated_type = Type::getInt(false, $left_type_part->value - $right_type_part->value);
} elseif ($parent instanceof PhpParser\Node\Expr\BinaryOp\Mod) {
$calculated_type = Type::getInt(false, $left_type_part->value % $right_type_part->value);
} elseif ($parent instanceof PhpParser\Node\Expr\BinaryOp\Mul) {
$result = $left_type_part->value * $right_type_part->value;
if ($result <= PHP_INT_MAX) {
$calculated_type = Type::getInt(false, $result);
} else {
$calculated_type = Type::getFloat($result);
}
} elseif ($parent instanceof PhpParser\Node\Expr\BinaryOp\Pow) {
$result = $left_type_part->value ** $right_type_part->value;
if ($result <= PHP_INT_MAX) {
$calculated_type = Type::getInt(false, $result);
} else {
$calculated_type = Type::getFloat($result);
}
} elseif ($parent instanceof PhpParser\Node\Expr\BinaryOp\BitwiseOr) {
$calculated_type = Type::getInt(false, $left_type_part->value | $right_type_part->value);
} elseif ($parent instanceof PhpParser\Node\Expr\BinaryOp\BitwiseAnd) {
$calculated_type = Type::getInt(false, $left_type_part->value & $right_type_part->value);
} elseif ($parent instanceof PhpParser\Node\Expr\BinaryOp\BitwiseXor) {
$calculated_type = Type::getInt(false, $left_type_part->value ^ $right_type_part->value);
} elseif ($parent instanceof PhpParser\Node\Expr\BinaryOp\ShiftLeft) {
$calculated_type = Type::getInt(false, $left_type_part->value << $right_type_part->value);
} elseif ($parent instanceof PhpParser\Node\Expr\BinaryOp\ShiftRight) {
$calculated_type = Type::getInt(false, $left_type_part->value >> $right_type_part->value);

@orklah orklah added the easy problems Issues that can be fixed without background knowledge of Psalm label Jun 11, 2021
@BafS
Copy link
Contributor Author

BafS commented Jun 11, 2021

Pow is not completely fixed btw, you need to check PHP_INT_MAX but PHP_INT_MIN too.

See https://psalm.dev/r/e4949e1737

@psalm-github-bot
Copy link

I found these snippets:

https://psalm.dev/r/e4949e1737
<?php

2 ** 63;
Psalm encountered an internal error:

/vendor/vimeo/psalm/src/Psalm/Type.php: Argument 2 passed to Psalm\Type::getInt() must be of the type int or null, float given, called in /vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOp/NonDivArithmeticOpAnalyzer.php on line 327

@weirdan weirdan changed the title Uncaught TypeError with some shifts (Psalm\Type::getInt() must be of the type int or null, float given) Constexpr evaluator unnderflow / overflow handling for + and - Jun 13, 2021
@weirdan weirdan changed the title Constexpr evaluator unnderflow / overflow handling for + and - Constexpr evaluator underflow / overflow handling for + and - Jun 13, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug causes crash easy problems Issues that can be fixed without background knowledge of Psalm
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants