mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #11484 from ethereum/fix-unreachable-code-anaysis
Fix revert pruner modifying function flows wrong
This commit is contained in:
commit
1f8f1a3db9
@ -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(); }
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -10,3 +10,4 @@ contract C {
|
|||||||
// ====
|
// ====
|
||||||
// SMTEngine: all
|
// SMTEngine: all
|
||||||
// ----
|
// ----
|
||||||
|
// Warning 5740: (122-136): Unreachable code.
|
||||||
|
@ -5,3 +5,4 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
|
// Warning 5740: (78-79): Unreachable code.
|
||||||
|
@ -10,4 +10,5 @@ contract C {
|
|||||||
function h() internal pure returns (bytes memory, string storage s) { s = s; }
|
function h() internal pure returns (bytes memory, string storage s) { s = s; }
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
|
// Warning 5740: (111-115): Unreachable code.
|
||||||
// Warning 6321: (250-262): Unnamed return variable can remain unassigned. Add an explicit return with value to all non-reverting code paths or name the variable.
|
// Warning 6321: (250-262): Unnamed return variable can remain unassigned. Add an explicit return with value to all non-reverting code paths or name the variable.
|
||||||
|
@ -3,4 +3,5 @@ contract test {
|
|||||||
function f(uint256) public returns (uint out) { f(variable); test; out; }
|
function f(uint256) public returns (uint out) { f(variable); test; out; }
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
|
// Warning 5740: (103-112): Unreachable code.
|
||||||
// Warning 6133: (103-107): Statement has no effect.
|
// Warning 6133: (103-107): Statement has no effect.
|
||||||
|
@ -5,3 +5,9 @@ contract C {
|
|||||||
function i() payable public { i(); h(); g(); f(); }
|
function i() payable public { i(); h(); g(); f(); }
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
|
// Warning 5740: (102-105): Unreachable code.
|
||||||
|
// Warning 5740: (140-143): Unreachable code.
|
||||||
|
// Warning 5740: (145-148): Unreachable code.
|
||||||
|
// Warning 5740: (191-194): Unreachable code.
|
||||||
|
// Warning 5740: (196-199): Unreachable code.
|
||||||
|
// Warning 5740: (201-204): Unreachable code.
|
||||||
|
@ -7,3 +7,4 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
|
// Warning 5740: (142-237): Unreachable code.
|
||||||
|
Loading…
Reference in New Issue
Block a user