diff --git a/package.json b/package.json index d03925dc5a..2a82b75ea6 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,8 @@ "watchify": "^3.9.0", "web3": "^0.18.0", "webworkify": "^1.2.1", - "yo-yo": "^1.2.2" + "yo-yo": "^1.2.2", + "fast-levenshtein": "^2.0.6" }, "repository": { "type": "git", diff --git a/src/app/staticanalysis/modules/blockBlockhash.js b/src/app/staticanalysis/modules/blockBlockhash.js index 8b039db5f9..4fc7e29893 100644 --- a/src/app/staticanalysis/modules/blockBlockhash.js +++ b/src/app/staticanalysis/modules/blockBlockhash.js @@ -14,7 +14,7 @@ blockBlockhash.prototype.visit = function (node) { blockBlockhash.prototype.report = function (compilationResults) { return this.warningNodes.map(function (item, i) { return { - warning: `use of "block.blockhash": "block.blockhash" is used to access the last 256 block hashes. A miner computes the block hash be "summing up" the information in the current block mined. By "summing up" the information in a clever way a miner can try to influence the outcome of a transaction in the current block.`, + warning: `use of "block.blockhash": "block.blockhash" is used to access the last 256 block hashes. A miner computes the block hash by "summing up" the information in the current block mined. By "summing up" the information in a clever way a miner can try to influence the outcome of a transaction in the current block. This is especially easy if there are only a small number of equally likely outcomes.`, location: item.src } }) diff --git a/src/app/staticanalysis/modules/blockTimestamp.js b/src/app/staticanalysis/modules/blockTimestamp.js index 5e70c47c84..1a0e6e1bd0 100644 --- a/src/app/staticanalysis/modules/blockTimestamp.js +++ b/src/app/staticanalysis/modules/blockTimestamp.js @@ -16,7 +16,7 @@ blockTimestamp.prototype.visit = function (node) { blockTimestamp.prototype.report = function (compilationResults) { return this.warningNowNodes.map(function (item, i) { return { - warning: `use of "now": "now" does not mean current time now is an alias for block.timestamp. Block.timestamp can be influenced by miners to a certain degree, be carefull.`, + warning: `use of "now": "now" does not mean current time. Now is an alias for block.timestamp. Block.timestamp can be influenced by miners to a certain degree, be careful.`, location: item.src, more: 'http://solidity.readthedocs.io/en/develop/frequently-asked-questions.html#are-timestamps-now-block-timestamp-reliable' } diff --git a/src/app/staticanalysis/modules/lowLevelCalls.js b/src/app/staticanalysis/modules/lowLevelCalls.js index 9269e64fa9..3962da632b 100644 --- a/src/app/staticanalysis/modules/lowLevelCalls.js +++ b/src/app/staticanalysis/modules/lowLevelCalls.js @@ -25,20 +25,20 @@ lowLevelCalls.prototype.report = function (compilationResults) { var morehref = null switch (item.type) { case common.lowLevelCallTypes.CALL: - text = `use of "call": the use of low level "call" should be avoided whenever possible. It can lead to unexpected behavior if return value is not handled properly. Please use Direct Calls via specifying the called contracts interface.
` + text = `use of "call": the use of low level "call" should be avoided whenever possible. It can lead to unexpected behavior if return value is not handled properly. Please use Direct Calls via specifying the called contract's interface.
` morehref = `http://solidity.readthedocs.io/en/develop/control-structures.html?#external-function-calls` // http://solidity.readthedocs.io/en/develop/frequently-asked-questions.html?#why-is-the-low-level-function-call-less-favorable-than-instantiating-a-contract-with-a-variable-contractb-b-and-executing-its-functions-b-dosomething break case common.lowLevelCallTypes.CALLCODE: - text = `use of "callcode": the use of low level "callcode" should be avoided whenever possible. External code that is called can change the state of the calling contract and send ether form the callers balance. If this is wantend behaviour use the Solidity library feature if possible.
` + text = `use of "callcode": the use of low level "callcode" should be avoided whenever possible. External code that is called can change the state of the calling contract and send ether form the caller's balance. If this is wantend behaviour use the Solidity library feature if possible.
` morehref = `http://solidity.readthedocs.io/en/develop/contracts.html#libraries` break case common.lowLevelCallTypes.DELEGATECALL: - text = `use of "delegatecall": the use of low level "delegatecall" should be avoided whenever possible. External code that is called can change the state of the calling contract and send ether form the callers balance. If this is wantend behaviour use the Solidity library feature if possible.
` + text = `use of "delegatecall": the use of low level "delegatecall" should be avoided whenever possible. External code that is called can change the state of the calling contract and send ether form the caller's balance. If this is wantend behaviour use the Solidity library feature if possible.
` morehref = `http://solidity.readthedocs.io/en/develop/contracts.html#libraries` break case common.lowLevelCallTypes.SEND: - text = `use of "send": using "send" has several quirks. "send" does not throw an exception when not successful, make sure you deal with the failure case accordingly. Use "transfer" whenever failure of the ether transfer should rollback the whole transaction. Additionally if you send ether to a contract the fallback function is called which makes reentrancy vulnerabilities possible. "send" is more or less syntactic sugar for a "call" to the fallback function with 2300 gas and a specified ether value.
` + text = `use of "send": "send" does not throw an exception when not successful, make sure you deal with the failure case accordingly. Use "transfer" whenever failure of the ether transfer should rollback the whole transaction. Additionally if you "send" ether to a contract the fallback function is called, the callees fallback function is very limited due to the limited amount of gas provided by "send". No state changes are possible but the callee can log the event or revert the transfer. "send" is syntactic sugar for a "call" to the fallback function with 2300 gas and a specified ether value.
` morehref = `http://solidity.readthedocs.io/en/develop/security-considerations.html#sending-and-receiving-ether` break } diff --git a/src/app/staticanalysis/modules/similarVariableNames.js b/src/app/staticanalysis/modules/similarVariableNames.js index f02b1b5ac5..9d13c68a56 100644 --- a/src/app/staticanalysis/modules/similarVariableNames.js +++ b/src/app/staticanalysis/modules/similarVariableNames.js @@ -1,8 +1,9 @@ var name = 'Similar Variable Names' -var desc = 'Check if variable names are to similar' +var desc = 'Check if variable names are too similar' var categories = require('./categories') var common = require('./staticAnalysisCommon') var AbstractAst = require('./abstractAstView') +var levenshtein = require('fast-levenshtein') function similarVariableNames () { this.abstractAst = new AbstractAst() @@ -45,48 +46,21 @@ function findSimilarVarNames (vars) { var similar = [] var comb = {} vars.map((varName1) => vars.map((varName2) => { - if (varName1.length > 1 && varName2.length > 1 && varName2 !== varName1 && !(comb[varName1 + ';' + varName2] || comb[varName2 + ';' + varName1])) { + if (varName1.length > 1 && varName2.length > 1 && varName2 !== varName1 && !isCommonPrefixedVersion(varName1, varName2) && !(comb[varName1 + ';' + varName2] || comb[varName2 + ';' + varName1])) { comb[varName1 + ';' + varName2] = true - var distance = levenshteinDistance(varName1, varName2) + var distance = levenshtein.get(varName1, varName2) if (distance <= 2) similar.push({ var1: varName1, var2: varName2, distance: distance }) } })) return similar } -function getFunctionVariables (contract, func) { - return contract.stateVariables.concat(func.localVariables) +function isCommonPrefixedVersion (varName1, varName2) { + return (varName1.startsWith('_') || varName2.startsWith('_')) && (varName1.slice(1) === varName2 || varName1 === varName2.slice(1)) } -/* -* Props to DerekZiemba (see https://gist.github.com/andrei-m/982927) -* Probably better solutions out there. Libs? -*/ -function levenshteinDistance (a, b) { - let tmp - if (a.length === 0) return b.length - if (b.length === 0) return a.length - if (a.length > b.length) { - tmp = a - a = b - b = tmp - } - - let i, j, res - let alen = a.length - let blen = b.length - let row = Array(alen) - for (i = 0; i <= alen; i++) { row[i] = i } - - for (i = 1; i <= blen; i++) { - res = i - for (j = 1; j <= alen; j++) { - tmp = row[j - 1] - row[j - 1] = res - res = b[i - 1] === a[j - 1] ? tmp : Math.min(tmp + 1, Math.min(res + 1, row[j] + 1)) - } - } - return res +function getFunctionVariables (contract, func) { + return contract.stateVariables.concat(func.localVariables) } module.exports = {