From 7dccce2db618fc99152198cebb2228b6258093ea Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Thu, 15 Nov 2018 12:22:50 +0100 Subject: [PATCH 1/2] Update tests.sol.js --- remix-tests/sol/tests.sol.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/remix-tests/sol/tests.sol.js b/remix-tests/sol/tests.sol.js index 0fd3e5b35d..c2c203daec 100644 --- a/remix-tests/sol/tests.sol.js +++ b/remix-tests/sol/tests.sol.js @@ -1,5 +1,5 @@ module.exports = ` -pragma solidity ^0.5.0; +pragma solidity >=0.4.22 <0.6.0; library Assert { From e33b76ac59fc0669c217697bb98832abaefcdb7e Mon Sep 17 00:00:00 2001 From: yann300 Date: Thu, 15 Nov 2018 17:00:26 +0100 Subject: [PATCH 2/2] fixStatixAnalysis0.5 --- remix-analyzer/package.json | 6 +- .../modules/lowLevelCalls.js | 6 + .../modules/staticAnalysisCommon.js | 61 +- .../src/solidity-analyzer/modules/txOrigin.js | 2 +- ... staticAnalysisIntegration-test-0.4.24.js} | 9 +- .../staticAnalysisIntegration-test-0.5.0.js | 866 ++++++++++++++++++ .../staticAnalysisIssues-test-0.4.24.js | 37 + ....js => staticAnalysisIssues-test-0.5.0.js} | 7 +- .../{ => solidity-v0.4.24}/ERC20.sol | 0 .../KingOfTheEtherThrone.sol | 0 .../{ => solidity-v0.4.24}/assembly.sol | 0 .../{ => solidity-v0.4.24}/ballot.sol | 0 .../ballot_reentrant.sol | 0 .../ballot_withoutWarnings.sol | 0 .../blockLevelCompare.sol | 0 .../{ => solidity-v0.4.24}/cross_contract.sol | 0 .../{ => solidity-v0.4.24}/ctor.sol | 0 .../deleteDynamicArray.sol | 0 .../deleteFromDynamicArray.sol | 0 .../forLoopIteratesOverDynamicArray.sol | 0 .../forgottenReturn.sol | 0 .../functionParameters.sol | 0 .../{ => solidity-v0.4.24}/globals.sol | 0 .../{ => solidity-v0.4.24}/inheritance.sol | 0 .../intDivisionTruncate.sol | 0 .../{ => solidity-v0.4.24}/library.sol | 0 .../{ => solidity-v0.4.24}/modifier1.sol | 0 .../{ => solidity-v0.4.24}/modifier2.sol | 0 .../{ => solidity-v0.4.24}/notReentrant.sol | 0 .../{ => solidity-v0.4.24}/reentrant.sol | 0 .../{ => solidity-v0.4.24}/selfdestruct.sol | 0 .../stringBytesLength.sol | 0 .../structReentrant.sol | 0 .../{ => solidity-v0.4.24}/thisLocal.sol | 0 .../{ => solidity-v0.4.24}/transfer.sol | 0 .../test-contracts/solidity-v0.5/ERC20.sol | 46 + .../solidity-v0.5/KingOfTheEtherThrone.sol | 23 + .../test-contracts/solidity-v0.5/assembly.sol | 30 + .../test-contracts/solidity-v0.5/ballot.sol | 145 +++ .../solidity-v0.5/ballot_reentrant.sol | 111 +++ .../solidity-v0.5/ballot_withoutWarnings.sol | 31 + .../solidity-v0.5/blockLevelCompare.sol | 45 + .../solidity-v0.5/cross_contract.sol | 19 + .../test-contracts/solidity-v0.5/ctor.sol | 8 + .../solidity-v0.5/deleteDynamicArray.sol | 37 + .../solidity-v0.5/deleteFromDynamicArray.sol | 22 + .../forLoopIteratesOverDynamicArray.sol | 15 + .../solidity-v0.5/forgottenReturn.sol | 13 + .../solidity-v0.5/functionParameters.sol | 16 + .../test-contracts/solidity-v0.5/globals.sol | 57 ++ .../solidity-v0.5/inheritance.sol | 41 + .../solidity-v0.5/intDivisionTruncate.sol | 38 + .../test-contracts/solidity-v0.5/library.sol | 54 ++ .../solidity-v0.5/modifier1.sol | 17 + .../solidity-v0.5/modifier2.sol | 28 + .../solidity-v0.5/notReentrant.sol | 13 + .../solidity-v0.5/reentrant.sol | 49 + .../solidity-v0.5/selfdestruct.sol | 14 + .../solidity-v0.5/stringBytesLength.sol | 10 + .../solidity-v0.5/structReentrant.sol | 36 + .../solidity-v0.5/thisLocal.sol | 16 + .../test-contracts/solidity-v0.5/transfer.sol | 7 + remix-analyzer/test/tests.js | 9 +- 63 files changed, 1929 insertions(+), 15 deletions(-) rename remix-analyzer/test/analysis/{staticAnalysisIntegration-test.js => staticAnalysisIntegration-test-0.4.24.js} (98%) create mode 100644 remix-analyzer/test/analysis/staticAnalysisIntegration-test-0.5.0.js create mode 100644 remix-analyzer/test/analysis/staticAnalysisIssues-test-0.4.24.js rename remix-analyzer/test/analysis/{staticAnalysisIssues-test.js => staticAnalysisIssues-test-0.5.0.js} (86%) rename remix-analyzer/test/analysis/test-contracts/{ => solidity-v0.4.24}/ERC20.sol (100%) rename remix-analyzer/test/analysis/test-contracts/{ => solidity-v0.4.24}/KingOfTheEtherThrone.sol (100%) rename remix-analyzer/test/analysis/test-contracts/{ => solidity-v0.4.24}/assembly.sol (100%) rename remix-analyzer/test/analysis/test-contracts/{ => solidity-v0.4.24}/ballot.sol (100%) rename remix-analyzer/test/analysis/test-contracts/{ => solidity-v0.4.24}/ballot_reentrant.sol (100%) rename remix-analyzer/test/analysis/test-contracts/{ => solidity-v0.4.24}/ballot_withoutWarnings.sol (100%) rename remix-analyzer/test/analysis/test-contracts/{ => solidity-v0.4.24}/blockLevelCompare.sol (100%) rename remix-analyzer/test/analysis/test-contracts/{ => solidity-v0.4.24}/cross_contract.sol (100%) rename remix-analyzer/test/analysis/test-contracts/{ => solidity-v0.4.24}/ctor.sol (100%) rename remix-analyzer/test/analysis/test-contracts/{ => solidity-v0.4.24}/deleteDynamicArray.sol (100%) rename remix-analyzer/test/analysis/test-contracts/{ => solidity-v0.4.24}/deleteFromDynamicArray.sol (100%) rename remix-analyzer/test/analysis/test-contracts/{ => solidity-v0.4.24}/forLoopIteratesOverDynamicArray.sol (100%) rename remix-analyzer/test/analysis/test-contracts/{ => solidity-v0.4.24}/forgottenReturn.sol (100%) rename remix-analyzer/test/analysis/test-contracts/{ => solidity-v0.4.24}/functionParameters.sol (100%) rename remix-analyzer/test/analysis/test-contracts/{ => solidity-v0.4.24}/globals.sol (100%) rename remix-analyzer/test/analysis/test-contracts/{ => solidity-v0.4.24}/inheritance.sol (100%) rename remix-analyzer/test/analysis/test-contracts/{ => solidity-v0.4.24}/intDivisionTruncate.sol (100%) rename remix-analyzer/test/analysis/test-contracts/{ => solidity-v0.4.24}/library.sol (100%) rename remix-analyzer/test/analysis/test-contracts/{ => solidity-v0.4.24}/modifier1.sol (100%) rename remix-analyzer/test/analysis/test-contracts/{ => solidity-v0.4.24}/modifier2.sol (100%) rename remix-analyzer/test/analysis/test-contracts/{ => solidity-v0.4.24}/notReentrant.sol (100%) rename remix-analyzer/test/analysis/test-contracts/{ => solidity-v0.4.24}/reentrant.sol (100%) rename remix-analyzer/test/analysis/test-contracts/{ => solidity-v0.4.24}/selfdestruct.sol (100%) rename remix-analyzer/test/analysis/test-contracts/{ => solidity-v0.4.24}/stringBytesLength.sol (100%) rename remix-analyzer/test/analysis/test-contracts/{ => solidity-v0.4.24}/structReentrant.sol (100%) rename remix-analyzer/test/analysis/test-contracts/{ => solidity-v0.4.24}/thisLocal.sol (100%) rename remix-analyzer/test/analysis/test-contracts/{ => solidity-v0.4.24}/transfer.sol (100%) create mode 100644 remix-analyzer/test/analysis/test-contracts/solidity-v0.5/ERC20.sol create mode 100644 remix-analyzer/test/analysis/test-contracts/solidity-v0.5/KingOfTheEtherThrone.sol create mode 100644 remix-analyzer/test/analysis/test-contracts/solidity-v0.5/assembly.sol create mode 100644 remix-analyzer/test/analysis/test-contracts/solidity-v0.5/ballot.sol create mode 100644 remix-analyzer/test/analysis/test-contracts/solidity-v0.5/ballot_reentrant.sol create mode 100644 remix-analyzer/test/analysis/test-contracts/solidity-v0.5/ballot_withoutWarnings.sol create mode 100644 remix-analyzer/test/analysis/test-contracts/solidity-v0.5/blockLevelCompare.sol create mode 100644 remix-analyzer/test/analysis/test-contracts/solidity-v0.5/cross_contract.sol create mode 100644 remix-analyzer/test/analysis/test-contracts/solidity-v0.5/ctor.sol create mode 100644 remix-analyzer/test/analysis/test-contracts/solidity-v0.5/deleteDynamicArray.sol create mode 100644 remix-analyzer/test/analysis/test-contracts/solidity-v0.5/deleteFromDynamicArray.sol create mode 100644 remix-analyzer/test/analysis/test-contracts/solidity-v0.5/forLoopIteratesOverDynamicArray.sol create mode 100644 remix-analyzer/test/analysis/test-contracts/solidity-v0.5/forgottenReturn.sol create mode 100644 remix-analyzer/test/analysis/test-contracts/solidity-v0.5/functionParameters.sol create mode 100644 remix-analyzer/test/analysis/test-contracts/solidity-v0.5/globals.sol create mode 100644 remix-analyzer/test/analysis/test-contracts/solidity-v0.5/inheritance.sol create mode 100644 remix-analyzer/test/analysis/test-contracts/solidity-v0.5/intDivisionTruncate.sol create mode 100644 remix-analyzer/test/analysis/test-contracts/solidity-v0.5/library.sol create mode 100644 remix-analyzer/test/analysis/test-contracts/solidity-v0.5/modifier1.sol create mode 100644 remix-analyzer/test/analysis/test-contracts/solidity-v0.5/modifier2.sol create mode 100644 remix-analyzer/test/analysis/test-contracts/solidity-v0.5/notReentrant.sol create mode 100644 remix-analyzer/test/analysis/test-contracts/solidity-v0.5/reentrant.sol create mode 100644 remix-analyzer/test/analysis/test-contracts/solidity-v0.5/selfdestruct.sol create mode 100644 remix-analyzer/test/analysis/test-contracts/solidity-v0.5/stringBytesLength.sol create mode 100644 remix-analyzer/test/analysis/test-contracts/solidity-v0.5/structReentrant.sol create mode 100644 remix-analyzer/test/analysis/test-contracts/solidity-v0.5/thisLocal.sol create mode 100644 remix-analyzer/test/analysis/test-contracts/solidity-v0.5/transfer.sol diff --git a/remix-analyzer/package.json b/remix-analyzer/package.json index a4bf9c2aff..e2c5b395cf 100644 --- a/remix-analyzer/package.json +++ b/remix-analyzer/package.json @@ -22,7 +22,6 @@ "babel-plugin-transform-object-assign": "^6.22.0", "babel-preset-es2015": "^6.24.0", "remix-lib": "0.3.11", - "solc": "^0.4.24", "standard": "^7.0.1", "tape": "^4.6.0" }, @@ -38,5 +37,8 @@ }, "author": "Remix Team", "license": "MIT", - "homepage": "https://github.com/ethereum/remix#readme" + "homepage": "https://github.com/ethereum/remix#readme", + "devDependencies": { + "npm-install-version": "^6.0.2" + } } diff --git a/remix-analyzer/src/solidity-analyzer/modules/lowLevelCalls.js b/remix-analyzer/src/solidity-analyzer/modules/lowLevelCalls.js index 3c70ad2859..380aa0ea23 100644 --- a/remix-analyzer/src/solidity-analyzer/modules/lowLevelCalls.js +++ b/remix-analyzer/src/solidity-analyzer/modules/lowLevelCalls.js @@ -11,12 +11,18 @@ function lowLevelCalls () { lowLevelCalls.prototype.visit = function (node) { if (common.isLowLevelCallInst(node)) { this.llcNodes.push({node: node, type: common.lowLevelCallTypes.CALL}) + } else if (common.isLowLevelCallInst050(node)) { + this.llcNodes.push({node: node, type: common.lowLevelCallTypes.CALL}) } else if (common.isLowLevelCallcodeInst(node)) { this.llcNodes.push({node: node, type: common.lowLevelCallTypes.CALLCODE}) } else if (common.isLowLevelDelegatecallInst(node)) { this.llcNodes.push({node: node, type: common.lowLevelCallTypes.DELEGATECALL}) } else if (common.isLowLevelSendInst(node)) { this.llcNodes.push({node: node, type: common.lowLevelCallTypes.SEND}) + } else if (common.isLowLevelSendInst050(node)) { + this.llcNodes.push({node: node, type: common.lowLevelCallTypes.SEND}) + } else if (common.isLLDelegatecallInst050(node)) { + this.llcNodes.push({node: node, type: common.lowLevelCallTypes.DELEGATECALL}) } } diff --git a/remix-analyzer/src/solidity-analyzer/modules/staticAnalysisCommon.js b/remix-analyzer/src/solidity-analyzer/modules/staticAnalysisCommon.js index eb5db00554..4243ea0258 100644 --- a/remix-analyzer/src/solidity-analyzer/modules/staticAnalysisCommon.js +++ b/remix-analyzer/src/solidity-analyzer/modules/staticAnalysisCommon.js @@ -33,6 +33,7 @@ var basicTypes = { UINT: 'uint256', BOOL: 'bool', ADDRESS: 'address', + PAYABLE_ADDRESS: 'address payable', BYTES32: 'bytes32', STRING_MEM: 'string memory', BYTES_MEM: 'bytes memory', @@ -52,7 +53,9 @@ var basicRegex = { var basicFunctionTypes = { SEND: buildFunctionSignature([basicTypes.UINT], [basicTypes.BOOL], false), CALL: buildFunctionSignature([], [basicTypes.BOOL], true), + 'CALL-v0.5': buildFunctionSignature([basicTypes.BYTES_MEM], [basicTypes.BOOL, basicTypes.BYTES_MEM], true), DELEGATECALL: buildFunctionSignature([], [basicTypes.BOOL], false), + 'DELEGATECALL-v0.5': buildFunctionSignature([basicTypes.BYTES_MEM], [basicTypes.BOOL, basicTypes.BYTES_MEM], false), TRANSFER: buildFunctionSignature([basicTypes.UINT], [], false) } @@ -65,6 +68,7 @@ var builtinFunctions = { 'addmod(uint256,uint256,uint256)': true, 'mulmod(uint256,uint256,uint256)': true, 'selfdestruct(address)': true, + 'selfdestruct(address payable)': true, 'revert()': true, 'revert(string memory)': true, 'assert(bool)': true, @@ -77,8 +81,10 @@ var builtinFunctions = { var lowLevelCallTypes = { CALL: { ident: 'call', type: basicFunctionTypes.CALL }, + 'CALL-v0.5': { ident: 'call', type: basicFunctionTypes['CALL-v0.5'] }, CALLCODE: { ident: 'callcode', type: basicFunctionTypes.CALL }, DELEGATECALL: { ident: 'delegatecall', type: basicFunctionTypes.DELEGATECALL }, + 'DELEGATECALL-v0.5': { ident: 'delegatecall', type: basicFunctionTypes['DELEGATECALL-v0.5'] }, SEND: { ident: 'send', type: basicFunctionTypes.SEND }, TRANSFER: { ident: 'transfer', type: basicFunctionTypes.TRANSFER } } @@ -588,7 +594,7 @@ function isStorageVariableDeclaration (node) { * @return {bool} */ function isInteraction (node) { - return isLLCall(node) || isLLSend(node) || isExternalDirectCall(node) || isTransfer(node) + return isLLCall(node) || isLLSend(node) || isExternalDirectCall(node) || isTransfer(node) || isLLCall050(node) || isLLSend050(node) } /** @@ -833,11 +839,25 @@ function isLowLevelCall (node) { return isLLCall(node) || isLLCallcode(node) || isLLDelegatecall(node) || - isLLSend(node) + isLLSend(node) || + isLLSend050(node) || + isLLCall050(node) || + isLLDelegatecall050(node) } /** - * True if low level send + * True if low level send (solidity >= 0.5) + * @node {ASTNode} some AstNode + * @return {bool} + */ +function isLLSend050 (node) { + return isMemberAccess(node, + exactMatch(util.escapeRegExp(lowLevelCallTypes.SEND.type)), + undefined, exactMatch(basicTypes.PAYABLE_ADDRESS), exactMatch(lowLevelCallTypes.SEND.ident)) +} + +/** + * True if low level send (solidity < 0.5) * @node {ASTNode} some AstNode * @return {bool} */ @@ -858,6 +878,17 @@ function isLLCall (node) { undefined, exactMatch(basicTypes.ADDRESS), exactMatch(lowLevelCallTypes.CALL.ident)) } +/** + * True if low level payable call (solidity >= 0.5) + * @node {ASTNode} some AstNode + * @return {bool} + */ +function isLLCall050 (node) { + return isMemberAccess(node, + exactMatch(util.escapeRegExp(lowLevelCallTypes['CALL-v0.5'].type)), + undefined, exactMatch(basicTypes.PAYABLE_ADDRESS), exactMatch(lowLevelCallTypes['CALL-v0.5'].ident)) +} + /** * True if low level callcode * @node {ASTNode} some AstNode @@ -880,6 +911,17 @@ function isLLDelegatecall (node) { undefined, exactMatch(basicTypes.ADDRESS), exactMatch(lowLevelCallTypes.DELEGATECALL.ident)) } +/** + * True if low level delegatecall (solidity >= 0.5) + * @node {ASTNode} some AstNode + * @return {bool} + */ +function isLLDelegatecall050 (node) { + return isMemberAccess(node, + exactMatch(util.escapeRegExp(lowLevelCallTypes['DELEGATECALL-v0.5'].type)), + undefined, matches(basicTypes.PAYABLE_ADDRESS, basicTypes.ADDRESS), exactMatch(lowLevelCallTypes['DELEGATECALL-v0.5'].ident)) +} + /** * True if transfer call * @node {ASTNode} some AstNode @@ -888,7 +930,7 @@ function isLLDelegatecall (node) { function isTransfer (node) { return isMemberAccess(node, exactMatch(util.escapeRegExp(lowLevelCallTypes.TRANSFER.type)), - undefined, exactMatch(basicTypes.ADDRESS), exactMatch(lowLevelCallTypes.TRANSFER.ident)) + undefined, matches(basicTypes.ADDRESS, basicTypes.PAYABLE_ADDRESS), exactMatch(lowLevelCallTypes.TRANSFER.ident)) } function isStringToBytesConversion (node) { @@ -962,6 +1004,14 @@ function exactMatch (regexStr) { return '^' + regexStr + '$' } +function matches () { + var args = [] + for (var k = 0; k < arguments.length; k++) { + args.push(arguments[k]) + } + return '(' + args.join('|') + ')' +} + /** * Builds an function signature as used in the AST of the solc-json AST * @param {Array} paramTypes @@ -1048,6 +1098,9 @@ module.exports = { isTransfer: isTransfer, isLowLevelCall: isLowLevelCall, isLowLevelCallInst: isLLCall, + isLowLevelCallInst050: isLLCall050, + isLowLevelSendInst050: isLLSend050, + isLLDelegatecallInst050: isLLDelegatecall050, isLowLevelCallcodeInst: isLLCallcode, isLowLevelDelegatecallInst: isLLDelegatecall, isLowLevelSendInst: isLLSend, diff --git a/remix-analyzer/src/solidity-analyzer/modules/txOrigin.js b/remix-analyzer/src/solidity-analyzer/modules/txOrigin.js index 512fe579f7..ec35afb1a0 100644 --- a/remix-analyzer/src/solidity-analyzer/modules/txOrigin.js +++ b/remix-analyzer/src/solidity-analyzer/modules/txOrigin.js @@ -10,7 +10,7 @@ function txOrigin () { txOrigin.prototype.visit = function (node) { if (node.name === 'MemberAccess' && node.attributes.member_name === 'origin' && - node.attributes.type === 'address' && + (node.attributes.type === 'address' || node.attributes.type === 'address payable') && node.children && node.children.length && node.children[0].attributes.type === 'tx' && node.children[0].attributes.value === 'tx') { diff --git a/remix-analyzer/test/analysis/staticAnalysisIntegration-test.js b/remix-analyzer/test/analysis/staticAnalysisIntegration-test-0.4.24.js similarity index 98% rename from remix-analyzer/test/analysis/staticAnalysisIntegration-test.js rename to remix-analyzer/test/analysis/staticAnalysisIntegration-test-0.4.24.js index 9d002ad3e3..febecb38a2 100644 --- a/remix-analyzer/test/analysis/staticAnalysisIntegration-test.js +++ b/remix-analyzer/test/analysis/staticAnalysisIntegration-test-0.4.24.js @@ -4,10 +4,13 @@ var remixLib = require('remix-lib') var StatRunner = require('../../src/solidity-analyzer') var compilerInput = remixLib.helpers.compiler.compilerInput -var compiler = require('solc') +const niv = require('npm-install-version') +niv.install('solc@0.4.24') +var compiler = niv.require('solc@0.4.24') var fs = require('fs') var path = require('path') +var folder = 'solidity-v0.4.24' var testFiles = [ 'KingOfTheEtherThrone.sol', @@ -40,8 +43,8 @@ var testFiles = [ var testFileAsts = {} testFiles.forEach((fileName) => { - var content = fs.readFileSync(path.join(__dirname, 'test-contracts', fileName), 'utf8') - testFileAsts[fileName] = JSON.parse(compiler.compile(compilerInput(content))) + var content = fs.readFileSync(path.join(__dirname, 'test-contracts/' + folder, fileName), 'utf8') + testFileAsts[fileName] = JSON.parse(compiler.compileStandardWrapper(compilerInput(content))) }) test('Integration test thisLocal.js', function (t) { diff --git a/remix-analyzer/test/analysis/staticAnalysisIntegration-test-0.5.0.js b/remix-analyzer/test/analysis/staticAnalysisIntegration-test-0.5.0.js new file mode 100644 index 0000000000..0f2e6ba696 --- /dev/null +++ b/remix-analyzer/test/analysis/staticAnalysisIntegration-test-0.5.0.js @@ -0,0 +1,866 @@ +var test = require('tape') +var remixLib = require('remix-lib') + +var StatRunner = require('../../src/solidity-analyzer') +var compilerInput = remixLib.helpers.compiler.compilerInput + +const niv = require('npm-install-version') +niv.install('solc@0.5.0') +var compiler = niv.require('solc@0.5.0') + +var fs = require('fs') +var path = require('path') +var folder = 'solidity-v0.5' + +var testFiles = [ + 'KingOfTheEtherThrone.sol', + 'assembly.sol', + 'ballot.sol', + 'ballot_reentrant.sol', + 'ballot_withoutWarnings.sol', + 'cross_contract.sol', + 'inheritance.sol', + 'modifier1.sol', + 'modifier2.sol', + 'notReentrant.sol', + 'structReentrant.sol', + 'thisLocal.sol', + 'globals.sol', + 'library.sol', + 'transfer.sol', + 'ctor.sol', + 'forgottenReturn.sol', + 'selfdestruct.sol', + 'deleteDynamicArray.sol', + 'deleteFromDynamicArray.sol', + 'blockLevelCompare.sol', + 'intDivisionTruncate.sol', + 'ERC20.sol', + 'stringBytesLength.sol', + 'forLoopIteratesOverDynamicArray.sol' +] + +var testFileAsts = {} + +testFiles.forEach((fileName) => { + var content = fs.readFileSync(path.join(__dirname, 'test-contracts/' + folder, fileName), 'utf8') + testFileAsts[fileName] = JSON.parse(compiler.compile(compilerInput(content))) +}) + +test('Integration test thisLocal.js', function (t) { + t.plan(testFiles.length) + + var module = require('../../src/solidity-analyzer/modules/thisLocal') + + var lengthCheck = { + 'KingOfTheEtherThrone.sol': 0, + 'assembly.sol': 0, + 'ballot.sol': 0, + 'ballot_reentrant.sol': 1, + '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': 1, + '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, + 'forLoopIteratesOverDynamicArray.sol': 0 + } + + runModuleOnFiles(module, t, (file, report) => { + t.equal(report.length, lengthCheck[file], `${file} has right amount of this local warnings`) + }) +}) + +test('Integration test checksEffectsInteraction.js', function (t) { + t.plan(testFiles.length) + + var module = require('../../src/solidity-analyzer/modules/checksEffectsInteraction') + + var lengthCheck = { + 'KingOfTheEtherThrone.sol': 1, + 'assembly.sol': 1, + 'ballot.sol': 0, + 'ballot_reentrant.sol': 1, + 'ballot_withoutWarnings.sol': 0, + 'cross_contract.sol': 0, + 'inheritance.sol': 1, + 'modifier1.sol': 0, + 'modifier2.sol': 0, + 'notReentrant.sol': 0, + 'structReentrant.sol': 1, + 'thisLocal.sol': 0, + 'globals.sol': 1, + 'library.sol': 1, + 'transfer.sol': 1, + '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, + 'forLoopIteratesOverDynamicArray.sol': 0 + } + + runModuleOnFiles(module, t, (file, report) => { + t.equal(report.length, lengthCheck[file], `${file} has right amount of checks-effects-interaction warnings`) + }) +}) + +test('Integration test constantFunctions.js', function (t) { + t.plan(testFiles.length) + + var module = require('../../src/solidity-analyzer/modules/constantFunctions') + + 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': 1, + 'modifier2.sol': 0, + 'notReentrant.sol': 0, + 'structReentrant.sol': 1, + 'thisLocal.sol': 1, + 'globals.sol': 0, + 'library.sol': 3, + '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, + 'forLoopIteratesOverDynamicArray.sol': 0 + } + + runModuleOnFiles(module, t, (file, report) => { + t.equal(report.length, lengthCheck[file], `${file} has right amount of constant warnings`) + }) +}) + +test('Integration test inlineAssembly.js', function (t) { + t.plan(testFiles.length) + + var module = require('../../src/solidity-analyzer/modules/inlineAssembly') + + var lengthCheck = { + 'KingOfTheEtherThrone.sol': 0, + 'assembly.sol': 2, + '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, + 'forLoopIteratesOverDynamicArray.sol': 0 + } + + runModuleOnFiles(module, t, (file, report) => { + t.equal(report.length, lengthCheck[file], `${file} has right amount of inline assembly warnings`) + }) +}) + +test('Integration test txOrigin.js', function (t) { + t.plan(testFiles.length) + + var module = require('../../src/solidity-analyzer/modules/txOrigin') + + var lengthCheck = { + 'KingOfTheEtherThrone.sol': 0, + 'assembly.sol': 1, + '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': 1, + '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, + 'forLoopIteratesOverDynamicArray.sol': 0 + } + + runModuleOnFiles(module, t, (file, report) => { + t.equal(report.length, lengthCheck[file], `${file} has right amount of tx.origin warnings`) + }) +}) + +test('Integration test gasCosts.js', function (t) { + t.plan(testFiles.length) + + var module = require('../../src/solidity-analyzer/modules/gasCosts') + + var lengthCheck = { + 'KingOfTheEtherThrone.sol': 2, + 'assembly.sol': 2, + 'ballot.sol': 3, + 'ballot_reentrant.sol': 2, + 'ballot_withoutWarnings.sol': 0, + 'cross_contract.sol': 1, + 'inheritance.sol': 1, + 'modifier1.sol': 0, + 'modifier2.sol': 1, + 'notReentrant.sol': 1, + 'structReentrant.sol': 1, + 'thisLocal.sol': 1, + 'globals.sol': 1, + 'library.sol': 1, + 'transfer.sol': 1, + 'ctor.sol': 0, + 'forgottenReturn.sol': 3, + 'selfdestruct.sol': 0, + 'deleteDynamicArray.sol': 2, + 'deleteFromDynamicArray.sol': 1, + 'blockLevelCompare.sol': 1, + 'intDivisionTruncate.sol': 1, + 'ERC20.sol': 2, + 'stringBytesLength.sol': 1, + 'forLoopIteratesOverDynamicArray.sol': 1 + } + + runModuleOnFiles(module, t, (file, report) => { + t.equal(report.length, lengthCheck[file], `${file} has right amount of gasCost warnings`) + }) +}) + +test('Integration test similarVariableNames.js', function (t) { + t.plan(testFiles.length) + + var module = require('../../src/solidity-analyzer/modules/similarVariableNames') + + var lengthCheck = { + 'KingOfTheEtherThrone.sol': 0, + 'assembly.sol': 0, + 'ballot.sol': 2, + 'ballot_reentrant.sol': 11, + 'ballot_withoutWarnings.sol': 0, + 'cross_contract.sol': 0, + 'inheritance.sol': 0, + 'modifier1.sol': 0, + 'modifier2.sol': 0, + 'notReentrant.sol': 1, + 'structReentrant.sol': 0, + 'thisLocal.sol': 0, + 'globals.sol': 0, + 'library.sol': 0, + 'transfer.sol': 0, + 'ctor.sol': 1, + 'forgottenReturn.sol': 0, + 'selfdestruct.sol': 0, + 'deleteDynamicArray.sol': 1, + 'deleteFromDynamicArray.sol': 0, + 'blockLevelCompare.sol': 0, + 'intDivisionTruncate.sol': 0, + 'ERC20.sol': 0, + 'stringBytesLength.sol': 0, + 'forLoopIteratesOverDynamicArray.sol': 0 + } + + runModuleOnFiles(module, t, (file, report) => { + t.equal(report.length, lengthCheck[file], `${file} has right amount of similarVariableNames warnings`) + }) +}) + +test('Integration test inlineAssembly.js', function (t) { + t.plan(testFiles.length) + + var module = require('../../src/solidity-analyzer/modules/inlineAssembly') + + var lengthCheck = { + 'KingOfTheEtherThrone.sol': 0, + 'assembly.sol': 2, + '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, + 'forLoopIteratesOverDynamicArray.sol': 0 + } + + runModuleOnFiles(module, t, (file, report) => { + t.equal(report.length, lengthCheck[file], `${file} has right amount of inlineAssembly warnings`) + }) +}) + +test('Integration test blockTimestamp.js', function (t) { + t.plan(testFiles.length) + + var module = require('../../src/solidity-analyzer/modules/blockTimestamp') + + var lengthCheck = { + 'KingOfTheEtherThrone.sol': 1, + 'assembly.sol': 0, + 'ballot.sol': 0, + 'ballot_reentrant.sol': 3, + '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': 2, + '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, + 'forLoopIteratesOverDynamicArray.sol': 0 + } + + runModuleOnFiles(module, t, (file, report) => { + t.equal(report.length, lengthCheck[file], `${file} has right amount of blockTimestamp warnings`) + }) +}) + +test('Integration test lowLevelCalls.js', function (t) { + t.plan(testFiles.length) + + var module = require('../../src/solidity-analyzer/modules/lowLevelCalls') + + var lengthCheck = { + 'KingOfTheEtherThrone.sol': 1, + 'assembly.sol': 1, + 'ballot.sol': 0, + 'ballot_reentrant.sol': 7, + 'ballot_withoutWarnings.sol': 0, + 'cross_contract.sol': 1, + 'inheritance.sol': 1, + 'modifier1.sol': 0, + 'modifier2.sol': 0, + 'notReentrant.sol': 1, + 'structReentrant.sol': 1, + 'thisLocal.sol': 2, + 'globals.sol': 1, + 'library.sol': 1, + '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, + 'forLoopIteratesOverDynamicArray.sol': 0 + } + + runModuleOnFiles(module, t, (file, report) => { + t.equal(report.length, lengthCheck[file], `${file} has right amount of lowLevelCalls warnings`) + }) +}) + +test('Integration test blockBlockhash.js', function (t) { + t.plan(testFiles.length) + + var module = require('../../src/solidity-analyzer/modules/blockBlockhash') + + 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, // was 1 !! @TODO + '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, + 'forLoopIteratesOverDynamicArray.sol': 0 + } + + runModuleOnFiles(module, t, (file, report) => { + t.equal(report.length, lengthCheck[file], `${file} has right amount of blockBlockhash warnings`) + }) +}) + +/* + +! No return gives compilation error with solidity 0.5.0 + +test('Integration test noReturn.js', function (t) { + t.plan(testFiles.length) + + var module = require('../../src/solidity-analyzer/modules/noReturn') + + var lengthCheck = { + 'KingOfTheEtherThrone.sol': 0, + 'assembly.sol': 1, + 'ballot.sol': 0, + 'ballot_reentrant.sol': 0, + 'ballot_withoutWarnings.sol': 0, + 'cross_contract.sol': 0, + 'inheritance.sol': 0, + 'modifier1.sol': 1, + 'modifier2.sol': 0, + 'notReentrant.sol': 0, + 'structReentrant.sol': 0, + 'thisLocal.sol': 1, + 'globals.sol': 0, + 'library.sol': 0, + 'transfer.sol': 0, + 'ctor.sol': 0, + 'forgottenReturn.sol': 1, + 'selfdestruct.sol': 0, + 'deleteDynamicArray.sol': 0, + 'deleteFromDynamicArray.sol': 0, + 'blockLevelCompare.sol': 0, + 'intDivisionTruncate.sol': 0, + 'ERC20.sol': 0, + 'stringBytesLength.sol': 0, + 'forLoopIteratesOverDynamicArray.sol': 0 + } + + runModuleOnFiles(module, t, (file, report) => { + t.equal(report.length, lengthCheck[file], `${file} has right amount of noReturn warnings`) + }) +}) +*/ + +test('Integration test selfdestruct.js', function (t) { + t.plan(testFiles.length) + + var module = require('../../src/solidity-analyzer/modules/selfdestruct') + + 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': 2, + 'library.sol': 0, + 'transfer.sol': 0, + 'ctor.sol': 0, + 'forgottenReturn.sol': 0, + 'selfdestruct.sol': 3, + 'deleteDynamicArray.sol': 0, + 'deleteFromDynamicArray.sol': 0, + 'blockLevelCompare.sol': 0, + 'ERC20.sol': 0, + 'intDivisionTruncate.sol': 5, + 'stringBytesLength.sol': 0, + 'forLoopIteratesOverDynamicArray.sol': 0 + } + + runModuleOnFiles(module, t, (file, report) => { + t.equal(report.length, lengthCheck[file], `${file} has right amount of selfdestruct warnings`) + }) +}) + +test('Integration test guardConditions.js', function (t) { + t.plan(testFiles.length) + + var module = require('../../src/solidity-analyzer/modules/guardConditions') + + var lengthCheck = { + 'KingOfTheEtherThrone.sol': 0, + 'assembly.sol': 1, + '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': 1, + 'library.sol': 0, + 'transfer.sol': 0, + 'ctor.sol': 0, + 'forgottenReturn.sol': 0, + 'selfdestruct.sol': 0, + 'deleteDynamicArray.sol': 1, + 'deleteFromDynamicArray.sol': 0, + 'blockLevelCompare.sol': 0, + 'intDivisionTruncate.sol': 1, + 'ERC20.sol': 0, + 'stringBytesLength.sol': 0, + 'forLoopIteratesOverDynamicArray.sol': 0 + } + + runModuleOnFiles(module, t, (file, report) => { + t.equal(report.length, lengthCheck[file], `${file} has right amount of guardCondition warnings`) + }) +}) + +test('Integration test deleteDynamicArrays.js', function (t) { + t.plan(testFiles.length) + + var module = require('../../src/solidity-analyzer/modules/deleteDynamicArrays') + + 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': 2, + 'deleteFromDynamicArray.sol': 0, + 'blockLevelCompare.sol': 0, + 'intDivisionTruncate.sol': 0, + 'ERC20.sol': 0, + 'stringBytesLength.sol': 0, + 'forLoopIteratesOverDynamicArray.sol': 0 + } + + runModuleOnFiles(module, t, (file, report) => { + t.equal(report.length, lengthCheck[file], `${file} has right amount of deleteDynamicArrays warnings`) + }) +}) + +test('Integration test deleteFromDynamicArray.js', function (t) { + t.plan(testFiles.length) + + var module = require('../../src/solidity-analyzer/modules/deleteFromDynamicArray') + + 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': 1, + 'blockLevelCompare.sol': 0, + 'intDivisionTruncate.sol': 0, + 'ERC20.sol': 0, + 'stringBytesLength.sol': 0, + 'forLoopIteratesOverDynamicArray.sol': 0 + } + + runModuleOnFiles(module, t, (file, report) => { + t.equal(report.length, lengthCheck[file], `${file} has right amount of deleteFromDynamicArray warnings`) + }) +}) + +test('Integration test assignAndCompare.js', function (t) { + t.plan(testFiles.length) + + var module = require('../../src/solidity-analyzer/modules/assignAndCompare') + + 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': 8, + 'intDivisionTruncate.sol': 0, + 'ERC20.sol': 0, + 'stringBytesLength.sol': 0, + 'forLoopIteratesOverDynamicArray.sol': 0 + } + + runModuleOnFiles(module, t, (file, report) => { + t.equal(report.length, lengthCheck[file], `${file} has right amount of assignAndCompare warnings`) + }) +}) + +test('Integration test intDivisionTruncate.js', function (t) { + t.plan(testFiles.length) + + var module = require('../../src/solidity-analyzer/modules/intDivisionTruncate') + + 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': 2, + 'ERC20.sol': 0, + 'stringBytesLength.sol': 0, + 'forLoopIteratesOverDynamicArray.sol': 0 + } + + runModuleOnFiles(module, t, (file, report) => { + t.equal(report.length, lengthCheck[file], `${file} has right amount of intDivisionTruncate warnings`) + }) +}) + +test('Integration test erc20Decimal.js', function (t) { + t.plan(testFiles.length) + + var module = require('../../src/solidity-analyzer/modules/erc20Decimals') + + 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': 1, + 'stringBytesLength.sol': 0, + 'forLoopIteratesOverDynamicArray.sol': 0 + } + + runModuleOnFiles(module, t, (file, report) => { + t.equal(report.length, lengthCheck[file], `${file} has right amount of erc20Decimals warnings`) + }) +}) + +test('Integration test stringBytesLength.js', function (t) { + t.plan(testFiles.length) + + var module = require('../../src/solidity-analyzer/modules/stringBytesLength') + + 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': 1, + 'forLoopIteratesOverDynamicArray.sol': 0 + } + + runModuleOnFiles(module, t, (file, report) => { + t.equal(report.length, lengthCheck[file], `${file} has right amount of stringBytesLength warnings`) + }) +}) + +test('Integration test forLoopIteratesOverDynamicArray.js', function (t) { + t.plan(testFiles.length) + + var module = require('../../src/solidity-analyzer/modules/forLoopIteratesOverDynamicArray') + + var lengthCheck = { + 'KingOfTheEtherThrone.sol': 0, + 'assembly.sol': 0, + 'ballot.sol': 2, + 'ballot_reentrant.sol': 1, + '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, + 'forLoopIteratesOverDynamicArray.sol': 1 + } + + runModuleOnFiles(module, t, (file, report) => { + t.equal(report.length, lengthCheck[file], `${file} has right amount of forLoopIteratesOverDynamicArray warnings`) + }) +}) + +// #################### Helpers +function runModuleOnFiles (module, t, cb) { + var statRunner = new StatRunner() + + testFiles.forEach((fileName) => { + statRunner.runWithModuleList(testFileAsts[fileName], [{ name: module.name, mod: new module.Module() }], (reports) => { + let report = reports[0].report + if (report.some((x) => x['warning'].includes('INTERNAL ERROR'))) { + t.comment('Error while executing Module: ' + JSON.stringify(report)) + } + cb(fileName, report) + }) + }) +} diff --git a/remix-analyzer/test/analysis/staticAnalysisIssues-test-0.4.24.js b/remix-analyzer/test/analysis/staticAnalysisIssues-test-0.4.24.js new file mode 100644 index 0000000000..e0c9ccf18b --- /dev/null +++ b/remix-analyzer/test/analysis/staticAnalysisIssues-test-0.4.24.js @@ -0,0 +1,37 @@ +var test = require('tape') +var remixLib = require('remix-lib') + +var StatRunner = require('../../src/solidity-analyzer') +var compilerInput = remixLib.helpers.compiler.compilerInput + +const niv = require('npm-install-version') +niv.install('solc@0.4.24') +var compiler = niv.require('solc@0.4.24') + +var fs = require('fs') +var path = require('path') +var folder = 'solidity-v0.4.24' + +function compile (fileName) { + var content = fs.readFileSync(path.join(__dirname, 'test-contracts/' + folder, fileName), 'utf8') + return JSON.parse(compiler.compileStandardWrapper(compilerInput(content))) +} + +test('staticAnalysisIssues.functionParameterPassingError', function (t) { + // https://github.com/ethereum/remix-ide/issues/889#issuecomment-351746474 + t.plan(2) + var res = compile('functionParameters.sol') + + var module = require('../../src/solidity-analyzer/modules/checksEffectsInteraction') + + var statRunner = new StatRunner() + + t.doesNotThrow(() => { + statRunner.runWithModuleList(res, [{ name: module.name, mod: new module.Module() }], (reports) => { + }) + }, true, 'Analysis should not throw') + + statRunner.runWithModuleList(res, [{ name: module.name, mod: new module.Module() }], (reports) => { + t.ok(!reports.some((mod) => mod.report.some((rep) => rep.warning.includes('INTERNAL ERROR')), 'Should not have internal errors')) + }) +}) diff --git a/remix-analyzer/test/analysis/staticAnalysisIssues-test.js b/remix-analyzer/test/analysis/staticAnalysisIssues-test-0.5.0.js similarity index 86% rename from remix-analyzer/test/analysis/staticAnalysisIssues-test.js rename to remix-analyzer/test/analysis/staticAnalysisIssues-test-0.5.0.js index c51108fb86..bc9e98c049 100644 --- a/remix-analyzer/test/analysis/staticAnalysisIssues-test.js +++ b/remix-analyzer/test/analysis/staticAnalysisIssues-test-0.5.0.js @@ -4,13 +4,16 @@ var remixLib = require('remix-lib') var StatRunner = require('../../src/solidity-analyzer') var compilerInput = remixLib.helpers.compiler.compilerInput -var compiler = require('solc') +const niv = require('npm-install-version') +niv.install('solc@0.5.0') +var compiler = niv.require('solc@0.5.0') var fs = require('fs') var path = require('path') +var folder = 'solidity-v0.5' function compile (fileName) { - var content = fs.readFileSync(path.join(__dirname, 'test-contracts', fileName), 'utf8') + var content = fs.readFileSync(path.join(__dirname, 'test-contracts/' + folder, fileName), 'utf8') return JSON.parse(compiler.compile(compilerInput(content))) } diff --git a/remix-analyzer/test/analysis/test-contracts/ERC20.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/ERC20.sol similarity index 100% rename from remix-analyzer/test/analysis/test-contracts/ERC20.sol rename to remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/ERC20.sol diff --git a/remix-analyzer/test/analysis/test-contracts/KingOfTheEtherThrone.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/KingOfTheEtherThrone.sol similarity index 100% rename from remix-analyzer/test/analysis/test-contracts/KingOfTheEtherThrone.sol rename to remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/KingOfTheEtherThrone.sol diff --git a/remix-analyzer/test/analysis/test-contracts/assembly.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/assembly.sol similarity index 100% rename from remix-analyzer/test/analysis/test-contracts/assembly.sol rename to remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/assembly.sol diff --git a/remix-analyzer/test/analysis/test-contracts/ballot.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/ballot.sol similarity index 100% rename from remix-analyzer/test/analysis/test-contracts/ballot.sol rename to remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/ballot.sol diff --git a/remix-analyzer/test/analysis/test-contracts/ballot_reentrant.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/ballot_reentrant.sol similarity index 100% rename from remix-analyzer/test/analysis/test-contracts/ballot_reentrant.sol rename to remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/ballot_reentrant.sol diff --git a/remix-analyzer/test/analysis/test-contracts/ballot_withoutWarnings.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/ballot_withoutWarnings.sol similarity index 100% rename from remix-analyzer/test/analysis/test-contracts/ballot_withoutWarnings.sol rename to remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/ballot_withoutWarnings.sol diff --git a/remix-analyzer/test/analysis/test-contracts/blockLevelCompare.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/blockLevelCompare.sol similarity index 100% rename from remix-analyzer/test/analysis/test-contracts/blockLevelCompare.sol rename to remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/blockLevelCompare.sol diff --git a/remix-analyzer/test/analysis/test-contracts/cross_contract.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/cross_contract.sol similarity index 100% rename from remix-analyzer/test/analysis/test-contracts/cross_contract.sol rename to remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/cross_contract.sol diff --git a/remix-analyzer/test/analysis/test-contracts/ctor.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/ctor.sol similarity index 100% rename from remix-analyzer/test/analysis/test-contracts/ctor.sol rename to remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/ctor.sol diff --git a/remix-analyzer/test/analysis/test-contracts/deleteDynamicArray.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/deleteDynamicArray.sol similarity index 100% rename from remix-analyzer/test/analysis/test-contracts/deleteDynamicArray.sol rename to remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/deleteDynamicArray.sol diff --git a/remix-analyzer/test/analysis/test-contracts/deleteFromDynamicArray.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/deleteFromDynamicArray.sol similarity index 100% rename from remix-analyzer/test/analysis/test-contracts/deleteFromDynamicArray.sol rename to remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/deleteFromDynamicArray.sol diff --git a/remix-analyzer/test/analysis/test-contracts/forLoopIteratesOverDynamicArray.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/forLoopIteratesOverDynamicArray.sol similarity index 100% rename from remix-analyzer/test/analysis/test-contracts/forLoopIteratesOverDynamicArray.sol rename to remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/forLoopIteratesOverDynamicArray.sol diff --git a/remix-analyzer/test/analysis/test-contracts/forgottenReturn.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/forgottenReturn.sol similarity index 100% rename from remix-analyzer/test/analysis/test-contracts/forgottenReturn.sol rename to remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/forgottenReturn.sol diff --git a/remix-analyzer/test/analysis/test-contracts/functionParameters.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/functionParameters.sol similarity index 100% rename from remix-analyzer/test/analysis/test-contracts/functionParameters.sol rename to remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/functionParameters.sol diff --git a/remix-analyzer/test/analysis/test-contracts/globals.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/globals.sol similarity index 100% rename from remix-analyzer/test/analysis/test-contracts/globals.sol rename to remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/globals.sol diff --git a/remix-analyzer/test/analysis/test-contracts/inheritance.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/inheritance.sol similarity index 100% rename from remix-analyzer/test/analysis/test-contracts/inheritance.sol rename to remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/inheritance.sol diff --git a/remix-analyzer/test/analysis/test-contracts/intDivisionTruncate.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/intDivisionTruncate.sol similarity index 100% rename from remix-analyzer/test/analysis/test-contracts/intDivisionTruncate.sol rename to remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/intDivisionTruncate.sol diff --git a/remix-analyzer/test/analysis/test-contracts/library.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/library.sol similarity index 100% rename from remix-analyzer/test/analysis/test-contracts/library.sol rename to remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/library.sol diff --git a/remix-analyzer/test/analysis/test-contracts/modifier1.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/modifier1.sol similarity index 100% rename from remix-analyzer/test/analysis/test-contracts/modifier1.sol rename to remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/modifier1.sol diff --git a/remix-analyzer/test/analysis/test-contracts/modifier2.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/modifier2.sol similarity index 100% rename from remix-analyzer/test/analysis/test-contracts/modifier2.sol rename to remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/modifier2.sol diff --git a/remix-analyzer/test/analysis/test-contracts/notReentrant.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/notReentrant.sol similarity index 100% rename from remix-analyzer/test/analysis/test-contracts/notReentrant.sol rename to remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/notReentrant.sol diff --git a/remix-analyzer/test/analysis/test-contracts/reentrant.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/reentrant.sol similarity index 100% rename from remix-analyzer/test/analysis/test-contracts/reentrant.sol rename to remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/reentrant.sol diff --git a/remix-analyzer/test/analysis/test-contracts/selfdestruct.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/selfdestruct.sol similarity index 100% rename from remix-analyzer/test/analysis/test-contracts/selfdestruct.sol rename to remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/selfdestruct.sol diff --git a/remix-analyzer/test/analysis/test-contracts/stringBytesLength.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/stringBytesLength.sol similarity index 100% rename from remix-analyzer/test/analysis/test-contracts/stringBytesLength.sol rename to remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/stringBytesLength.sol diff --git a/remix-analyzer/test/analysis/test-contracts/structReentrant.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/structReentrant.sol similarity index 100% rename from remix-analyzer/test/analysis/test-contracts/structReentrant.sol rename to remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/structReentrant.sol diff --git a/remix-analyzer/test/analysis/test-contracts/thisLocal.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/thisLocal.sol similarity index 100% rename from remix-analyzer/test/analysis/test-contracts/thisLocal.sol rename to remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/thisLocal.sol diff --git a/remix-analyzer/test/analysis/test-contracts/transfer.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/transfer.sol similarity index 100% rename from remix-analyzer/test/analysis/test-contracts/transfer.sol rename to remix-analyzer/test/analysis/test-contracts/solidity-v0.4.24/transfer.sol diff --git a/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/ERC20.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/ERC20.sol new file mode 100644 index 0000000000..e72f46a4aa --- /dev/null +++ b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/ERC20.sol @@ -0,0 +1,46 @@ + +pragma solidity >=0.4.9 <0.6.0; +contract EIP20 { + + uint public decimals = 12; + + // optional + function name() public pure returns (string memory) { + return "MYTOKEN"; + } + + // optional + function symbol() public pure returns (string memory) { + return "MT"; + } + + // optional + //function decimals() internal pure returns (uint8) { + // return 12; + //} + + function totalSupply() public pure returns (uint256) { + return 12000; + } + + function balanceOf(address _owner) public pure returns (uint256) { + return 0; + } + + function transfer(address _to, uint256 _value) public pure returns (bool success) { + return true; + } + + function transferFrom(address _from, address _to, uint256 _value) public pure returns (bool) { + return true; + } + + function approve(address _spender, uint256 _value) public pure returns (bool) { + return true; + } + + function allowance(address _owner, address _spender) public pure returns (uint256) { + return 0; + } + +} \ No newline at end of file diff --git a/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/KingOfTheEtherThrone.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/KingOfTheEtherThrone.sol new file mode 100644 index 0000000000..565f2cf980 --- /dev/null +++ b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/KingOfTheEtherThrone.sol @@ -0,0 +1,23 @@ +// return value send +contract KingOfTheEtherThrone{ + struct Monarch { + // address of the king . + address payable ethAddr ; + string name ; + // how much he pays to previous king + uint claimPrice ; + uint coronationTimestamp; + } + Monarch public currentMonarch ; + + function claimThrone ( string memory name ) public { + address wizardAddress; + uint compensation = 100; + uint valuePaid = 10; + + if ( currentMonarch.ethAddr != wizardAddress ) + if (currentMonarch.ethAddr.send( compensation )) revert(); + + currentMonarch = Monarch(msg.sender,name,valuePaid,block.timestamp); + } +} diff --git a/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/assembly.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/assembly.sol new file mode 100644 index 0000000000..d081756d24 --- /dev/null +++ b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/assembly.sol @@ -0,0 +1,30 @@ + pragma solidity >=0.4.9 <0.6.0; + contract test { + + address owner; + + function at(address _addr) public returns (bytes memory o_code) { + assert(_addr != address(0x0)); + assembly { + // retrieve the size of the code, this needs assembly + let size := extcodesize(_addr) + // allocate output byte array - this could also be done without assembly + // by using o_code = new bytes(size) + o_code := mload(0x40) + // new "memory end" including padding + mstore(0x40, add(o_code, and(add(add(size, 0x20), 0x1f), not(0x1f)))) + // store length in memory + mstore(o_code, size) + // actually retrieve the code, this needs assembly + extcodecopy(_addr, add(o_code, 0x20), 0, size) + } + } + + function bla() public { + require(tx.origin == owner); + msg.sender.send(19); + assembly { + + } + } + } diff --git a/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/ballot.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/ballot.sol new file mode 100644 index 0000000000..6e8c877a6b --- /dev/null +++ b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/ballot.sol @@ -0,0 +1,145 @@ +pragma solidity >=0.4.9 <0.6.0; + +/// @title Voting with delegation. +contract Ballot { + // This declares a new complex type which will + // be used for variables later. + // It will represent a single voter. + struct Voter { + uint weight; // weight is accumulated by delegation + bool voted; // if true, that person already voted + address delegate; // person delegated to + uint vote; // index of the voted proposal + } + + // This is a type for a single proposal. + struct Proposal + { + bytes32 name; // short name (up to 32 bytes) + uint voteCount; // number of accumulated votes + } + + address public chairperson; + + // This declares a state variable that + // stores a `Voter` struct for each possible address. + mapping(address => Voter) public voters; + + // A dynamically-sized array of `Proposal` structs. + Proposal[] public proposals; + + /// Create a new ballot to choose one of `proposalNames`. + constructor(bytes32[] memory proposalNames) public { + chairperson = msg.sender; + voters[chairperson].weight = 1; + + // For each of the provided proposal names, + // create a new proposal object and add it + // to the end of the array. + for (uint i = 0; i < proposalNames.length; i++) { + // `Proposal({...})` creates a temporary + // Proposal object and `proposals.push(...)` + // appends it to the end of `proposals`. + proposals.push(Proposal({ + name: proposalNames[i], + voteCount: 0 + })); + } + } + + // Give `voter` the right to vote on this ballot. + // May only be called by `chairperson`. + function giveRightToVote(address voter) public { + if (msg.sender != chairperson || voters[voter].voted) { + // `throw` terminates and reverts all changes to + // the state and to Ether balances. It is often + // a good idea to use this if functions are + // called incorrectly. But watch out, this + // will also consume all provided gas. + revert(); + } + voters[voter].weight = 1; + } + + /// Delegate your vote to the voter `to`. + function delegate(address to) public { + // assigns reference + Voter memory sender = voters[msg.sender]; + if (sender.voted) + revert(); + + // Forward the delegation as long as + // `to` also delegated. + // In general, such loops are very dangerous, + // because if they run too long, they might + // need more gas than is available in a block. + // In this case, the delegation will not be executed, + // but in other situations, such loops might + // cause a contract to get "stuck" completely. + while ( + voters[to].delegate != address(0) && + voters[to].delegate != msg.sender + ) { + to = voters[to].delegate; + } + + // We found a loop in the delegation, not allowed. + if (to == msg.sender) { + revert(); + } + + // Since `sender` is a reference, this + // modifies `voters[msg.sender].voted` + sender.voted = true; + sender.delegate = to; + Voter memory delegate = voters[to]; + if (delegate.voted) { + // If the delegate already voted, + // directly add to the number of votes + proposals[delegate.vote].voteCount += sender.weight; + } else { + // If the delegate did not vote yet, + // add to her weight. + delegate.weight += sender.weight; + } + } + + /// Give your vote (including votes delegated to you) + /// to proposal `proposals[proposal].name`. + function vote(uint proposal) public { + Voter memory sender = voters[msg.sender]; + if (sender.voted) + revert(); + sender.voted = true; + sender.vote = proposal; + + // If `proposal` is out of the range of the array, + // this will throw automatically and revert all + // changes. + proposals[proposal].voteCount += sender.weight; + } + + /// @dev Computes the winning proposal taking all + /// previous votes into account. + function winningProposal() view public + returns (uint winningProposal) + { + uint winningVoteCount = 0; + for (uint p = 0; p < proposals.length; p++) { + if (proposals[p].voteCount > winningVoteCount) { + winningVoteCount = proposals[p].voteCount; + winningProposal = p; + } + } + } + + // Calls winningProposal() function to get the index + // of the winner contained in the proposals array and then + // returns the name of the winner + function winnerName() view public + returns (bytes32 winnerName) + { + winnerName = proposals[winningProposal()].name; + } +} + diff --git a/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/ballot_reentrant.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/ballot_reentrant.sol new file mode 100644 index 0000000000..8455c3da3a --- /dev/null +++ b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/ballot_reentrant.sol @@ -0,0 +1,111 @@ +pragma solidity >=0.4.9 <0.6.0; + +contract InfoFeed { + function info() public payable returns (uint ret); + function call1(uint a) public payable returns (bool); +} + + +contract Ballot { + + InfoFeed feed; + + struct Voter { + uint weight; + bool voted; + uint8 vote; + address delegate; + } + struct Proposal { + uint voteCount; + } + + address chairperson; + mapping(address => Voter) voters; + Proposal[] proposals; + + function send1(address a) public { + giveRightToVote(a,a); + } + + /// Create a new ballot with $(_numProposals) different proposals. + constructor(uint8 _numProposals) public { + address payable d; + + (bool success, bytes memory data) = d.delegatecall.gas(800)(abi.encodeWithSignature('function_name', 'arg1', 'arg2')); + if(!success) revert(); + + (bool success2, bytes memory data2) = d.delegatecall.gas(800)(abi.encodeWithSignature('function_name', 'arg1', 'arg2')); + if(!success2) revert(); + + (bool success3, bytes memory data3) = d.call.value(10).gas(800)(abi.encodeWithSignature('function_name', 'arg1', 'arg2')); + if(!success3) revert(); + + (bool success4, bytes memory data4) = d.call.value(10).gas(800)(abi.encodeWithSignature('function_name', 'arg1', 'arg2')); + if(!success4) revert(); + + + address payable o = msg.sender; + if(!o.send(1 wei)) revert(); + + (bool success5, bytes memory data5) = d.call(abi.encodeWithSignature('function_name', 'arg1', 'arg2')); + if(!success5) revert(); + + + uint a = now; + uint c = block.timestamp; + if(block.timestamp < 100){} + chairperson = msg.sender; + voters[chairperson].weight = 1; + proposals.length = _numProposals; + if(!d.send(1 wei)) revert(); + feed.info.value(10).gas(800)(); + + feed.call1(1); + + this.send1(d); + } + + + /// Give $(voter) the right to vote on this ballot. + /// May only be called by $(chairperson). + function giveRightToVote(address voter, address b) public payable returns (bool){ + if (msg.sender != chairperson || voters[voter].voted) return false; + voters[voter].weight = 1; + return true; + } + + /// Delegate your vote to the voter $(to). + function delegate(address to) public { + Voter memory sender = voters[msg.sender]; // assigns reference + if (sender.voted) return; + while (voters[to].delegate != address(0) && voters[to].delegate != msg.sender) + to = voters[to].delegate; + if (to == msg.sender) return; + sender.voted = true; + sender.delegate = to; + Voter memory delegate = voters[to]; + if (delegate.voted) + proposals[delegate.vote].voteCount += sender.weight; + else + delegate.weight += sender.weight; + } + + /// Give a single vote to proposal $(proposal). + function vote(uint8 proposal) public { + Voter memory sender = voters[msg.sender]; + if (sender.voted || proposal >= proposals.length) return; + sender.voted = true; + sender.vote = proposal; + proposals[proposal].voteCount += sender.weight; + } + + function winningProposal() view public returns (uint8 winningProposal) { + uint256 winningVoteCount = 0; + for (uint8 proposal = 0; proposal < proposals.length; proposal++) + if (proposals[proposal].voteCount > winningVoteCount) { + winningVoteCount = proposals[proposal].voteCount; + winningProposal = proposal; + } + } +} diff --git a/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/ballot_withoutWarnings.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/ballot_withoutWarnings.sol new file mode 100644 index 0000000000..416df05400 --- /dev/null +++ b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/ballot_withoutWarnings.sol @@ -0,0 +1,31 @@ +pragma solidity >=0.4.9 <0.6.0; + +/// @title Voting with delegation. +contract Ballot { + + struct Proposal + { + bytes32 name; // short name (up to 32 bytes) + uint voteCount; // number of accumulated votes + } + + // A dynamically-sized array of `Proposal` structs. + Proposal[] public proposals; + + /// @dev Computes the winning proposal taking all + /// previous votes into account. + function winningProposal() public view + returns (uint winningProposal) + { + winningProposal = 0; + } + + // Calls winningProposal() function to get the index + // of the winner contained in the proposals array and then + // returns the name of the winner + function winnerName() public view + returns (bytes32 winnerName) + { + winnerName = proposals[winningProposal()].name; + } +} diff --git a/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/blockLevelCompare.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/blockLevelCompare.sol new file mode 100644 index 0000000000..1b8af64afd --- /dev/null +++ b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/blockLevelCompare.sol @@ -0,0 +1,45 @@ +pragma solidity >=0.4.9 <0.6.0; +contract grr { + bool breaker; + + function() external { + uint a = 1; + string memory sig = "withdraw()"; + uint b = 3; + + bytes4 selector = bytes4(keccak256(abi.encodePacked(sig))); + + abi.encode(a,b); + + abi.encodePacked(a,b); + + a = -b; + + a == b; + + if(a == b) { + abi.encodeWithSelector(selector, a, b); + abi.encodeWithSignature(sig, a, b); + } + + if(b < 4) { a == b; } + + if(b > 4) b == a; + + while(true) a == b; + + for(int i = 0; i < 3; i++) b == a; + + while(false) { + int c = 3; + uint(c) + a; + + c == 5; + + } + + a + b; + breaker = false; + } + +} \ No newline at end of file diff --git a/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/cross_contract.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/cross_contract.sol new file mode 100644 index 0000000000..db858bc9c8 --- /dev/null +++ b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/cross_contract.sol @@ -0,0 +1,19 @@ +pragma solidity >=0.4.9 <0.6.0; + +contract a { + + uint x; + + function foo() public { + x++; + } +} + +contract b { + a x; + function bar() public { + address payable a; + a.send(100 wei); + x.foo(); + } +} diff --git a/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/ctor.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/ctor.sol new file mode 100644 index 0000000000..c43dd240f5 --- /dev/null +++ b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/ctor.sol @@ -0,0 +1,8 @@ +contract c { + uint x; + uint x_abc; + constructor(uint _x, uint _abc) public { + x=_x; + x_abc=_abc; + } +} \ No newline at end of file diff --git a/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/deleteDynamicArray.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/deleteDynamicArray.sol new file mode 100644 index 0000000000..3dace99902 --- /dev/null +++ b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/deleteDynamicArray.sol @@ -0,0 +1,37 @@ +pragma solidity >=0.4.9 <0.6.0; +contract arr { + uint[] users; + + bytes access_rights_per_user; + + uint user_index; + + address owner; + + string grr = "message"; + + uint[100] last_100_users; + + constructor(address owner1) public { + owner = owner1; + user_index = 0; + } + + function addUser(uint id, byte rights) public{ + users[user_index] = id; + last_100_users[user_index % 100] = id; + access_rights_per_user[user_index] = rights; + user_index++; + } + + function resetState() public{ + require(msg.sender == owner, grr); + delete users; + delete access_rights_per_user; + delete last_100_users; + } + + function bla(string memory bal) public { + grr = bal; + } +} \ No newline at end of file diff --git a/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/deleteFromDynamicArray.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/deleteFromDynamicArray.sol new file mode 100644 index 0000000000..aa69d134cf --- /dev/null +++ b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/deleteFromDynamicArray.sol @@ -0,0 +1,22 @@ +pragma solidity >=0.4.9 <0.6.0; +contract arr { + uint[] array = [1,2,3]; + function removeAtIndex() public returns (uint[] memory) { + delete array[1]; + return array; + } + + // TODO: deleteFromDynamicArray should not generate warnings if array item is shifted and removed + /* function safeRemoveAtIndex(uint index) returns (uint[] memory) { + if (index >= array.length) return; + + for (uint i = index; i < array.length-1; i++) { + array[i] = array[i+1]; + } + + delete array[array.length-1]; + array.length--; + + return array; + } */ +} diff --git a/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/forLoopIteratesOverDynamicArray.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/forLoopIteratesOverDynamicArray.sol new file mode 100644 index 0000000000..48aeebd296 --- /dev/null +++ b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/forLoopIteratesOverDynamicArray.sol @@ -0,0 +1,15 @@ +pragma solidity >=0.4.9 <0.6.0; +contract forLoopArr { + uint[] array; + constructor(uint[] memory _array) public { + array = _array; + } + + function shiftArrItem(uint index) public returns(uint[] memory) { + // TODO: for (uint i = index; i < array.length-1; i++) should also generate warning + for (uint i = index; i < array.length; i++) { + array[i] = array[i+1]; + } + return array; + } +} diff --git a/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/forgottenReturn.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/forgottenReturn.sol new file mode 100644 index 0000000000..7b06f8ad79 --- /dev/null +++ b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/forgottenReturn.sol @@ -0,0 +1,13 @@ +contract Sheep { + string public name; + string public dna; + bool g = true; + constructor(string memory _name, string memory _dna) public { + name = _name; + dna = _dna; + } + + function geneticallyEngineer(string memory _dna) public returns (bool) { + dna = _dna; + } +} \ No newline at end of file diff --git a/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/functionParameters.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/functionParameters.sol new file mode 100644 index 0000000000..c90e55a45a --- /dev/null +++ b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/functionParameters.sol @@ -0,0 +1,16 @@ +pragma solidity >=0.4.9 <0.6.0; + +contract B { + function plus(uint a, uint b) pure internal returns (uint) { + return a + b; + } + + function eval(function (uint, uint) pure internal returns (uint) f, uint x, uint y) pure internal returns (uint) { + return f(x, y); + } + + function calc(uint x, uint y) pure public returns (uint) { + return eval(plus, x, y); + // return plus(x, y); + } +} \ No newline at end of file diff --git a/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/globals.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/globals.sol new file mode 100644 index 0000000000..7cdf4c1cb0 --- /dev/null +++ b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/globals.sol @@ -0,0 +1,57 @@ +pragma solidity >=0.4.9 <0.6.0; +contract bla { + uint brr; + function duper() public { + brr++; + } +} + +contract a is bla { + + function blub() public { + brr++; + } + + function r () public payable { + address payable a; + bytes32 hash; + uint8 v; + bytes32 r; + bytes32 s; + + blockhash(1); + block.coinbase; + block.difficulty; + block.gaslimit; + block.number; + block.timestamp; + msg.data; + gasleft(); + msg.sender; + msg.value; + now; + tx.gasprice; + tx.origin; + // assert(1 == 2); + // require(1 == 1); + keccak256(abi.encodePacked(a)); + sha256(abi.encodePacked(a)); + ripemd160(abi.encodePacked(a)); + ecrecover(hash, v, r, s); + addmod(1, 2, 2); + mulmod(4,4,12); + + a.balance; + blub(); + a.send(a.balance); + + + + super.duper(); + //a.transfer(a.balance); + selfdestruct(a); + //revert(); + assert(a.balance == 0); + } + +} \ No newline at end of file diff --git a/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/inheritance.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/inheritance.sol new file mode 100644 index 0000000000..21e20512b5 --- /dev/null +++ b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/inheritance.sol @@ -0,0 +1,41 @@ +pragma solidity >=0.4.9 <0.6.0; + +contract r { + function s() public view {} +} + +contract a is r { + uint x = 1; + + function getX() public view returns (uint) { + return x; + } +} + +contract b is a { + uint y = 2; + uint x = 3; + + + function getY(uint z, bool r) public returns (uint) { + return y++; + } + + function getY(string storage n) internal view returns (uint) { return 10; } + +} + +contract c is b { + string x; + + function d() public returns (uint a, uint b) { + //d(); + //sha3("bla"); + address payable o = msg.sender; + o.call.gas(200000).value(address(this).balance)(abi.encode("pay()")); + //x++; + getY(x); + a = getX() + getY(1, false); + b = getX() + getY(x); + } +} diff --git a/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/intDivisionTruncate.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/intDivisionTruncate.sol new file mode 100644 index 0000000000..fe0654af9a --- /dev/null +++ b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/intDivisionTruncate.sol @@ -0,0 +1,38 @@ +pragma solidity >=0.4.9 <0.6.0; + +contract CharityCampaign { + mapping (address => uint) contributions; + int128 feePercentage; + uint p2; + address payable processor; + address payable beneficiary; + + constructor(address payable _beneficiary, int128 _feePercentage) public { + processor = msg.sender; + beneficiary = _beneficiary; + feePercentage = _feePercentage; + } + + function contribute() payable public returns (uint feeCollected) { + uint fee = msg.value * uint256(feePercentage / 100); + fee = msg.value * (p2 / 100); + contributions[msg.sender] = msg.value - fee; + processor.transfer(fee); + return fee; + } + + function endCampaign() public returns (bool) { + require(msg.sender == processor || msg.sender == beneficiary); + selfdestruct(beneficiary); + return true; + } + + // FALSE POSITIVE FOR SELFDESTRUCT TERMINAL + function endAmbiguous() public { + if(msg.sender == address(0x0)) { + selfdestruct(beneficiary); + } else { + selfdestruct(processor); + } + } +} \ No newline at end of file diff --git a/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/library.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/library.sol new file mode 100644 index 0000000000..0f89a014f3 --- /dev/null +++ b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/library.sol @@ -0,0 +1,54 @@ +pragma solidity >=0.4.9 <0.6.0; + +library Set { + // We define a new struct datatype that will be used to + // hold its data in the calling contract. + struct Data { mapping(uint => bool) flags; } + + // Note that the first parameter is of type "storage + // reference" and thus only its storage address and not + // its contents is passed as part of the call. This is a + // special feature of library functions. It is idiomatic + // to call the first parameter 'self', if the function can + // be seen as a method of that object. + function insert(Data storage self, uint value) public + returns (bool) + { + if (self.flags[value]) + return false; // already there + self.flags[value] = true; + + return true; + } + + function remove(Data storage self, uint value) public + returns (bool) + { + if (!self.flags[value]) + return false; // not there + self.flags[value] = false; + return true; + } + + function contains(Data storage self, uint value) public + returns (bool) + { + return self.flags[value]; + } +} + + +contract C { + Set.Data knownValues; + + function register(uint value) public { + // The library functions can be called without a + // specific instance of the library, since the + // "instance" will be the current contract. + address payable a; + a.send(10 wei); + if (!Set.insert(knownValues, value)) + revert(); + } + // In this contract, we can also directly access knownValues.flags, if we want. +} \ No newline at end of file diff --git a/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/modifier1.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/modifier1.sol new file mode 100644 index 0000000000..839e702b7a --- /dev/null +++ b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/modifier1.sol @@ -0,0 +1,17 @@ +pragma solidity >=0.4.9 <0.6.0; + +contract test { + + address owner; + + modifier onlyOwner { + uint a = 0; + if (msg.sender != owner) + revert(); + _; + } + + function b(address a) public onlyOwner returns (bool) { + return true; + } +} \ No newline at end of file diff --git a/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/modifier2.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/modifier2.sol new file mode 100644 index 0000000000..ec24515a84 --- /dev/null +++ b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/modifier2.sol @@ -0,0 +1,28 @@ +pragma solidity >=0.4.9 <0.6.0; + +contract owned { + + uint r=0; + + modifier ntimes(uint n) { + for(uint i=0;i=0.4.9 <0.6.0; + +contract Fund { + /// Mapping of ether shares of the contract. + mapping(address => uint) shares; + /// Withdraw your share. + function withdraw() public { + uint share = shares[msg.sender]; + shares[msg.sender] = 0; + if (!msg.sender.send(share)) + revert(); + } +} diff --git a/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/reentrant.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/reentrant.sol new file mode 100644 index 0000000000..39aa13444e --- /dev/null +++ b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/reentrant.sol @@ -0,0 +1,49 @@ +pragma solidity >=0.4.9 <0.6.0; + +contract InfoFeed { + uint c; + function info() constant returns (uint ret) {return c;} + function call1(uint a) constant returns (bool) {return true;} +} + +// THIS CONTRACT CONTAINS A BUG - DO NOT USE +contract Fund { + /// Mapping of ether shares of the contract. + //mapping(address => uint) shares; + /// Withdraw your share. + + uint c = 0; + function withdraw() constant { + InfoFeed f; + + + //shares[msg.sender] /= 1; + + f.info(); + + //if (msg.sender.send(shares[msg.sender])) throw; + // shares[msg.sender] = 0; + + + b(true, false); + //shares[msg.sender]++; + //c++; + + } + mapping(address => uint) shares; + + function b(bool a, bool b) returns (bool) { + mapping(address => uint) c = shares; + c[msg.sender] = 0; + //f(); + //withdraw(); + //shares[msg.sender]++; + //c++; + return true; + } + + function f() { + c++; + withdraw(); + } +} diff --git a/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/selfdestruct.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/selfdestruct.sol new file mode 100644 index 0000000000..6bbae7ba5b --- /dev/null +++ b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/selfdestruct.sol @@ -0,0 +1,14 @@ +contract sd { + + uint x = 0; + function() external payable { } + + function c () public { + selfdestruct(address(0xdeadbeef)); + } + + function b () public { + selfdestruct(address(0xdeadbeef)); + x = 1; + } +} \ No newline at end of file diff --git a/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/stringBytesLength.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/stringBytesLength.sol new file mode 100644 index 0000000000..ca1f78dc09 --- /dev/null +++ b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/stringBytesLength.sol @@ -0,0 +1,10 @@ +pragma solidity >=0.4.9 <0.6.0; +contract bytesString { + + function length(string memory a) public pure returns(uint) { + bytes memory x = bytes(a); + + return x.length; + } + +} \ No newline at end of file diff --git a/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/structReentrant.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/structReentrant.sol new file mode 100644 index 0000000000..44591d5514 --- /dev/null +++ b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/structReentrant.sol @@ -0,0 +1,36 @@ +pragma solidity >=0.4.9 <0.6.0; + +contract Ballot { + + struct Voter { + uint weight; + bool voted; + uint8 vote; + address delegate; + baz foo; + } + + struct baz{ + uint bar; + } + + mapping(address => Voter) voters; + + /// Create a new ballot with $(_numProposals) different proposals. + function bla(address payable a) public { + Voter storage x = voters[a]; + + if (!a.send(10)) + revert(); + + //voters[a] = Voter(10,true,1,a); + //x.foo.bar *= 100; + bli(x); + } + + //function bla(){} + + function bli(Voter storage x) private { + x.foo.bar++; + } +} diff --git a/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/thisLocal.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/thisLocal.sol new file mode 100644 index 0000000000..d10271c5c9 --- /dev/null +++ b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/thisLocal.sol @@ -0,0 +1,16 @@ +pragma solidity >=0.4.9 <0.6.0; + +contract test { + + function () external { + address payable x; + this.b(x); + x.call('something'); + x.send(1 wei); + + } + + function b(address a) public returns (bool) { + + } +} diff --git a/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/transfer.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/transfer.sol new file mode 100644 index 0000000000..aca7cb29c0 --- /dev/null +++ b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/transfer.sol @@ -0,0 +1,7 @@ +contract c { + uint x; + function f(address payable r) public payable { + r.transfer(1); + x = 2; + } +} \ No newline at end of file diff --git a/remix-analyzer/test/tests.js b/remix-analyzer/test/tests.js index 0df3206d12..466d917277 100644 --- a/remix-analyzer/test/tests.js +++ b/remix-analyzer/test/tests.js @@ -1,4 +1,7 @@ - require('./analysis/staticAnalysisCommon-test.js') -require('./analysis/staticAnalysisIntegration-test.js') -require('./analysis/staticAnalysisIssues-test.js') + +require('./analysis/staticAnalysisIntegration-test-0.4.24.js') +require('./analysis/staticAnalysisIssues-test-0.4.24.js') + +require('./analysis/staticAnalysisIntegration-test-0.5.0.js') +require('./analysis/staticAnalysisIssues-test-0.5.0.js')