def analyser(self): mapASTSourceToLineNumbers = MapASTSourceToLineNumbers() print("\n<<<<<<<<<< Analyser: Tainted Variables >>>>>>>>>>") externalFunctions = AnalyseFunctionDefinition.getAllFunctionDefinitionsWithExternalVisibility() publicFunctions = AnalyseFunctionDefinition.getAllFunctionDefinitionsWithPublicVisibility() taintedFunctions = externalFunctions + publicFunctions taintedVariables = defaultdict(list) for function in taintedFunctions: taintFlow = TaintPropagate.getTaintPropagationForFunction(function) for item in taintFlow: _in = MySet() _out = [] if(item["in"] is not None): for var in item["in"]._set: if(AnalyseVariable.getVariableNameForId(var) != "Error"): _in.add(AnalyseVariable.getVariableNameForId(var), item["in"].idToNodeMapping[var].src) if(item["out"] is not None): for var in item["out"]._set: if(AnalyseVariable.getVariableNameForId(var) != "Error"): _out.append(AnalyseVariable.getVariableNameForId(var)) print("At line: " + str(mapASTSourceToLineNumbers.getLine(int(item["src"].split(":",)[0])))) for var in _in._set: print(" Incoming tainted variable: " + var + " defined at line:" + str(mapASTSourceToLineNumbers.getLine(int(_in.idToNodeMapping[var].split(":",)[0])))) print(" Outgoing tainted variables: " + str(_out)) self.statsTaintedVariables.append({ "line":str(mapASTSourceToLineNumbers.getLine(int(item["src"].split(":",)[0]))), "info":_out, })
def analyser(self): mapASTSourceToLineNumbers = MapASTSourceToLineNumbers() print("\n<<<<<<<<<< Analyser: Control Flow Graph >>>>>>>>>>") functionCalls = AnalyseFunctionCall.getAllFunctionCalls() for functionCall in functionCalls: found = True if (functionCall.name is not None): logging.debug("functionCall: " + functionCall.name) node = functionCall.parent while (node.nodeType != "FunctionDefinition"): node = node.parent if (isinstance(node, AST)): found = False break if (found): self.controlFlowGraph.append({ "callerName": node.name, "calleeName": functionCall.name, "line": str( mapASTSourceToLineNumbers.getLine( int(functionCall.src.split(":", )[0]))) }) for item in self.controlFlowGraph: print(item)
def test_exceptions(self): parseAST = ParseAST() astFD = open(self.testPath + ".ast", "r") parseResults = parseAST.parse(astFD) mapASTSourceToLineNumbers = MapASTSourceToLineNumbers() mapASTSourceToLineNumbers.analyser(self.testDir + "Contracts/" + self.testFile + ".sol") analyseExternalContractInteractions = AnalyseExternalContractInteractions( ) analyseExternalContractInteractions.analyser() self.assertEqual( len(analyseExternalContractInteractions.statsTransfers), 1) self.assertEqual( analyseExternalContractInteractions.statsTransfers[0]["line"], "6") self.assertEqual(len(analyseExternalContractInteractions.statsSends), 1) self.assertEqual( analyseExternalContractInteractions.statsSends[0]["line"], "7") self.assertEqual(len(analyseExternalContractInteractions.statsCalls), 1) self.assertEqual( analyseExternalContractInteractions.statsCalls[0]["line"], "8") self.assertEqual( len(analyseExternalContractInteractions.statsDelegateCalls), 1) self.assertEqual( analyseExternalContractInteractions.statsDelegateCalls[0]["line"], "9") astFD.close()
def test_selfDestruct(self): parseAST = ParseAST() astFD = open(self.testPath+".ast","r") parseResults = parseAST.parse(astFD) mapASTSourceToLineNumbers = MapASTSourceToLineNumbers() mapASTSourceToLineNumbers.analyser(self.testDir+"Contracts/"+self.testFile+".sol") analyseDoSPatterns = AnalyseDoSPatterns() analyseDoSPatterns.analyser() self.assertEqual(len(analyseDoSPatterns.statsDoSWithUnexpectedRevert), 1) self.assertEqual(analyseDoSPatterns.statsDoSWithUnexpectedRevert[0]["line"], "9") self.assertEqual(analyseDoSPatterns.statsDoSWithUnexpectedRevert[0]["info"], "send") astFD.close()
def test_exceptions(self): parseAST = ParseAST() astFD = open(self.testPath + ".ast", "r") parseResults = parseAST.parse(astFD) mapASTSourceToLineNumbers = MapASTSourceToLineNumbers() mapASTSourceToLineNumbers.analyser(self.testDir + "Contracts/" + self.testFile + ".sol") analyseReentrancy = AnalyseReentrancy() analyseReentrancy.analyser() self.assertEqual(len(analyseReentrancy.statsPotentialReentrancy), 1) self.assertEqual(analyseReentrancy.statsPotentialReentrancy[0]["line"], "8") astFD.close()
def test_exceptions(self): parseAST = ParseAST() astFD = open(self.testPath + ".ast", "r") parseResults = parseAST.parse(astFD) mapASTSourceToLineNumbers = MapASTSourceToLineNumbers() mapASTSourceToLineNumbers.analyser(self.testDir + "Contracts/" + self.testFile + ".sol") analyseControlFlowGraph = AnalyseControlFlowGraph() analyseControlFlowGraph.analyser() self.assertEqual(len(analyseControlFlowGraph.controlFlowGraph), 1) for item in analyseControlFlowGraph.controlFlowGraph: print(item) astFD.close()
def test_exceptions(self): parseAST = ParseAST() astFD = open(self.testPath+".ast","r") parseResults = parseAST.parse(astFD) mapASTSourceToLineNumbers = MapASTSourceToLineNumbers() mapASTSourceToLineNumbers.analyser(self.testDir+"Contracts/"+self.testFile+".sol") analyseDeprecatedConstructs = AnalyseDeprecatedConstructs() analyseDeprecatedConstructs.analyser() self.assertEqual(len(analyseDeprecatedConstructs.statsTxOrigin), 1) self.assertEqual(analyseDeprecatedConstructs.statsTxOrigin[0]["line"], "21") self.assertEqual(len(analyseDeprecatedConstructs.statsBlockMembers), 1) self.assertEqual(analyseDeprecatedConstructs.statsBlockMembers[0]["line"], "7") astFD.close()
def test_exceptions(self): parseAST = ParseAST() astFD = open(self.testPath + ".ast", "r") parseResults = parseAST.parse(astFD) mapASTSourceToLineNumbers = MapASTSourceToLineNumbers() mapASTSourceToLineNumbers.analyser(self.testDir + "Contracts/" + self.testFile + ".sol") analyseExceptions = AnalyseExceptions() analyseExceptions.analyser() self.assertEqual(len(analyseExceptions.statsRequires), 1) self.assertEqual(analyseExceptions.statsRequires[0]["line"], "9") self.assertEqual(len(analyseExceptions.statsAsserts), 1) self.assertEqual(analyseExceptions.statsAsserts[0]["line"], "11") self.assertEqual(len(analyseExceptions.statsReverts), 1) self.assertEqual(analyseExceptions.statsReverts[0]["line"], "13") astFD.close()
def test_exceptions(self): parseAST = ParseAST() astFD = open(self.testPath + ".ast", "r") parseResults = parseAST.parse(astFD) mapASTSourceToLineNumbers = MapASTSourceToLineNumbers() mapASTSourceToLineNumbers.analyser(self.testDir + "Contracts/" + self.testFile + ".sol") analyseUninitialisedStoragePointers = AnalyseUninitialisedStoragePointers( ) analyseUninitialisedStoragePointers.analyser() self.assertEqual( len(analyseUninitialisedStoragePointers. statsUninitialisedStoragePointers), 1) self.assertEqual( analyseUninitialisedStoragePointers. statsUninitialisedStoragePointers[0]["line"], "17") astFD.close()
def analyser(self): mapASTSourceToLineNumbers = MapASTSourceToLineNumbers() print("\n<<<<<<<<<< Analyser: Unchecked Selfdestructs >>>>>>>>>>") functionCalls = AnalyseFunctionCall.getAllFunctionCalls() for functionCall in functionCalls: if (functionCall.name == "selfdestruct"): print("selfdestruct() at line:" + str( mapASTSourceToLineNumbers.getLine( int(functionCall.src.split(":", )[0])))) node = functionCall.parent checked = False while (node.nodeType != "ContractDefinition"): if ( node.nodeType == "IfStatement" ): # Add check for ifStatementCondition containing ownership check via msg.sender self.statsConditionalCheckedSelfdestructs.append({ "line": str( mapASTSourceToLineNumbers.getLine( int(functionCall.src.split(":", )[0]))), "info": "conditional checked selfdestruct" }) print( "selfdestruct likely checked with conditional if()" ) checked = True break # Add check for Function Definition containing ownership check in a modifer via msg.sender node = node.parent if (checked): continue else: self.statsUncheckedSelfdestructs.append({ "line": str( mapASTSourceToLineNumbers.getLine( int(functionCall.src.split(":", )[0]))), "info": "Unchecked selfdestruct" }) print("Unchecked selfdestruct()")
def test_exceptions(self): parseAST = ParseAST() astFD = open(self.testPath + ".ast", "r") parseResults = parseAST.parse(astFD) mapASTSourceToLineNumbers = MapASTSourceToLineNumbers() mapASTSourceToLineNumbers.analyser(self.testDir + "Contracts/" + self.testFile + ".sol") analyseDefaultVisibility = AnalyseDefaultVisibility() analyseDefaultVisibility.analyser() self.assertEqual( len(analyseDefaultVisibility.statsDefaultVisibilityForFunction), 1) self.assertEqual( analyseDefaultVisibility.statsDefaultVisibilityForFunction[0] ["line"], "8") self.assertEqual( len(analyseDefaultVisibility.statsDefaultVisibilityForVariable), 1) self.assertEqual( analyseDefaultVisibility.statsDefaultVisibilityForVariable[0] ["line"], "5") astFD.close()
def analyser(self): mapASTSourceToLineNumbers = MapASTSourceToLineNumbers() print("\n<<<<<<<<<< Analyser: Default Visibility >>>>>>>>>>") functionDefinitions = AnalyseFunctionDefinition.getAllFunctionDefinitions( ) for function in functionDefinitions: if (function.visibility == "public"): # Determine if "public" visibility was explicitly specified or implicitly inferred # Check if "public" keyword is present between input parameters and return parameters parametersSrc = function.parameters.get("src") returnParametersSrc = function.returnParameters.get("src") found = mapASTSourceToLineNumbers.chkStringPresent( "public", parametersSrc, returnParametersSrc) if (not found): self.statsDefaultVisibilityForFunction.append({ "line": str( mapASTSourceToLineNumbers.getLine( int(function.src.split(":", )[0]))), "info": "default public visibility for function" }) print("Default public visibility for Function: " + function.name + " at line:" + str( mapASTSourceToLineNumbers.getLine( int(function.src.split(":", )[0])))) variableDeclarations = AnalyseVariable.getAllVariables() for variable in variableDeclarations: if (variable.visibility == "internal" and (not (variable.parent.nodeType == "FunctionDefinition"))): # Determine if "internal" visibility was explicitly specified or implicitly inferred # Check if "internal" keyword is present between type and variable name variableSrc = variable.src typeSrc = variable.typeName.get("src") found = mapASTSourceToLineNumbers.chkStringPresentVariableVisibility( "internal", typeSrc, variableSrc) if (not found): self.statsDefaultVisibilityForVariable.append({ "line": str( mapASTSourceToLineNumbers.getLine( int(variable.src.split(":", )[0]))), "info": "default public visibility for variable" }) print("Default internal visibility for Variable: " + variable.name + " at line:" + str( mapASTSourceToLineNumbers.getLine( int(variable.src.split(":", )[0]))))
def test_exceptions(self): parseAST = ParseAST() astFD = open(self.testPath + ".ast", "r") parseResults = parseAST.parse(astFD) mapASTSourceToLineNumbers = MapASTSourceToLineNumbers() mapASTSourceToLineNumbers.analyser(self.testDir + "Contracts/" + self.testFile + ".sol") analyseUncheckedSelfdestructs = AnalyseUncheckedSelfdestructs() analyseUncheckedSelfdestructs.analyser() self.assertEqual( len(analyseUncheckedSelfdestructs. statsConditionalCheckedSelfdestructs), 1) self.assertEqual( analyseUncheckedSelfdestructs. statsConditionalCheckedSelfdestructs[0]["line"], "13") self.assertEqual( len(analyseUncheckedSelfdestructs.statsUncheckedSelfdestructs), 1) self.assertEqual( analyseUncheckedSelfdestructs.statsUncheckedSelfdestructs[0] ["line"], "17") astFD.close()
def analyser(self): mapASTSourceToLineNumbers = MapASTSourceToLineNumbers() print("\n<<<<<<<<<< Analyser: Unchecked Calls >>>>>>>>>>") calls = AnalyseExpression.getAllCalls() for call in calls: print("call() at line:" + str(mapASTSourceToLineNumbers.getLine(int(call.src.split(":",)[0])))) node = call.parent checked = False while(node.nodeType != "ContractDefinition"): if(node.nodeType == "FunctionCall" and (node.name == "assert" or node.name == "require")): self.statsAssertCheckedCalls.append({ "line":str(mapASTSourceToLineNumbers.getLine(int(call.src.split(":",)[0]))), "info":"assert checked call" }) print("call checked with assert() or require()") checked = True break if((node.nodeType == "UnaryOperation" or node.nodeType == "BinaryOperation") and node.type == "ifStatementCondition"): self.statsConditionalCheckedCalls.append({ "line":str(mapASTSourceToLineNumbers.getLine(int(call.src.split(":",)[0]))), "info":"conditional checked call" }) print("call checked with conditional if()") checked = True break node = node.parent if(checked): continue else: self.statsUncheckedCalls.append({ "line":str(mapASTSourceToLineNumbers.getLine(int(call.src.split(":",)[0]))), "info":"Unchecked call" }) print("Unchecked call()")
def analyser(self): mapASTSourceToLineNumbers = MapASTSourceToLineNumbers() print( "\n<<<<<<<<<< Analyser: Uninitialised Storage Variables >>>>>>>>>>" ) variables = AnalyseVariable.getAllVariables() for variable in variables: logging.debug("Variable: " + str(variable)) logging.debug("stateVariable: " + str(variable.stateVariable)) logging.debug("storageLocation: " + variable.storageLocation) logging.debug("type: " + variable.typeDescriptions.get("typeIdentifier")) isVariableUninitialised = True parent = variable.parent if ((parent.nodeType == "VariableDeclarationStatement" and parent.initialValue != None) or parent.nodeType == "FunctionDefinition"): isVariableUninitialised = False if (variable.stateVariable is False and isVariableUninitialised and (variable.storageLocation == "storage" or (variable.storageLocation == "default" and ("struct" in variable.typeDescriptions.get("typeIdentifier") or "array" in variable.typeDescriptions.get( "typeIdentifier") or "mapping" in variable.typeDescriptions.get("typeIdentifier"))))): self.statsUninitialisedStoragePointers.append({ "line": str( mapASTSourceToLineNumbers.getLine( int(variable.src.split(":", )[0]))), "info": "uninitialised storage pointer" }) print("Uninitialised storage pointer " + variable.name + " at line:" + str( mapASTSourceToLineNumbers.getLine( int(variable.src.split(":", )[0]))))
def analyser(self): mapASTSourceToLineNumbers = MapASTSourceToLineNumbers() print("\n<<<<<<<<<< Analyser: Exceptions >>>>>>>>>>") requires = AnalyseFunctionCall.getAllRequires() print("Number of require(): " + str(len(requires))) for require in requires: print("require() " + " at line:" + str( mapASTSourceToLineNumbers.getLine( int(require.src.split(":", )[0])))) self.statsRequires.append({ "line": str( mapASTSourceToLineNumbers.getLine( int(require.src.split(":", )[0]))), "info": "require" }) asserts = AnalyseFunctionCall.getAllAsserts() print("Number of assert(): " + str(len(asserts))) for _assert in asserts: print("assert() " + " at line:" + str( mapASTSourceToLineNumbers.getLine( int(_assert.src.split(":", )[0])))) self.statsAsserts.append({ "line": str( mapASTSourceToLineNumbers.getLine( int(_assert.src.split(":", )[0]))), "info": "assert" }) reverts = AnalyseFunctionCall.getAllReverts() print("Number of revert(): " + str(len(reverts))) for revert in reverts: print("revert() " + " at line:" + str( mapASTSourceToLineNumbers.getLine( int(revert.src.split(":", )[0])))) self.statsReverts.append({ "line": str( mapASTSourceToLineNumbers.getLine( int(revert.src.split(":", )[0]))), "info": "revert" })
def analyser(self): expressions = AnalyseExpression.getAllExpressions() mapASTSourceToLineNumbers = MapASTSourceToLineNumbers() print("\n<<<<<<<<<< Analyser: Reentrancy >>>>>>>>>>") calls = AnalyseExpression.getAllCalls() for call in calls: logging.debug("Call at line:" + str(mapASTSourceToLineNumbers.getLine(int(call.src.split(":",)[0])))) parent = call.parent found = False defs = [] while(True): if (parent.nodeType == "ExpressionStatement"): logging.debug("Found ExpressionStatement: " + str(parent.id)) found = True break if (parent.nodeType == "ContractDefinition"): break parent = parent.parent if (found): defs = DefUseAnalysis.getAllDefintionsAfterStatement(parent) defsOfStateVariables = [] for _def in defs: logging.debug("_def: " + str(_def)) logging.debug("Def: " + _def["name"] + " at line:" + str(mapASTSourceToLineNumbers.getLine(int(_def["src"].split(":",)[0])))) variableID = _def["referencedDeclaration"] variables = AnalyseVariable.getAllVariables() for variable in variables: if (variableID == variable.id and variable.stateVariable): defsOfStateVariables.append(_def) if (len(defsOfStateVariables) != 0): self.statsPotentialReentrancy.append({ "line":str(mapASTSourceToLineNumbers.getLine(int(call.src.split(":",)[0]))), "info":"potential reentrancy: state change after call()" }) print("Potential Reentrancy: State change after call()") else: print("No Reentrancy: No state change after call()")
def test_exceptions(self): parseAST = ParseAST() astFD = open(self.testPath + ".ast", "r") parseResults = parseAST.parse(astFD) mapASTSourceToLineNumbers = MapASTSourceToLineNumbers() mapASTSourceToLineNumbers.analyser(self.testDir + "Contracts/" + self.testFile + ".sol") analyseTaintedVariables = AnalyseTaintedVariables() analyseTaintedVariables.analyser() self.assertEqual(len(analyseTaintedVariables.statsTaintedVariables), 6) self.assertEqual( len(analyseTaintedVariables.statsTaintedVariables[0]["info"]), 1) self.assertEqual( len(analyseTaintedVariables.statsTaintedVariables[1]["info"]), 2) self.assertEqual( len(analyseTaintedVariables.statsTaintedVariables[2]["info"]), 3) self.assertEqual( len(analyseTaintedVariables.statsTaintedVariables[3]["info"]), 3) self.assertEqual( len(analyseTaintedVariables.statsTaintedVariables[4]["info"]), 4) self.assertEqual( len(analyseTaintedVariables.statsTaintedVariables[5]["info"]), 5) astFD.close()
def analyser(self): mapASTSourceToLineNumbers = MapASTSourceToLineNumbers() print("\n<<<<<<<<<< Analyser: DoS Patterns >>>>>>>>>>") print("\n********** DoS Patterns with send()/transfer() **********") sends = AnalyseExpression.getAllSends() for send in sends: print("send() at line:" + str(mapASTSourceToLineNumbers.getLine(int(send.src.split(":",)[0])))) node = send.parent while(node.nodeType != "ContractDefinition"): if(node.nodeType == "WhileStatement" or node.nodeType == "ForStatement"): self.statsDoSWithBlockGasLimit.append({ "line":str(mapASTSourceToLineNumbers.getLine(int(send.src.split(":",)[0]))), "info":"send" }) print("send() within loops are susceptible to DoS with block gas limit") break if((node.nodeType == "FunctionCall" and node.name == "require")): self.statsDoSWithUnexpectedRevert.append({ "line":str(mapASTSourceToLineNumbers.getLine(int(send.src.split(":",)[0]))), "info":"send" }) print("Potential DoS with (unexpected) revert") break node = node.parent transfers = AnalyseExpression.getAllTransfers() for transfer in transfers: print("transfer() at line:" + str(mapASTSourceToLineNumbers.getLine(int(transfer.src.split(":",)[0])))) self.statsDoSWithUnexpectedRevert.append({ "line":str(mapASTSourceToLineNumbers.getLine(int(transfer.src.split(":",)[0]))), "info":"transfer" }) print("Potential DoS with (unexpected) revert") node = transfer.parent while(node.nodeType != "ContractDefinition"): if(node.nodeType == "WhileStatement" or node.nodeType == "ForStatement"): self.statsDoSWithBlockGasLimit.append({ "line":str(mapASTSourceToLineNumbers.getLine(int(transfer.src.split(":",)[0]))), "info":"transfer" }) print("transfer() within loops are susceptible to DoS with block gas limit") break node = node.parent
def analyser(self): mapASTSourceToLineNumbers = MapASTSourceToLineNumbers() print("\n<<<<<<<<<< Analyser: Unchecked Deprecated Constructs >>>>>>>>>>") print("\n********** Use of tx.origin **********") constructs = AnalyseExpression.getAllTxOrigins() for construct in constructs: self.statsTxOrigin.append({ "line":str(mapASTSourceToLineNumbers.getLine(int(construct.src.split(":",)[0]))), "info":"tx.origin" }) print("tx.origin at line:" + str(mapASTSourceToLineNumbers.getLine(int(construct.src.split(":",)[0])))) print("\n********** Use of block.<member> where member is number/hash/gaslimit/coinbase/timestamp **********") constructs = AnalyseExpression.getAllBlockMembers() for construct in constructs: self.statsBlockMembers.append({ "line":str(mapASTSourceToLineNumbers.getLine(int(construct.src.split(":",)[0]))), "info":"block.<member>" }) print("Predictable block member at line:" + str(mapASTSourceToLineNumbers.getLine(int(construct.src.split(":",)[0]))))
def analyse(self): parseAST = ParseAST() astFD = open(self.astFile,"r") parseResults = parseAST.parse(astFD) mapASTSourceToLineNumbers = MapASTSourceToLineNumbers() mapASTSourceToLineNumbers.analyser(self.inputFile) if (self.runAllAnalysers or self.runAnalyser1): analyseContractFeatures = AnalyseContractFeatures() analyseContractFeatures.analyser() if (self.runAllAnalysers or self.runAnalyser2): analyseControlFlowGraph = AnalyseControlFlowGraph() analyseControlFlowGraph.analyser() if (self.runAllAnalysers or self.runAnalyser3): analyseDefaultVisibility = AnalyseDefaultVisibility() analyseDefaultVisibility.analyser() if (self.runAllAnalysers or self.runAnalyser4): analyseDeprecatedConstructs = AnalyseDeprecatedConstructs() analyseDeprecatedConstructs.analyser() if (self.runAllAnalysers or (self.runAnalyser5 or self.runAnalyser6 or self.runAnalyser7)): analyseDoSPatterns = AnalyseDoSPatterns() analyseDoSPatterns.analyser() if (self.runAllAnalysers or self.runAnalyser8): analyseExternalContractInteractions = AnalyseExternalContractInteractions() analyseExternalContractInteractions.analyser() if (self.runAllAnalysers or self.runAnalyser9): analyseExceptions = AnalyseExceptions() analyseExceptions.analyser() if (self.runAllAnalysers or self.runAnalyser10): analyseReentrancy = AnalyseReentrancy() analyseReentrancy.analyser() if (self.runAllAnalysers or self.runAnalyser11): analyseUncheckedCalls = AnalyseUncheckedCalls() analyseUncheckedCalls.analyser() if (self.runAllAnalysers or self.runAnalyser12): analyseUncheckedSelfdestructs = AnalyseUncheckedSelfdestructs() analyseUncheckedSelfdestructs.analyser() if (self.runAllAnalysers or self.runAnalyser13): analyseUninitialisedStoragePointers = AnalyseUninitialisedStoragePointers() analyseUninitialisedStoragePointers.analyser() if (self.runAllAnalysers or self.runAnalyser14): analyseDefsUses = AnalyseDefsUses() analyseDefsUses.analyser() if (self.runAllAnalysers or self.runAnalyser15): analyseTaintVariables = AnalyseTaintedVariables() analyseTaintVariables.analyser() astFD.close()
def analyser(self): mapASTSourceToLineNumbers = MapASTSourceToLineNumbers() print("\n<<<<<<<<<< Analyser: Contract Features >>>>>>>>>>") contracts = AnalyseContract.getAllContracts() for contract in contracts: self.statsContractDefinitions.append({ "line":str(mapASTSourceToLineNumbers.getLine(int(contract.src.split(":",)[0]))), "info":"contract definition" }) print("\n********** Contract Features **********") print("Contract definition: " + contract.name + " at line:" + str(mapASTSourceToLineNumbers.getLine(int(contract.src.split(":",)[0])))) functionDefinitions = AnalyseFunctionDefinition.getAllFunctionDefinitions() for function in functionDefinitions: self.statsFunctionDefinitions.append({ "line":str(mapASTSourceToLineNumbers.getLine(int(function.src.split(":",)[0]))), "info":"function definition" }) print("\n********** Function Features **********") print("Function definition: " + function.name + " at line:" + str(mapASTSourceToLineNumbers.getLine(int(function.src.split(":",)[0])))) if (function.isConstructor): self.statsConstructors.append({ "line":str(mapASTSourceToLineNumbers.getLine(int(function.src.split(":",)[0]))), "info":"constructor definition" }) print("Constructor") print("Visibility: " + function.visibility) print("State Mutability: " + function.stateMutability) if (AnalyseFunctionDefinition.isFallbackFunction(function)): self.statsFallbackFunctions.append({ "line":str(mapASTSourceToLineNumbers.getLine(int(function.src.split(":",)[0]))), "info":"fallback definition" }) print("Fallback function") if (AnalyseFunctionDefinition.isPayableFallbackFunction(function)): print("Payable Fallback function") modifiers = function.modifiers for modifier in modifiers: print("Modifier: " + modifier['modifierName']['name']) variableDeclarations = AnalyseVariable.getAllVariables() for variable in variableDeclarations: self.statsVariableDeclarations.append({ "line":str(mapASTSourceToLineNumbers.getLine(int(variable.src.split(":",)[0]))), "info":"variable declaration" }) print("\n********** Variable Features **********") print("Variable declaration: " + variable.name + " at line:" + str(mapASTSourceToLineNumbers.getLine(int(variable.src.split(":",)[0])))) if (variable.stateVariable): self.statsStateVariables.append({ "line":str(mapASTSourceToLineNumbers.getLine(int(variable.src.split(":",)[0]))), "info":"state variable declaration" }) print("State variable") else: if (variable.parent.nodeType == "FunctionDefinition"): print("Function parameter") else: print("Local variable")
def analyser(self): expressions = AnalyseExpression.getAllExpressions() mapASTSourceToLineNumbers = MapASTSourceToLineNumbers() print( "\n<<<<<<<<<< Analyser: External Contract Interactions >>>>>>>>>>") transfers = AnalyseExpression.getAllTransfers() for transfer in transfers: for child in transfer.children: if (child.nodeType == "Identifier"): self.statsTransfers.append({ "line": str( mapASTSourceToLineNumbers.getLine( int(child.src.split(":", )[0]))), "info": "transfer" }) print("Transfer to " + child.name + " at line:" + str( mapASTSourceToLineNumbers.getLine( int(child.src.split(":", )[0])))) sends = AnalyseExpression.getAllSends() for send in sends: for child in send.children: if (child.nodeType == "Identifier"): self.statsSends.append({ "line": str( mapASTSourceToLineNumbers.getLine( int(child.src.split(":", )[0]))), "info": "send" }) print("Send to " + child.name + " at line:" + str( mapASTSourceToLineNumbers.getLine( int(child.src.split(":", )[0])))) calls = AnalyseExpression.getAllCalls() for call in calls: for child in call.children: if (child.nodeType == "Identifier"): self.statsCalls.append({ "line": str( mapASTSourceToLineNumbers.getLine( int(child.src.split(":", )[0]))), "info": "call" }) print("Call to " + child.name + " at line:" + str( mapASTSourceToLineNumbers.getLine( int(child.src.split(":", )[0])))) delegateCalls = AnalyseExpression.getAllDelegateCalls() for delegateCall in delegateCalls: for child in delegateCall.children: if (child.nodeType == "Identifier"): self.statsDelegateCalls.append({ "line": str( mapASTSourceToLineNumbers.getLine( int(child.src.split(":", )[0]))), "info": "delegateCall" }) print("DelegateCall to " + child.name + " at line:" + str( mapASTSourceToLineNumbers.getLine( int(child.src.split(":", )[0]))))
def analyser(self): mapASTSourceToLineNumbers = MapASTSourceToLineNumbers() print("\n<<<<<<<<<< Analyser: Defs and Uses >>>>>>>>>>") functionDefinitions = AnalyseFunctionDefinition.getAllFunctionDefinitions() for function in functionDefinitions: print("\n********** Function Defs/Uses **********") print("Function definition: " + function.name + " at line:" + str(mapASTSourceToLineNumbers.getLine(int(function.src.split(":",)[0])))) dataflow = DefUseAnalysis.getDataflowForFunction(function) if (self.loggingLevel == "DEBUG"): print("Dataflow length: " + str(len(dataflow))) for item in dataflow: _gen = [] _kill = [] _in = MySet() _out = [] if(item["gen"] is not None and item["gen"]._set is not None): for var in item["gen"]._set: if(AnalyseVariable.getVariableNameForId(var) != "Error"): _gen.append(AnalyseVariable.getVariableNameForId(var)) if(item["kill"] is not None): for var in item["kill"]._set: if(AnalyseVariable.getVariableNameForId(var) != "Error"): _kill.append(AnalyseVariable.getVariableNameForId(var)) if(item["in"] is not None): for var in item["in"]._set: if(AnalyseVariable.getVariableNameForId(var) != "Error"): _in.add(AnalyseVariable.getVariableNameForId(var), item["in"].idToNodeMapping[var].src) if(item["out"] is not None): for var in item["out"]._set: if(AnalyseVariable.getVariableNameForId(var) != "Error"): _out.append(AnalyseVariable.getVariableNameForId(var)) print("Node Id: " + str(item["id"]) + " at line:" + str(mapASTSourceToLineNumbers.getLine(int(item["src"].split(":",)[0]))) + " gen: " + str(_gen) + " kill: " + str(_kill) ) for var in _in._set: print("in: " + var + " defined at line:" + str(mapASTSourceToLineNumbers.getLine(int(_in.idToNodeMapping[var].split(":",)[0])))) print(" out: " + str(_out)) defs = [] defs = DefUseAnalysis.getAllDefsAtNode(function, defs) for _def in defs: self.statsDefs.append({ "line":str(mapASTSourceToLineNumbers.getLine(int(_def["src"].split(":",)[0]))), "info":_def["name"] }) if(self.loggingLevel == "DEBUG"): print("Def: " + _def["name"] + " at line:" + str(mapASTSourceToLineNumbers.getLine(int(_def["src"].split(":",)[0])))) uses = [] uses = DefUseAnalysis.getAllUsesAtNode(function, uses) for use in uses: self.statsUses.append({ "line":str(mapASTSourceToLineNumbers.getLine(int(use["src"].split(":",)[0]))), "info":use["name"] }) print("Use: " + use["name"] + " at line:" + str(mapASTSourceToLineNumbers.getLine(int(use["src"].split(":",)[0])))) print(" > Using value from definition on line: ",end='') line = mapASTSourceToLineNumbers.getLine(int(use["src"].split(":",)[0])) varRef = use["referencedDeclaration"] found = False for item in dataflow: if(mapASTSourceToLineNumbers.getLine(int(item["src"].split(":",)[0])) == line): if(item["in"] and varRef in item["in"]._set): print(mapASTSourceToLineNumbers.getLine(int(item["in"].idToNodeMapping[varRef].src.split(":",)[0]))) found = True break if(not found): print("Not Found")
def test_exceptions(self): parseAST = ParseAST() astFD = open(self.testPath + ".ast", "r") parseResults = parseAST.parse(astFD) mapASTSourceToLineNumbers = MapASTSourceToLineNumbers() mapASTSourceToLineNumbers.analyser(self.testDir + "Contracts/" + self.testFile + ".sol") analyseDefsUses = AnalyseDefsUses() analyseDefsUses.analyser() self.assertEqual(len(analyseDefsUses.statsDefs), 16) self.assertEqual(analyseDefsUses.statsDefs[0]["line"], "14") self.assertEqual(analyseDefsUses.statsDefs[0]["info"], "k") self.assertEqual(analyseDefsUses.statsDefs[1]["line"], "18") self.assertEqual(analyseDefsUses.statsDefs[1]["info"], "i") self.assertEqual(analyseDefsUses.statsDefs[2]["line"], "21") self.assertEqual(analyseDefsUses.statsDefs[2]["info"], "a") self.assertEqual(analyseDefsUses.statsDefs[3]["line"], "22") self.assertEqual(analyseDefsUses.statsDefs[3]["info"], "a") self.assertEqual(analyseDefsUses.statsDefs[4]["line"], "23") self.assertEqual(analyseDefsUses.statsDefs[4]["info"], "j") self.assertEqual(analyseDefsUses.statsDefs[5]["line"], "24") self.assertEqual(analyseDefsUses.statsDefs[5]["info"], "a") self.assertEqual(analyseDefsUses.statsDefs[6]["line"], "25") self.assertEqual(analyseDefsUses.statsDefs[6]["info"], "i") self.assertEqual(analyseDefsUses.statsDefs[7]["line"], "28") self.assertEqual(analyseDefsUses.statsDefs[7]["info"], "i") self.assertEqual(analyseDefsUses.statsDefs[8]["line"], "31") self.assertEqual(analyseDefsUses.statsDefs[8]["info"], "j") self.assertEqual(analyseDefsUses.statsDefs[9]["line"], "34") self.assertEqual(analyseDefsUses.statsDefs[9]["info"], "a") self.assertEqual(analyseDefsUses.statsDefs[10]["line"], "35") self.assertEqual(analyseDefsUses.statsDefs[10]["info"], "j") self.assertEqual(analyseDefsUses.statsDefs[11]["line"], "38") self.assertEqual(analyseDefsUses.statsDefs[11]["info"], "data") self.assertEqual(analyseDefsUses.statsDefs[12]["line"], "40") self.assertEqual(analyseDefsUses.statsDefs[12]["info"], "balances") self.assertEqual(analyseDefsUses.statsDefs[13]["line"], "40") self.assertEqual(analyseDefsUses.statsDefs[13]["info"], "msg") self.assertEqual(analyseDefsUses.statsDefs[14]["line"], "41") self.assertEqual(analyseDefsUses.statsDefs[14]["info"], "balances") self.assertEqual(analyseDefsUses.statsDefs[15]["line"], "41") self.assertEqual(analyseDefsUses.statsDefs[15]["info"], "i") self.assertEqual(len(analyseDefsUses.statsUses), 22) self.assertEqual(analyseDefsUses.statsUses[0]["line"], "15") self.assertEqual(analyseDefsUses.statsUses[0]["info"], "k") self.assertEqual(analyseDefsUses.statsUses[1]["line"], "21") self.assertEqual(analyseDefsUses.statsUses[1]["info"], "i") self.assertEqual(analyseDefsUses.statsUses[2]["line"], "22") self.assertEqual(analyseDefsUses.statsUses[2]["info"], "a") self.assertEqual(analyseDefsUses.statsUses[3]["line"], "23") self.assertEqual(analyseDefsUses.statsUses[3]["info"], "i") self.assertEqual(analyseDefsUses.statsUses[4]["line"], "24") self.assertEqual(analyseDefsUses.statsUses[4]["info"], "a") self.assertEqual(analyseDefsUses.statsUses[5]["line"], "24") self.assertEqual(analyseDefsUses.statsUses[5]["info"], "i") self.assertEqual(analyseDefsUses.statsUses[6]["line"], "24") self.assertEqual(analyseDefsUses.statsUses[6]["info"], "j") self.assertEqual(analyseDefsUses.statsUses[7]["line"], "25") self.assertEqual(analyseDefsUses.statsUses[7]["info"], "a") self.assertEqual(analyseDefsUses.statsUses[8]["line"], "25") self.assertEqual(analyseDefsUses.statsUses[8]["info"], "i") self.assertEqual(analyseDefsUses.statsUses[9]["line"], "25") self.assertEqual(analyseDefsUses.statsUses[9]["info"], "j") self.assertEqual(analyseDefsUses.statsUses[10]["line"], "25") self.assertEqual(analyseDefsUses.statsUses[10]["info"], "msg") self.assertEqual(analyseDefsUses.statsUses[11]["line"], "27") self.assertEqual(analyseDefsUses.statsUses[11]["info"], "a") self.assertEqual(analyseDefsUses.statsUses[12]["line"], "28") self.assertEqual(analyseDefsUses.statsUses[12]["info"], "i") self.assertEqual(analyseDefsUses.statsUses[13]["line"], "31") self.assertEqual(analyseDefsUses.statsUses[13]["info"], "bar") self.assertEqual(analyseDefsUses.statsUses[14]["line"], "31") self.assertEqual(analyseDefsUses.statsUses[14]["info"], "a") self.assertEqual(analyseDefsUses.statsUses[15]["line"], "31") self.assertEqual(analyseDefsUses.statsUses[15]["info"], "a") self.assertEqual(analyseDefsUses.statsUses[16]["line"], "34") self.assertEqual(analyseDefsUses.statsUses[16]["info"], "a") self.assertEqual(analyseDefsUses.statsUses[17]["line"], "35") self.assertEqual(analyseDefsUses.statsUses[17]["info"], "j") self.assertEqual(analyseDefsUses.statsUses[18]["line"], "38") self.assertEqual(analyseDefsUses.statsUses[18]["info"], "j") self.assertEqual(analyseDefsUses.statsUses[19]["line"], "40") self.assertEqual(analyseDefsUses.statsUses[19]["info"], "j") self.assertEqual(analyseDefsUses.statsUses[20]["line"], "41") self.assertEqual(analyseDefsUses.statsUses[20]["info"], "i") self.assertEqual(analyseDefsUses.statsUses[21]["line"], "41") self.assertEqual(analyseDefsUses.statsUses[21]["info"], "a") astFD.close()