Merge pull request #909 from soad003/selfdestructTerminal

Selfdestruct terminal
pull/7/head
yann300 6 years ago committed by GitHub
commit 8bee42d9f9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 9
      remix-analyzer/src/solidity-analyzer/modules/algorithmCategories.js
  2. 2
      remix-analyzer/src/solidity-analyzer/modules/assignAndCompare.js
  3. 2
      remix-analyzer/src/solidity-analyzer/modules/blockBlockhash.js
  4. 2
      remix-analyzer/src/solidity-analyzer/modules/blockTimestamp.js
  5. 2
      remix-analyzer/src/solidity-analyzer/modules/checksEffectsInteraction.js
  6. 2
      remix-analyzer/src/solidity-analyzer/modules/constantFunctions.js
  7. 2
      remix-analyzer/src/solidity-analyzer/modules/deleteDynamicArrays.js
  8. 2
      remix-analyzer/src/solidity-analyzer/modules/gasCosts.js
  9. 2
      remix-analyzer/src/solidity-analyzer/modules/guardConditions.js
  10. 2
      remix-analyzer/src/solidity-analyzer/modules/inlineAssembly.js
  11. 4
      remix-analyzer/src/solidity-analyzer/modules/intDivisionTruncate.js
  12. 2
      remix-analyzer/src/solidity-analyzer/modules/lowLevelCalls.js
  13. 2
      remix-analyzer/src/solidity-analyzer/modules/noReturn.js
  14. 54
      remix-analyzer/src/solidity-analyzer/modules/selfdestruct.js
  15. 2
      remix-analyzer/src/solidity-analyzer/modules/similarVariableNames.js
  16. 10
      remix-analyzer/src/solidity-analyzer/modules/staticAnalysisCommon.js
  17. 2
      remix-analyzer/src/solidity-analyzer/modules/thisLocal.js
  18. 2
      remix-analyzer/src/solidity-analyzer/modules/txOrigin.js
  19. 6
      remix-analyzer/test/analysis/staticAnalysisIntegration-test.js
  20. 12
      remix-analyzer/test/analysis/test-contracts/intDivisionTruncate.sol
  21. 2
      remix-analyzer/test/analysis/test-contracts/selfdestruct.sol

@ -0,0 +1,9 @@
/**
* Should be used to categorize different modules, main reason is to give users feedback if the modules
* Produce exact results or have false positives and negatives in them
* A further category could be approximate if some form of approximation is used
*/
module.exports = {
EXACT: { hasFalsePositives: false, hasFalseNegatives: false, id: 'EXACT' },
HEURISTIC: { hasFalsePositives: true, hasFalseNegatives: true, id: 'HEURI' }
}

@ -2,6 +2,7 @@ var name = 'Result not used: '
var desc = 'The result of an operation was not used.' var desc = 'The result of an operation was not used.'
var categories = require('./categories') var categories = require('./categories')
var common = require('./staticAnalysisCommon') var common = require('./staticAnalysisCommon')
var algo = require('./algorithmCategories')
function assignAndCompare () { function assignAndCompare () {
this.warningNodes = [] this.warningNodes = []
@ -24,5 +25,6 @@ module.exports = {
name: name, name: name,
description: desc, description: desc,
category: categories.MISC, category: categories.MISC,
algorithm: algo.EXACT,
Module: assignAndCompare Module: assignAndCompare
} }

@ -2,6 +2,7 @@ var name = 'Block.blockhash usage: '
var desc = 'Semantics maybe unclear' var desc = 'Semantics maybe unclear'
var categories = require('./categories') var categories = require('./categories')
var common = require('./staticAnalysisCommon') var common = require('./staticAnalysisCommon')
var algo = require('./algorithmCategories')
function blockBlockhash () { function blockBlockhash () {
this.warningNodes = [] this.warningNodes = []
@ -27,6 +28,7 @@ module.exports = {
name: name, name: name,
description: desc, description: desc,
category: categories.SECURITY, category: categories.SECURITY,
algorithm: algo.EXACT,
Module: blockBlockhash Module: blockBlockhash
} }

@ -2,6 +2,7 @@ var name = 'Block timestamp: '
var desc = 'Semantics maybe unclear' var desc = 'Semantics maybe unclear'
var categories = require('./categories') var categories = require('./categories')
var common = require('./staticAnalysisCommon') var common = require('./staticAnalysisCommon')
var algo = require('./algorithmCategories')
function blockTimestamp () { function blockTimestamp () {
this.warningNowNodes = [] this.warningNowNodes = []
@ -35,6 +36,7 @@ module.exports = {
name: name, name: name,
description: desc, description: desc,
category: categories.SECURITY, category: categories.SECURITY,
algorithm: algo.EXACT,
Module: blockTimestamp Module: blockTimestamp
} }

@ -4,6 +4,7 @@ var categories = require('./categories')
var common = require('./staticAnalysisCommon') var common = require('./staticAnalysisCommon')
var fcallGraph = require('./functionCallGraph') var fcallGraph = require('./functionCallGraph')
var AbstractAst = require('./abstractAstView') var AbstractAst = require('./abstractAstView')
var algo = require('./algorithmCategories')
function checksEffectsInteraction () { function checksEffectsInteraction () {
this.abstractAst = new AbstractAst() this.abstractAst = new AbstractAst()
@ -84,5 +85,6 @@ module.exports = {
name: name, name: name,
description: desc, description: desc,
category: categories.SECURITY, category: categories.SECURITY,
algorithm: algo.HEURISTIC,
Module: checksEffectsInteraction Module: checksEffectsInteraction
} }

@ -4,6 +4,7 @@ var categories = require('./categories')
var common = require('./staticAnalysisCommon') var common = require('./staticAnalysisCommon')
var fcallGraph = require('./functionCallGraph') var fcallGraph = require('./functionCallGraph')
var AbstractAst = require('./abstractAstView') var AbstractAst = require('./abstractAstView')
var algo = require('./algorithmCategories')
function constantFunctions () { function constantFunctions () {
this.abstractAst = new AbstractAst() this.abstractAst = new AbstractAst()
@ -104,5 +105,6 @@ module.exports = {
name: name, name: name,
description: desc, description: desc,
category: categories.MISC, category: categories.MISC,
algorithm: algo.HEURISTIC,
Module: constantFunctions Module: constantFunctions
} }

@ -2,6 +2,7 @@ var name = 'Delete on dynamic Array: '
var desc = 'Use require and appropriately' var desc = 'Use require and appropriately'
var categories = require('./categories') var categories = require('./categories')
var common = require('./staticAnalysisCommon') var common = require('./staticAnalysisCommon')
var algo = require('./algorithmCategories')
function deleteDynamicArrays () { function deleteDynamicArrays () {
this.rel = [] this.rel = []
@ -25,5 +26,6 @@ module.exports = {
name: name, name: name,
description: desc, description: desc,
category: categories.GAS, category: categories.GAS,
algorithm: algo.EXACT,
Module: deleteDynamicArrays Module: deleteDynamicArrays
} }

@ -1,6 +1,7 @@
var name = 'Gas costs: ' var name = 'Gas costs: '
var desc = 'Warn if the gas requirements of functions are too high.' var desc = 'Warn if the gas requirements of functions are too high.'
var categories = require('./categories') var categories = require('./categories')
var algo = require('./algorithmCategories')
function gasCosts () { function gasCosts () {
} }
@ -61,5 +62,6 @@ module.exports = {
name: name, name: name,
description: desc, description: desc,
category: categories.GAS, category: categories.GAS,
algorithm: algo.EXACT,
Module: gasCosts Module: gasCosts
} }

@ -2,6 +2,7 @@ var name = 'Guard Conditions: '
var desc = 'Use require and appropriately' var desc = 'Use require and appropriately'
var categories = require('./categories') var categories = require('./categories')
var common = require('./staticAnalysisCommon') var common = require('./staticAnalysisCommon')
var algo = require('./algorithmCategories')
function guardConditions () { function guardConditions () {
this.guards = [] this.guards = []
@ -25,5 +26,6 @@ module.exports = {
name: name, name: name,
description: desc, description: desc,
category: categories.MISC, category: categories.MISC,
algorithm: algo.EXACT,
Module: guardConditions Module: guardConditions
} }

@ -2,6 +2,7 @@ var name = 'Inline assembly: '
var desc = 'Use of Inline Assembly' var desc = 'Use of Inline Assembly'
var categories = require('./categories') var categories = require('./categories')
var common = require('./staticAnalysisCommon') var common = require('./staticAnalysisCommon')
var algo = require('./algorithmCategories')
function inlineAssembly () { function inlineAssembly () {
this.inlineAssNodes = [] this.inlineAssNodes = []
@ -26,5 +27,6 @@ module.exports = {
name: name, name: name,
description: desc, description: desc,
category: categories.SECURITY, category: categories.SECURITY,
algorithm: algo.EXACT,
Module: inlineAssembly Module: inlineAssembly
} }

@ -2,6 +2,7 @@ var name = 'Data Trucated: '
var desc = 'Division on int/uint values truncates the result.' var desc = 'Division on int/uint values truncates the result.'
var categories = require('./categories') var categories = require('./categories')
var common = require('./staticAnalysisCommon') var common = require('./staticAnalysisCommon')
var algo = require('./algorithmCategories')
function intDivitionTruncate () { function intDivitionTruncate () {
this.warningNodes = [] this.warningNodes = []
@ -14,7 +15,7 @@ intDivitionTruncate.prototype.visit = function (node) {
intDivitionTruncate.prototype.report = function (compilationResults) { intDivitionTruncate.prototype.report = function (compilationResults) {
return this.warningNodes.map(function (item, i) { return this.warningNodes.map(function (item, i) {
return { return {
warning: 'Division of integer values yields an integer value again. That means eg. a / 100 = 0 instead of 0.a since the result is an integer again. This does not hold for division of (only) literal values since those yield rational constants.', warning: 'Division of integer values yields an integer value again. That means e.g. 10 / 100 = 0 instead of 0.1 since the result is an integer again. This does not hold for division of (only) literal values since those yield rational constants.',
location: item.src location: item.src
} }
}) })
@ -24,5 +25,6 @@ module.exports = {
name: name, name: name,
description: desc, description: desc,
category: categories.MISC, category: categories.MISC,
algorithm: algo.EXACT,
Module: intDivitionTruncate Module: intDivitionTruncate
} }

@ -2,6 +2,7 @@ var name = 'Low level calls: '
var desc = 'Semantics maybe unclear' var desc = 'Semantics maybe unclear'
var categories = require('./categories') var categories = require('./categories')
var common = require('./staticAnalysisCommon') var common = require('./staticAnalysisCommon')
var algo = require('./algorithmCategories')
function lowLevelCalls () { function lowLevelCalls () {
this.llcNodes = [] this.llcNodes = []
@ -59,6 +60,7 @@ module.exports = {
name: name, name: name,
description: desc, description: desc,
category: categories.SECURITY, category: categories.SECURITY,
algorithm: algo.EXACT,
Module: lowLevelCalls Module: lowLevelCalls
} }

@ -3,6 +3,7 @@ var desc = 'Function with return type is not returning'
var categories = require('./categories') var categories = require('./categories')
var common = require('./staticAnalysisCommon') var common = require('./staticAnalysisCommon')
var AbstractAst = require('./abstractAstView') var AbstractAst = require('./abstractAstView')
var algo = require('./algorithmCategories')
function noReturn () { function noReturn () {
this.abstractAst = new AbstractAst() this.abstractAst = new AbstractAst()
@ -69,5 +70,6 @@ module.exports = {
name: name, name: name,
description: desc, description: desc,
category: categories.MISC, category: categories.MISC,
algorithm: algo.EXACT,
Module: noReturn Module: noReturn
} }

@ -2,30 +2,58 @@ var name = 'Selfdestruct: '
var desc = 'Be aware of caller contracts.' var desc = 'Be aware of caller contracts.'
var categories = require('./categories') var categories = require('./categories')
var common = require('./staticAnalysisCommon') var common = require('./staticAnalysisCommon')
var AbstractAst = require('./abstractAstView')
var algo = require('./algorithmCategories')
function selfdestruct () { function selfdestruct () {
this.relevantNodes = [] this.abstractAst = new AbstractAst()
}
this.visit = this.abstractAst.build_visit(
(node) => common.isStatement(node) ||
common.isSelfdestructCall(node)
)
selfdestruct.prototype.visit = function (node) { this.report = this.abstractAst.build_report(report)
if (common.isSelfdestructCall(node)) {
this.relevantNodes.push(node)
}
} }
selfdestruct.prototype.report = function () { selfdestruct.prototype.visit = function () { throw new Error('selfdestruct.js no visit function set upon construction') }
return this.relevantNodes.map(function (item, i) {
return { selfdestruct.prototype.report = function () { throw new Error('selfdestruct.js no report function set upon construction') }
warning: 'Use of selfdestruct: can block calling contracts unexpectedly. Be especially careful if this contract is planned to be used by other contracts (i.e. library contracts, interactions). Selfdestruction of the callee contract can leave callers in an inoperable state.',
location: item.src, function report (contracts, multipleContractsWithSameName) {
more: 'https://paritytech.io/blog/security-alert.html' var warnings = []
}
contracts.forEach((contract) => {
contract.functions.forEach((func) => {
let hasSelf = false
func.relevantNodes.forEach((node) => {
if (common.isSelfdestructCall(node)) {
warnings.push({
warning: 'Use of selfdestruct: can block calling contracts unexpectedly. Be especially careful if this contract is planned to be used by other contracts (i.e. library contracts, interactions). Selfdestruction of the callee contract can leave callers in an inoperable state.',
location: node.src,
more: 'https://paritytech.io/blog/security-alert.html'
})
hasSelf = true
}
if (common.isStatement(node) && hasSelf) {
warnings.push({
warning: 'Use of selfdestruct: No code after selfdestruct is executed. Selfdestruct is a terminal.',
location: node.src,
more: 'http://solidity.readthedocs.io/en/develop/introduction-to-smart-contracts.html#self-destruct'
})
hasSelf = false
}
})
})
}) })
return warnings
} }
module.exports = { module.exports = {
name: name, name: name,
description: desc, description: desc,
category: categories.SECURITY, category: categories.SECURITY,
algorithm: algo.HEURISTIC,
Module: selfdestruct Module: selfdestruct
} }

@ -6,6 +6,7 @@ var AbstractAst = require('./abstractAstView')
var levenshtein = require('fast-levenshtein') var levenshtein = require('fast-levenshtein')
var remixLib = require('remix-lib') var remixLib = require('remix-lib')
var util = remixLib.util var util = remixLib.util
var algo = require('./algorithmCategories')
function similarVariableNames () { function similarVariableNames () {
this.abstractAst = new AbstractAst() this.abstractAst = new AbstractAst()
@ -82,5 +83,6 @@ module.exports = {
name: name, name: name,
description: desc, description: desc,
category: categories.MISC, category: categories.MISC,
algorithm: algo.EXACT,
Module: similarVariableNames Module: similarVariableNames
} }

@ -396,6 +396,14 @@ function isFunctionDefinition (node) {
return nodeType(node, exactMatch(nodeTypes.FUNCTIONDEFINITION)) return nodeType(node, exactMatch(nodeTypes.FUNCTIONDEFINITION))
} }
function isStatement (node) {
return nodeType(node, 'Statement$') || isBlock(node) || isReturn(node)
}
function isBlock (node) {
return nodeType(node, exactMatch(nodeTypes.BLOCK))
}
function isModifierDefinition (node) { function isModifierDefinition (node) {
return nodeType(node, exactMatch(nodeTypes.MODIFIERDEFINITION)) return nodeType(node, exactMatch(nodeTypes.MODIFIERDEFINITION))
} }
@ -1009,6 +1017,8 @@ module.exports = {
isInlineAssembly: isInlineAssembly, isInlineAssembly: isInlineAssembly,
isNewExpression: isNewExpression, isNewExpression: isNewExpression,
isReturn: isReturn, isReturn: isReturn,
isStatement: isStatement,
isBlock: isBlock,
// #################### Constants // #################### Constants
nodeTypes: nodeTypes, nodeTypes: nodeTypes,

@ -2,6 +2,7 @@ var name = 'This on local calls: '
var desc = 'Invocation of local functions via this' var desc = 'Invocation of local functions via this'
var categories = require('./categories') var categories = require('./categories')
var common = require('./staticAnalysisCommon') var common = require('./staticAnalysisCommon')
var algo = require('./algorithmCategories')
function thisLocal () { function thisLocal () {
this.warningNodes = [] this.warningNodes = []
@ -25,5 +26,6 @@ module.exports = {
name: name, name: name,
description: desc, description: desc,
category: categories.GAS, category: categories.GAS,
algorithm: algo.EXACT,
Module: thisLocal Module: thisLocal
} }

@ -1,6 +1,7 @@
var name = 'Transaction origin: ' var name = 'Transaction origin: '
var desc = 'Warn if tx.origin is used' var desc = 'Warn if tx.origin is used'
var categories = require('./categories') var categories = require('./categories')
var algo = require('./algorithmCategories')
function txOrigin () { function txOrigin () {
this.txOriginNodes = [] this.txOriginNodes = []
@ -31,5 +32,6 @@ module.exports = {
name: name, name: name,
description: desc, description: desc,
category: categories.SECURITY, category: categories.SECURITY,
algorithm: algo.EXACT,
Module: txOrigin Module: txOrigin
} }

@ -466,15 +466,15 @@ test('Integration test selfdestruct.js', function (t) {
'notReentrant.sol': 0, 'notReentrant.sol': 0,
'structReentrant.sol': 0, 'structReentrant.sol': 0,
'thisLocal.sol': 0, 'thisLocal.sol': 0,
'globals.sol': 1, 'globals.sol': 2,
'library.sol': 0, 'library.sol': 0,
'transfer.sol': 0, 'transfer.sol': 0,
'ctor.sol': 0, 'ctor.sol': 0,
'forgottenReturn.sol': 0, 'forgottenReturn.sol': 0,
'selfdestruct.sol': 2, 'selfdestruct.sol': 3,
'deleteDynamicArray.sol': 0, 'deleteDynamicArray.sol': 0,
'blockLevelCompare.sol': 0, 'blockLevelCompare.sol': 0,
'intDivisionTruncate.sol': 1 'intDivisionTruncate.sol': 5
} }
runModuleOnFiles(module, t, (file, report) => { runModuleOnFiles(module, t, (file, report) => {

@ -21,8 +21,18 @@ contract CharityCampaign {
return fee; return fee;
} }
function endCampaign() public { function endCampaign() public returns (bool) {
require(msg.sender == processor || msg.sender == beneficiary); require(msg.sender == processor || msg.sender == beneficiary);
selfdestruct(beneficiary); selfdestruct(beneficiary);
return true;
}
// FALSE POSITIVE FOR SELFDESTRUCT TERMINAL
function endAmbiguous() public {
if(msg.sender == 0x0) {
selfdestruct(beneficiary);
} else {
selfdestruct(processor);
}
} }
} }

@ -1,5 +1,6 @@
contract sd { contract sd {
uint x = 0;
function() public payable { } function() public payable { }
function c () public constant { function c () public constant {
@ -8,5 +9,6 @@ contract sd {
function b () public payable { function b () public payable {
selfdestruct(address(0xdeadbeef)); selfdestruct(address(0xdeadbeef));
x = 1;
} }
} }
Loading…
Cancel
Save