diff options
author | Daniel Kirchner <daniel@ekpyron.org> | 2018-12-08 01:20:35 +0800 |
---|---|---|
committer | Daniel Kirchner <daniel@ekpyron.org> | 2018-12-12 11:20:53 +0800 |
commit | 788612d2efef33aad711646a1ace9dfee6237730 (patch) | |
tree | ea4f403f1bf1bdfe027afa2f3401fdb450feb30a /libsolidity/analysis/ControlFlowBuilder.cpp | |
parent | 1476acb8045033a9a3d2e1a1d13c5aaa8ed6942c (diff) | |
download | dexon-solidity-788612d2efef33aad711646a1ace9dfee6237730.tar.gz dexon-solidity-788612d2efef33aad711646a1ace9dfee6237730.tar.zst dexon-solidity-788612d2efef33aad711646a1ace9dfee6237730.zip |
Refactoring of the ControlFlowGraph and use for detecting all uninitialized storage accesses.
Diffstat (limited to 'libsolidity/analysis/ControlFlowBuilder.cpp')
-rw-r--r-- | libsolidity/analysis/ControlFlowBuilder.cpp | 262 |
1 files changed, 192 insertions, 70 deletions
diff --git a/libsolidity/analysis/ControlFlowBuilder.cpp b/libsolidity/analysis/ControlFlowBuilder.cpp index 5bd39da3..3dab8b16 100644 --- a/libsolidity/analysis/ControlFlowBuilder.cpp +++ b/libsolidity/analysis/ControlFlowBuilder.cpp @@ -22,7 +22,10 @@ using namespace solidity; using namespace std; ControlFlowBuilder::ControlFlowBuilder(CFG::NodeContainer& _nodeContainer, FunctionFlow const& _functionFlow): - m_nodeContainer(_nodeContainer), m_currentFunctionFlow(_functionFlow), m_currentNode(_functionFlow.entry) + m_nodeContainer(_nodeContainer), + m_currentNode(_functionFlow.entry), + m_returnNode(_functionFlow.exit), + m_revertNode(_functionFlow.revert) { } @@ -37,26 +40,8 @@ unique_ptr<FunctionFlow> ControlFlowBuilder::createFunctionFlow( functionFlow->revert = _nodeContainer.newNode(); ControlFlowBuilder builder(_nodeContainer, *functionFlow); builder.appendControlFlow(_function); - connect(builder.m_currentNode, functionFlow->exit); - return functionFlow; -} - -unique_ptr<ModifierFlow> ControlFlowBuilder::createModifierFlow( - CFG::NodeContainer& _nodeContainer, - ModifierDefinition const& _modifier -) -{ - auto modifierFlow = unique_ptr<ModifierFlow>(new ModifierFlow()); - modifierFlow->entry = _nodeContainer.newNode(); - modifierFlow->exit = _nodeContainer.newNode(); - modifierFlow->revert = _nodeContainer.newNode(); - modifierFlow->placeholderEntry = _nodeContainer.newNode(); - modifierFlow->placeholderExit = _nodeContainer.newNode(); - ControlFlowBuilder builder(_nodeContainer, *modifierFlow); - builder.appendControlFlow(_modifier); - connect(builder.m_currentNode, modifierFlow->exit); - return modifierFlow; + return functionFlow; } bool ControlFlowBuilder::visit(BinaryOperation const& _operation) @@ -219,64 +204,24 @@ bool ControlFlowBuilder::visit(Continue const&) bool ControlFlowBuilder::visit(Throw const&) { solAssert(!!m_currentNode, ""); - solAssert(!!m_currentFunctionFlow.revert, ""); - connect(m_currentNode, m_currentFunctionFlow.revert); + solAssert(!!m_revertNode, ""); + connect(m_currentNode, m_revertNode); m_currentNode = newLabel(); return false; } -bool ControlFlowBuilder::visit(Block const&) -{ - solAssert(!!m_currentNode, ""); - createLabelHere(); - return true; -} - -void ControlFlowBuilder::endVisit(Block const&) -{ - solAssert(!!m_currentNode, ""); - createLabelHere(); -} - -bool ControlFlowBuilder::visit(Return const& _return) -{ - solAssert(!!m_currentNode, ""); - solAssert(!!m_currentFunctionFlow.exit, ""); - solAssert(!m_currentNode->block.returnStatement, ""); - m_currentNode->block.returnStatement = &_return; - connect(m_currentNode, m_currentFunctionFlow.exit); - m_currentNode = newLabel(); - return true; -} - - bool ControlFlowBuilder::visit(PlaceholderStatement const&) { solAssert(!!m_currentNode, ""); - auto modifierFlow = dynamic_cast<ModifierFlow const*>(&m_currentFunctionFlow); - solAssert(!!modifierFlow, ""); - - connect(m_currentNode, modifierFlow->placeholderEntry); + solAssert(!!m_placeholderEntry, ""); + solAssert(!!m_placeholderExit, ""); + connect(m_currentNode, m_placeholderEntry); m_currentNode = newLabel(); - - connect(modifierFlow->placeholderExit, m_currentNode); + connect(m_placeholderExit, m_currentNode); return false; } -bool ControlFlowBuilder::visitNode(ASTNode const& node) -{ - solAssert(!!m_currentNode, ""); - if (auto const* expression = dynamic_cast<Expression const*>(&node)) - m_currentNode->block.expressions.emplace_back(expression); - else if (auto const* variableDeclaration = dynamic_cast<VariableDeclaration const*>(&node)) - m_currentNode->block.variableDeclarations.emplace_back(variableDeclaration); - else if (auto const* assembly = dynamic_cast<InlineAssembly const*>(&node)) - m_currentNode->block.inlineAssemblyStatements.emplace_back(assembly); - - return true; -} - bool ControlFlowBuilder::visit(FunctionCall const& _functionCall) { solAssert(!!m_currentNode, ""); @@ -286,19 +231,19 @@ bool ControlFlowBuilder::visit(FunctionCall const& _functionCall) switch (functionType->kind()) { case FunctionType::Kind::Revert: - solAssert(!!m_currentFunctionFlow.revert, ""); + solAssert(!!m_revertNode, ""); _functionCall.expression().accept(*this); ASTNode::listAccept(_functionCall.arguments(), *this); - connect(m_currentNode, m_currentFunctionFlow.revert); + connect(m_currentNode, m_revertNode); m_currentNode = newLabel(); return false; case FunctionType::Kind::Require: case FunctionType::Kind::Assert: { - solAssert(!!m_currentFunctionFlow.revert, ""); + solAssert(!!m_revertNode, ""); _functionCall.expression().accept(*this); ASTNode::listAccept(_functionCall.arguments(), *this); - connect(m_currentNode, m_currentFunctionFlow.revert); + connect(m_currentNode, m_revertNode); auto nextNode = newLabel(); connect(m_currentNode, nextNode); m_currentNode = nextNode; @@ -310,6 +255,183 @@ bool ControlFlowBuilder::visit(FunctionCall const& _functionCall) return ASTConstVisitor::visit(_functionCall); } +bool ControlFlowBuilder::visit(ModifierInvocation const& _modifierInvocation) +{ + if (auto arguments = _modifierInvocation.arguments()) + for (auto& argument: *arguments) + appendControlFlow(*argument); + + auto modifierDefinition = dynamic_cast<ModifierDefinition const*>( + _modifierInvocation.name()->annotation().referencedDeclaration + ); + if (!modifierDefinition) return false; + solAssert(!!modifierDefinition, ""); + solAssert(!!m_returnNode, ""); + + m_placeholderEntry = newLabel(); + m_placeholderExit = newLabel(); + + appendControlFlow(*modifierDefinition); + connect(m_currentNode, m_returnNode); + + m_currentNode = m_placeholderEntry; + m_returnNode = m_placeholderExit; + + m_placeholderEntry = nullptr; + m_placeholderExit = nullptr; + + return false; +} + +bool ControlFlowBuilder::visit(FunctionDefinition const& _functionDefinition) +{ + for (auto const& parameter: _functionDefinition.parameters()) + appendControlFlow(*parameter); + + for (auto const& returnParameter: _functionDefinition.returnParameters()) + { + appendControlFlow(*returnParameter); + m_returnNode->variableOccurrences.emplace_back( + *returnParameter, + VariableOccurrence::Kind::Return, + nullptr + ); + + } + + for (auto const& modifier: _functionDefinition.modifiers()) + appendControlFlow(*modifier); + + appendControlFlow(_functionDefinition.body()); + + connect(m_currentNode, m_returnNode); + m_currentNode = nullptr; + + return false; +} + +bool ControlFlowBuilder::visit(Return const& _return) +{ + solAssert(!!m_currentNode, ""); + solAssert(!!m_returnNode, ""); + if (_return.expression()) + { + appendControlFlow(*_return.expression()); + // Returns with return expression are considered to be assignments to the return parameters. + for (auto returnParameter: _return.annotation().functionReturnParameters->parameters()) + m_currentNode->variableOccurrences.emplace_back( + *returnParameter, + VariableOccurrence::Kind::Assignment, + &_return + ); + } + connect(m_currentNode, m_returnNode); + m_currentNode = newLabel(); + return true; +} + +bool ControlFlowBuilder::visit(FunctionTypeName const&) +{ + // Do not visit the parameters and return values of a function type name. + // We do not want to consider them as variable declarations for the control flow graph. + return false; +} + +bool ControlFlowBuilder::visit(InlineAssembly const& _inlineAssembly) +{ + solAssert(!!m_currentNode, ""); + for (auto const& ref: _inlineAssembly.annotation().externalReferences) + { + if (auto variableDeclaration = dynamic_cast<VariableDeclaration const*>(ref.second.declaration)) + m_currentNode->variableOccurrences.emplace_back( + *variableDeclaration, + VariableOccurrence::Kind::InlineAssembly, + &_inlineAssembly + ); + } + return true; +} + +bool ControlFlowBuilder::visit(VariableDeclaration const& _variableDeclaration) +{ + solAssert(!!m_currentNode, ""); + + m_currentNode->variableOccurrences.emplace_back( + _variableDeclaration, + VariableOccurrence::Kind::Declaration, + nullptr + ); + + // Handle declaration with immediate assignment. + if (_variableDeclaration.value()) + m_currentNode->variableOccurrences.emplace_back( + _variableDeclaration, + VariableOccurrence::Kind::Assignment, + _variableDeclaration.value().get() + ); + // Function arguments are considered to be immediately assigned as well (they are "externally assigned"). + else if (_variableDeclaration.isCallableParameter() && !_variableDeclaration.isReturnParameter()) + m_currentNode->variableOccurrences.emplace_back( + _variableDeclaration, + VariableOccurrence::Kind::Assignment, + nullptr + ); + return true; +} + +bool ControlFlowBuilder::visit(VariableDeclarationStatement const& _variableDeclarationStatement) +{ + solAssert(!!m_currentNode, ""); + + for (auto const& var: _variableDeclarationStatement.declarations()) + if (var) + var->accept(*this); + if (_variableDeclarationStatement.initialValue()) + { + _variableDeclarationStatement.initialValue()->accept(*this); + for (size_t i = 0; i < _variableDeclarationStatement.declarations().size(); i++) + if (auto const& var = _variableDeclarationStatement.declarations()[i]) + { + auto expression = _variableDeclarationStatement.initialValue(); + if (auto tupleExpression = dynamic_cast<TupleExpression const*>(expression)) + if (tupleExpression->components().size() > 1) + { + solAssert(tupleExpression->components().size() > i, ""); + expression = tupleExpression->components()[i].get(); + } + while (auto tupleExpression = dynamic_cast<TupleExpression const*>(expression)) + if (tupleExpression->components().size() == 1) + expression = tupleExpression->components().front().get(); + else + break; + m_currentNode->variableOccurrences.emplace_back( + *var, + VariableOccurrence::Kind::Assignment, + expression + ); + } + } + return false; +} + +bool ControlFlowBuilder::visit(Identifier const& _identifier) +{ + solAssert(!!m_currentNode, ""); + + if (auto const* variableDeclaration = dynamic_cast<VariableDeclaration const*>(_identifier.annotation().referencedDeclaration)) + m_currentNode->variableOccurrences.emplace_back( + *variableDeclaration, + static_cast<Expression const&>(_identifier).annotation().lValueRequested ? + VariableOccurrence::Kind::Assignment : + VariableOccurrence::Kind::Access, + &_identifier + ); + + return true; +} + + + void ControlFlowBuilder::appendControlFlow(ASTNode const& _node) { _node.accept(*this); |