mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #3848 from ethereum/constantDivisionByZero
Error on invalid arithmetic with constant expressions.
This commit is contained in:
commit
c3dc67d0e0
@ -39,6 +39,7 @@ Bugfixes:
|
|||||||
* Type System: Make external library functions accessible.
|
* Type System: Make external library functions accessible.
|
||||||
* Type System: Prevent encoding of weird types.
|
* Type System: Prevent encoding of weird types.
|
||||||
* Static Analyzer: Fix non-deterministic order of unused variable warnings.
|
* Static Analyzer: Fix non-deterministic order of unused variable warnings.
|
||||||
|
* Static Analyzer: Invalid arithmetic with constant expressions causes errors.
|
||||||
|
|
||||||
### 0.4.21 (2018-03-07)
|
### 0.4.21 (2018-03-07)
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <libsolidity/analysis/StaticAnalyzer.h>
|
#include <libsolidity/analysis/StaticAnalyzer.h>
|
||||||
|
#include <libsolidity/analysis/ConstantEvaluator.h>
|
||||||
#include <libsolidity/ast/AST.h>
|
#include <libsolidity/ast/AST.h>
|
||||||
#include <libsolidity/interface/ErrorReporter.h>
|
#include <libsolidity/interface/ErrorReporter.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@ -231,6 +232,47 @@ bool StaticAnalyzer::visit(InlineAssembly const& _inlineAssembly)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool StaticAnalyzer::visit(BinaryOperation const& _operation)
|
||||||
|
{
|
||||||
|
if (
|
||||||
|
_operation.rightExpression().annotation().isPure &&
|
||||||
|
(_operation.getOperator() == Token::Div || _operation.getOperator() == Token::Mod)
|
||||||
|
)
|
||||||
|
if (auto rhs = dynamic_pointer_cast<RationalNumberType const>(
|
||||||
|
ConstantEvaluator(m_errorReporter).evaluate(_operation.rightExpression())
|
||||||
|
))
|
||||||
|
if (rhs->isZero())
|
||||||
|
m_errorReporter.typeError(
|
||||||
|
_operation.location(),
|
||||||
|
(_operation.getOperator() == Token::Div) ? "Division by zero." : "Modulo zero."
|
||||||
|
);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StaticAnalyzer::visit(FunctionCall const& _functionCall)
|
||||||
|
{
|
||||||
|
if (_functionCall.annotation().kind == FunctionCallKind::FunctionCall)
|
||||||
|
{
|
||||||
|
auto functionType = dynamic_pointer_cast<FunctionType const>(_functionCall.expression().annotation().type);
|
||||||
|
solAssert(functionType, "");
|
||||||
|
if (functionType->kind() == FunctionType::Kind::AddMod || functionType->kind() == FunctionType::Kind::MulMod)
|
||||||
|
{
|
||||||
|
solAssert(_functionCall.arguments().size() == 3, "");
|
||||||
|
if (_functionCall.arguments()[2]->annotation().isPure)
|
||||||
|
if (auto lastArg = dynamic_pointer_cast<RationalNumberType const>(
|
||||||
|
ConstantEvaluator(m_errorReporter).evaluate(*(_functionCall.arguments())[2])
|
||||||
|
))
|
||||||
|
if (lastArg->isZero())
|
||||||
|
m_errorReporter.typeError(
|
||||||
|
_functionCall.location(),
|
||||||
|
"Arithmetic modulo zero."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bigint StaticAnalyzer::structureSizeEstimate(Type const& _type, set<StructDefinition const*>& _structsSeen)
|
bigint StaticAnalyzer::structureSizeEstimate(Type const& _type, set<StructDefinition const*>& _structsSeen)
|
||||||
{
|
{
|
||||||
switch (_type.category())
|
switch (_type.category())
|
||||||
|
@ -64,6 +64,8 @@ private:
|
|||||||
virtual bool visit(Return const& _return) override;
|
virtual bool visit(Return const& _return) override;
|
||||||
virtual bool visit(MemberAccess const& _memberAccess) override;
|
virtual bool visit(MemberAccess const& _memberAccess) override;
|
||||||
virtual bool visit(InlineAssembly const& _inlineAssembly) override;
|
virtual bool visit(InlineAssembly const& _inlineAssembly) override;
|
||||||
|
virtual bool visit(BinaryOperation const& _operation) override;
|
||||||
|
virtual bool visit(FunctionCall const& _functionCall) override;
|
||||||
|
|
||||||
/// @returns the size of this type in storage, including all sub-types.
|
/// @returns the size of this type in storage, including all sub-types.
|
||||||
static bigint structureSizeEstimate(Type const& _type, std::set<StructDefinition const*>& _structsSeen);
|
static bigint structureSizeEstimate(Type const& _type, std::set<StructDefinition const*>& _structsSeen);
|
||||||
|
@ -446,6 +446,9 @@ public:
|
|||||||
/// @returns true if the value is negative.
|
/// @returns true if the value is negative.
|
||||||
bool isNegative() const { return m_value < 0; }
|
bool isNegative() const { return m_value < 0; }
|
||||||
|
|
||||||
|
/// @returns true if the value is zero.
|
||||||
|
bool isZero() const { return m_value == 0; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
rational m_value;
|
rational m_value;
|
||||||
|
|
||||||
|
@ -7847,12 +7847,12 @@ BOOST_AUTO_TEST_CASE(addmod_mulmod_zero)
|
|||||||
{
|
{
|
||||||
char const* sourceCode = R"(
|
char const* sourceCode = R"(
|
||||||
contract C {
|
contract C {
|
||||||
function f() pure returns (uint) {
|
function f(uint d) pure returns (uint) {
|
||||||
addmod(1, 2, 0);
|
addmod(1, 2, d);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
function g() pure returns (uint) {
|
function g(uint d) pure returns (uint) {
|
||||||
mulmod(1, 2, 0);
|
mulmod(1, 2, d);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
function h() pure returns (uint) {
|
function h() pure returns (uint) {
|
||||||
@ -7865,8 +7865,8 @@ BOOST_AUTO_TEST_CASE(addmod_mulmod_zero)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
ABI_CHECK(callContractFunction("f()"), encodeArgs());
|
ABI_CHECK(callContractFunction("f(uint)", 0), encodeArgs());
|
||||||
ABI_CHECK(callContractFunction("g()"), encodeArgs());
|
ABI_CHECK(callContractFunction("g(uint)", 0), encodeArgs());
|
||||||
ABI_CHECK(callContractFunction("h()"), encodeArgs(2));
|
ABI_CHECK(callContractFunction("h()"), encodeArgs(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4772,20 +4772,6 @@ BOOST_AUTO_TEST_CASE(integer_and_fixed_interaction)
|
|||||||
CHECK_SUCCESS(text);
|
CHECK_SUCCESS(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(signed_rational_modulus)
|
|
||||||
{
|
|
||||||
char const* text = R"(
|
|
||||||
contract test {
|
|
||||||
function f() public {
|
|
||||||
fixed a = 0.42578125 % -0.4271087646484375;
|
|
||||||
fixed b = .5 % a;
|
|
||||||
fixed c = a % b;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)";
|
|
||||||
CHECK_SUCCESS(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(one_divided_by_three_integer_conversion)
|
BOOST_AUTO_TEST_CASE(one_divided_by_three_integer_conversion)
|
||||||
{
|
{
|
||||||
char const* text = R"(
|
char const* text = R"(
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
contract C {
|
||||||
|
uint constant a = addmod(3, 4, 0.1);
|
||||||
|
uint constant b = mulmod(3, 4, 0.1);
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// TypeError: (48-51): Invalid type for argument in function call. Invalid implicit conversion from rational_const 1 / 10 to uint256 requested.
|
||||||
|
// TypeError: (89-92): Invalid type for argument in function call. Invalid implicit conversion from rational_const 1 / 10 to uint256 requested.
|
11
test/libsolidity/syntaxTests/constants/addmod_zero.sol
Normal file
11
test/libsolidity/syntaxTests/constants/addmod_zero.sol
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
contract c {
|
||||||
|
uint constant a1 = 0;
|
||||||
|
uint constant a2 = 1;
|
||||||
|
uint constant b1 = addmod(3, 4, 0);
|
||||||
|
uint constant b2 = addmod(3, 4, a1);
|
||||||
|
uint constant b3 = addmod(3, 4, a2 - 1);
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// TypeError: (88-103): Arithmetic modulo zero.
|
||||||
|
// TypeError: (128-144): Arithmetic modulo zero.
|
||||||
|
// TypeError: (169-189): Arithmetic modulo zero.
|
@ -0,0 +1,9 @@
|
|||||||
|
contract c {
|
||||||
|
uint constant a1 = 0;
|
||||||
|
uint constant a2 = 1;
|
||||||
|
uint constant b1 = 7 / a1;
|
||||||
|
uint constant b2 = 7 / (a2 - 1);
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// TypeError: (88-94): Division by zero.
|
||||||
|
// TypeError: (119-131): Division by zero.
|
@ -0,0 +1,6 @@
|
|||||||
|
contract C {
|
||||||
|
fixed a1 = 0.1 % -0.4271087646484375;
|
||||||
|
fixed a2 = 0.1 % 0.4271087646484375;
|
||||||
|
fixed a3 = 0 / 0.123;
|
||||||
|
fixed a4 = 0 / -0.123;
|
||||||
|
}
|
9
test/libsolidity/syntaxTests/constants/mod_zero.sol
Normal file
9
test/libsolidity/syntaxTests/constants/mod_zero.sol
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
contract c {
|
||||||
|
uint constant a1 = 0;
|
||||||
|
uint constant a2 = 1;
|
||||||
|
uint constant b1 = 3 % a1;
|
||||||
|
uint constant b2 = 3 % (a2 - 1);
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// TypeError: (88-94): Modulo zero.
|
||||||
|
// TypeError: (119-131): Modulo zero.
|
11
test/libsolidity/syntaxTests/constants/mulmod_zero.sol
Normal file
11
test/libsolidity/syntaxTests/constants/mulmod_zero.sol
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
contract c {
|
||||||
|
uint constant a1 = 0;
|
||||||
|
uint constant a2 = 1;
|
||||||
|
uint constant b1 = mulmod(3, 4, 0);
|
||||||
|
uint constant b2 = mulmod(3, 4, a1);
|
||||||
|
uint constant b3 = mulmod(3, 4, a2 - 1);
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// TypeError: (88-103): Arithmetic modulo zero.
|
||||||
|
// TypeError: (128-144): Arithmetic modulo zero.
|
||||||
|
// TypeError: (169-189): Arithmetic modulo zero.
|
11
test/libsolidity/syntaxTests/constants/pure_non_rational.sol
Normal file
11
test/libsolidity/syntaxTests/constants/pure_non_rational.sol
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// Tests that the ConstantEvaluator does not crash for pure non-rational functions.
|
||||||
|
// Currently it does not evaluate such functions, but this may change in the future
|
||||||
|
// causing a division by zero error for a.
|
||||||
|
contract C {
|
||||||
|
uint constant a = 1 / (uint(keccak256([0])[0]) - uint(keccak256([0])[0]));
|
||||||
|
uint constant b = 1 / uint(keccak256([0]));
|
||||||
|
uint constant c = uint(keccak256([0]));
|
||||||
|
uint[c] mem;
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// TypeError: (392-393): Invalid array length, expected integer literal or constant expression.
|
@ -0,0 +1,5 @@
|
|||||||
|
contract C {
|
||||||
|
uint constant a = 1 / 0;
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// TypeError: (35-40): Operator / not compatible with types int_const 1 and int_const 0
|
@ -0,0 +1,5 @@
|
|||||||
|
contract C {
|
||||||
|
uint constant a = 1 / ((1+3)-4);
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// TypeError: (35-48): Operator / not compatible with types int_const 1 and int_const 0
|
@ -0,0 +1,5 @@
|
|||||||
|
contract C {
|
||||||
|
uint constant b3 = 1 % 0;
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// TypeError: (36-41): Operator % not compatible with types int_const 1 and int_const 0
|
@ -0,0 +1,5 @@
|
|||||||
|
contract C {
|
||||||
|
uint constant b3 = 1 % (-4+((2)*2));
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// TypeError: (36-52): Operator % not compatible with types int_const 1 and int_const 0
|
8
test/libsolidity/syntaxTests/signed_rational_modulus.sol
Normal file
8
test/libsolidity/syntaxTests/signed_rational_modulus.sol
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
contract test {
|
||||||
|
function f() public pure {
|
||||||
|
fixed a = 0.42578125 % -0.4271087646484375;
|
||||||
|
fixed b = .5 % a;
|
||||||
|
fixed c = a % b;
|
||||||
|
a; b; c;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user