/* This file is part of solidity. solidity is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. solidity is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with solidity. If not, see . */ /** * Unit tests for the SMT checker. */ #include #include #include using namespace std; using namespace langutil; namespace dev { namespace solidity { namespace test { class SMTCheckerFramework: public AnalysisFramework { protected: virtual std::pair parseAnalyseAndReturnError( std::string const& _source, bool _reportWarnings = false, bool _insertVersionPragma = true, bool _allowMultipleErrors = false ) { return AnalysisFramework::parseAnalyseAndReturnError( "pragma experimental SMTChecker;\n" + _source, _reportWarnings, _insertVersionPragma, _allowMultipleErrors ); } }; BOOST_FIXTURE_TEST_SUITE(SMTChecker, SMTCheckerFramework) BOOST_AUTO_TEST_CASE(division) { string text = R"( contract C { function f(uint x, uint y) public pure returns (uint) { return x / y; } } )"; CHECK_WARNING(text, "Division by zero"); text = R"( contract C { function f(uint x, uint y) public pure returns (uint) { require(y != 0); return x / y; } } )"; CHECK_SUCCESS_NO_WARNINGS(text); text = R"( contract C { function f(int x, int y) public pure returns (int) { require(y != 0); return x / y; } } )"; CHECK_WARNING(text, "Overflow"); text = R"( contract C { function f(int x, int y) public pure returns (int) { require(y != 0); require(y != -1); return x / y; } } )"; CHECK_SUCCESS_NO_WARNINGS(text); text = R"( contract C { function mul(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c; if (a != 0) { c = a * b; require(c / a == b); } return c; } } )"; CHECK_SUCCESS_NO_WARNINGS(text); text = R"( contract C { function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b); return c; } } )"; CHECK_WARNING(text, "Division by zero"); text = R"( contract C { function div(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0); uint256 c = a / b; return c; } } )"; CHECK_SUCCESS_NO_WARNINGS(text); } BOOST_AUTO_TEST_CASE(division_truncates_correctly) { string text = R"( contract C { function f(uint x, uint y) public pure { x = 7; y = 2; assert(x / y == 3); } } )"; CHECK_SUCCESS_NO_WARNINGS(text); text = R"( contract C { function f(int x, int y) public pure { x = 7; y = 2; assert(x / y == 3); } } )"; CHECK_SUCCESS_NO_WARNINGS(text); text = R"( contract C { function f(int x, int y) public pure { x = -7; y = 2; assert(x / y == -3); } } )"; CHECK_SUCCESS_NO_WARNINGS(text); text = R"( contract C { function f(int x, int y) public pure { x = 7; y = -2; assert(x / y == -3); } } )"; CHECK_SUCCESS_NO_WARNINGS(text); text = R"( contract C { function f(int x, int y) public pure { x = -7; y = -2; assert(x / y == 3); } } )"; CHECK_SUCCESS_NO_WARNINGS(text); } BOOST_AUTO_TEST_CASE(compound_assignment_division) { string text = R"( contract C { function f(uint x) public pure { require(x == 2); uint y = 10; y /= y / x; assert(y == x); assert(y == 0); } } )"; CHECK_WARNING(text, "Assertion violation"); text = R"( contract C { uint[] array; function f(uint x, uint p) public { require(x == 2); require(array[p] == 10); array[p] /= array[p] / x; assert(array[p] == x); assert(array[p] == 0); } } )"; CHECK_WARNING(text, "Assertion violation"); text = R"( contract C { mapping (uint => uint) map; function f(uint x, uint p) public { require(x == 2); require(map[p] == 10); map[p] /= map[p] / x; assert(map[p] == x); assert(map[p] == 0); } } )"; CHECK_WARNING(text, "Assertion violation"); } BOOST_AUTO_TEST_SUITE_END() } } }