Fix revert pruner modifying function flows wrong

This commit is contained in:
Mathias Baumann 2021-06-03 15:43:05 +02:00
parent 424edcc562
commit d8ffdf11c8
3 changed files with 24 additions and 3 deletions

View File

@ -44,6 +44,7 @@ this nonsensical example::
// SPDX-License-Identifier: GPL-3.0 // SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.22 <0.9.0; pragma solidity >=0.4.22 <0.9.0;
// This will report a warning
contract C { contract C {
function g(uint a) public pure returns (uint ret) { return a + f(); } function g(uint a) public pure returns (uint ret) { return a + f(); }
function f() internal pure returns (uint ret) { return g(7) + f(); } function f() internal pure returns (uint ret) { return g(7) + f(); }

View File

@ -260,6 +260,7 @@ bool ControlFlowBuilder::visit(PlaceholderStatement const&)
bool ControlFlowBuilder::visit(FunctionCall const& _functionCall) bool ControlFlowBuilder::visit(FunctionCall const& _functionCall)
{ {
solAssert(!!m_revertNode, "");
solAssert(!!m_currentNode, ""); solAssert(!!m_currentNode, "");
solAssert(!!_functionCall.expression().annotation().type, ""); solAssert(!!_functionCall.expression().annotation().type, "");
@ -267,30 +268,43 @@ bool ControlFlowBuilder::visit(FunctionCall const& _functionCall)
switch (functionType->kind()) switch (functionType->kind())
{ {
case FunctionType::Kind::Revert: case FunctionType::Kind::Revert:
solAssert(!!m_revertNode, "");
visitNode(_functionCall); visitNode(_functionCall);
_functionCall.expression().accept(*this); _functionCall.expression().accept(*this);
ASTNode::listAccept(_functionCall.arguments(), *this); ASTNode::listAccept(_functionCall.arguments(), *this);
connect(m_currentNode, m_revertNode); connect(m_currentNode, m_revertNode);
m_currentNode = newLabel(); m_currentNode = newLabel();
return false; return false;
case FunctionType::Kind::Require: case FunctionType::Kind::Require:
case FunctionType::Kind::Assert: case FunctionType::Kind::Assert:
{ {
solAssert(!!m_revertNode, "");
visitNode(_functionCall); visitNode(_functionCall);
_functionCall.expression().accept(*this); _functionCall.expression().accept(*this);
ASTNode::listAccept(_functionCall.arguments(), *this); ASTNode::listAccept(_functionCall.arguments(), *this);
connect(m_currentNode, m_revertNode); connect(m_currentNode, m_revertNode);
auto nextNode = newLabel(); auto nextNode = newLabel();
connect(m_currentNode, nextNode); connect(m_currentNode, nextNode);
m_currentNode = nextNode; m_currentNode = nextNode;
return false; return false;
} }
case FunctionType::Kind::Internal: case FunctionType::Kind::Internal:
{ {
visitNode(_functionCall);
_functionCall.expression().accept(*this);
ASTNode::listAccept(_functionCall.arguments(), *this);
m_currentNode->functionCalls.emplace_back(&_functionCall); m_currentNode->functionCalls.emplace_back(&_functionCall);
break;
auto nextNode = newLabel();
connect(m_currentNode, nextNode);
m_currentNode = nextNode;
return false;
} }
default: default:
break; break;

View File

@ -20,6 +20,8 @@
#include <libsolutil/Algorithms.h> #include <libsolutil/Algorithms.h>
#include <range/v3/algorithm/remove.hpp>
namespace solidity::frontend namespace solidity::frontend
{ {
@ -192,7 +194,11 @@ void ControlFlowRevertPruner::modifyFunctionFlows()
// change anymore, we treat all "unknown" states as // change anymore, we treat all "unknown" states as
// "reverting", since they can only be caused by // "reverting", since they can only be caused by
// recursion. // recursion.
for (CFGNode * node: _node->exits)
ranges::remove(node->entries, _node);
_node->exits = {functionFlow.revert}; _node->exits = {functionFlow.revert};
functionFlow.revert->entries.push_back(_node);
return; return;
default: default:
break; break;