method updates

pull/5370/head
aniket-engg 5 years ago committed by Aniket
parent 28a9149d6c
commit ffa8dd8bcc
  1. 6
      remix-analyzer/src/solidity-analyzer/modules/abstractAstView.ts
  2. 2
      remix-analyzer/src/solidity-analyzer/modules/constantFunctions.ts
  3. 6
      remix-analyzer/src/solidity-analyzer/modules/deleteDynamicArrays.ts
  4. 26
      remix-analyzer/src/solidity-analyzer/modules/forLoopIteratesOverDynamicArray.ts
  5. 6
      remix-analyzer/src/solidity-analyzer/modules/intDivisionTruncate.ts
  6. 6
      remix-analyzer/src/solidity-analyzer/modules/lowLevelCalls.ts
  7. 153
      remix-analyzer/src/solidity-analyzer/modules/staticAnalysisCommon.ts
  8. 6
      remix-analyzer/src/solidity-analyzer/modules/thisLocal.ts
  9. 14
      remix-analyzer/src/types.ts

@ -3,7 +3,7 @@ import { getStateVariableDeclarationsFormContractNode,
getFunctionOrModifierDefinitionParameterPart, getType, getDeclaredVariableName, getFunctionOrModifierDefinitionParameterPart, getType, getDeclaredVariableName,
getFunctionDefinitionReturnParameterPart } from './staticAnalysisCommon' getFunctionDefinitionReturnParameterPart } from './staticAnalysisCommon'
import { AstWalker } from 'remix-astwalker' import { AstWalker } from 'remix-astwalker'
import { CommonAstNode, FunctionDefinitionAstNode, ParameterListAstNode } from 'types' import { CommonAstNode, FunctionDefinitionAstNode, ParameterListAstNode, ModifierDefinitionAstNode } from 'types'
export default class abstractAstView { export default class abstractAstView {
contracts = [] contracts = []
@ -159,11 +159,11 @@ export default class abstractAstView {
return that.getCurrentContract(that).modifiers[that.currentModifierIndex] return that.getCurrentContract(that).modifiers[that.currentModifierIndex]
} }
private getLocalParameters (funcNode) { private getLocalParameters (funcNode: FunctionDefinitionAstNode | ModifierDefinitionAstNode) {
return getFunctionOrModifierDefinitionParameterPart(funcNode).parameters.map(getType) return getFunctionOrModifierDefinitionParameterPart(funcNode).parameters.map(getType)
} }
private getReturnParameters (funcNode) { private getReturnParameters (funcNode: FunctionDefinitionAstNode) {
return this.getLocalVariables(getFunctionDefinitionReturnParameterPart(funcNode)).map((n) => { return this.getLocalVariables(getFunctionDefinitionReturnParameterPart(funcNode)).map((n) => {
return { return {
type: getType(n), type: getType(n),

@ -17,7 +17,7 @@ export default class constantFunctions implements AnalyzerModule {
abstractAst: AbstractAst = new AbstractAst() abstractAst: AbstractAst = new AbstractAst()
visit = this.abstractAst.build_visit( visit = this.abstractAst.build_visit(
(node: CommonAstNode) => isLowLevelCall(node) || (node: any) => isLowLevelCall(node) ||
isTransfer(node) || isTransfer(node) ||
isExternalDirectCall(node) || isExternalDirectCall(node) ||
isEffect(node) || isEffect(node) ||

@ -1,16 +1,16 @@
import { default as category } from './categories' import { default as category } from './categories'
import { isDeleteOfDynamicArray } from './staticAnalysisCommon' import { isDeleteOfDynamicArray } from './staticAnalysisCommon'
import { default as algorithm } from './algorithmCategories' import { default as algorithm } from './algorithmCategories'
import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, AstNodeLegacy, CompilationResult} from './../../types' import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, CompilationResult, UnaryOperationAstNode} from './../../types'
export default class deleteDynamicArrays implements AnalyzerModule { export default class deleteDynamicArrays implements AnalyzerModule {
rel: AstNodeLegacy[] = [] rel: UnaryOperationAstNode[] = []
name: string = 'Delete on dynamic Array: ' name: string = 'Delete on dynamic Array: '
description: string = 'Use require and appropriately' description: string = 'Use require and appropriately'
category: ModuleCategory = category.GAS category: ModuleCategory = category.GAS
algorithm: ModuleAlgorithm = algorithm.EXACT algorithm: ModuleAlgorithm = algorithm.EXACT
visit (node: AstNodeLegacy): void { visit (node: UnaryOperationAstNode): void {
if (isDeleteOfDynamicArray(node)) this.rel.push(node) if (isDeleteOfDynamicArray(node)) this.rel.push(node)
} }

@ -1,32 +1,24 @@
import { default as category } from './categories' import { default as category } from './categories'
import { default as algorithm } from './algorithmCategories' import { default as algorithm } from './algorithmCategories'
import { isForLoop, isDynamicArrayLengthAccess, isBinaryOperation } from './staticAnalysisCommon' import { isDynamicArrayLengthAccess } from './staticAnalysisCommon'
import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, AstNodeLegacy, CompilationResult, CommonAstNode} from './../../types' import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, CompilationResult, ForStatementAstNode} from './../../types'
export default class forLoopIteratesOverDynamicArray implements AnalyzerModule { export default class forLoopIteratesOverDynamicArray implements AnalyzerModule {
relevantNodes: CommonAstNode[] = [] relevantNodes: ForStatementAstNode[] = []
name: string = 'For loop iterates over dynamic array: ' name: string = 'For loop iterates over dynamic array: '
description: string = 'The number of \'for\' loop iterations depends on dynamic array\'s size' description: string = 'The number of \'for\' loop iterations depends on dynamic array\'s size'
category: ModuleCategory = category.GAS category: ModuleCategory = category.GAS
algorithm: ModuleAlgorithm = algorithm.EXACT algorithm: ModuleAlgorithm = algorithm.EXACT
visit (node: CommonAstNode): void { visit (node: ForStatementAstNode): void {
if (node.nodeType === "Forstatement" && node.children) { const { condition } = node
let conditionChildrenNode: AstNodeLegacy | null = null // Check if condition is `i < array.length - 1`
// Access 'condition' node of 'for' loop statement if ((condition.nodeType === "BinaryOperation" && condition.rightExpression.nodeType === "BinaryOperation" && isDynamicArrayLengthAccess(condition.rightExpression.leftExpression)) ||
const forLoopConditionNode: AstNodeLegacy = node.children[1] // or condition is `i < array.length`
// Access right side of condition as its children (condition.nodeType === "BinaryOperation" && isDynamicArrayLengthAccess(condition.rightExpression))) {
if(forLoopConditionNode && forLoopConditionNode.children){
conditionChildrenNode = forLoopConditionNode.children[1]
}
// Check if it is a binary operation. if yes, check if its children node access length of dynamic array
if (conditionChildrenNode && conditionChildrenNode.children && isBinaryOperation(conditionChildrenNode) && isDynamicArrayLengthAccess(conditionChildrenNode.children[0])) {
this.relevantNodes.push(node)
} else if (isDynamicArrayLengthAccess(conditionChildrenNode)) { // else check if condition node itself access length of dynamic array
this.relevantNodes.push(node) this.relevantNodes.push(node)
} }
} }
}
report (compilationResults: CompilationResult): ReportObj[] { report (compilationResults: CompilationResult): ReportObj[] {
return this.relevantNodes.map((node) => { return this.relevantNodes.map((node) => {

@ -1,16 +1,16 @@
import { default as category } from './categories' import { default as category } from './categories'
import { isIntDivision } from './staticAnalysisCommon' import { isIntDivision } from './staticAnalysisCommon'
import { default as algorithm } from './algorithmCategories' import { default as algorithm } from './algorithmCategories'
import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, AstNodeLegacy, CompilationResult} from './../../types' import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, CompilationResult, BinaryOperationAstNode} from './../../types'
export default class intDivisionTruncate implements AnalyzerModule { export default class intDivisionTruncate implements AnalyzerModule {
warningNodes: AstNodeLegacy[] = [] warningNodes: BinaryOperationAstNode[] = []
name: string = 'Data Truncated: ' name: string = 'Data Truncated: '
description: string = 'Division on int/uint values truncates the result.' description: string = 'Division on int/uint values truncates the result.'
category: ModuleCategory = category.MISC category: ModuleCategory = category.MISC
algorithm: ModuleAlgorithm = algorithm.EXACT algorithm: ModuleAlgorithm = algorithm.EXACT
visit (node: AstNodeLegacy): void { visit (node: BinaryOperationAstNode): void {
if (isIntDivision(node)) this.warningNodes.push(node) if (isIntDivision(node)) this.warningNodes.push(node)
} }

@ -2,10 +2,10 @@ import { default as category } from './categories'
import { isLowLevelCallInst, isLowLevelCallInst050, isLowLevelCallcodeInst, isLowLevelDelegatecallInst, import { isLowLevelCallInst, isLowLevelCallInst050, isLowLevelCallcodeInst, isLowLevelDelegatecallInst,
isLowLevelSendInst, isLowLevelSendInst050, isLLDelegatecallInst050, lowLevelCallTypes } from './staticAnalysisCommon' isLowLevelSendInst, isLowLevelSendInst050, isLLDelegatecallInst050, lowLevelCallTypes } from './staticAnalysisCommon'
import { default as algorithm } from './algorithmCategories' import { default as algorithm } from './algorithmCategories'
import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, AstNodeLegacy, CompilationResult} from './../../types' import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, CompilationResult, MemberAccessAstNode} from './../../types'
interface llcNode { interface llcNode {
node: AstNodeLegacy node: MemberAccessAstNode
type: { type: {
ident: string, ident: string,
type: string type: string
@ -19,7 +19,7 @@ export default class lowLevelCalls implements AnalyzerModule {
category: ModuleCategory = category.SECURITY category: ModuleCategory = category.SECURITY
algorithm: ModuleAlgorithm = algorithm.EXACT algorithm: ModuleAlgorithm = algorithm.EXACT
visit (node : AstNodeLegacy): void { visit (node : MemberAccessAstNode): void {
if (isLowLevelCallInst(node)) { if (isLowLevelCallInst(node)) {
this.llcNodes.push({node: node, type: lowLevelCallTypes.CALL}) this.llcNodes.push({node: node, type: lowLevelCallTypes.CALL})
} else if (isLowLevelCallInst050(node)) { } else if (isLowLevelCallInst050(node)) {

@ -1,6 +1,6 @@
'use strict' 'use strict'
import { FunctionDefinitionAstNode, ModifierDefinitionAstNode, ParameterListAstNode, CommonAstNode, ForStatementAstNode, WhileStatementAstNode, VariableDeclarationAstNode, ContractDefinitionAstNode, InheritanceSpecifierAstNode, MemberAccessAstNode } from "types" import { FunctionDefinitionAstNode, ModifierDefinitionAstNode, ParameterListAstNode, CommonAstNode, ForStatementAstNode, WhileStatementAstNode, VariableDeclarationAstNode, ContractDefinitionAstNode, InheritanceSpecifierAstNode, MemberAccessAstNode, BinaryOperationAstNode, FunctionCallAstNode, ExpressionStatementAstNode, UnaryOperationAstNode, IdentifierAstNode, MappingAstNode, IndexAccessAstNode } from "types"
const remixLib = require('remix-lib') const remixLib = require('remix-lib')
const util = remixLib.util const util = remixLib.util
@ -433,8 +433,8 @@ function isBinaryOperation (node) {
* @funcNode {ASTNode} function defintion node * @funcNode {ASTNode} function defintion node
* @return {bool} * @return {bool}
*/ */
function hasFunctionBody (funcNode) { function hasFunctionBody (funcNode: FunctionDefinitionAstNode) {
return findFirstSubNodeLTR(funcNode, exactMatch(nodeTypes.BLOCK)) != null return funcNode.body != null
} }
/** /**
@ -442,8 +442,8 @@ function hasFunctionBody (funcNode) {
* @node {ASTNode} node to check for * @node {ASTNode} node to check for
* @return {bool} * @return {bool}
*/ */
function isDeleteOfDynamicArray (node) { function isDeleteOfDynamicArray (node: UnaryOperationAstNode) {
return isDeleteUnaryOperation(node) && isDynamicArrayAccess(node.children[0]) return isDeleteUnaryOperation(node) && isDynamicArrayAccess(node.subExpression)
} }
/** /**
@ -451,8 +451,8 @@ function isDeleteOfDynamicArray (node) {
* @node {ASTNode} node to check for * @node {ASTNode} node to check for
* @return {bool} * @return {bool}
*/ */
function isDynamicArrayAccess (node) { function isDynamicArrayAccess (node: IdentifierAstNode) {
return node && nodeType(node, exactMatch(nodeTypes.IDENTIFIER)) && (node.attributes.type.endsWith('[] storage ref') || node.attributes.type === 'bytes storage ref' || node.attributes.type === 'string storage ref') return typeDescription(node, '[] storage ref') || typeDescription(node, 'bytes storage ref') || typeDescription(node, 'string storage ref')
} }
/** /**
@ -460,11 +460,9 @@ function isDynamicArrayAccess (node) {
* @node {ASTNode} node to check for * @node {ASTNode} node to check for
* @return {bool} * @return {bool}
*/ */
function isDynamicArrayLengthAccess (node) { function isDynamicArrayLengthAccess (node: MemberAccessAstNode) {
return node && // if node exists return (node.memberName === 'length') && // accessing 'length' member
nodeType(node, exactMatch(nodeTypes.MEMBERACCESS)) && // is memberAccess Node node.expression['typeDescriptions']['typeString'].indexOf('[]') !== -1 // member is accessed from dynamic array, notice [] without any number
(node.attributes.member_name === 'length') && // accessing 'length' member
node.children[0].attributes.type.indexOf('[]') !== -1 // member is accessed from dynamic array, notice [] without any number
} }
/** /**
@ -627,8 +625,8 @@ function isConstructor (node: FunctionDefinitionAstNode): boolean {
* @node {ASTNode} some AstNode * @node {ASTNode} some AstNode
* @return {bool} * @return {bool}
*/ */
function isIntDivision (node) { function isIntDivision (node: BinaryOperationAstNode) {
return isBinaryOperation(node) && operator(node, exactMatch(util.escapeRegExp('/'))) && expressionType(node, util.escapeRegExp('int')) return operator(node, exactMatch(util.escapeRegExp('/'))) && typeDescription(node.rightExpression, util.escapeRegExp('int'))
} }
/** /**
@ -646,7 +644,7 @@ function isSubScopeStatement (node) {
nodeType(node, exactMatch(nodeTypes.FORSTATEMENT)) || nodeType(node, exactMatch(nodeTypes.FORSTATEMENT)) ||
nodeType(node, exactMatch(nodeTypes.WHILESTATEMENT)) || nodeType(node, exactMatch(nodeTypes.WHILESTATEMENT)) ||
nodeType(node, exactMatch(nodeTypes.DOWHILESTATEMENT))) && nodeType(node, exactMatch(nodeTypes.DOWHILESTATEMENT))) &&
minNrOfChildren(node, 2) && !nodeType(node.children[1], exactMatch(nodeTypes.BLOCK)) !nodeType(node.children[1], exactMatch(nodeTypes.BLOCK))
} }
/** /**
@ -654,8 +652,8 @@ function isSubScopeStatement (node) {
* @node {ASTNode} some AstNode * @node {ASTNode} some AstNode
* @return {bool} * @return {bool}
*/ */
function isBinaryOpInExpression (node) { function isBinaryOpInExpression (node: ExpressionStatementAstNode) {
return node.nodeType === "ExpressionStatement" && nrOfChildren(node, 1) && isBinaryOperation(node.children[0]) return node.nodeType === "ExpressionStatement" && node.expression.nodeType === "BinaryOperation"
} }
/** /**
@ -663,8 +661,8 @@ function isBinaryOpInExpression (node) {
* @node {ASTNode} some AstNode * @node {ASTNode} some AstNode
* @return {bool} * @return {bool}
*/ */
function isPlusPlusUnaryOperation (node) { function isPlusPlusUnaryOperation (node: UnaryOperationAstNode) {
return nodeType(node, exactMatch(nodeTypes.UNARYOPERATION)) && operator(node, exactMatch(util.escapeRegExp('++'))) return node.operator === '++'
} }
/** /**
@ -672,8 +670,8 @@ function isPlusPlusUnaryOperation (node) {
* @node {ASTNode} some AstNode * @node {ASTNode} some AstNode
* @return {bool} * @return {bool}
*/ */
function isDeleteUnaryOperation (node) { function isDeleteUnaryOperation (node: UnaryOperationAstNode) {
return nodeType(node, exactMatch(nodeTypes.UNARYOPERATION)) && operator(node, exactMatch(util.escapeRegExp('delete'))) return node.operator === 'delete'
} }
/** /**
@ -681,8 +679,8 @@ function isDeleteUnaryOperation (node) {
* @node {ASTNode} some AstNode * @node {ASTNode} some AstNode
* @return {bool} * @return {bool}
*/ */
function isMinusMinusUnaryOperation (node) { function isMinusMinusUnaryOperation (node: UnaryOperationAstNode) {
return nodeType(node, exactMatch(nodeTypes.UNARYOPERATION)) && operator(node, exactMatch(util.escapeRegExp('--'))) return node.operator === '--'
} }
/** /**
@ -690,8 +688,8 @@ function isMinusMinusUnaryOperation (node) {
* @node {ASTNode} some AstNode * @node {ASTNode} some AstNode
* @return {bool} * @return {bool}
*/ */
function isFullyImplementedContract (node) { function isFullyImplementedContract (node: ContractDefinitionAstNode) {
return nodeType(node, exactMatch(nodeTypes.CONTRACTDEFINITION)) && node.attributes.fullyImplemented === true return node.fullyImplemented === true
} }
/** /**
@ -699,8 +697,8 @@ function isFullyImplementedContract (node) {
* @node {ASTNode} some AstNode * @node {ASTNode} some AstNode
* @return {bool} * @return {bool}
*/ */
function isLibrary (node) { function isLibrary (node: ContractDefinitionAstNode) {
return nodeType(node, exactMatch(nodeTypes.CONTRACTDEFINITION)) && node.attributes.isLibrary === true return node.contractKind === 'library'
} }
/** /**
@ -708,8 +706,8 @@ function isLibrary (node) {
* @node {ASTNode} some AstNode * @node {ASTNode} some AstNode
* @return {bool} * @return {bool}
*/ */
function isCallToNonConstLocalFunction (node) { function isCallToNonConstLocalFunction (node: FunctionCallAstNode) {
return isLocalCall(node) && !expressionType(node.children[0], basicRegex.CONSTANTFUNCTIONTYPE) return isLocalCall(node) && !expressionType(node, basicRegex.CONSTANTFUNCTIONTYPE)
} }
/** /**
@ -717,7 +715,7 @@ function isCallToNonConstLocalFunction (node) {
* @node {ASTNode} some AstNode * @node {ASTNode} some AstNode
* @return {bool} * @return {bool}
*/ */
function isLibraryCall (node) { function isLibraryCall (node: MemberAccessAstNode) {
return isMemberAccess(node, basicRegex.FUNCTIONTYPE, undefined, basicRegex.LIBRARYTYPE, undefined) return isMemberAccess(node, basicRegex.FUNCTIONTYPE, undefined, basicRegex.LIBRARYTYPE, undefined)
} }
@ -726,7 +724,7 @@ function isLibraryCall (node) {
* @node {ASTNode} some AstNode * @node {ASTNode} some AstNode
* @return {bool} * @return {bool}
*/ */
function isExternalDirectCall (node) { function isExternalDirectCall (node: MemberAccessAstNode) {
return isMemberAccess(node, basicRegex.EXTERNALFUNCTIONTYPE, undefined, basicRegex.CONTRACTTYPE, undefined) && !isThisLocalCall(node) && !isSuperLocalCall(node) return isMemberAccess(node, basicRegex.EXTERNALFUNCTIONTYPE, undefined, basicRegex.CONTRACTTYPE, undefined) && !isThisLocalCall(node) && !isSuperLocalCall(node)
} }
@ -735,10 +733,8 @@ function isExternalDirectCall (node) {
* @node {ASTNode} some AstNode * @node {ASTNode} some AstNode
* @return {bool} * @return {bool}
*/ */
function isNowAccess (node) { function isNowAccess (node: IdentifierAstNode) {
return nodeType(node, exactMatch(nodeTypes.IDENTIFIER)) && return node.name === "now" && typeDescription(node, exactMatch(basicTypes.UINT))
expressionType(node, exactMatch(basicTypes.UINT)) &&
memName(node, exactMatch('now'))
} }
/** /**
@ -746,7 +742,7 @@ function isNowAccess (node) {
* @node {ASTNode} some AstNode * @node {ASTNode} some AstNode
* @return {bool} * @return {bool}
*/ */
function isBlockTimestampAccess (node) { function isBlockTimestampAccess (node: MemberAccessAstNode) {
return isSpecialVariableAccess(node, specialVariables.BLOCKTIMESTAMP) return isSpecialVariableAccess(node, specialVariables.BLOCKTIMESTAMP)
} }
@ -755,7 +751,7 @@ function isBlockTimestampAccess (node) {
* @node {ASTNode} some AstNode * @node {ASTNode} some AstNode
* @return {bool} * @return {bool}
*/ */
function isBlockBlockHashAccess (node) { function isBlockBlockHashAccess (node: MemberAccessAstNode) {
return isSpecialVariableAccess(node, specialVariables.BLOCKHASH) || isBuiltinFunctionCall(node) && getLocalCallName(node) === 'blockhash' return isSpecialVariableAccess(node, specialVariables.BLOCKHASH) || isBuiltinFunctionCall(node) && getLocalCallName(node) === 'blockhash'
} }
@ -764,7 +760,7 @@ function isBlockBlockHashAccess (node) {
* @node {ASTNode} some AstNode * @node {ASTNode} some AstNode
* @return {bool} * @return {bool}
*/ */
function isThisLocalCall (node) { function isThisLocalCall (node: MemberAccessAstNode) {
return isMemberAccess(node, basicRegex.FUNCTIONTYPE, exactMatch('this'), basicRegex.CONTRACTTYPE, undefined) return isMemberAccess(node, basicRegex.FUNCTIONTYPE, exactMatch('this'), basicRegex.CONTRACTTYPE, undefined)
} }
@ -773,7 +769,7 @@ function isThisLocalCall (node) {
* @node {ASTNode} some AstNode * @node {ASTNode} some AstNode
* @return {bool} * @return {bool}
*/ */
function isSuperLocalCall (node) { function isSuperLocalCall (node: MemberAccessAstNode) {
return isMemberAccess(node, basicRegex.FUNCTIONTYPE, exactMatch('super'), basicRegex.CONTRACTTYPE, undefined) return isMemberAccess(node, basicRegex.FUNCTIONTYPE, exactMatch('super'), basicRegex.CONTRACTTYPE, undefined)
} }
@ -782,13 +778,11 @@ function isSuperLocalCall (node) {
* @node {ASTNode} some AstNode * @node {ASTNode} some AstNode
* @return {bool} * @return {bool}
*/ */
function isLocalCall (node) { function isLocalCall (node: FunctionCallAstNode) {
return nodeType(node, exactMatch(nodeTypes.FUNCTIONCALL)) && return node.kind === 'functionCall' &&
minNrOfChildren(node, 1) && node.expression.nodeType === 'Identifier' &&
nodeType(node.children[0], exactMatch(nodeTypes.IDENTIFIER)) && expressionTypeDescription(node, basicRegex.FUNCTIONTYPE) &&
expressionType(node.children[0], basicRegex.FUNCTIONTYPE) && !expressionTypeDescription(node, basicRegex.FUNCTIONTYPE)
!expressionType(node.children[0], basicRegex.EXTERNALFUNCTIONTYPE) &&
nrOfChildren(node.children[0], 0)
} }
/** /**
@ -811,7 +805,7 @@ function isLowLevelCall (node) {
* @node {ASTNode} some AstNode * @node {ASTNode} some AstNode
* @return {bool} * @return {bool}
*/ */
function isLLSend050 (node) { function isLLSend050 (node: MemberAccessAstNode) {
return isMemberAccess(node, return isMemberAccess(node,
exactMatch(util.escapeRegExp(lowLevelCallTypes.SEND.type)), exactMatch(util.escapeRegExp(lowLevelCallTypes.SEND.type)),
undefined, exactMatch(basicTypes.PAYABLE_ADDRESS), exactMatch(lowLevelCallTypes.SEND.ident)) undefined, exactMatch(basicTypes.PAYABLE_ADDRESS), exactMatch(lowLevelCallTypes.SEND.ident))
@ -822,7 +816,7 @@ function isLLSend050 (node) {
* @node {ASTNode} some AstNode * @node {ASTNode} some AstNode
* @return {bool} * @return {bool}
*/ */
function isLLSend (node) { function isLLSend (node: MemberAccessAstNode) {
return isMemberAccess(node, return isMemberAccess(node,
exactMatch(util.escapeRegExp(lowLevelCallTypes.SEND.type)), exactMatch(util.escapeRegExp(lowLevelCallTypes.SEND.type)),
undefined, exactMatch(basicTypes.ADDRESS), exactMatch(lowLevelCallTypes.SEND.ident)) undefined, exactMatch(basicTypes.ADDRESS), exactMatch(lowLevelCallTypes.SEND.ident))
@ -833,7 +827,7 @@ function isLLSend (node) {
* @node {ASTNode} some AstNode * @node {ASTNode} some AstNode
* @return {bool} * @return {bool}
*/ */
function isLLCall (node) { function isLLCall (node: MemberAccessAstNode) {
return isMemberAccess(node, return isMemberAccess(node,
exactMatch(util.escapeRegExp(lowLevelCallTypes.CALL.type)), exactMatch(util.escapeRegExp(lowLevelCallTypes.CALL.type)),
undefined, exactMatch(basicTypes.ADDRESS), exactMatch(lowLevelCallTypes.CALL.ident)) undefined, exactMatch(basicTypes.ADDRESS), exactMatch(lowLevelCallTypes.CALL.ident))
@ -844,7 +838,7 @@ function isLLCall (node) {
* @node {ASTNode} some AstNode * @node {ASTNode} some AstNode
* @return {bool} * @return {bool}
*/ */
function isLLCall050 (node) { function isLLCall050 (node: MemberAccessAstNode) {
return isMemberAccess(node, return isMemberAccess(node,
exactMatch(util.escapeRegExp(lowLevelCallTypes['CALL-v0.5'].type)), exactMatch(util.escapeRegExp(lowLevelCallTypes['CALL-v0.5'].type)),
undefined, exactMatch(basicTypes.PAYABLE_ADDRESS), exactMatch(lowLevelCallTypes['CALL-v0.5'].ident)) undefined, exactMatch(basicTypes.PAYABLE_ADDRESS), exactMatch(lowLevelCallTypes['CALL-v0.5'].ident))
@ -855,7 +849,7 @@ function isLLCall050 (node) {
* @node {ASTNode} some AstNode * @node {ASTNode} some AstNode
* @return {bool} * @return {bool}
*/ */
function isLLCallcode (node) { function isLLCallcode (node: MemberAccessAstNode) {
return isMemberAccess(node, return isMemberAccess(node,
exactMatch(util.escapeRegExp(lowLevelCallTypes.CALLCODE.type)), exactMatch(util.escapeRegExp(lowLevelCallTypes.CALLCODE.type)),
undefined, exactMatch(basicTypes.ADDRESS), exactMatch(lowLevelCallTypes.CALLCODE.ident)) undefined, exactMatch(basicTypes.ADDRESS), exactMatch(lowLevelCallTypes.CALLCODE.ident))
@ -866,7 +860,7 @@ function isLLCallcode (node) {
* @node {ASTNode} some AstNode * @node {ASTNode} some AstNode
* @return {bool} * @return {bool}
*/ */
function isLLDelegatecall (node) { function isLLDelegatecall (node: MemberAccessAstNode) {
return isMemberAccess(node, return isMemberAccess(node,
exactMatch(util.escapeRegExp(lowLevelCallTypes.DELEGATECALL.type)), exactMatch(util.escapeRegExp(lowLevelCallTypes.DELEGATECALL.type)),
undefined, exactMatch(basicTypes.ADDRESS), exactMatch(lowLevelCallTypes.DELEGATECALL.ident)) undefined, exactMatch(basicTypes.ADDRESS), exactMatch(lowLevelCallTypes.DELEGATECALL.ident))
@ -877,7 +871,7 @@ function isLLDelegatecall (node) {
* @node {ASTNode} some AstNode * @node {ASTNode} some AstNode
* @return {bool} * @return {bool}
*/ */
function isLLDelegatecall050 (node) { function isLLDelegatecall050 (node: MemberAccessAstNode) {
return isMemberAccess(node, return isMemberAccess(node,
exactMatch(util.escapeRegExp(lowLevelCallTypes['DELEGATECALL-v0.5'].type)), exactMatch(util.escapeRegExp(lowLevelCallTypes['DELEGATECALL-v0.5'].type)),
undefined, matches(basicTypes.PAYABLE_ADDRESS, basicTypes.ADDRESS), exactMatch(lowLevelCallTypes['DELEGATECALL-v0.5'].ident)) undefined, matches(basicTypes.PAYABLE_ADDRESS, basicTypes.ADDRESS), exactMatch(lowLevelCallTypes['DELEGATECALL-v0.5'].ident))
@ -888,7 +882,7 @@ function isLLDelegatecall050 (node) {
* @node {ASTNode} some AstNode * @node {ASTNode} some AstNode
* @return {bool} * @return {bool}
*/ */
function isTransfer (node) { function isTransfer (node: MemberAccessAstNode) {
return isMemberAccess(node, return isMemberAccess(node,
exactMatch(util.escapeRegExp(lowLevelCallTypes.TRANSFER.type)), exactMatch(util.escapeRegExp(lowLevelCallTypes.TRANSFER.type)),
undefined, matches(basicTypes.ADDRESS, basicTypes.PAYABLE_ADDRESS), exactMatch(lowLevelCallTypes.TRANSFER.ident)) undefined, matches(basicTypes.ADDRESS, basicTypes.PAYABLE_ADDRESS), exactMatch(lowLevelCallTypes.TRANSFER.ident))
@ -898,13 +892,13 @@ function isStringToBytesConversion (node) {
return isExplicitCast(node, util.escapeRegExp('string *'), util.escapeRegExp('bytes')) return isExplicitCast(node, util.escapeRegExp('string *'), util.escapeRegExp('bytes'))
} }
function isExplicitCast (node, castFromType, castToType) { function isExplicitCast (node: FunctionCallAstNode, castFromType: string, castToType: string) {
return nodeType(node, exactMatch(nodeTypes.FUNCTIONCALL)) && nrOfChildren(node, 2) && return node.kind === "typeConversion" &&
nodeType(node.children[0], exactMatch(nodeTypes.ELEMENTARYTYPENAMEEXPRESSION)) && memName(node.children[0], castToType) && nodeType(node.expression, exactMatch(nodeTypes.ELEMENTARYTYPENAMEEXPRESSION)) && node.expression.typeName.name === castToType &&
nodeType(node.children[1], exactMatch(nodeTypes.IDENTIFIER)) && expressionType(node.children[1], castFromType) nodeType(node.arguments[0], exactMatch(nodeTypes.IDENTIFIER)) && typeDescription(node.arguments[0], castFromType)
} }
function isBytesLengthCheck (node) { function isBytesLengthCheck (node: MemberAccessAstNode) {
return isMemberAccess(node, exactMatch(util.escapeRegExp(basicTypes.UINT)), undefined, util.escapeRegExp('bytes *'), 'length') return isMemberAccess(node, exactMatch(util.escapeRegExp(basicTypes.UINT)), undefined, util.escapeRegExp('bytes *'), 'length')
} }
@ -925,41 +919,48 @@ function isBytesLengthCheck (node) {
* @return {bool} * @return {bool}
* TODO: This should be removed once for loop iterates Over dynamic array fixed * TODO: This should be removed once for loop iterates Over dynamic array fixed
*/ */
function isForLoop (node) { // function isForLoop (node) {
return nodeType(node, exactMatch(nodeTypes.FORSTATEMENT)) // return nodeType(node, exactMatch(nodeTypes.FORSTATEMENT))
} // }
// #################### Complex Node Identification - Private // #################### Complex Node Identification - Private
function isMemberAccess (node: MemberAccessAstNode, retType, accessor, accessorType, memberName) { function isMemberAccess (node: MemberAccessAstNode, retType: string, accessor: string| undefined, accessorType, memberName: string | undefined) {
return nodeType(node, exactMatch(nodeTypes.MEMBERACCESS)) && return nodeType(node, exactMatch(nodeTypes.MEMBERACCESS)) &&
expressionType(node, retType) && expressionType(node, retType) &&
memName(node, memberName) && memName(node, memberName) &&
nrOfChildren(node, 1) &&
memName(node.expression, accessor) && memName(node.expression, accessor) &&
expressionType(node.expression, accessorType) expressionType(node.expression, accessorType)
} }
function isSpecialVariableAccess (node, varType) { function isSpecialVariableAccess (node: MemberAccessAstNode, varType) {
return isMemberAccess(node, exactMatch(util.escapeRegExp(varType.type)), varType.obj, varType.obj, varType.member) return isMemberAccess(node, exactMatch(util.escapeRegExp(varType.type)), varType.obj, varType.obj, varType.member)
} }
// #################### Node Identification Primitives // #################### Node Identification Primitives
function nrOfChildren (node, nr) { // function nrOfChildren (node, nr) {
return (node && (nr === undefined || nr === null)) || (node && nr === 0 && !node.children) || (node && node.children && node.children.length === nr) // return (node && (nr === undefined || nr === null)) || (node && nr === 0 && !node.children) || (node && node.children && node.children.length === nr)
// }
// function minNrOfChildren (node, nr) {
// return (node && (nr === undefined || nr === null)) || (node && nr === 0 && !node.children) || (node && node.children && node.children.length >= nr)
// }
function expressionType (node, typeRegex) {
return new RegExp(typeRegex).test(node.expression.typeDescriptions.typeString)
} }
function minNrOfChildren (node, nr) { function expressionTypeDescription (node, typeRegex) {
return (node && (nr === undefined || nr === null)) || (node && nr === 0 && !node.children) || (node && node.children && node.children.length >= nr) return new RegExp(typeRegex).test(node.expression.typeDescriptions.typeString)
} }
function expressionType (node, typeRegex) { function typeDescription (node, typeRegex) {
return (node && !typeRegex) || (node && node.attributes && new RegExp(typeRegex).test(node.attributes.type)) return new RegExp(typeRegex).test(node.typeDescriptions.typeString)
} }
function nodeType (node, typeRegex) { function nodeType (node, typeRegex) {
return (node && !typeRegex) || (node && new RegExp(typeRegex).test(node.name)) return new RegExp(typeRegex).test(node.nodeType)
} }
function memName (node, memNameRegex) { function memName (node, memNameRegex) {
@ -968,7 +969,7 @@ function memName (node, memNameRegex) {
} }
function operator (node, opRegex) { function operator (node, opRegex) {
return (node && !opRegex) || (node && new RegExp(opRegex).test(node.attributes.operator)) return new RegExp(opRegex).test(node.operator)
} }
// #################### Helpers // #################### Helpers
@ -1021,8 +1022,8 @@ function findFirstSubNodeLTR (node, type) {
} }
const helpers = { const helpers = {
nrOfChildren, // nrOfChildren,
minNrOfChildren, // minNrOfChildren,
expressionType, expressionType,
nodeType, nodeType,
memName, memName,
@ -1104,7 +1105,7 @@ export {
isIntDivision, isIntDivision,
isStringToBytesConversion, isStringToBytesConversion,
isBytesLengthCheck, isBytesLengthCheck,
isForLoop, // isForLoop,
// #################### Trivial Node Identification // #################### Trivial Node Identification
isDeleteUnaryOperation, isDeleteUnaryOperation,

@ -1,16 +1,16 @@
import { default as category } from './categories' import { default as category } from './categories'
import { isThisLocalCall } from './staticAnalysisCommon' import { isThisLocalCall } from './staticAnalysisCommon'
import { default as algorithm } from './algorithmCategories' import { default as algorithm } from './algorithmCategories'
import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, AstNodeLegacy, CompilationResult} from './../../types' import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, AstNodeLegacy, CompilationResult, MemberAccessAstNode} from './../../types'
export default class thisLocal implements AnalyzerModule { export default class thisLocal implements AnalyzerModule {
warningNodes: AstNodeLegacy[] = [] warningNodes: MemberAccessAstNode[] = []
name: string = 'This on local calls: ' name: string = 'This on local calls: '
description: string = 'Invocation of local functions via this' description: string = 'Invocation of local functions via this'
category: ModuleCategory = category.GAS category: ModuleCategory = category.GAS
algorithm: ModuleAlgorithm = algorithm.EXACT algorithm: ModuleAlgorithm = algorithm.EXACT
visit (node: AstNodeLegacy): void { visit (node: MemberAccessAstNode): void {
if (isThisLocalCall(node)) this.warningNodes.push(node) if (isThisLocalCall(node)) this.warningNodes.push(node)
} }

@ -337,7 +337,7 @@ export interface WhileStatementAstNode {
id: number id: number
nodeType: 'WhileStatement' | 'DoWhileStatement' nodeType: 'WhileStatement' | 'DoWhileStatement'
src: string src: string
condition: object condition: any
body: BlockAstNode body: BlockAstNode
} }
@ -346,7 +346,7 @@ export interface ForStatementAstNode {
nodeType: 'ForStatement' nodeType: 'ForStatement'
src: string src: string
initializationExpression: VariableDeclarationStatementAstNode initializationExpression: VariableDeclarationStatementAstNode
condition: object condition: any
loopExpression: ExpressionStatementAstNode loopExpression: ExpressionStatementAstNode
body: BlockAstNode body: BlockAstNode
} }
@ -397,7 +397,7 @@ export interface ExpressionStatementAstNode {
id: number id: number
nodeType: 'ExpressionStatement' nodeType: 'ExpressionStatement'
src: string src: string
expression: object expression: any
} }
interface ExpressionAttributes { interface ExpressionAttributes {
@ -441,7 +441,7 @@ export interface UnaryOperationAstNode extends ExpressionAttributes {
src: string src: string
prefix: boolean prefix: boolean
operator: string operator: string
subExpression: object subExpression: any
} }
export interface BinaryOperationAstNode extends ExpressionAttributes { export interface BinaryOperationAstNode extends ExpressionAttributes {
@ -458,7 +458,7 @@ export interface FunctionCallAstNode extends ExpressionAttributes {
id: number id: number
nodeType: 'FunctionCall' nodeType: 'FunctionCall'
src: string src: string
expression: object expression: any
names: Array<any> names: Array<any>
arguments: object arguments: object
tryCall: boolean tryCall: boolean
@ -481,10 +481,8 @@ export interface NewExpressionAstNode extends ExpressionAttributes {
typeName: UserDefinedTypeNameAstNode | ElementaryTypeNameAstNode typeName: UserDefinedTypeNameAstNode | ElementaryTypeNameAstNode
} }
export interface MemberAccessAstNode extends ExpressionAttributes { export interface MemberAccessAstNode extends CommonAstNode, ExpressionAttributes {
id: number
nodeType: 'MemberAccess' nodeType: 'MemberAccess'
src: string
memberName: string memberName: string
expression: object expression: object
referencedDeclaration: number | null referencedDeclaration: number | null

Loading…
Cancel
Save