Commit 32a68276 authored by soad003's avatar soad003

Static Analysis: require / assert

parent eae29196
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
"scripts": { "scripts": {
"postinstall": "npm-link-local ../remix-lib && npm-link-local ../remix-core", "postinstall": "npm-link-local ../remix-lib && npm-link-local ../remix-core",
"test": "standard && npm run downloadsolc && tape ./test/tests.js", "test": "standard && npm run downloadsolc && tape ./test/tests.js",
"downloadsolc": "wget https://ethereum.github.io/solc-bin/soljson.js" "downloadsolc": "test -e soljson.js || wget https://ethereum.github.io/solc-bin/soljson.js"
}, },
"standard": { "standard": {
"ignore": [ "ignore": [
......
var name = 'Guard Conditions: '
var desc = 'Use require and appropriately'
var categories = require('./categories')
var common = require('./staticAnalysisCommon')
function guardConditions () {
this.guards = []
}
guardConditions.prototype.visit = function (node) {
if (common.isRequireCall(node) || common.isAssertCall(node)) this.guards.push(node)
}
guardConditions.prototype.report = function (compilationResults) {
if (this.guards.length > 0) {
return [{
warning: 'Use <i>assert(x)</i> if you never ever want <i>x</i> to be false, not in any circumstance (apart from a bug in your code). Use <i>require(x)</i> if <i>x</i> can be false, due to e.g. invalid input or a failing external component.',
more: 'http://solidity.readthedocs.io/en/develop/control-structures.html#error-handling-assert-require-revert-and-exceptions'
}]
}
return []
}
module.exports = {
name: name,
description: desc,
category: categories.MISC,
Module: guardConditions
}
...@@ -10,5 +10,6 @@ module.exports = [ ...@@ -10,5 +10,6 @@ module.exports = [
require('./lowLevelCalls'), require('./lowLevelCalls'),
require('./blockBlockhash'), require('./blockBlockhash'),
require('./noReturn'), require('./noReturn'),
require('./selfdestruct') require('./selfdestruct'),
require('./guardConditions')
] ]
...@@ -20,7 +20,9 @@ var nodeTypes = { ...@@ -20,7 +20,9 @@ var nodeTypes = {
INLINEASSEMBLY: 'InlineAssembly', INLINEASSEMBLY: 'InlineAssembly',
BLOCK: 'Block', BLOCK: 'Block',
NEWEXPRESSION: 'NewExpression', NEWEXPRESSION: 'NewExpression',
RETURN: 'Return' RETURN: 'Return',
ASSERT: 'assert',
REQUIRE: 'require'
} }
var basicTypes = { var basicTypes = {
...@@ -417,6 +419,24 @@ function isSelfdestructCall (node) { ...@@ -417,6 +419,24 @@ function isSelfdestructCall (node) {
} }
/** /**
* True if node is a call to assert
* @node {ASTNode} some AstNode
* @return {bool}
*/
function isAssertCall (node) {
return isBuiltinFunctionCall(node) && getLocalCallName(node) === 'assert'
}
/**
* True if node is a call to assert
* @node {ASTNode} some AstNode
* @return {bool}
*/
function isRequireCall (node) {
return isBuiltinFunctionCall(node) && getLocalCallName(node) === 'require'
}
/**
* True if is storage variable declaration * True if is storage variable declaration
* @node {ASTNode} some AstNode * @node {ASTNode} some AstNode
* @return {bool} * @return {bool}
...@@ -810,6 +830,8 @@ module.exports = { ...@@ -810,6 +830,8 @@ module.exports = {
isMinusMinusUnaryOperation: isMinusMinusUnaryOperation, isMinusMinusUnaryOperation: isMinusMinusUnaryOperation,
isBuiltinFunctionCall: isBuiltinFunctionCall, isBuiltinFunctionCall: isBuiltinFunctionCall,
isSelfdestructCall: isSelfdestructCall, isSelfdestructCall: isSelfdestructCall,
isAssertCall: isAssertCall,
isRequireCall: isRequireCall,
// #################### Trivial Node Identification // #################### Trivial Node Identification
isFunctionDefinition: isFunctionDefinition, isFunctionDefinition: isFunctionDefinition,
......
...@@ -441,6 +441,37 @@ test('Integration test selfdestruct.js', function (t) { ...@@ -441,6 +441,37 @@ test('Integration test selfdestruct.js', function (t) {
}) })
}) })
test('Integration test guardConditions.js', function (t) {
t.plan(testFiles.length)
var module = require('../../src/analysis/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
}
runModuleOnFiles(module, t, (file, report) => {
t.equal(report.length, lengthCheck[file], `${file} has right amount of guardCondition warnings`)
})
})
// #################### Helpers // #################### Helpers
function runModuleOnFiles (module, t, cb) { function runModuleOnFiles (module, t, cb) {
var statRunner = new StatRunner() var statRunner = new StatRunner()
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
address owner; address owner;
function at(address _addr) returns (bytes o_code) { function at(address _addr) returns (bytes o_code) {
assert(_addr != 0x0);
assembly { assembly {
// retrieve the size of the code, this needs assembly // retrieve the size of the code, this needs assembly
let size := extcodesize(_addr) let size := extcodesize(_addr)
...@@ -20,7 +21,7 @@ ...@@ -20,7 +21,7 @@
} }
function bla() { function bla() {
if(tx.origin == owner) require(tx.origin == owner);
msg.sender.send(19); msg.sender.send(19);
assembly { assembly {
......
...@@ -32,8 +32,8 @@ contract a is bla { ...@@ -32,8 +32,8 @@ contract a is bla {
now; now;
tx.gasprice; tx.gasprice;
tx.origin; tx.origin;
//assert(now == block.timestamp); // assert(1 == 2);
//require(now == block.timestamp); // require(1 == 1);
keccak256(a); keccak256(a);
sha3(a); sha3(a);
sha256(a); sha256(a);
...@@ -52,6 +52,7 @@ contract a is bla { ...@@ -52,6 +52,7 @@ contract a is bla {
//a.transfer(a.balance); //a.transfer(a.balance);
selfdestruct(a); selfdestruct(a);
//revert(); //revert();
assert(a.balance == 0);
} }
} }
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment