diff options
author | chriseth <chris@ethereum.org> | 2018-04-12 17:49:08 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-04-12 17:49:08 +0800 |
commit | c3dc67d0e0c311a907e7a27e159f9159d78af949 (patch) | |
tree | 5931874703a65e74c9319a06381ea769c2e402a9 | |
parent | ea445b9d372ad99f5c705628104db36bcb0d33a2 (diff) | |
parent | d42476e241489447e5dc4f5b1fafc8000e635fbc (diff) | |
download | dexon-solidity-c3dc67d0e0c311a907e7a27e159f9159d78af949.tar.gz dexon-solidity-c3dc67d0e0c311a907e7a27e159f9159d78af949.tar.zst dexon-solidity-c3dc67d0e0c311a907e7a27e159f9159d78af949.zip |
Merge pull request #3848 from ethereum/constantDivisionByZero
Error on invalid arithmetic with constant expressions.
18 files changed, 146 insertions, 20 deletions
diff --git a/Changelog.md b/Changelog.md index e2174cfd..6288e848 100644 --- a/Changelog.md +++ b/Changelog.md @@ -39,6 +39,7 @@ Bugfixes: * Type System: Make external library functions accessible. * Type System: Prevent encoding of weird types. * 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) diff --git a/libsolidity/analysis/StaticAnalyzer.cpp b/libsolidity/analysis/StaticAnalyzer.cpp index 33b0e296..51aa0b28 100644 --- a/libsolidity/analysis/StaticAnalyzer.cpp +++ b/libsolidity/analysis/StaticAnalyzer.cpp @@ -21,6 +21,7 @@ */ #include <libsolidity/analysis/StaticAnalyzer.h> +#include <libsolidity/analysis/ConstantEvaluator.h> #include <libsolidity/ast/AST.h> #include <libsolidity/interface/ErrorReporter.h> #include <memory> @@ -231,6 +232,47 @@ bool StaticAnalyzer::visit(InlineAssembly const& _inlineAssembly) 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) { switch (_type.category()) diff --git a/libsolidity/analysis/StaticAnalyzer.h b/libsolidity/analysis/StaticAnalyzer.h index 0a806bbd..2a62e391 100644 --- a/libsolidity/analysis/StaticAnalyzer.h +++ b/libsolidity/analysis/StaticAnalyzer.h @@ -64,6 +64,8 @@ private: virtual bool visit(Return const& _return) override; virtual bool visit(MemberAccess const& _memberAccess) 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. static bigint structureSizeEstimate(Type const& _type, std::set<StructDefinition const*>& _structsSeen); diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 05f506f1..ecfc2333 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -446,6 +446,9 @@ public: /// @returns true if the value is negative. bool isNegative() const { return m_value < 0; } + /// @returns true if the value is zero. + bool isZero() const { return m_value == 0; } + private: rational m_value; diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 39f4b03e..f7f1062d 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -7847,12 +7847,12 @@ BOOST_AUTO_TEST_CASE(addmod_mulmod_zero) { char const* sourceCode = R"( contract C { - function f() pure returns (uint) { - addmod(1, 2, 0); + function f(uint d) pure returns (uint) { + addmod(1, 2, d); return 2; } - function g() pure returns (uint) { - mulmod(1, 2, 0); + function g(uint d) pure returns (uint) { + mulmod(1, 2, d); return 2; } function h() pure returns (uint) { @@ -7865,8 +7865,8 @@ BOOST_AUTO_TEST_CASE(addmod_mulmod_zero) } )"; compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs()); - ABI_CHECK(callContractFunction("g()"), encodeArgs()); + ABI_CHECK(callContractFunction("f(uint)", 0), encodeArgs()); + ABI_CHECK(callContractFunction("g(uint)", 0), encodeArgs()); ABI_CHECK(callContractFunction("h()"), encodeArgs(2)); } diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index 18a414e0..6b6c86a1 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -4772,20 +4772,6 @@ BOOST_AUTO_TEST_CASE(integer_and_fixed_interaction) 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) { char const* text = R"( diff --git a/test/libsolidity/syntaxTests/constants/addmod_mulmod_rational.sol b/test/libsolidity/syntaxTests/constants/addmod_mulmod_rational.sol new file mode 100644 index 00000000..26712735 --- /dev/null +++ b/test/libsolidity/syntaxTests/constants/addmod_mulmod_rational.sol @@ -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. diff --git a/test/libsolidity/syntaxTests/constants/addmod_zero.sol b/test/libsolidity/syntaxTests/constants/addmod_zero.sol new file mode 100644 index 00000000..18f7d64a --- /dev/null +++ b/test/libsolidity/syntaxTests/constants/addmod_zero.sol @@ -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. diff --git a/test/libsolidity/syntaxTests/constants/division_by_zero.sol b/test/libsolidity/syntaxTests/constants/division_by_zero.sol new file mode 100644 index 00000000..bf6000ec --- /dev/null +++ b/test/libsolidity/syntaxTests/constants/division_by_zero.sol @@ -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. diff --git a/test/libsolidity/syntaxTests/constants/mod_div_rational.sol b/test/libsolidity/syntaxTests/constants/mod_div_rational.sol new file mode 100644 index 00000000..f8b6ce31 --- /dev/null +++ b/test/libsolidity/syntaxTests/constants/mod_div_rational.sol @@ -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; +} diff --git a/test/libsolidity/syntaxTests/constants/mod_zero.sol b/test/libsolidity/syntaxTests/constants/mod_zero.sol new file mode 100644 index 00000000..f5e4a23a --- /dev/null +++ b/test/libsolidity/syntaxTests/constants/mod_zero.sol @@ -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. diff --git a/test/libsolidity/syntaxTests/constants/mulmod_zero.sol b/test/libsolidity/syntaxTests/constants/mulmod_zero.sol new file mode 100644 index 00000000..856d01eb --- /dev/null +++ b/test/libsolidity/syntaxTests/constants/mulmod_zero.sol @@ -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. diff --git a/test/libsolidity/syntaxTests/constants/pure_non_rational.sol b/test/libsolidity/syntaxTests/constants/pure_non_rational.sol new file mode 100644 index 00000000..4b96f1c7 --- /dev/null +++ b/test/libsolidity/syntaxTests/constants/pure_non_rational.sol @@ -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. diff --git a/test/libsolidity/syntaxTests/literalOperations/division_by_zero.sol b/test/libsolidity/syntaxTests/literalOperations/division_by_zero.sol new file mode 100644 index 00000000..b52b4c51 --- /dev/null +++ b/test/libsolidity/syntaxTests/literalOperations/division_by_zero.sol @@ -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 diff --git a/test/libsolidity/syntaxTests/literalOperations/division_by_zero_complex.sol b/test/libsolidity/syntaxTests/literalOperations/division_by_zero_complex.sol new file mode 100644 index 00000000..8cc3b6f2 --- /dev/null +++ b/test/libsolidity/syntaxTests/literalOperations/division_by_zero_complex.sol @@ -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 diff --git a/test/libsolidity/syntaxTests/literalOperations/mod_zero.sol b/test/libsolidity/syntaxTests/literalOperations/mod_zero.sol new file mode 100644 index 00000000..1bbbc3fc --- /dev/null +++ b/test/libsolidity/syntaxTests/literalOperations/mod_zero.sol @@ -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 diff --git a/test/libsolidity/syntaxTests/literalOperations/mod_zero_complex.sol b/test/libsolidity/syntaxTests/literalOperations/mod_zero_complex.sol new file mode 100644 index 00000000..4899cac3 --- /dev/null +++ b/test/libsolidity/syntaxTests/literalOperations/mod_zero_complex.sol @@ -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 diff --git a/test/libsolidity/syntaxTests/signed_rational_modulus.sol b/test/libsolidity/syntaxTests/signed_rational_modulus.sol new file mode 100644 index 00000000..b37d33d0 --- /dev/null +++ b/test/libsolidity/syntaxTests/signed_rational_modulus.sol @@ -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; + } +} |