Unverified Commit fd2d4c83 authored by yann300's avatar yann300 Committed by GitHub

Merge pull request #617 from ethereum/staticanalysismodule

Move static analysis to remix-solidity
parents f3e30d92 1d6e50c7
{ {
"name": "remix-lib", "name": "remix-lib",
"version": "0.0.3", "version": "0.0.4",
"description": "Ethereum IDE and tools for the web", "description": "Ethereum IDE and tools for the web",
"contributors": [ "contributors": [
{ {
......
...@@ -182,7 +182,10 @@ module.exports = { ...@@ -182,7 +182,10 @@ module.exports = {
return true return true
} }
return false return false
} },
groupBy: groupBy,
concatWithSeperator: concatWithSeperator,
escapeRegExp: escapeRegExp
} }
function replaceLibReference (code, pos) { function replaceLibReference (code, pos) {
...@@ -213,3 +216,22 @@ function findCallInternal (index, rootCall, callsPath) { ...@@ -213,3 +216,22 @@ function findCallInternal (index, rootCall, callsPath) {
} }
return ret return ret
} }
/* util extracted out from browser-solidity. @TODO split this file, cause it mix real util fn with solidity related stuff ... */
function groupBy (arr, key) {
return arr.reduce((sum, item) => {
const groupByVal = item[key]
var groupedItems = sum[groupByVal] || []
groupedItems.push(item)
sum[groupByVal] = groupedItems
return sum
}, {})
}
function concatWithSeperator (list, seperator) {
return list.reduce((sum, item) => sum + item + seperator, '').slice(0, -seperator.length)
}
function escapeRegExp (str) {
return str.replace(/[-[\]/{}()+?.\\^$|]/g, '\\$&')
}
...@@ -29,3 +29,43 @@ tape('Util', function (t) { ...@@ -29,3 +29,43 @@ tape('Util', function (t) {
st.equal(lowerBound, -1) st.equal(lowerBound, -1)
}) })
}) })
tape('util.groupBy on valid input', function (t) {
t.plan(1)
var result = util.groupBy([
{category: 'GAS', name: 'a'},
{category: 'SEC', name: 'b'},
{category: 'GAS', name: 'c'}
], 'category')
var expectedResult = {
'GAS': [
{category: 'GAS', name: 'a'},
{category: 'GAS', name: 'c'}
],
'SEC': [
{category: 'SEC', name: 'b'}
]
}
t.deepEqual(result, expectedResult)
})
tape('util.concatWithSeperator valid output', function (t) {
t.plan(4)
t.notEqual(util.concatWithSeperator(['a', 'b', 'c'], ','), 'a, b, c', 'Concat with comma should not produce spaces')
t.equal(util.concatWithSeperator(['a', 'b', 'c'], ','), 'a,b,c', 'Concat with comma should not produce spaces')
t.equal(util.concatWithSeperator(['a', 'b', 'c'], ', '), 'a, b, c', 'Concat with comma space should not produce trailing comma')
t.equal(util.concatWithSeperator(['a', 'b', 'c'], '+'), 'a+b+c', 'Concat with plus')
})
tape('util.escapeRegExp', function (t) {
t.plan(3)
var original = 'function (uint256) returns (bool)'
t.equal(util.escapeRegExp('abcd'), 'abcd', 'String with no regex')
t.equal(util.escapeRegExp(original), 'function \\(uint256\\) returns \\(bool\\)', 'function string with regex')
t.ok(new RegExp(util.escapeRegExp(original)).test(original), 'should still test for original string')
})
var InternalCallTree = require('./src/internalCallTree') var InternalCallTree = require('./src/decoder/internalCallTree')
var SolidityProxy = require('./src/solidityProxy') var SolidityProxy = require('./src/decoder/solidityProxy')
var localDecoder = require('./src/localDecoder') var localDecoder = require('./src/decoder/localDecoder')
var stateDecoder = require('./src/stateDecoder') var stateDecoder = require('./src/decoder/stateDecoder')
var CodeAnalysis = require('./src/analysis/staticAnalysisRunner')
module.exports = { module.exports = {
InternalCallTree: InternalCallTree, InternalCallTree: InternalCallTree,
SolidityProxy: SolidityProxy, SolidityProxy: SolidityProxy,
localDecoder: localDecoder, localDecoder: localDecoder,
stateDecoder: stateDecoder stateDecoder: stateDecoder,
CodeAnalysis: CodeAnalysis
} }
{ {
"name": "remix-solidity", "name": "remix-solidity",
"version": "0.0.2", "version": "0.0.3",
"description": "Ethereum IDE and tools for the web", "description": "Ethereum IDE and tools for the web",
"contributors": [ "contributors": [
{ {
...@@ -30,12 +30,13 @@ ...@@ -30,12 +30,13 @@
}, },
"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 && tape ./test/tests.js" "test": "standard && npm run downloadsolc && tape ./test/tests.js",
"downloadsolc": "wget https://ethereum.github.io/solc-bin/soljson.js"
}, },
"standard": { "standard": {
"ignore": [ "ignore": [
"node_modules/*", "node_modules/*",
"build/*" "soljson.js"
], ],
"parser": "babel-eslint" "parser": "babel-eslint"
}, },
......
var common = require('./staticAnalysisCommon')
var AstWalker = require('remix-lib').AstWalker
function abstractAstView () {
this.contracts = []
this.currentContractIndex = null
this.currentFunctionIndex = null
this.currentModifierIndex = null
this.isFunctionNotModifier = false
/*
file1: contract c{}
file2: import "file1" as x; contract c{}
therefore we have two contracts with the same name c. At the moment this is not handled because alias name "x" is not
available in the current AST implementation thus can not be resolved.
Additionally the fullQuallified function names e.g. [contractName].[functionName](param1Type, param2Type, ... ) must be prefixed to
fully support this and when inheritance is resolved it must include alias resolving e.g x.c = file1.c
*/
this.multipleContractsWithSameName = false
}
/**
* Builds a higher level AST view. I creates a list with each contract as an object in it.
* Example contractsOut:
*
* {
* "node": {}, // actual AST Node of the contract
* "functions": [
* {
* "node": {}, // actual AST Node of the function
* "relevantNodes": [], // AST nodes in the function that are relevant for the anlysis of this function
* "modifierInvocations": [], // Modifier invocation AST nodes that are applied on this function
* "localVariables": [], // Local variable declaration nodes
* "parameters": [] // Parameter types of the function in order of definition
* }
* ],
* "modifiers": [], // Modifiers definded by the contract, format similar to functions
* "inheritsFrom": [], // Names of contract this one inherits from in order of definition
* "stateVariables": [] // AST nodes of all State variables
* }
*
* @relevantNodeFilter {ASTNode -> bool} function that selects relevant ast nodes for analysis on function level.
* @contractsOut {list} return list for high level AST view
* @return {ASTNode -> void} returns a function that can be used as visit function for static analysis modules, to build up a higher level AST view for further analysis.
*/
abstractAstView.prototype.build_visit = function (relevantNodeFilter) {
var that = this
return function (node) {
if (common.isContractDefinition(node)) {
setCurrentContract(that, {
node: node,
functions: [],
relevantNodes: [],
modifiers: [],
inheritsFrom: [],
stateVariables: common.getStateVariableDeclarationsFormContractNode(node)
})
} else if (common.isInheritanceSpecifier(node)) {
var currentContract = getCurrentContract(that)
var inheritsFromName = common.getInheritsFromName(node)
currentContract.inheritsFrom.push(inheritsFromName)
} else if (common.isFunctionDefinition(node)) {
setCurrentFunction(that, {
node: node,
relevantNodes: [],
modifierInvocations: [],
localVariables: getLocalVariables(node),
parameters: getLocalParameters(node),
returns: getReturnParameters(node)
})
// push back relevant nodes to their the current fn if any
getCurrentContract(that).relevantNodes.map((item) => {
if (item.referencedDeclaration === node.id) {
getCurrentFunction(that).relevantNodes.push(item.node)
}
})
} else if (common.isModifierDefinition(node)) {
setCurrentModifier(that, {
node: node,
relevantNodes: [],
localVariables: getLocalVariables(node),
parameters: getLocalParameters(node)
})
} else if (common.isModifierInvocation(node)) {
if (!that.isFunctionNotModifier) throw new Error('abstractAstView.js: Found modifier invocation outside of function scope.')
getCurrentFunction(that).modifierInvocations.push(node)
} else if (relevantNodeFilter(node)) {
var scope = (that.isFunctionNotModifier) ? getCurrentFunction(that) : getCurrentModifier(that)
if (scope) {
scope.relevantNodes.push(node)
} else {
scope = getCurrentContract(that) // if we are not in a function scope, add the node to the contract scope
if (scope && node.children[0] && node.children[0].attributes && node.children[0].attributes.referencedDeclaration) {
scope.relevantNodes.push({ referencedDeclaration: node.children[0].attributes.referencedDeclaration, node: node })
}
}
}
}
}
abstractAstView.prototype.build_report = function (wrap) {
var that = this
return function (compilationResult) {
resolveStateVariablesInHierarchy(that.contracts)
return wrap(that.contracts, that.multipleContractsWithSameName)
}
}
function resolveStateVariablesInHierarchy (contracts) {
contracts.map((c) => {
resolveStateVariablesInHierarchyForContract(c, contracts)
})
}
function resolveStateVariablesInHierarchyForContract (currentContract, contracts) {
currentContract.inheritsFrom.map((inheritsFromName) => {
// add variables from inherited contracts
var inheritsFrom = contracts.find((contract) => common.getContractName(contract.node) === inheritsFromName)
if (inheritsFrom) {
currentContract.stateVariables = currentContract.stateVariables.concat(inheritsFrom.stateVariables)
} else {
console.log('abstractAstView.js: could not find contract defintion inherited from ' + inheritsFromName)
}
})
}
function setCurrentContract (that, contract) {
var name = common.getContractName(contract.node)
if (that.contracts.map((c) => common.getContractName(c.node)).filter((n) => n === name).length > 0) {
console.log('abstractAstView.js: two or more contracts with the same name dectected, import aliases not supported at the moment')
that.multipleContractsWithSameName = true
}
that.currentContractIndex = (that.contracts.push(contract) - 1)
}
function setCurrentFunction (that, func) {
that.isFunctionNotModifier = true
that.currentFunctionIndex = (getCurrentContract(that).functions.push(func) - 1)
}
function setCurrentModifier (that, modi) {
that.isFunctionNotModifier = false
that.currentModifierIndex = (getCurrentContract(that).modifiers.push(modi) - 1)
}
function getCurrentContract (that) {
return that.contracts[that.currentContractIndex]
}
function getCurrentFunction (that) {
return getCurrentContract(that).functions[that.currentFunctionIndex]
}
function getCurrentModifier (that) {
return getCurrentContract(that).modifiers[that.currentModifierIndex]
}
function getLocalParameters (funcNode) {
return getLocalVariables(common.getFunctionOrModifierDefinitionParameterPart(funcNode)).map(common.getType)
}
function getReturnParameters (funcNode) {
return getLocalVariables(common.getFunctionOrModifierDefinitionReturnParameterPart(funcNode)).map((n) => {
return {
type: common.getType(n),
name: common.getDeclaredVariableName(n)
}
})
}
function getLocalVariables (funcNode) {
var locals = []
new AstWalker().walk(funcNode, {'*': function (node) {
if (common.isVariableDeclaration(node)) locals.push(node)
return true
}})
return locals
}
module.exports = abstractAstView
var name = 'Block.blockhash usage: '
var desc = 'Semantics maybe unclear'
var categories = require('./categories')
var common = require('./staticAnalysisCommon')
function blockBlockhash () {
this.warningNodes = []
}
blockBlockhash.prototype.visit = function (node) {
if (common.isBlockBlockHashAccess(node)) this.warningNodes.push(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 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
}
})
}
module.exports = {
name: name,
description: desc,
category: categories.SECURITY,
Module: blockBlockhash
}
var name = 'Block timestamp: '
var desc = 'Semantics maybe unclear'
var categories = require('./categories')
var common = require('./staticAnalysisCommon')
function blockTimestamp () {
this.warningNowNodes = []
this.warningblockTimestampNodes = []
}
blockTimestamp.prototype.visit = function (node) {
if (common.isNowAccess(node)) this.warningNowNodes.push(node)
else if (common.isBlockTimestampAccess(node)) this.warningblockTimestampNodes.push(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 careful.`,
location: item.src,
more: 'http://solidity.readthedocs.io/en/develop/frequently-asked-questions.html#are-timestamps-now-block-timestamp-reliable'
}
}).concat(this.warningblockTimestampNodes.map(function (item, i) {
return {
warning: `use of "block.timestamp": "block.timestamp" can be influenced by miners to a certain degree.
That means that a miner can "choose" the block.timestamp, to a certain degree, to change the outcome of a transaction in the mined block.`,
location: item.src,
more: 'http://solidity.readthedocs.io/en/develop/frequently-asked-questions.html#are-timestamps-now-block-timestamp-reliable'
}
}))
}
module.exports = {
name: name,
description: desc,
category: categories.SECURITY,
Module: blockTimestamp
}
module.exports = {
SECURITY: {displayName: 'Security', id: 'SEC'},
GAS: {displayName: 'Gas & Economy', id: 'GAS'},
MISC: {displayName: 'Miscellaneous', id: 'MISC'}
}
var name = 'Check effects: '
var desc = 'Avoid potential reentrancy bugs'
var categories = require('./categories')
var common = require('./staticAnalysisCommon')
var fcallGraph = require('./functionCallGraph')
var AbstractAst = require('./abstractAstView')
function checksEffectsInteraction () {
this.abstractAst = new AbstractAst()
this.visit = this.abstractAst.build_visit(
(node) => common.isInteraction(node) || common.isEffect(node) || common.isLocalCallGraphRelevantNode(node)
)
this.report = this.abstractAst.build_report(report)
}
checksEffectsInteraction.prototype.visit = function () { throw new Error('checksEffectsInteraction.js no visit function set upon construction') }
checksEffectsInteraction.prototype.report = function () { throw new Error('checksEffectsInteraction.js no report function set upon construction') }
function report (contracts, multipleContractsWithSameName) {
var warnings = []
var hasModifiers = contracts.some((item) => item.modifiers.length > 0)
var callGraph = fcallGraph.buildGlobalFuncCallGraph(contracts)
contracts.forEach((contract) => {
contract.functions.forEach((func) => {
func.changesState = checkIfChangesState(common.getFullQuallyfiedFuncDefinitionIdent(contract.node, func.node, func.parameters),
getContext(callGraph, contract, func))
})
contract.functions.forEach((func) => {
if (isPotentialVulnerableFunction(func, getContext(callGraph, contract, func))) {
var funcName = common.getFullQuallyfiedFuncDefinitionIdent(contract.node, func.node, func.parameters)
var comments = (hasModifiers) ? '<br/><i>Note:</i> Modifiers are currently not considered by this static analysis.' : ''
comments += (multipleContractsWithSameName) ? '<br/><i>Note:</i> Import aliases are currently not supported by this static analysis.' : ''
warnings.push({
warning: `Potential Violation of Checks-Effects-Interaction pattern in <i>${funcName}</i>: Could potentially lead to re-entrancy vulnerability. ${comments}`,
location: func.src,
more: 'http://solidity.readthedocs.io/en/develop/security-considerations.html#re-entrancy'
})
}
})
})
return warnings
}
function getContext (callGraph, currentContract, func) {
return { callGraph: callGraph, currentContract: currentContract, stateVariables: getStateVariables(currentContract, func) }
}
function getStateVariables (contract, func) {
return contract.stateVariables.concat(func.localVariables.filter(common.isStorageVariableDeclaration))
}
function isPotentialVulnerableFunction (func, context) {
var isPotentialVulnerable = false
var interaction = false
func.relevantNodes.forEach((node) => {
if (common.isInteraction(node)) {
interaction = true
} else if (interaction && (common.isWriteOnStateVariable(node, context.stateVariables) || isLocalCallWithStateChange(node, context))) {
isPotentialVulnerable = true
}
})
return isPotentialVulnerable
}
function isLocalCallWithStateChange (node, context) {
if (common.isLocalCallGraphRelevantNode(node)) {
var func = fcallGraph.resolveCallGraphSymbol(context.callGraph, common.getFullQualifiedFunctionCallIdent(context.currentContract.node, node))
return !func || (func && func.node.changesState)
}
return false
}
function checkIfChangesState (startFuncName, context) {
return fcallGraph.analyseCallGraph(context.callGraph, startFuncName, context, (node, context) => common.isWriteOnStateVariable(node, context.stateVariables))
}
module.exports = {
name: name,
description: desc,
category: categories.SECURITY,
Module: checksEffectsInteraction
}
var name = 'Constant functions: '
var desc = 'Check for potentially constant functions'
var categories = require('./categories')
var common = require('./staticAnalysisCommon')
var fcallGraph = require('./functionCallGraph')
var AbstractAst = require('./abstractAstView')
function constantFunctions () {
this.abstractAst = new AbstractAst()
this.visit = this.abstractAst.build_visit(
(node) => common.isLowLevelCall(node) ||
common.isTransfer(node) ||
common.isExternalDirectCall(node) ||
common.isEffect(node) ||
common.isLocalCallGraphRelevantNode(node) ||
common.isInlineAssembly(node) ||
common.isNewExpression(node) ||
common.isSelfdestructCall(node)
)
this.report = this.abstractAst.build_report(report)
}
constantFunctions.prototype.visit = function () { throw new Error('constantFunctions.js no visit function set upon construction') }
constantFunctions.prototype.report = function () { throw new Error('constantFunctions.js no report function set upon construction') }
function report (contracts, multipleContractsWithSameName) {
var warnings = []
var hasModifiers = contracts.some((item) => item.modifiers.length > 0)
var callGraph = fcallGraph.buildGlobalFuncCallGraph(contracts)
contracts.forEach((contract) => {
contract.functions.forEach((func) => {
if (common.isPayableFunction(func.node)) {
func.potentiallyshouldBeConst = false
} else {
func.potentiallyshouldBeConst = checkIfShouldBeConstant(common.getFullQuallyfiedFuncDefinitionIdent(contract.node, func.node, func.parameters),
getContext(callGraph, contract, func))
}
})
contract.functions.filter((func) => common.hasFunctionBody(func.node)).forEach((func) => {
if (common.isConstantFunction(func.node) !== func.potentiallyshouldBeConst) {
var funcName = common.getFullQuallyfiedFuncDefinitionIdent(contract.node, func.node, func.parameters)
var comments = (hasModifiers) ? '<br/><i>Note:</i> Modifiers are currently not considered by this static analysis.' : ''
comments += (multipleContractsWithSameName) ? '<br/><i>Note:</i> Import aliases are currently not supported by this static analysis.' : ''
if (func.potentiallyshouldBeConst) {
warnings.push({
warning: `${funcName} : Potentially should be constant but is not. ${comments}`,
location: func.src,
more: 'http://solidity.readthedocs.io/en/develop/contracts.html#constant-functions'
})
} else {
warnings.push({
warning: `${funcName} : Is constant but potentially should not be. ${comments}`,
location: func.src,
more: 'http://solidity.readthedocs.io/en/develop/contracts.html#constant-functions'
})
}
}
})
})
return warnings
}
function getContext (callGraph, currentContract, func) {
return { callGraph: callGraph, currentContract: currentContract, stateVariables: getStateVariables(currentContract, func) }
}
function getStateVariables (contract, func) {
return contract.stateVariables.concat(func.localVariables.filter(common.isStorageVariableDeclaration))
}
function checkIfShouldBeConstant (startFuncName, context) {
return !fcallGraph.analyseCallGraph(context.callGraph, startFuncName, context, isConstBreaker)
}
function isConstBreaker (node, context) {
return common.isWriteOnStateVariable(node, context.stateVariables) ||
common.isLowLevelCall(node) ||
common.isTransfer(node) ||
isCallOnNonConstExternalInterfaceFunction(node, context) ||
common.isCallToNonConstLocalFunction(node) ||
common.isInlineAssembly(node) ||
common.isNewExpression(node) ||
common.isSelfdestructCall(node)
}
function isCallOnNonConstExternalInterfaceFunction (node, context) {
if (common.isExternalDirectCall(node)) {
var func = fcallGraph.resolveCallGraphSymbol(context.callGraph, common.getFullQualifiedFunctionCallIdent(context.currentContract, node))
return !func || (func && !common.isConstantFunction(func.node.node))
}
return false
}
module.exports = {
name: name,
description: desc,
category: categories.MISC,
Module: constantFunctions
}
'use strict'
var common = require('./staticAnalysisCommon')
function buildLocalFuncCallGraphInternal (functions, nodeFilter, extractNodeIdent, extractFuncDefIdent) {
var callGraph = {}
functions.forEach((func) => {
var calls = func.relevantNodes
.filter(nodeFilter)
.map(extractNodeIdent)
.filter((name) => name !== extractFuncDefIdent(func)) // filter self recursive call
callGraph[extractFuncDefIdent(func)] = { node: func, calls: calls }
})
return callGraph
}
/**
* Builds a function call graph for the current contracts.
* Example Contract call graph:
*
* {
* "KingOfTheEtherThrone": {
* "contracts": {...}, // Contract node as defined in abstractAstView.js
* "functions": {
* "KingOfTheEtherThrone.claimThrone(string memory)": { // function in KingOfEtherThrone
* "node": {...}, // function node as defined in abstractAstView.js
* "calls": { // list of full qualified function names which are called form this function
* }
* }
* }
* },
* "foo": {
* "contract": {...}, // Contract node as definded in abstractAstView.js
* "functions": {} // map from full qualified function name to func node
* }
* }
*
* @contracts {list contracts} Expects as input the contract structure defined in abstractAstView.js
* @return {map (string -> Contract Call Graph)} returns map from contract name to contract call graph
*/
function buildGlobalFuncCallGraph (contracts) {
var callGraph = {}
contracts.forEach((contract) => {
var filterNodes = (node) => { return common.isLocalCallGraphRelevantNode(node) || common.isExternalDirectCall(node) }
var getNodeIdent = (node) => { return common.getFullQualifiedFunctionCallIdent(contract.node, node) }
var getFunDefIdent = (funcDef) => { return common.getFullQuallyfiedFuncDefinitionIdent(contract.node, funcDef.node, funcDef.parameters) }
callGraph[common.getContractName(contract.node)] = { contract: contract, functions: buildLocalFuncCallGraphInternal(contract.functions, filterNodes, getNodeIdent, getFunDefIdent) }
})
return callGraph
}
/**
* Walks through the call graph from a defined starting function, true if nodeCheck holds for every relevant node in the callgraph
* @callGraph {callGraph} As returned by buildGlobalFuncCallGraph
* @funcName {string} full qualified name of the starting function
* @context {Object} provides additional context information that can be used by the nodeCheck function
* @nodeCheck {(ASTNode, context) -> bool} applied on every relevant node in the call graph
* @return {bool} returns map from contract name to contract call graph
*/
function analyseCallGraph (callGraph, funcName, context, nodeCheck) {
return analyseCallGraphInternal(callGraph, funcName, context, (a, b) => a || b, nodeCheck, {})
}
function analyseCallGraphInternal (callGraph, funcName, context, combinator, nodeCheck, visited) {
var current = resolveCallGraphSymbol(callGraph, funcName)
if (current === undefined || visited[funcName] === true) return true
visited[funcName] = true
return combinator(current.node.relevantNodes.reduce((acc, val) => combinator(acc, nodeCheck(val, context)), false),
current.calls.reduce((acc, val) => combinator(acc, analyseCallGraphInternal(callGraph, val, context, combinator, nodeCheck, visited)), false))
}
function resolveCallGraphSymbol (callGraph, funcName) {
return resolveCallGraphSymbolInternal(callGraph, funcName, false)
}
function resolveCallGraphSymbolInternal (callGraph, funcName, silent) {
var current
if (funcName.includes('.')) {
var parts = funcName.split('.')
var contractPart = parts[0]
var functionPart = parts[1]
var currentContract = callGraph[contractPart]
if (!(currentContract === undefined)) {
current = currentContract.functions[funcName]
// resolve inheritance hierarchy
if (current === undefined) {
// resolve inheritance lookup in linearized fashion
var inheritsFromNames = currentContract.contract.inheritsFrom.reverse()
for (var i = 0; i < inheritsFromNames.length; i++) {
var res = resolveCallGraphSymbolInternal(callGraph, inheritsFromNames[i] + '.' + functionPart, true)
if (!(res === undefined)) return res
}
}
} else {
if (!silent) console.log(`static analysis functionCallGraph.js: Contract ${contractPart} not found in function call graph.`)
}
} else {
throw new Error('functionCallGraph.js: function does not have full qualified name.')
}
if (current === undefined && !silent) console.log(`static analysis functionCallGraph.js: ${funcName} not found in function call graph.`)
return current
}
module.exports = {
analyseCallGraph: analyseCallGraph,
buildGlobalFuncCallGraph: buildGlobalFuncCallGraph,
resolveCallGraphSymbol: resolveCallGraphSymbol
}
var name = 'Gas costs: '
var desc = 'Warn if the gas requirements of functions are too high.'
var categories = require('./categories')
function gasCosts () {
}
/**
* call the given @arg cb (function) for all the contracts. Uses last compilation result
* stop visiting when cb return true
* @param {Function} cb - callback
*/
// @TODO has been copied from browser-solidity repo ! should fix that soon !
function visitContracts (contracts, cb) {
for (var file in contracts) {
for (var name in contracts[file]) {
if (cb({ name: name, object: contracts[file][name], file: file })) return
}
}
}
gasCosts.prototype.report = function (compilationResults) {
var report = []
visitContracts(compilationResults.contracts, (contract) => {
if (
!contract.object.evm.gasEstimates ||
!contract.object.evm.gasEstimates.external
) {
return
}
var fallback = contract.object.evm.gasEstimates.external['']
if (fallback !== undefined) {
if (fallback === null || fallback >= 2100 || fallback === 'infinite') {
report.push({
warning: `Fallback function of contract ${contract.name} requires too much gas (${fallback}).
If the fallback function requires more than 2300 gas, the contract cannot receive Ether.`
})
}
}
for (var functionName in contract.object.evm.gasEstimates.external) {
if (functionName === '') {
continue
}
var gas = contract.object.evm.gasEstimates.external[functionName]
var gasString = gas === null ? 'unknown or not constant' : 'high: ' + gas
if (gas === null || gas >= 3000000 || gas === 'infinite') {
report.push({
warning: `Gas requirement of function ${contract.name}.${functionName} ${gasString}.
If the gas requirement of a function is higher than the block gas limit, it cannot be executed.
Please avoid loops in your functions or actions that modify large areas of storage
(this includes clearing or copying arrays in storage)`
})
}
}
})
return report
}
module.exports = {
name: name,
description: desc,
category: categories.GAS,
Module: gasCosts
}
var name = 'Inline assembly: '
var desc = 'Use of Inline Assembly'
var categories = require('./categories')
var common = require('./staticAnalysisCommon')
function inlineAssembly () {
this.inlineAssNodes = []
}
inlineAssembly.prototype.visit = function (node) {
if (common.isInlineAssembly(node)) this.inlineAssNodes.push(node)
}
inlineAssembly.prototype.report = function (compilationResults) {
return this.inlineAssNodes.map((node) => {
return {
warning: `CAUTION: The Contract uses inline assembly, this is only advised in rare cases.
Additionally static analysis modules do not parse inline Assembly, this can lead to wrong analysis results.`,
location: node.src,
more: 'http://solidity.readthedocs.io/en/develop/assembly.html#solidity-assembly'
}
})
}
module.exports = {
name: name,
description: desc,
category: categories.SECURITY,
Module: inlineAssembly
}
module.exports = [
require('./txOrigin'),
require('./gasCosts'),
require('./thisLocal'),
require('./checksEffectsInteraction'),
require('./constantFunctions'),
require('./similarVariableNames.js'),
require('./inlineAssembly'),
require('./blockTimestamp'),
require('./lowLevelCalls'),
require('./blockBlockhash'),
require('./noReturn'),
require('./selfdestruct')
]
var name = 'Low level calls: '
var desc = 'Semantics maybe unclear'
var categories = require('./categories')
var common = require('./staticAnalysisCommon')
function lowLevelCalls () {
this.llcNodes = []
}
lowLevelCalls.prototype.visit = function (node) {
if (common.isLowLevelCallInst(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})
}
}
lowLevelCalls.prototype.report = function (compilationResults) {
return this.llcNodes.map(function (item, i) {
var text = ''
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 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 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 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": "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.
Note: if you "send/transfer" 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/transfer".
No state changes are possible but the callee can log the event or revert the transfer. "send/transfer" 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
}
return { warning: text, more: morehref, location: item.node.src }
})
}
module.exports = {
name: name,
description: desc,
category: categories.SECURITY,
Module: lowLevelCalls
}
var name = 'no return: '
var desc = 'Function with return type is not returning'
var categories = require('./categories')
var common = require('./staticAnalysisCommon')
var AbstractAst = require('./abstractAstView')
function noReturn () {
this.abstractAst = new AbstractAst()
this.visit = this.abstractAst.build_visit(
(node) => common.isReturn(node) || common.isAssignment(node)
)
this.report = this.abstractAst.build_report(report)
}
noReturn.prototype.visit = function () { throw new Error('noReturn.js no visit function set upon construction') }
noReturn.prototype.report = function () { throw new Error('noReturn.js no report function set upon construction') }
function report (contracts, multipleContractsWithSameName) {
var warnings = []
contracts.forEach((contract) => {
contract.functions.filter((func) => common.hasFunctionBody(func.node)).forEach((func) => {
var funcName = common.getFullQuallyfiedFuncDefinitionIdent(contract.node, func.node, func.parameters)
if (hasNamedAndUnnamedReturns(func)) {
warnings.push({
warning: `${funcName}: Mixing of named and unnamed return parameters is not advised.`,
location: func.src
})
} else if (shouldReturn(func) && !(hasReturnStatement(func) || (hasNamedReturns(func) && hasAssignToAllNamedReturns(func)))) {
warnings.push({
warning: `${funcName}: Defines a return type but never explicitly returns a value.`,
location: func.src
})
}
})
})
return warnings
}
function shouldReturn (func) {
return func.returns.length > 0
}
function hasReturnStatement (func) {
return func.relevantNodes.filter(common.isReturn).length > 0
}
function hasAssignToAllNamedReturns (func) {
var namedReturns = func.returns.filter((n) => n.name.length > 0).map((n) => n.name)
var assignedVars = func.relevantNodes.filter(common.isAssignment).map(common.getEffectedVariableName)
var diff = namedReturns.filter(e => !assignedVars.includes(e))
return diff.length === 0
}
function hasNamedReturns (func) {
return func.returns.filter((n) => n.name.length > 0).length > 0
}
function hasNamedAndUnnamedReturns (func) {
return func.returns.filter((n) => n.name.length === 0).length > 0 &&
hasNamedReturns(func)
}
module.exports = {
name: name,
description: desc,
category: categories.MISC,
Module: noReturn
}
var name = 'Selfdestruct: '
var desc = 'Be aware of caller contracts.'
var categories = require('./categories')
var common = require('./staticAnalysisCommon')
function selfdestruct () {
this.relevantNodes = []
}
selfdestruct.prototype.visit = function (node) {
if (common.isSelfdestructCall(node)) {
this.relevantNodes.push(node)
}
}
selfdestruct.prototype.report = function () {
return this.relevantNodes.map(function (item, i) {
return {
warning: 'Use of selfdestruct: can block calling contracts unexpectedly. Be especially careful if this contract is planed 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,
more: 'https://paritytech.io/blog/security-alert.html'
}
})
}
module.exports = {
name: name,
description: desc,
category: categories.SECURITY,
Module: selfdestruct
}
var name = 'Similar variable names: '
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()
this.visit = this.abstractAst.build_visit(
(node) => false
)
this.report = this.abstractAst.build_report(report)
}
similarVariableNames.prototype.visit = function () { throw new Error('similarVariableNames.js no visit function set upon construction') }
similarVariableNames.prototype.report = function () { throw new Error('similarVariableNames.js no report function set upon construction') }
function report (contracts, multipleContractsWithSameName) {
var warnings = []
var hasModifiers = contracts.some((item) => item.modifiers.length > 0)
contracts.forEach((contract) => {
contract.functions.forEach((func) => {
var funcName = common.getFullQuallyfiedFuncDefinitionIdent(contract.node, func.node, func.parameters)
var hasModifiersComments = ''
if (hasModifiers) {
hasModifiersComments = 'Note: Modifiers are currently not considered by this static analysis.'
}
var multipleContractsWithSameNameComments = ''
if (multipleContractsWithSameName) {
multipleContractsWithSameNameComments = 'Note: Import aliases are currently not supported by this static analysis.'
}
var vars = getFunctionVariables(contract, func).map(common.getDeclaredVariableName)
findSimilarVarNames(vars).map((sim) => {
warnings.push({
warning: `${funcName} : Variables have very similar names ${sim.var1} and ${sim.var2}. ${hasModifiersComments} ${multipleContractsWithSameNameComments}`,
location: func.src
})
})
})
})
return warnings
}
function findSimilarVarNames (vars) {
var similar = []
var comb = {}
vars.map((varName1) => vars.map((varName2) => {
if (varName1.length > 1 && varName2.length > 1 && varName2 !== varName1 && !isCommonPrefixedVersion(varName1, varName2) && !(comb[varName1 + ';' + varName2] || comb[varName2 + ';' + varName1])) {
comb[varName1 + ';' + varName2] = true
var distance = levenshtein.get(varName1, varName2)
if (distance <= 2) similar.push({ var1: varName1, var2: varName2, distance: distance })
}
}))
return similar
}
function isCommonPrefixedVersion (varName1, varName2) {
return (varName1.startsWith('_') && varName1.slice(1) === varName2) || (varName2.startsWith('_') && varName2.slice(1) === varName1)
}
function getFunctionVariables (contract, func) {
return contract.stateVariables.concat(func.localVariables)
}
module.exports = {
name: name,
description: desc,
category: categories.MISC,
Module: similarVariableNames
}
This diff is collapsed.
var name = 'This on local calls: '
var desc = 'Invocation of local functions via this'
var categories = require('./categories')
var common = require('./staticAnalysisCommon')
function thisLocal () {
this.warningNodes = []
}
thisLocal.prototype.visit = function (node) {
if (common.isThisLocalCall(node)) this.warningNodes.push(node)
}
thisLocal.prototype.report = function (compilationResults) {
return this.warningNodes.map(function (item, i) {
return {
warning: 'Use of "this" for local functions: Never use this to call functions in the same contract, it only consumes more gas than normal local calls.',
location: item.src,
more: 'http://solidity.readthedocs.io/en/develop/control-structures.html#external-function-calls'
}
})
}
module.exports = {
name: name,
description: desc,
category: categories.GAS,
Module: thisLocal
}
var name = 'Transaction origin: '
var desc = 'Warn if tx.origin is used'
var categories = require('./categories')
function txOrigin () {
this.txOriginNodes = []
}
txOrigin.prototype.visit = function (node) {
if (node.name === 'MemberAccess' &&
node.attributes.member_name === 'origin' &&
node.attributes.type === 'address' &&
node.children && node.children.length &&
node.children[0].attributes.type === 'tx' &&
node.children[0].attributes.value === 'tx') {
this.txOriginNodes.push(node)
}
}
txOrigin.prototype.report = function () {
return this.txOriginNodes.map(function (item, i) {
return {
warning: `Use of tx.origin: "tx.origin" is useful only in very exceptional cases.
If you use it for authentication, you usually want to replace it by "msg.sender", because otherwise any contract you call can act on your behalf.`,
location: item.src
}
})
}
module.exports = {
name: name,
description: desc,
category: categories.SECURITY,
Module: txOrigin
}
'use strict'
var AstWalker = require('remix-lib').AstWalker
var list = require('./modules/list')
function staticAnalysisRunner () {
}
staticAnalysisRunner.prototype.run = function (compilationResult, toRun, callback) {
var self = this
var modules = toRun.map(function (i) {
var m = self.modules()[i]
return { 'name': m.name, 'mod': new m.Module() }
})
this.runWithModuleList(compilationResult, modules, callback)
}
staticAnalysisRunner.prototype.runWithModuleList = function (compilationResult, modules, callback) {
// Also provide convenience analysis via the AST walker.
var walker = new AstWalker()
for (var k in compilationResult.sources) {
walker.walk(compilationResult.sources[k].legacyAST, {'*': function (node) {
modules.map(function (item, i) {
if (item.mod.visit !== undefined) {
item.mod.visit(node)
}
})
return true
}})
}
// Here, modules can just collect the results from the AST walk,
// but also perform new analysis.
var reports = modules.map(function (item, i) {
return { name: item.name, report: item.mod.report(compilationResult) }
})
callback(reports)
}
staticAnalysisRunner.prototype.modules = function () {
return list
}
module.exports = staticAnalysisRunner
This diff is collapsed.
This diff is collapsed.
// return value send
contract KingOfTheEtherThrone{
struct Monarch {
// address of the king .
address ethAddr ;
string name ;
// how much he pays to previous king
uint claimPrice ;
uint coronationTimestamp;
}
Monarch public currentMonarch ;
function claimThrone ( string name ) {
address wizardAddress;
uint compensation = 100;
uint valuePaid = 10;
if ( currentMonarch.ethAddr != wizardAddress )
if (currentMonarch.ethAddr.send( compensation )) throw;
currentMonarch = Monarch(msg.sender,name,valuePaid,block.timestamp);
}
}
pragma solidity ^0.4.9;
contract test {
address owner;
function at(address _addr) returns (bytes o_code) {
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() {
if(tx.origin == owner)
msg.sender.send(19);
assembly {
}
}
}
pragma solidity ^0.4.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`.
function Ballot(bytes32[] proposalNames) {
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) {
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.
throw;
}
voters[voter].weight = 1;
}
/// Delegate your vote to the voter `to`.
function delegate(address to) {
// assigns reference
Voter sender = voters[msg.sender];
if (sender.voted)
throw;
// 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) {
throw;
}
// Since `sender` is a reference, this
// modifies `voters[msg.sender].voted`
sender.voted = true;
sender.delegate = to;
Voter 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) {
Voter sender = voters[msg.sender];
if (sender.voted)
throw;
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() constant
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() constant
returns (bytes32 winnerName)
{
winnerName = proposals[winningProposal()].name;
}
}
pragma solidity ^0.4.0;
contract InfoFeed {
function info() payable returns (uint ret);
function call1(uint a) 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) {
giveRightToVote(a,a);
}
/// Create a new ballot with $(_numProposals) different proposals.
function Ballot(uint8 _numProposals) {
address d;
if(!d.delegatecall.gas(800)('function_name', 'arg1', 'arg2')) throw;
if(!d.callcode.gas(800)('function_name', 'arg1', 'arg2')) throw;
if(!d.call.value(10).gas(800)('function_name', 'arg1', 'arg2')) throw;
if(!d.call.value(10).gas(800)('function_name', 'arg1', 'arg2')) throw;
if(!msg.sender.send(1 wei)) throw;
if(!d.call('function_name', 'arg1', 'arg2')) throw;
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)) throw;
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) payable returns (bool){
if (msg.sender != chairperson || voters[voter].voted) return;
voters[voter].weight = 1;
return true;
}
/// Delegate your vote to the voter $(to).
function delegate(address to) {
Voter 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 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) {
Voter sender = voters[msg.sender];
if (sender.voted || proposal >= proposals.length) return;
sender.voted = true;
sender.vote = proposal;
proposals[proposal].voteCount += sender.weight;
}
function winningProposal() constant 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;
}
}
}
pragma solidity ^0.4.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() constant
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() constant
returns (bytes32 winnerName)
{
winnerName = proposals[winningProposal()].name;
}
}
pragma solidity ^0.4.0;
contract a {
uint x;
function foo() {
x++;
}
}
contract b {
a x;
function bar() constant {
address a;
a.send(100 wei);
x.foo();
}
}
contract c {
uint x;
uint x_abc;
function c(uint _x, uint _abc) {
x=_x;
x_abc=_abc;
}
}
\ No newline at end of file
contract Sheep {
string public name;
string public dna;
bool g = true;
function Sheep(string _name, string _dna) {
name = _name;
dna = _dna;
}
function geneticallyEngineer(string _dna) returns (bool) {
dna = _dna;
}
}
\ No newline at end of file
pragma solidity ^0.4.9;
contract bla {
uint brr;
function duper() {
brr++;
}
}
contract a is bla {
function blub() {
brr++;
}
function r () {
address a;
bytes32 hash;
uint8 v;
bytes32 r;
bytes32 s;
block.blockhash(1);
block.coinbase;
block.difficulty;
block.gaslimit;
block.number;
block.timestamp;
msg.data;
msg.gas;
msg.sender;
msg.value;
now;
tx.gasprice;
tx.origin;
//assert(now == block.timestamp);
//require(now == block.timestamp);
keccak256(a);
sha3(a);
sha256(a);
ripemd160(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();
}
}
\ No newline at end of file
pragma solidity ^0.4.9;
contract r {
function s() constant {}
}
contract a is r {
uint x = 1;
function getX() constant returns (uint) {
return x;
}
}
contract b is a {
uint y = 2;
uint x = 3;
function getY(uint z, bool r) returns (uint) {
return y++;
}
function getY(string storage n) internal constant returns (uint) { return 10; }
}
contract c is b {
string x;
function d() returns (uint a, uint b) {
//d();
//sha3("bla");
msg.sender.call.gas(200000).value(this.balance)(bytes4(sha3("pay()")));
//x++;
getY(x);
a = getX() + getY(1, false);
b = getX() + getY(x);
}
}
pragma solidity ^0.4.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)
returns (bool)
{
if (self.flags[value])
return false; // already there
self.flags[value] = true;
return true;
}
function remove(Data storage self, uint value)
returns (bool)
{
if (!self.flags[value])
return false; // not there
self.flags[value] = false;
return true;
}
function contains(Data storage self, uint value)
returns (bool)
{
return self.flags[value];
}
}
contract C {
Set.Data knownValues;
function register(uint value) {
// The library functions can be called without a
// specific instance of the library, since the
// "instance" will be the current contract.
address a;
a.send(10 wei);
if (!Set.insert(knownValues, value))
throw;
}
// In this contract, we can also directly access knownValues.flags, if we want.
}
\ No newline at end of file
pragma solidity ^0.4.0;
contract test {
address owner;
modifier onlyOwner {
var a = 0;
if (msg.sender != owner)
throw;
_;
}
function b(address a) onlyOwner returns (bool) {
}
}
\ No newline at end of file
pragma solidity ^0.4.0;
contract owned {
uint r=0;
modifier ntimes(uint n) {
for(uint i=0;i<n-1;i++){
_;
}
_;
}
modifier plus100 {
var bla=1;
r+=100;
_;
}
function a() ntimes(10) plus100 payable returns (uint) {
{
uint bla=5;
}
r += bla;
return r;
}
}
pragma solidity ^0.4.0;
contract Fund {
/// Mapping of ether shares of the contract.
mapping(address => uint) shares;
/// Withdraw your share.
function withdraw() {
var share = shares[msg.sender];
shares[msg.sender] = 0;
if (!msg.sender.send(share))
throw;
}
}
pragma solidity ^0.4.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();
}
}
contract sd {
function() public payable { }
function c () public constant {
selfdestruct(address(0xdeadbeef));
}
function b () public payable {
selfdestruct(address(0xdeadbeef));
}
}
\ No newline at end of file
pragma solidity ^0.4.9;
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 a) {
Voter x = voters[a];
if (!a.send(10))
throw;
//voters[a] = Voter(10,true,1,a);
//x.foo.bar *= 100;
bli(x);
}
//function bla(){}
function bli(Voter storage x) private {
x.foo.bar++;
}
}
pragma solidity ^0.4.0;
contract test {
function (){
address x;
this.b(x);
x.call('something');
x.send(1 wei);
}
function b(address a) returns (bool) {
}
}
contract c {
uint x;
function f(address r) {
r.transfer(1);
x = 2;
}
}
\ No newline at end of file
'use strict' 'use strict'
var tape = require('tape') var tape = require('tape')
var compiler = require('solc') var compiler = require('solc')
var astHelper = require('../src/astHelper') var astHelper = require('../../src/decoder/astHelper')
var decodeInfo = require('../src/decodeInfo') var decodeInfo = require('../../src/decoder/decodeInfo')
var stateDecoder = require('../src/stateDecoder') var stateDecoder = require('../../src/decoder/stateDecoder')
var contracts = require('./contracts/miscContracts') var contracts = require('./contracts/miscContracts')
var simplecontracts = require('./contracts/simpleContract') var simplecontracts = require('./contracts/simpleContract')
......
'use strict' 'use strict'
var localDecoder = require('../../src/localDecoder') var localDecoder = require('../../../src/decoder/localDecoder')
/* /*
Decode local variable Decode local variable
......
...@@ -7,8 +7,8 @@ var remixLib = require('remix-lib') ...@@ -7,8 +7,8 @@ var remixLib = require('remix-lib')
var traceHelper = remixLib.helpers.trace var traceHelper = remixLib.helpers.trace
var global = remixLib.global var global = remixLib.global
var SolidityProxy = require('../../src/solidityProxy') var SolidityProxy = require('../../../src/decoder/solidityProxy')
var InternalCallTree = require('../../src/internalCallTree') var InternalCallTree = require('../../../src/decoder/internalCallTree')
var EventManager = remixLib.EventManager var EventManager = remixLib.EventManager
var helper = require('./helper') var helper = require('./helper')
......
...@@ -6,8 +6,8 @@ var vmSendTx = require('./vmCall') ...@@ -6,8 +6,8 @@ var vmSendTx = require('./vmCall')
var remixLib = require('remix-lib') var remixLib = require('remix-lib')
var traceHelper = remixLib.helpers.trace var traceHelper = remixLib.helpers.trace
var global = remixLib.global var global = remixLib.global
var SolidityProxy = require('../../src/solidityProxy') var SolidityProxy = require('../../../src/decoder/solidityProxy')
var InternalCallTree = require('../../src/internalCallTree') var InternalCallTree = require('../../../src/decoder/internalCallTree')
var EventManager = remixLib.EventManager var EventManager = remixLib.EventManager
var helper = require('./helper') var helper = require('./helper')
......
...@@ -6,8 +6,8 @@ var vmSendTx = require('./vmCall') ...@@ -6,8 +6,8 @@ var vmSendTx = require('./vmCall')
var remixLib = require('remix-lib') var remixLib = require('remix-lib')
var traceHelper = remixLib.helpers.trace var traceHelper = remixLib.helpers.trace
var global = remixLib.global var global = remixLib.global
var SolidityProxy = require('../../src/solidityProxy') var SolidityProxy = require('../../../src/decoder/solidityProxy')
var InternalCallTree = require('../../src/internalCallTree') var InternalCallTree = require('../../../src/decoder/internalCallTree')
var EventManager = remixLib.EventManager var EventManager = remixLib.EventManager
var helper = require('./helper') var helper = require('./helper')
......
...@@ -6,8 +6,8 @@ var vmSendTx = require('./vmCall') ...@@ -6,8 +6,8 @@ var vmSendTx = require('./vmCall')
var remixLib = require('remix-lib') var remixLib = require('remix-lib')
var traceHelper = remixLib.helpers.trace var traceHelper = remixLib.helpers.trace
var global = remixLib.global var global = remixLib.global
var SolidityProxy = require('../../src/solidityProxy') var SolidityProxy = require('../../../src/decoder/solidityProxy')
var InternalCallTree = require('../../src/internalCallTree') var InternalCallTree = require('../../../src/decoder/internalCallTree')
var EventManager = remixLib.EventManager var EventManager = remixLib.EventManager
var helper = require('./helper') var helper = require('./helper')
......
'use strict' 'use strict'
var tape = require('tape') var tape = require('tape')
var compiler = require('solc') var compiler = require('solc')
var stateDecoder = require('../src/stateDecoder') var stateDecoder = require('../../src/decoder/stateDecoder')
var MockStorageResolver = require('./mockStorageResolver') var MockStorageResolver = require('./mockStorageResolver')
tape('solidity', function (t) { tape('solidity', function (t) {
......
'use strict' 'use strict'
var tape = require('tape') var tape = require('tape')
var compiler = require('solc') var compiler = require('solc')
var stateDecoder = require('../src/stateDecoder') var stateDecoder = require('../../src/decoder/stateDecoder')
var contracts = require('./contracts/miscContracts') var contracts = require('./contracts/miscContracts')
tape('solidity', function (t) { tape('solidity', function (t) {
......
require('./decodeInfo.js') require('./decoder/decodeInfo.js')
require('./storageLocation.js') require('./decoder/storageLocation.js')
require('./storageDecoder.js') require('./decoder/storageDecoder.js')
require('./localDecoder.js') require('./decoder/localDecoder.js')
require('./analysis/staticAnalysisCommon-test.js')
require('./analysis/staticAnalysisIntegration-test.js')
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