/* 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 . */ // SPDX-License-Identifier: GPL-3.0 /** * Class that can answer questions about values of variables and their relations. */ #include #include #include #include #include #include #include #include using namespace std; using namespace solidity; using namespace solidity::yul; bool KnowledgeBase::knownToBeZero(YulString _a) { if (!m_variableValues.count(_a) || !m_variableValues.at(_a).value) return false; Expression const& expr = *m_variableValues.at(_a).value; if (!holds_alternative(expr)) return false; u256 val = valueOfLiteral(std::get(expr)); return val == 0; } bool KnowledgeBase::knownToBeDifferent(YulString _a, YulString _b) { // Try to use the simplification rules together with the // current values to turn `sub(_a, _b)` into a nonzero constant. // If that fails, try `eq(_a, _b)`. Expression expr1 = simplify(FunctionCall{{}, {{}, "sub"_yulstring}, util::make_vector(Identifier{{}, _a}, Identifier{{}, _b})}); if (holds_alternative(expr1)) return valueOfLiteral(std::get(expr1)) != 0; Expression expr2 = simplify(FunctionCall{{}, {{}, "eq"_yulstring}, util::make_vector(Identifier{{}, _a}, Identifier{{}, _b})}); if (holds_alternative(expr2)) return valueOfLiteral(std::get(expr2)) == 0; return false; } bool KnowledgeBase::knownToBeDifferentByAtLeast32(YulString _a, YulString _b) { // Try to use the simplification rules together with the // current values to turn `sub(_a, _b)` into a constant whose absolute value is at least 32. Expression expr1 = simplify(FunctionCall{{}, {{}, "sub"_yulstring}, util::make_vector(Identifier{{}, _a}, Identifier{{}, _b})}); if (holds_alternative(expr1)) { u256 val = valueOfLiteral(std::get(expr1)); return val >= 32 && val <= u256(0) - 32; } return false; } bool KnowledgeBase::knownToBeNonOverlapping(YulString _address, YulString _start, YulString _length) { cout << "Overlap check: " << _address.str() << " in " << _start.str() << " - " << _length.str() << endl; if (knownToBeZero(_length)) return true; (void)_address; (void)_start; // TODO extend this by trying to simplify: // _address + 31 < _start (what about overflow?) // _start - _address is a number larger than 31 (what about overflow?) return false; } Expression KnowledgeBase::simplify(Expression _expression) { bool startedRecursion = (m_recursionCounter == 0); ScopeGuard{[&] { if (startedRecursion) m_recursionCounter = 0; }}; if (startedRecursion) m_recursionCounter = 100; else if (m_recursionCounter == 1) return _expression; else --m_recursionCounter; if (holds_alternative(_expression)) for (Expression& arg: std::get(_expression).arguments) arg = simplify(arg); if (auto match = SimplificationRules::findFirstMatch(_expression, m_dialect, m_variableValues)) return simplify(match->action().toExpression(locationOf(_expression))); return _expression; }