Unverified Commit b93b3577 authored by Aniket's avatar Aniket Committed by GitHub

Merge pull request #1242 from Aniket-Engg/fix/#854

[Static analysis] Interaction with different addresses inside the loop handled
parents 7ea3f1df 376baccd
var name = 'Ether transfer in a loop: '
var desc = 'Avoid transferring Ether to multiple addresses in a loop'
var categories = require('./categories')
var common = require('./staticAnalysisCommon')
function etherTransferInLoop () {
this.relevantNodes = []
}
etherTransferInLoop.prototype.visit = function (node) {
if (common.isLoop(node)) {
var transferNodes = []
var loopBlockStartIndex = common.getLoopBlockStartIndex(node)
if (common.isBlock(node.children[loopBlockStartIndex])) {
transferNodes = node.children[loopBlockStartIndex].children
.filter(child => (common.isExpressionStatement(child) &&
child.children[0].name === 'FunctionCall' &&
common.isTransfer(child.children[0].children[0])))
if (transferNodes.length > 0) {
this.relevantNodes.push(...transferNodes)
}
}
}
}
etherTransferInLoop.prototype.report = function (compilationResults) {
return this.relevantNodes.map((node) => {
return {
warning: 'Ether payout should not be done in a loop: Due to the block gas limit, transactions can only consume a certain amount of gas. The number of iterations in a loop can grow beyond the block gas limit which can cause the complete contract to be stalled at a certain point. If required then make sure that number of iterations are low and you trust each address involved.',
location: node.src,
more: 'https://solidity.readthedocs.io/en/latest/security-considerations.html#gas-limit-and-loops'
}
})
}
module.exports = {
name: name,
description: desc,
category: categories.GAS,
Module: etherTransferInLoop
}
......@@ -410,6 +410,16 @@ function getUnAssignedTopLevelBinOps (subScope) {
return subScope.children.filter(isBinaryOpInExpression)
}
function getLoopBlockStartIndex (node) {
if (isLoop(node)) {
if (nodeType(node, exactMatch(nodeTypes.FORSTATEMENT))) {
return 3 // For 'for' loop
} else {
return 1 // For 'while' and 'do-while' loop
}
}
}
// #################### Trivial Node Identification
function isFunctionDefinition (node) {
......@@ -948,6 +958,17 @@ function isBytesLengthCheck (node) {
}
/**
* True if it is a loop
* @node {ASTNode} some AstNode
* @return {bool}
*/
function isLoop (node) {
return nodeType(node, exactMatch(nodeTypes.FORSTATEMENT)) ||
nodeType(node, exactMatch(nodeTypes.WHILESTATEMENT)) ||
nodeType(node, exactMatch(nodeTypes.DOWHILESTATEMENT))
}
/**
* True if it is a 'for' loop
* @node {ASTNode} some AstNode
* @return {bool}
......@@ -1073,6 +1094,7 @@ module.exports = {
getFunctionOrModifierDefinitionParameterPart: getFunctionOrModifierDefinitionParameterPart,
getFunctionOrModifierDefinitionReturnParameterPart: getFunctionOrModifierDefinitionReturnParameterPart,
getUnAssignedTopLevelBinOps: getUnAssignedTopLevelBinOps,
getLoopBlockStartIndex: getLoopBlockStartIndex,
// #################### Complex Node Identification
isDeleteOfDynamicArray: isDeleteOfDynamicArray,
......@@ -1117,6 +1139,7 @@ module.exports = {
isIntDivision: isIntDivision,
isStringToBytesConversion: isStringToBytesConversion,
isBytesLengthCheck: isBytesLengthCheck,
isLoop: isLoop,
isForLoop: isForLoop,
// #################### Trivial Node Identification
......@@ -1136,6 +1159,7 @@ module.exports = {
isNewExpression: isNewExpression,
isReturn: isReturn,
isStatement: isStatement,
isExpressionStatement: isExpressionStatement,
isBlock: isBlock,
// #################### Constants
......
......@@ -1119,6 +1119,686 @@ test('staticAnalysisCommon.getFullQuallyfiedFuncDefinitionIdent', function (t) {
t.throws(() => common.getFullQuallyfiedFuncDefinitionIdent({ name: 'FunctionCall' }, funDef, ['uint256', 'bool']), undefined, 'throws on wrong nodes')
})
test('staticAnalysisCommon.getLoopBlockStartIndex', function (t) {
t.plan(3)
var node1 = {
'children':
[
{
'attributes':
{
'assignments':
[
21
]
},
'children':
[
{
'attributes':
{
'constant': false,
'name': 'i',
'scope': 39,
'stateVariable': false,
'storageLocation': 'default',
'type': 'uint256',
'value': null,
'visibility': 'internal'
},
'children':
[
{
'attributes':
{
'name': 'uint',
'type': 'uint256'
},
'id': 20,
'name': 'ElementaryTypeName',
'src': '207:4:0'
}
],
'id': 21,
'name': 'VariableDeclaration',
'src': '207:6:0'
},
{
'attributes':
{
'argumentTypes': null,
'overloadedDeclarations':
[
null
],
'referencedDeclaration': 17,
'type': 'uint256',
'value': 'index'
},
'id': 22,
'name': 'Identifier',
'src': '216:5:0'
}
],
'id': 23,
'name': 'VariableDeclarationStatement',
'src': '207:14:0'
},
{
'attributes':
{
'argumentTypes': null,
'commonType':
{
'typeIdentifier': 't_uint256',
'typeString': 'uint256'
},
'isConstant': false,
'isLValue': false,
'isPure': false,
'lValueRequested': false,
'operator': '<',
'type': 'bool'
},
'children':
[
{
'attributes':
{
'argumentTypes': null,
'overloadedDeclarations':
[
null
],
'referencedDeclaration': 21,
'type': 'uint256',
'value': 'i'
},
'id': 24,
'name': 'Identifier',
'src': '223:1:0'
},
{
'attributes':
{
'argumentTypes': null,
'hexvalue': '3130',
'isConstant': false,
'isLValue': false,
'isPure': true,
'lValueRequested': false,
'subdenomination': null,
'token': 'number',
'type': 'int_const 10',
'value': '10'
},
'id': 25,
'name': 'Literal',
'src': '227:2:0'
}
],
'id': 26,
'name': 'BinaryOperation',
'src': '223:6:0'
},
{
'children':
[
{
'attributes':
{
'argumentTypes': null,
'isConstant': false,
'isLValue': false,
'isPure': false,
'lValueRequested': false,
'operator': '++',
'prefix': false,
'type': 'uint256'
},
'children':
[
{
'attributes':
{
'argumentTypes': null,
'overloadedDeclarations':
[
null
],
'referencedDeclaration': 21,
'type': 'uint256',
'value': 'i'
},
'id': 27,
'name': 'Identifier',
'src': '231:1:0'
}
],
'id': 28,
'name': 'UnaryOperation',
'src': '231:3:0'
}
],
'id': 29,
'name': 'ExpressionStatement',
'src': '231:3:0'
},
{
'children':
[
{
'children':
[
{
'attributes':
{
'argumentTypes': null,
'isConstant': false,
'isLValue': false,
'isPure': false,
'isStructConstructorCall': false,
'lValueRequested': false,
'names':
[
null
],
'type': 'uint256',
'type_conversion': false
},
'children':
[
{
'attributes':
{
'argumentTypes':
[
{
'typeIdentifier': 't_uint256',
'typeString': 'uint256'
}
],
'isConstant': false,
'isLValue': false,
'isPure': false,
'lValueRequested': false,
'member_name': 'push',
'referencedDeclaration': null,
'type': 'function (uint256) returns (uint256)'
},
'children':
[
{
'attributes':
{
'argumentTypes': null,
'overloadedDeclarations':
[
null
],
'referencedDeclaration': 4,
'type': 'uint256[] storage ref',
'value': 'array'
},
'id': 30,
'name': 'Identifier',
'src': '250:5:0'
}
],
'id': 32,
'name': 'MemberAccess',
'src': '250:10:0'
},
{
'attributes':
{
'argumentTypes': null,
'overloadedDeclarations':
[
null
],
'referencedDeclaration': 21,
'type': 'uint256',
'value': 'i'
},
'id': 33,
'name': 'Identifier',
'src': '261:1:0'
}
],
'id': 34,
'name': 'FunctionCall',
'src': '250:13:0'
}
],
'id': 35,
'name': 'ExpressionStatement',
'src': '250:13:0'
}
],
'id': 36,
'name': 'Block',
'src': '236:38:0'
}
],
'id': 37,
'name': 'ForStatement',
'src': '202:72:0'
}
var node2 = {
'children':
[
{
'attributes':
{
'argumentTypes': null,
'commonType':
{
'typeIdentifier': 't_uint256',
'typeString': 'uint256'
},
'isConstant': false,
'isLValue': false,
'isPure': false,
'lValueRequested': false,
'operator': '<',
'type': 'bool'
},
'children':
[
{
'attributes':
{
'argumentTypes': null,
'overloadedDeclarations':
[
null
],
'referencedDeclaration': 69,
'type': 'uint256',
'value': 'i'
},
'id': 82,
'name': 'Identifier',
'src': '592:1:0'
},
{
'attributes':
{
'argumentTypes': null,
'hexvalue': '3130',
'isConstant': false,
'isLValue': false,
'isPure': true,
'lValueRequested': false,
'subdenomination': null,
'token': 'number',
'type': 'int_const 10',
'value': '10'
},
'id': 83,
'name': 'Literal',
'src': '596:2:0'
}
],
'id': 84,
'name': 'BinaryOperation',
'src': '592:6:0'
},
{
'children':
[
{
'children':
[
{
'attributes':
{
'argumentTypes': null,
'isConstant': false,
'isLValue': false,
'isPure': false,
'isStructConstructorCall': false,
'lValueRequested': false,
'names':
[
null
],
'type': 'uint256',
'type_conversion': false
},
'children':
[
{
'attributes':
{
'argumentTypes':
[
{
'typeIdentifier': 't_uint256',
'typeString': 'uint256'
}
],
'isConstant': false,
'isLValue': false,
'isPure': false,
'lValueRequested': false,
'member_name': 'push',
'referencedDeclaration': null,
'type': 'function (uint256) returns (uint256)'
},
'children':
[
{
'attributes':
{
'argumentTypes': null,
'overloadedDeclarations':
[
null
],
'referencedDeclaration': 4,
'type': 'uint256[] storage ref',
'value': 'array'
},
'id': 72,
'name': 'Identifier',
'src': '544:5:0'
}
],
'id': 74,
'name': 'MemberAccess',
'src': '544:10:0'
},
{
'attributes':
{
'argumentTypes': null,
'overloadedDeclarations':
[
null
],
'referencedDeclaration': 69,
'type': 'uint256',
'value': 'i'
},
'id': 75,
'name': 'Identifier',
'src': '555:1:0'
}
],
'id': 76,
'name': 'FunctionCall',
'src': '544:13:0'
}
],
'id': 77,
'name': 'ExpressionStatement',
'src': '544:13:0'
},
{
'children':
[
{
'attributes':
{
'argumentTypes': null,
'isConstant': false,
'isLValue': false,
'isPure': false,
'lValueRequested': false,
'operator': '++',
'prefix': false,
'type': 'uint256'
},
'children':
[
{
'attributes':
{
'argumentTypes': null,
'overloadedDeclarations':
[
null
],
'referencedDeclaration': 69,
'type': 'uint256',
'value': 'i'
},
'id': 78,
'name': 'Identifier',
'src': '571:1:0'
}
],
'id': 79,
'name': 'UnaryOperation',
'src': '571:3:0'
}
],
'id': 80,
'name': 'ExpressionStatement',
'src': '571:3:0'
}
],
'id': 81,
'name': 'Block',
'src': '530:55:0'
}
],
'id': 85,
'name': 'DoWhileStatement',
'src': '528:72:0'
}
var node3 = {
'children':
[
{
'attributes':
{
'argumentTypes': null,
'commonType':
{
'typeIdentifier': 't_uint256',
'typeString': 'uint256'
},
'isConstant': false,
'isLValue': false,
'isPure': false,
'lValueRequested': false,
'operator': '<',
'type': 'bool'
},
'children':
[
{
'attributes':
{
'argumentTypes': null,
'overloadedDeclarations':
[
null
],
'referencedDeclaration': 45,
'type': 'uint256',
'value': 'i'
},
'id': 48,
'name': 'Identifier',
'src': '372:1:0'
},
{
'attributes':
{
'argumentTypes': null,
'hexvalue': '3130',
'isConstant': false,
'isLValue': false,
'isPure': true,
'lValueRequested': false,
'subdenomination': null,
'token': 'number',
'type': 'int_const 10',
'value': '10'
},
'id': 49,
'name': 'Literal',
'src': '376:2:0'
}
],
'id': 50,
'name': 'BinaryOperation',
'src': '372:6:0'
},
{
'children':
[
{
'children':
[
{
'attributes':
{
'argumentTypes': null,
'isConstant': false,
'isLValue': false,
'isPure': false,
'isStructConstructorCall': false,
'lValueRequested': false,
'names':
[
null
],
'type': 'uint256',
'type_conversion': false
},
'children':
[
{
'attributes':
{
'argumentTypes':
[
{
'typeIdentifier': 't_uint256',
'typeString': 'uint256'
}
],
'isConstant': false,
'isLValue': false,
'isPure': false,
'lValueRequested': false,
'member_name': 'push',
'referencedDeclaration': null,
'type': 'function (uint256) returns (uint256)'
},
'children':
[
{
'attributes':
{
'argumentTypes': null,
'overloadedDeclarations':
[
null
],
'referencedDeclaration': 4,
'type': 'uint256[] storage ref',
'value': 'array'
},
'id': 51,
'name': 'Identifier',
'src': '394:5:0'
}
],
'id': 53,
'name': 'MemberAccess',
'src': '394:10:0'
},
{
'attributes':
{
'argumentTypes': null,
'overloadedDeclarations':
[
null
],
'referencedDeclaration': 45,
'type': 'uint256',
'value': 'i'
},
'id': 54,
'name': 'Identifier',
'src': '405:1:0'
}
],
'id': 55,
'name': 'FunctionCall',
'src': '394:13:0'
}
],
'id': 56,
'name': 'ExpressionStatement',
'src': '394:13:0'
},
{
'children':
[
{
'attributes':
{
'argumentTypes': null,
'isConstant': false,
'isLValue': false,
'isPure': false,
'lValueRequested': false,
'operator': '++',
'prefix': false,
'type': 'uint256'
},
'children':
[
{
'attributes':
{
'argumentTypes': null,
'overloadedDeclarations':
[
null
],
'referencedDeclaration': 45,
'type': 'uint256',
'value': 'i'
},
'id': 57,
'name': 'Identifier',
'src': '421:1:0'
}
],
'id': 58,
'name': 'UnaryOperation',
'src': '421:3:0'
}
],
'id': 59,
'name': 'ExpressionStatement',
'src': '421:3:0'
}
],
'id': 60,
'name': 'Block',
'src': '380:55:0'
}
],
'id': 61,
'name': 'WhileStatement',
'src': '365:70:0'
}
t.equal(common.getLoopBlockStartIndex(node1), 3) // 'for' loop
t.equal(common.getLoopBlockStartIndex(node2), 1) // 'do-while' loop
t.equal(common.getLoopBlockStartIndex(node3), 1) // 'while' loop
})
// #################### Trivial Node Identification
test('staticAnalysisCommon.isFunctionDefinition', function (t) {
......@@ -1204,9 +1884,689 @@ test('staticAnalysisCommon.isInlineAssembly', function (t) {
var node2 = { name: 'MemberAccess' }
var node3 = { name: 'InlineAssemblyBLABLA' }
t.ok(common.isInlineAssembly(node1), 'is exact match should work')
t.notOk(common.isInlineAssembly(node2), 'different node should not work')
t.notOk(common.isInlineAssembly(node3), 'substring should not work')
t.ok(common.isInlineAssembly(node1), 'is exact match should work')
t.notOk(common.isInlineAssembly(node2), 'different node should not work')
t.notOk(common.isInlineAssembly(node3), 'substring should not work')
})
test('staticAnalysisCommon.isLoop', function (t) {
t.plan(3)
var node1 = {
'children':
[
{
'attributes':
{
'assignments':
[
21
]
},
'children':
[
{
'attributes':
{
'constant': false,
'name': 'i',
'scope': 39,
'stateVariable': false,
'storageLocation': 'default',
'type': 'uint256',
'value': null,
'visibility': 'internal'
},
'children':
[
{
'attributes':
{
'name': 'uint',
'type': 'uint256'
},
'id': 20,
'name': 'ElementaryTypeName',
'src': '207:4:0'
}
],
'id': 21,
'name': 'VariableDeclaration',
'src': '207:6:0'
},
{
'attributes':
{
'argumentTypes': null,
'overloadedDeclarations':
[
null
],
'referencedDeclaration': 17,
'type': 'uint256',
'value': 'index'
},
'id': 22,
'name': 'Identifier',
'src': '216:5:0'
}
],
'id': 23,
'name': 'VariableDeclarationStatement',
'src': '207:14:0'
},
{
'attributes':
{
'argumentTypes': null,
'commonType':
{
'typeIdentifier': 't_uint256',
'typeString': 'uint256'
},
'isConstant': false,
'isLValue': false,
'isPure': false,
'lValueRequested': false,
'operator': '<',
'type': 'bool'
},
'children':
[
{
'attributes':
{
'argumentTypes': null,
'overloadedDeclarations':
[
null
],
'referencedDeclaration': 21,
'type': 'uint256',
'value': 'i'
},
'id': 24,
'name': 'Identifier',
'src': '223:1:0'
},
{
'attributes':
{
'argumentTypes': null,
'hexvalue': '3130',
'isConstant': false,
'isLValue': false,
'isPure': true,
'lValueRequested': false,
'subdenomination': null,
'token': 'number',
'type': 'int_const 10',
'value': '10'
},
'id': 25,
'name': 'Literal',
'src': '227:2:0'
}
],
'id': 26,
'name': 'BinaryOperation',
'src': '223:6:0'
},
{
'children':
[
{
'attributes':
{
'argumentTypes': null,
'isConstant': false,
'isLValue': false,
'isPure': false,
'lValueRequested': false,
'operator': '++',
'prefix': false,
'type': 'uint256'
},
'children':
[
{
'attributes':
{
'argumentTypes': null,
'overloadedDeclarations':
[
null
],
'referencedDeclaration': 21,
'type': 'uint256',
'value': 'i'
},
'id': 27,
'name': 'Identifier',
'src': '231:1:0'
}
],
'id': 28,
'name': 'UnaryOperation',
'src': '231:3:0'
}
],
'id': 29,
'name': 'ExpressionStatement',
'src': '231:3:0'
},
{
'children':
[
{
'children':
[
{
'attributes':
{
'argumentTypes': null,
'isConstant': false,
'isLValue': false,
'isPure': false,
'isStructConstructorCall': false,
'lValueRequested': false,
'names':
[
null
],
'type': 'uint256',
'type_conversion': false
},
'children':
[
{
'attributes':
{
'argumentTypes':
[
{
'typeIdentifier': 't_uint256',
'typeString': 'uint256'
}
],
'isConstant': false,
'isLValue': false,
'isPure': false,
'lValueRequested': false,
'member_name': 'push',
'referencedDeclaration': null,
'type': 'function (uint256) returns (uint256)'
},
'children':
[
{
'attributes':
{
'argumentTypes': null,
'overloadedDeclarations':
[
null
],
'referencedDeclaration': 4,
'type': 'uint256[] storage ref',
'value': 'array'
},
'id': 30,
'name': 'Identifier',
'src': '250:5:0'
}
],
'id': 32,
'name': 'MemberAccess',
'src': '250:10:0'
},
{
'attributes':
{
'argumentTypes': null,
'overloadedDeclarations':
[
null
],
'referencedDeclaration': 21,
'type': 'uint256',
'value': 'i'
},
'id': 33,
'name': 'Identifier',
'src': '261:1:0'
}
],
'id': 34,
'name': 'FunctionCall',
'src': '250:13:0'
}
],
'id': 35,
'name': 'ExpressionStatement',
'src': '250:13:0'
}
],
'id': 36,
'name': 'Block',
'src': '236:38:0'
}
],
'id': 37,
'name': 'ForStatement',
'src': '202:72:0'
}
var node2 = {
'children':
[
{
'attributes':
{
'argumentTypes': null,
'commonType':
{
'typeIdentifier': 't_uint256',
'typeString': 'uint256'
},
'isConstant': false,
'isLValue': false,
'isPure': false,
'lValueRequested': false,
'operator': '<',
'type': 'bool'
},
'children':
[
{
'attributes':
{
'argumentTypes': null,
'overloadedDeclarations':
[
null
],
'referencedDeclaration': 69,
'type': 'uint256',
'value': 'i'
},
'id': 82,
'name': 'Identifier',
'src': '592:1:0'
},
{
'attributes':
{
'argumentTypes': null,
'hexvalue': '3130',
'isConstant': false,
'isLValue': false,
'isPure': true,
'lValueRequested': false,
'subdenomination': null,
'token': 'number',
'type': 'int_const 10',
'value': '10'
},
'id': 83,
'name': 'Literal',
'src': '596:2:0'
}
],
'id': 84,
'name': 'BinaryOperation',
'src': '592:6:0'
},
{
'children':
[
{
'children':
[
{
'attributes':
{
'argumentTypes': null,
'isConstant': false,
'isLValue': false,
'isPure': false,
'isStructConstructorCall': false,
'lValueRequested': false,
'names':
[
null
],
'type': 'uint256',
'type_conversion': false
},
'children':
[
{
'attributes':
{
'argumentTypes':
[
{
'typeIdentifier': 't_uint256',
'typeString': 'uint256'
}
],
'isConstant': false,
'isLValue': false,
'isPure': false,
'lValueRequested': false,
'member_name': 'push',
'referencedDeclaration': null,
'type': 'function (uint256) returns (uint256)'
},
'children':
[
{
'attributes':
{
'argumentTypes': null,
'overloadedDeclarations':
[
null
],
'referencedDeclaration': 4,
'type': 'uint256[] storage ref',
'value': 'array'
},
'id': 72,
'name': 'Identifier',
'src': '544:5:0'
}
],
'id': 74,
'name': 'MemberAccess',
'src': '544:10:0'
},
{
'attributes':
{
'argumentTypes': null,
'overloadedDeclarations':
[
null
],
'referencedDeclaration': 69,
'type': 'uint256',
'value': 'i'
},
'id': 75,
'name': 'Identifier',
'src': '555:1:0'
}
],
'id': 76,
'name': 'FunctionCall',
'src': '544:13:0'
}
],
'id': 77,
'name': 'ExpressionStatement',
'src': '544:13:0'
},
{
'children':
[
{
'attributes':
{
'argumentTypes': null,
'isConstant': false,
'isLValue': false,
'isPure': false,
'lValueRequested': false,
'operator': '++',
'prefix': false,
'type': 'uint256'
},
'children':
[
{
'attributes':
{
'argumentTypes': null,
'overloadedDeclarations':
[
null
],
'referencedDeclaration': 69,
'type': 'uint256',
'value': 'i'
},
'id': 78,
'name': 'Identifier',
'src': '571:1:0'
}
],
'id': 79,
'name': 'UnaryOperation',
'src': '571:3:0'
}
],
'id': 80,
'name': 'ExpressionStatement',
'src': '571:3:0'
}
],
'id': 81,
'name': 'Block',
'src': '530:55:0'
}
],
'id': 85,
'name': 'DoWhileStatement',
'src': '528:72:0'
}
var node3 = {
'children':
[
{
'attributes':
{
'argumentTypes': null,
'commonType':
{
'typeIdentifier': 't_uint256',
'typeString': 'uint256'
},
'isConstant': false,
'isLValue': false,
'isPure': false,
'lValueRequested': false,
'operator': '<',
'type': 'bool'
},
'children':
[
{
'attributes':
{
'argumentTypes': null,
'overloadedDeclarations':
[
null
],
'referencedDeclaration': 45,
'type': 'uint256',
'value': 'i'
},
'id': 48,
'name': 'Identifier',
'src': '372:1:0'
},
{
'attributes':
{
'argumentTypes': null,
'hexvalue': '3130',
'isConstant': false,
'isLValue': false,
'isPure': true,
'lValueRequested': false,
'subdenomination': null,
'token': 'number',
'type': 'int_const 10',
'value': '10'
},
'id': 49,
'name': 'Literal',
'src': '376:2:0'
}
],
'id': 50,
'name': 'BinaryOperation',
'src': '372:6:0'
},
{
'children':
[
{
'children':
[
{
'attributes':
{
'argumentTypes': null,
'isConstant': false,
'isLValue': false,
'isPure': false,
'isStructConstructorCall': false,
'lValueRequested': false,
'names':
[
null
],
'type': 'uint256',
'type_conversion': false
},
'children':
[
{
'attributes':
{
'argumentTypes':
[
{
'typeIdentifier': 't_uint256',
'typeString': 'uint256'
}
],
'isConstant': false,
'isLValue': false,
'isPure': false,
'lValueRequested': false,
'member_name': 'push',
'referencedDeclaration': null,
'type': 'function (uint256) returns (uint256)'
},
'children':
[
{
'attributes':
{
'argumentTypes': null,
'overloadedDeclarations':
[
null
],
'referencedDeclaration': 4,
'type': 'uint256[] storage ref',
'value': 'array'
},
'id': 51,
'name': 'Identifier',
'src': '394:5:0'
}
],
'id': 53,
'name': 'MemberAccess',
'src': '394:10:0'
},
{
'attributes':
{
'argumentTypes': null,
'overloadedDeclarations':
[
null
],
'referencedDeclaration': 45,
'type': 'uint256',
'value': 'i'
},
'id': 54,
'name': 'Identifier',
'src': '405:1:0'
}
],
'id': 55,
'name': 'FunctionCall',
'src': '394:13:0'
}
],
'id': 56,
'name': 'ExpressionStatement',
'src': '394:13:0'
},
{
'children':
[
{
'attributes':
{
'argumentTypes': null,
'isConstant': false,
'isLValue': false,
'isPure': false,
'lValueRequested': false,
'operator': '++',
'prefix': false,
'type': 'uint256'
},
'children':
[
{
'attributes':
{
'argumentTypes': null,
'overloadedDeclarations':
[
null
],
'referencedDeclaration': 45,
'type': 'uint256',
'value': 'i'
},
'id': 57,
'name': 'Identifier',
'src': '421:1:0'
}
],
'id': 58,
'name': 'UnaryOperation',
'src': '421:3:0'
}
],
'id': 59,
'name': 'ExpressionStatement',
'src': '421:3:0'
}
],
'id': 60,
'name': 'Block',
'src': '380:55:0'
}
],
'id': 61,
'name': 'WhileStatement',
'src': '365:70:0'
}
t.equal(common.isLoop(node1), true)
t.equal(common.isLoop(node2), true)
t.equal(common.isLoop(node3), true)
})
// #################### Complex Node Identification
......
......@@ -37,6 +37,7 @@ var testFiles = [
'intDivisionTruncate.sol',
'ERC20.sol',
'stringBytesLength.sol',
'etherTransferInLoop.sol',
'forLoopIteratesOverDynamicArray.sol'
]
......@@ -77,6 +78,7 @@ test('Integration test thisLocal.js', function (t) {
'intDivisionTruncate.sol': 0,
'ERC20.sol': 0,
'stringBytesLength.sol': 0,
'etherTransferInLoop.sol': 0,
'forLoopIteratesOverDynamicArray.sol': 0
}
......@@ -115,6 +117,7 @@ test('Integration test checksEffectsInteraction.js', function (t) {
'intDivisionTruncate.sol': 0,
'ERC20.sol': 0,
'stringBytesLength.sol': 0,
'etherTransferInLoop.sol': 0,
'forLoopIteratesOverDynamicArray.sol': 0
}
......@@ -153,6 +156,7 @@ test('Integration test constantFunctions.js', function (t) {
'intDivisionTruncate.sol': 0,
'ERC20.sol': 0,
'stringBytesLength.sol': 0,
'etherTransferInLoop.sol': 0,
'forLoopIteratesOverDynamicArray.sol': 0
}
......@@ -191,6 +195,7 @@ test('Integration test inlineAssembly.js', function (t) {
'intDivisionTruncate.sol': 0,
'ERC20.sol': 0,
'stringBytesLength.sol': 0,
'etherTransferInLoop.sol': 0,
'forLoopIteratesOverDynamicArray.sol': 0
}
......@@ -229,6 +234,7 @@ test('Integration test txOrigin.js', function (t) {
'intDivisionTruncate.sol': 0,
'ERC20.sol': 0,
'stringBytesLength.sol': 0,
'etherTransferInLoop.sol': 0,
'forLoopIteratesOverDynamicArray.sol': 0
}
......@@ -267,6 +273,7 @@ test('Integration test gasCosts.js', function (t) {
'intDivisionTruncate.sol': 1,
'ERC20.sol': 2,
'stringBytesLength.sol': 1,
'etherTransferInLoop.sol': 3,
'forLoopIteratesOverDynamicArray.sol': 1
}
......@@ -305,6 +312,7 @@ test('Integration test similarVariableNames.js', function (t) {
'intDivisionTruncate.sol': 0,
'ERC20.sol': 0,
'stringBytesLength.sol': 0,
'etherTransferInLoop.sol': 0,
'forLoopIteratesOverDynamicArray.sol': 0
}
......@@ -343,6 +351,7 @@ test('Integration test inlineAssembly.js', function (t) {
'intDivisionTruncate.sol': 0,
'ERC20.sol': 0,
'stringBytesLength.sol': 0,
'etherTransferInLoop.sol': 0,
'forLoopIteratesOverDynamicArray.sol': 0
}
......@@ -381,6 +390,7 @@ test('Integration test blockTimestamp.js', function (t) {
'intDivisionTruncate.sol': 0,
'ERC20.sol': 0,
'stringBytesLength.sol': 0,
'etherTransferInLoop.sol': 0,
'forLoopIteratesOverDynamicArray.sol': 0
}
......@@ -419,6 +429,7 @@ test('Integration test lowLevelCalls.js', function (t) {
'intDivisionTruncate.sol': 0,
'ERC20.sol': 0,
'stringBytesLength.sol': 0,
'etherTransferInLoop.sol': 0,
'forLoopIteratesOverDynamicArray.sol': 0
}
......@@ -457,6 +468,7 @@ test('Integration test blockBlockhash.js', function (t) {
'intDivisionTruncate.sol': 0,
'ERC20.sol': 0,
'stringBytesLength.sol': 0,
'etherTransferInLoop.sol': 0,
'forLoopIteratesOverDynamicArray.sol': 0
}
......@@ -495,6 +507,7 @@ test('Integration test noReturn.js', function (t) {
'intDivisionTruncate.sol': 0,
'ERC20.sol': 0,
'stringBytesLength.sol': 0,
'etherTransferInLoop.sol': 0,
'forLoopIteratesOverDynamicArray.sol': 0
}
......@@ -533,6 +546,7 @@ test('Integration test selfdestruct.js', function (t) {
'ERC20.sol': 0,
'intDivisionTruncate.sol': 5,
'stringBytesLength.sol': 0,
'etherTransferInLoop.sol': 0,
'forLoopIteratesOverDynamicArray.sol': 0
}
......@@ -571,6 +585,7 @@ test('Integration test guardConditions.js', function (t) {
'intDivisionTruncate.sol': 1,
'ERC20.sol': 0,
'stringBytesLength.sol': 0,
'etherTransferInLoop.sol': 0,
'forLoopIteratesOverDynamicArray.sol': 0
}
......@@ -609,6 +624,7 @@ test('Integration test deleteDynamicArrays.js', function (t) {
'intDivisionTruncate.sol': 0,
'ERC20.sol': 0,
'stringBytesLength.sol': 0,
'etherTransferInLoop.sol': 0,
'forLoopIteratesOverDynamicArray.sol': 0
}
......@@ -647,6 +663,7 @@ test('Integration test deleteFromDynamicArray.js', function (t) {
'intDivisionTruncate.sol': 0,
'ERC20.sol': 0,
'stringBytesLength.sol': 0,
'etherTransferInLoop.sol': 0,
'forLoopIteratesOverDynamicArray.sol': 0
}
......@@ -685,6 +702,7 @@ test('Integration test assignAndCompare.js', function (t) {
'intDivisionTruncate.sol': 0,
'ERC20.sol': 0,
'stringBytesLength.sol': 0,
'etherTransferInLoop.sol': 0,
'forLoopIteratesOverDynamicArray.sol': 0
}
......@@ -723,6 +741,7 @@ test('Integration test intDivisionTruncate.js', function (t) {
'intDivisionTruncate.sol': 2,
'ERC20.sol': 0,
'stringBytesLength.sol': 0,
'etherTransferInLoop.sol': 0,
'forLoopIteratesOverDynamicArray.sol': 0
}
......@@ -761,6 +780,7 @@ test('Integration test erc20Decimal.js', function (t) {
'intDivisionTruncate.sol': 0,
'ERC20.sol': 1,
'stringBytesLength.sol': 0,
'etherTransferInLoop.sol': 0,
'forLoopIteratesOverDynamicArray.sol': 0
}
......@@ -799,6 +819,7 @@ test('Integration test stringBytesLength.js', function (t) {
'intDivisionTruncate.sol': 0,
'ERC20.sol': 0,
'stringBytesLength.sol': 1,
'etherTransferInLoop.sol': 0,
'forLoopIteratesOverDynamicArray.sol': 0
}
......@@ -807,6 +828,45 @@ test('Integration test stringBytesLength.js', function (t) {
})
})
test('Integration test etherTransferInLoop.js', function (t) {
t.plan(testFiles.length)
var module = require('../../src/solidity-analyzer/modules/etherTransferInLoop')
var lengthCheck = {
'KingOfTheEtherThrone.sol': 0,
'assembly.sol': 0,
'ballot.sol': 0,
'ballot_reentrant.sol': 0,
'ballot_withoutWarnings.sol': 0,
'cross_contract.sol': 0,
'inheritance.sol': 0,
'modifier1.sol': 0,
'modifier2.sol': 0,
'notReentrant.sol': 0,
'structReentrant.sol': 0,
'thisLocal.sol': 0,
'globals.sol': 0,
'library.sol': 0,
'transfer.sol': 0,
'ctor.sol': 0,
'forgottenReturn.sol': 0,
'selfdestruct.sol': 0,
'deleteDynamicArray.sol': 0,
'deleteFromDynamicArray.sol': 0,
'blockLevelCompare.sol': 0,
'intDivisionTruncate.sol': 0,
'ERC20.sol': 0,
'stringBytesLength.sol': 0,
'etherTransferInLoop.sol': 3,
'forLoopIteratesOverDynamicArray.sol': 0
}
runModuleOnFiles(module, t, (file, report) => {
t.equal(report.length, lengthCheck[file], `${file} has right amount of etherTransferInLoop warnings`)
})
})
test('Integration test forLoopIteratesOverDynamicArray.js', function (t) {
t.plan(testFiles.length)
......@@ -837,6 +897,7 @@ test('Integration test forLoopIteratesOverDynamicArray.js', function (t) {
'intDivisionTruncate.sol': 0,
'ERC20.sol': 0,
'stringBytesLength.sol': 0,
'etherTransferInLoop.sol': 0,
'forLoopIteratesOverDynamicArray.sol': 1
}
......
......@@ -37,6 +37,7 @@ var testFiles = [
'intDivisionTruncate.sol',
'ERC20.sol',
'stringBytesLength.sol',
'etherTransferInLoop.sol',
'forLoopIteratesOverDynamicArray.sol'
]
......@@ -77,6 +78,7 @@ test('Integration test thisLocal.js', function (t) {
'intDivisionTruncate.sol': 0,
'ERC20.sol': 0,
'stringBytesLength.sol': 0,
'etherTransferInLoop.sol': 0,
'forLoopIteratesOverDynamicArray.sol': 0
}
......@@ -115,6 +117,7 @@ test('Integration test checksEffectsInteraction.js', function (t) {
'intDivisionTruncate.sol': 0,
'ERC20.sol': 0,
'stringBytesLength.sol': 0,
'etherTransferInLoop.sol': 0,
'forLoopIteratesOverDynamicArray.sol': 0
}
......@@ -153,6 +156,7 @@ test('Integration test constantFunctions.js', function (t) {
'intDivisionTruncate.sol': 0,
'ERC20.sol': 0,
'stringBytesLength.sol': 0,
'etherTransferInLoop.sol': 0,
'forLoopIteratesOverDynamicArray.sol': 0
}
......@@ -191,6 +195,7 @@ test('Integration test inlineAssembly.js', function (t) {
'intDivisionTruncate.sol': 0,
'ERC20.sol': 0,
'stringBytesLength.sol': 0,
'etherTransferInLoop.sol': 0,
'forLoopIteratesOverDynamicArray.sol': 0
}
......@@ -229,6 +234,7 @@ test('Integration test txOrigin.js', function (t) {
'intDivisionTruncate.sol': 0,
'ERC20.sol': 0,
'stringBytesLength.sol': 0,
'etherTransferInLoop.sol': 0,
'forLoopIteratesOverDynamicArray.sol': 0
}
......@@ -267,6 +273,7 @@ test('Integration test gasCosts.js', function (t) {
'intDivisionTruncate.sol': 1,
'ERC20.sol': 2,
'stringBytesLength.sol': 1,
'etherTransferInLoop.sol': 3,
'forLoopIteratesOverDynamicArray.sol': 1
}
......@@ -305,6 +312,7 @@ test('Integration test similarVariableNames.js', function (t) {
'intDivisionTruncate.sol': 0,
'ERC20.sol': 0,
'stringBytesLength.sol': 0,
'etherTransferInLoop.sol': 0,
'forLoopIteratesOverDynamicArray.sol': 0
}
......@@ -343,6 +351,7 @@ test('Integration test inlineAssembly.js', function (t) {
'intDivisionTruncate.sol': 0,
'ERC20.sol': 0,
'stringBytesLength.sol': 0,
'etherTransferInLoop.sol': 0,
'forLoopIteratesOverDynamicArray.sol': 0
}
......@@ -381,6 +390,7 @@ test('Integration test blockTimestamp.js', function (t) {
'intDivisionTruncate.sol': 0,
'ERC20.sol': 0,
'stringBytesLength.sol': 0,
'etherTransferInLoop.sol': 0,
'forLoopIteratesOverDynamicArray.sol': 0
}
......@@ -419,6 +429,7 @@ test('Integration test lowLevelCalls.js', function (t) {
'intDivisionTruncate.sol': 0,
'ERC20.sol': 0,
'stringBytesLength.sol': 0,
'etherTransferInLoop.sol': 0,
'forLoopIteratesOverDynamicArray.sol': 0
}
......@@ -457,6 +468,7 @@ test('Integration test blockBlockhash.js', function (t) {
'intDivisionTruncate.sol': 0,
'ERC20.sol': 0,
'stringBytesLength.sol': 0,
'etherTransferInLoop.sol': 0,
'forLoopIteratesOverDynamicArray.sol': 0
}
......@@ -538,6 +550,7 @@ test('Integration test selfdestruct.js', function (t) {
'ERC20.sol': 0,
'intDivisionTruncate.sol': 5,
'stringBytesLength.sol': 0,
'etherTransferInLoop.sol': 0,
'forLoopIteratesOverDynamicArray.sol': 0
}
......@@ -576,6 +589,7 @@ test('Integration test guardConditions.js', function (t) {
'intDivisionTruncate.sol': 1,
'ERC20.sol': 0,
'stringBytesLength.sol': 0,
'etherTransferInLoop.sol': 0,
'forLoopIteratesOverDynamicArray.sol': 0
}
......@@ -614,6 +628,7 @@ test('Integration test deleteDynamicArrays.js', function (t) {
'intDivisionTruncate.sol': 0,
'ERC20.sol': 0,
'stringBytesLength.sol': 0,
'etherTransferInLoop.sol': 0,
'forLoopIteratesOverDynamicArray.sol': 0
}
......@@ -652,6 +667,7 @@ test('Integration test deleteFromDynamicArray.js', function (t) {
'intDivisionTruncate.sol': 0,
'ERC20.sol': 0,
'stringBytesLength.sol': 0,
'etherTransferInLoop.sol': 0,
'forLoopIteratesOverDynamicArray.sol': 0
}
......@@ -690,6 +706,7 @@ test('Integration test assignAndCompare.js', function (t) {
'intDivisionTruncate.sol': 0,
'ERC20.sol': 0,
'stringBytesLength.sol': 0,
'etherTransferInLoop.sol': 0,
'forLoopIteratesOverDynamicArray.sol': 0
}
......@@ -728,6 +745,7 @@ test('Integration test intDivisionTruncate.js', function (t) {
'intDivisionTruncate.sol': 2,
'ERC20.sol': 0,
'stringBytesLength.sol': 0,
'etherTransferInLoop.sol': 0,
'forLoopIteratesOverDynamicArray.sol': 0
}
......@@ -766,6 +784,7 @@ test('Integration test erc20Decimal.js', function (t) {
'intDivisionTruncate.sol': 0,
'ERC20.sol': 1,
'stringBytesLength.sol': 0,
'etherTransferInLoop.sol': 0,
'forLoopIteratesOverDynamicArray.sol': 0
}
......@@ -804,6 +823,7 @@ test('Integration test stringBytesLength.js', function (t) {
'intDivisionTruncate.sol': 0,
'ERC20.sol': 0,
'stringBytesLength.sol': 1,
'etherTransferInLoop.sol': 0,
'forLoopIteratesOverDynamicArray.sol': 0
}
......@@ -812,6 +832,45 @@ test('Integration test stringBytesLength.js', function (t) {
})
})
test('Integration test etherTransferInLoop.js', function (t) {
t.plan(testFiles.length)
var module = require('../../src/solidity-analyzer/modules/etherTransferInLoop')
var lengthCheck = {
'KingOfTheEtherThrone.sol': 0,
'assembly.sol': 0,
'ballot.sol': 0,
'ballot_reentrant.sol': 0,
'ballot_withoutWarnings.sol': 0,
'cross_contract.sol': 0,
'inheritance.sol': 0,
'modifier1.sol': 0,
'modifier2.sol': 0,
'notReentrant.sol': 0,
'structReentrant.sol': 0,
'thisLocal.sol': 0,
'globals.sol': 0,
'library.sol': 0,
'transfer.sol': 0,
'ctor.sol': 0,
'forgottenReturn.sol': 0,
'selfdestruct.sol': 0,
'deleteDynamicArray.sol': 0,
'deleteFromDynamicArray.sol': 0,
'blockLevelCompare.sol': 0,
'intDivisionTruncate.sol': 0,
'ERC20.sol': 0,
'stringBytesLength.sol': 0,
'etherTransferInLoop.sol': 3,
'forLoopIteratesOverDynamicArray.sol': 0
}
runModuleOnFiles(module, t, (file, report) => {
t.equal(report.length, lengthCheck[file], `${file} has right amount of etherTransferInLoop warnings`)
})
})
test('Integration test forLoopIteratesOverDynamicArray.js', function (t) {
t.plan(testFiles.length)
......@@ -842,6 +901,7 @@ test('Integration test forLoopIteratesOverDynamicArray.js', function (t) {
'intDivisionTruncate.sol': 0,
'ERC20.sol': 0,
'stringBytesLength.sol': 0,
'etherTransferInLoop.sol': 0,
'forLoopIteratesOverDynamicArray.sol': 1
}
......
pragma solidity ^0.4.24;
contract etherTransferInLoop {
address owner;
constructor() public {
owner = msg.sender;
}
function transferInForLoop(uint index) public {
for (uint i = index; i < 10; i++) {
owner.transfer(i);
}
}
function transferInWhileLoop(uint index) public {
uint i = index;
while (i < 10) {
owner.transfer(i);
i++;
}
}
function transferInDoWhileLoop(uint index) public {
uint i = index;
do {
owner.transfer(i);
i++;
} while (i < 10);
}
}
\ No newline at end of file
pragma solidity ^0.4.9;
contract loops {
uint[] array;
constructor(uint[] memory _array) public {
array = _array;
}
function fnWithForLoop(uint index) public {
for (uint i = index; i < 10; i++) {
array.push(i);
}
}
function fnWithWhileLoop(uint index) public {
uint i = index;
while (i < 10) {
array.push(i);
i++;
}
}
function fnWithDoWhileLoop(uint index) public {
uint i = index;
do{
array.push(i);
i++;
}while (i < 10);
}
}
\ No newline at end of file
pragma solidity >=0.4.9 <0.6.0;
contract etherTransferInLoop {
address payable owner;
constructor() public {
owner = msg.sender;
}
function transferInForLoop(uint index) public {
for (uint i = index; i < 10; i++) {
owner.transfer(i);
}
}
function transferInWhileLoop(uint index) public {
uint i = index;
while (i < 10) {
owner.transfer(i);
i++;
}
}
function transferInDoWhileLoop(uint index) public {
uint i = index;
do {
owner.transfer(i);
i++;
} while (i < 10);
}
}
\ No newline at end of file
pragma solidity >=0.4.9 <0.6.0;
contract loops {
uint[] array;
constructor(uint[] memory _array) public {
array = _array;
}
function fnWithForLoop(uint index) public {
for (uint i = index; i < 10; i++) {
array.push(i);
}
}
function fnWithWhileLoop(uint index) public {
uint i = index;
while (i < 10) {
array.push(i);
i++;
}
}
function fnWithDoWhileLoop(uint index) public {
uint i = index;
do{
array.push(i);
i++;
}while (i < 10);
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment