Static Analysis: ChecksEffectsInteraction, Constant Function, Inline Assembly. Without integration tests and modifier support

pull/1/head
Michael Fröwis 8 years ago committed by chriseth
parent 01d700dc7c
commit 11917ffcfb
  1. 93
      src/app/staticanalysis/modules/abstractAstView.js
  2. 3
      src/app/staticanalysis/modules/categories.js
  3. 81
      src/app/staticanalysis/modules/checksEffectsInteraction.js
  4. 86
      src/app/staticanalysis/modules/constantFunctions.js
  5. 84
      src/app/staticanalysis/modules/functionCallGraph.js
  6. 29
      src/app/staticanalysis/modules/inlineAssembly.js
  7. 5
      src/app/staticanalysis/modules/list.js
  8. 290
      src/app/staticanalysis/modules/staticAnalysisCommon.js
  9. 1
      src/app/staticanalysis/modules/thisLocal.js
  10. 4
      src/app/staticanalysis/staticAnalysisRunner.js
  11. 1
      test/index.js
  12. 45
      test/staticanalysis/staticAnalysisCommon-test.js
  13. 47
      test/staticanalysis/staticAnalysisIntegration-test.js
  14. 23
      test/staticanalysis/test-contracts/KingOfTheEtherThrone.sol
  15. 26
      test/staticanalysis/test-contracts/assembly.sol
  16. 145
      test/staticanalysis/test-contracts/ballot.sol
  17. 101
      test/staticanalysis/test-contracts/ballot_reentrant.sol
  18. 31
      test/staticanalysis/test-contracts/ballot_withoutWarnings.sol
  19. 19
      test/staticanalysis/test-contracts/cross_contract.sol
  20. 40
      test/staticanalysis/test-contracts/inheritance.sol
  21. 17
      test/staticanalysis/test-contracts/modifier1.sol
  22. 28
      test/staticanalysis/test-contracts/modifier2.sol
  23. 13
      test/staticanalysis/test-contracts/notReentrant.sol
  24. 49
      test/staticanalysis/test-contracts/reentrant.sol
  25. 36
      test/staticanalysis/test-contracts/structReentrant.sol
  26. 16
      test/staticanalysis/test-contracts/thisLocal.sol

@ -0,0 +1,93 @@
var common = require('./staticAnalysisCommon')
var AstWalker = require('ethereum-remix').util.AstWalker
function abstractAstView () {
this.contracts = null
this.currentContractIndex = null
this.currentFunctionIndex = null
this.currentModifierIndex = null
this.isFunctionNotModifier = false
}
abstractAstView.prototype.builder = function (relevantNodeFilter, contractsOut) {
this.contracts = contractsOut
return function (node) {
if (common.isContractDefinition(node)) {
setCurrentContract(this, {
node: node,
functions: [],
modifiers: [],
inheritsFrom: [],
stateVariables: common.getStateVariableDeclarationsFormContractNode(node)
})
} else if (common.isInheritanceSpecifier(node)) {
var currentContract = getCurrentContract(this)
var inheritsFromName = common.getInheritsFromName(node)
currentContract.inheritsFrom.push(inheritsFromName)
// add variables from inherited contracts
var inheritsFrom = this.contracts.find((contract) => common.getContractName(contract.node) === inheritsFromName)
currentContract.stateVariables = currentContract.stateVariables.concat(inheritsFrom.stateVariables)
} else if (common.isFunctionDefinition(node)) {
setCurrentFunction(this, {
node: node,
relevantNodes: [],
modifierInvocations: [],
localVariables: getLocalVariables(node),
parameters: getLocalParameters(node)
})
} else if (common.isModifierDefinition(node)) {
setCurrentModifier(this, {
node: node,
relevantNodes: [],
localVariables: getLocalVariables(node),
parameters: getLocalParameters(node)
})
} else if (common.isModifierInvocation(node)) {
if (!this.isFunctionNotModifier) throw new Error('abstractAstView.js: Found modifier invocation outside of function scope.')
getCurrentFunction(this).modifierInvocations.push(node)
} else if (relevantNodeFilter(node)) {
((this.isFunctionNotModifier) ? getCurrentFunction(this) : getCurrentModifier(this)).relevantNodes.push(node)
}
}
}
function setCurrentContract (that, contract) {
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 getLocalVariables (funcNode) {
var locals = []
new AstWalker().walk(funcNode, {'*': function (node) {
if (common.isVariableDeclaration(node)) locals.push(node)
return true
}})
return locals
}
module.exports = abstractAstView

@ -1,4 +1,5 @@
module.exports = { module.exports = {
SECURITY: {displayName: 'Security', id: 'SEC'}, SECURITY: {displayName: 'Security', id: 'SEC'},
GAS: {displayName: 'Gas & Economy', id: 'GAS'} GAS: {displayName: 'Gas & Economy', id: 'GAS'},
MISC: {displayName: 'Miscellaneous', id: 'MISC'}
} }

@ -0,0 +1,81 @@
var name = 'Checks-Effects-Interaction pattern'
var desc = 'Avoid potential reentrancy bugs'
var categories = require('./categories')
var common = require('./staticAnalysisCommon')
var callGraph = require('./functionCallGraph')
var AbstractAst = require('./abstractAstView')
function checksEffectsInteraction () {
this.contracts = []
}
checksEffectsInteraction.prototype.visit = new AbstractAst().builder(
(node) => common.isInteraction(node) || common.isEffect(node) || common.isLocalCall(node),
this.contracts
)
checksEffectsInteraction.prototype.report = function (compilationResults) {
var warnings = []
var cg = callGraph.buildGlobalFuncCallGraph(this.contracts)
this.contracts.forEach((contract) => {
contract.functions.forEach((func) => {
func.changesState = checkIfChangesState(common.getFullQuallyfiedFuncDefinitionIdent(contract.node, func.node, func.parameters),
getContext(cg, contract, func))
})
contract.functions.forEach((func) => {
if (isPotentialVulnerableFunction(func, getContext(cg, contract, func))) {
var funcName = common.getFullQuallyfiedFuncDefinitionIdent(contract.node, func.node, func.parameters)
warnings.push({
warning: `Potential Violation of Checks-Effects-Interaction pattern in <i>${funcName}</i>: Could potentially lead to re-entrancy vulnerability.`,
location: func.src,
more: 'http://solidity.readthedocs.io/en/develop/security-considerations.html#re-entrancy'
})
}
})
})
return warnings
}
function getContext (cg, currentContract, func) {
return { cg: cg, 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.isLocalCall(node)) {
var func = callGraph.resolveCallGraphSymbol(context.cg, common.getFullQualifiedFunctionCallIdent(context.currentContract.node, node))
return !func || (func && func.node.changesState)
}
return false
}
function checkIfChangesState (startFuncName, context) {
return callGraph.analyseCallGraph(context.cg, startFuncName, context, (node, context) => common.isWriteOnStateVariable(node, context.stateVariables))
}
module.exports = {
name: name,
description: desc,
category: categories.SECURITY,
Module: checksEffectsInteraction
}

@ -0,0 +1,86 @@
var name = 'Constant functions'
var desc = 'Check for potentially constant functions'
var categories = require('./categories')
var common = require('./staticAnalysisCommon')
var callGraph = require('./functionCallGraph')
var AbstractAst = require('./abstractAstView')
function constantFunctions () {
this.contracts = []
}
constantFunctions.prototype.visit = new AbstractAst().builder(
(node) => common.isLowLevelCall(node) || common.isExternalDirectCall(node) || common.isEffect(node) || common.isLocalCall(node) || common.isInlineAssembly(node),
this.contracts
)
constantFunctions.prototype.report = function (compilationResults) {
var warnings = []
var cg = callGraph.buildGlobalFuncCallGraph(this.contracts)
this.contracts.forEach((contract) => {
if (!common.isFullyImplementedContract(contract.node)) return
contract.functions.forEach((func) => {
func.potentiallyshouldBeConst = checkIfShouldBeConstant(common.getFullQuallyfiedFuncDefinitionIdent(contract.node, func.node, func.parameters),
getContext(cg, contract, func))
})
contract.functions.forEach((func) => {
if (common.isConstantFunction(func.node) !== func.potentiallyshouldBeConst) {
var funcName = common.getFullQuallyfiedFuncDefinitionIdent(contract.node, func.node, func.parameters)
if (func.potentiallyshouldBeConst) {
warnings.push({
warning: `<i>${funcName}</i>: Potentially should be constant but is not.`,
location: func.src,
more: 'http://solidity.readthedocs.io/en/develop/contracts.html#constant-functions'
})
} else {
warnings.push({
warning: `<i>${funcName}</i>: Is constant but potentially should not be.`,
location: func.src,
more: 'http://solidity.readthedocs.io/en/develop/contracts.html#constant-functions'
})
}
}
})
})
return warnings
}
function getContext (cg, currentContract, func) {
return { cg: cg, currentContract: currentContract, stateVariables: getStateVariables(currentContract, func) }
}
function getStateVariables (contract, func) {
return contract.stateVariables.concat(func.localVariables.filter(common.isStorageVariableDeclaration))
}
function checkIfShouldBeConstant (startFuncName, context) {
return !callGraph.analyseCallGraph(context.cg, startFuncName, context, isConstBreaker)
}
function isConstBreaker (node, context) {
return common.isWriteOnStateVariable(node, context.stateVariables) ||
common.isLowLevelCall(node) ||
isCallOnNonConstExternalInterfaceFunction(node, context) ||
common.isCallToNonConstLocalFunction(node) ||
common.isInlineAssembly(node)
}
function isCallOnNonConstExternalInterfaceFunction (node, context) {
if (common.isExternalDirectCall(node)) {
var func = callGraph.resolveCallGraphSymbol(context.cg, 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
}

@ -0,0 +1,84 @@
'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
}
function buildGlobalFuncCallGraph (contracts) {
var callGraph = {}
contracts.forEach((contract) => {
var filterNodes = (node) => { return common.isLocalCall(node) || common.isThisLocalCall(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
}
function analyseCallGraph (cg, funcName, context, nodeCheck) {
return analyseCallGraphInternal(cg, funcName, context, (a, b) => a || b, nodeCheck, {})
}
function analyseCallGraphInternal (cg, funcName, context, combinator, nodeCheck, visited) {
var current = resolveCallGraphSymbol(cg, funcName)
if (!current || visited[funcName]) 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(cg, val, context, combinator, nodeCheck, visited)), false))
}
function resolveCallGraphSymbol (cg, funcName) {
return resolveCallGraphSymbolInternal(cg, funcName, false)
}
function resolveCallGraphSymbolInternal (cg, funcName, silent) {
var current = null
if (funcName.includes('.')) {
var parts = funcName.split('.')
var contractPart = parts[0]
var functionPart = parts[1]
var currentContract = cg[contractPart]
if (currentContract) {
current = currentContract.functions[funcName]
// resolve inheritance hierarchy
if (!current) {
// resolve inheritance lookup in linearized fashion
var inheritsFromNames = currentContract.contract.inheritsFrom.reverse()
for (var i = 0; i < inheritsFromNames.length; i++) {
var res = resolveCallGraphSymbolInternal(cg, inheritsFromNames[i] + '.' + functionPart, true)
if (res) return res
}
}
}
} else {
throw new Error('functionCallGraph.js: function does not have full qualified name.')
}
if (!current) {
if (!silent) console.log(`static analysis functionCallGraph.js: ${funcName} not found in function call graph.`)
return null
} else {
return current
}
}
module.exports = {
analyseCallGraph: analyseCallGraph,
buildGlobalFuncCallGraph: buildGlobalFuncCallGraph,
resolveCallGraphSymbol: resolveCallGraphSymbol
}

@ -0,0 +1,29 @@
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
}

@ -1,5 +1,8 @@
module.exports = [ module.exports = [
require('./txOrigin'), require('./txOrigin'),
require('./gasCosts'), require('./gasCosts'),
require('./thisLocal') require('./thisLocal'),
require('./checksEffectsInteraction'),
require('./constantFunctions'),
require('./inlineAssembly')
] ]

@ -5,7 +5,18 @@ var utils = require('../../utils')
var nodeTypes = { var nodeTypes = {
IDENTIFIER: 'Identifier', IDENTIFIER: 'Identifier',
MEMBERACCESS: 'MemberAccess', MEMBERACCESS: 'MemberAccess',
FUNCTIONCALL: 'FunctionCall' FUNCTIONCALL: 'FunctionCall',
FUNCTIONDEFINITION: 'FunctionDefinition',
VARIABLEDECLARATION: 'VariableDeclaration',
ASSIGNMENT: 'Assignment',
CONTRACTDEFINITION: 'ContractDefinition',
UNARYOPERATION: 'UnaryOperation',
EXPRESSIONSTATEMENT: 'ExpressionStatement',
MODIFIERDEFINITION: 'ModifierDefinition',
MODIFIERINVOCATION: 'ModifierInvocation',
INHERITANCESPECIFIER: 'InheritanceSpecifier',
USERDEFINEDTYPENAME: 'UserDefinedTypeName',
INLINEASSEMBLY: 'InlineAssembly'
} }
var basicTypes = { var basicTypes = {
@ -17,7 +28,11 @@ var basicTypes = {
var basicRegex = { var basicRegex = {
CONTRACTTYPE: '^contract ', CONTRACTTYPE: '^contract ',
FUNCTIONTYPE: '^function \\(' FUNCTIONTYPE: '^function \\(',
EXTERNALFUNCTIONTYPE: '^function \\(.*\\).* external',
CONSTANTFUNCTIONTYPE: '^function \\(.*\\).* constant',
REFTYPE: '( storage )|(mapping\\()|(\\[\\])',
FUNCTIONSIGNATURE: '^function \\(([^\\(]*)\\)'
} }
var basicFunctionTypes = { var basicFunctionTypes = {
@ -42,11 +57,175 @@ var specialVariables = {
} }
} }
// #################### Trivial Getters
function getType (node) {
return node.attributes.type
}
// #################### Complex Getters
function getFunctionCallType (func) {
if (!(isExternalDirectCall(func) || isThisLocalCall(func) || isLocalCall(func))) throw new Error('staticAnalysisCommon.js: not function call Node')
if (isExternalDirectCall(func)) return func.attributes.type
return findFirstSubNodeLTR(func, exactMatch(nodeTypes.IDENTIFIER)).attributes.type
}
function getEffectedVariableName (effectNode) {
if (!isEffect(effectNode)) throw new Error('staticAnalysisCommon.js: not an effect Node')
return findFirstSubNodeLTR(effectNode, exactMatch(nodeTypes.IDENTIFIER)).attributes.value
}
function getLocalCallName (localCallNode) {
if (!isLocalCall(localCallNode)) throw new Error('staticAnalysisCommon.js: not an local call Node')
return localCallNode.children[0].attributes.value
}
function getThisLocalCallName (localCallNode) {
if (!isThisLocalCall(localCallNode)) throw new Error('staticAnalysisCommon.js: not an this local call Node')
return localCallNode.attributes.value
}
function getExternalDirectCallContractName (extDirectCall) {
if (!isExternalDirectCall(extDirectCall)) throw new Error('staticAnalysisCommon.js: not an external direct call Node')
return extDirectCall.children[0].attributes.type.replace(new RegExp(basicRegex.CONTRACTTYPE), '')
}
function getExternalDirectCallMemberName (extDirectCall) {
if (!isExternalDirectCall(extDirectCall)) throw new Error('staticAnalysisCommon.js: not an external direct call Node')
return extDirectCall.attributes.member_name
}
function getContractName (contract) {
if (!isContractDefinition(contract)) throw new Error('staticAnalysisCommon.js: not an contractDefinition Node')
return contract.attributes.name
}
function getFunctionDefinitionName (funcDef) {
if (!isFunctionDefinition(funcDef)) throw new Error('staticAnalysisCommon.js: not an functionDefinition Node')
return funcDef.attributes.name
}
function getInheritsFromName (inheritsNode) {
if (!isInheritanceSpecifier(inheritsNode)) throw new Error('staticAnalysisCommon.js: not an InheritanceSpecifier node Node')
return inheritsNode.children[0].attributes.name
}
function getDeclaredVariableName (varDeclNode) {
if (!isVariableDeclaration(varDeclNode)) throw new Error('staticAnalysisCommon.js: not an variable declaration')
return varDeclNode.attributes.name
}
function getStateVariableDeclarationsFormContractNode (contractNode) {
if (!isContractDefinition(contractNode)) throw new Error('staticAnalysisCommon.js: not an contract definition declaration')
return contractNode.children.filter((el) => isVariableDeclaration(el))
}
function getFunctionOrModifierDefinitionParameterPart (funcNode) {
if (!isFunctionDefinition(funcNode) && !isModifierDefinition(funcNode)) throw new Error('staticAnalysisCommon.js: not an function definition')
return funcNode.children[0]
}
function getFunctionCallTypeParameterType (func) {
return new RegExp(basicRegex.FUNCTIONSIGNATURE).exec(getFunctionCallType(func))[1]
}
function getFullQualifiedFunctionCallIdent (contract, func) {
if (isLocalCall(func)) return getContractName(contract) + '.' + getLocalCallName(func) + '(' + getFunctionCallTypeParameterType(func) + ')'
else if (isThisLocalCall(func)) return getContractName(contract) + '.' + getThisLocalCallName(func) + '(' + getFunctionCallTypeParameterType(func) + ')'
else if (isExternalDirectCall(func)) return getExternalDirectCallContractName(func) + '.' + getExternalDirectCallMemberName(func) + '(' + getFunctionCallTypeParameterType(func) + ')'
else throw new Error('staticAnalysisCommon.js: Can not get function name form non function call node')
}
function getFullQuallyfiedFuncDefinitionIdent (contract, func, paramTypes) {
return getContractName(contract) + '.' + getFunctionDefinitionName(func) + '(' + utils.concatWithSeperator(paramTypes, ',') + ')'
}
// #################### Trivial Node Identification
function isFunctionDefinition (node) {
return nodeType(node, exactMatch(nodeTypes.FUNCTIONDEFINITION))
}
function isModifierDefinition (node) {
return nodeType(node, exactMatch(nodeTypes.MODIFIERDEFINITION))
}
function isModifierInvocation (node) {
return nodeType(node, exactMatch(nodeTypes.MODIFIERINVOCATION))
}
function isVariableDeclaration (node) {
return nodeType(node, exactMatch(nodeTypes.VARIABLEDECLARATION))
}
function isInheritanceSpecifier (node) {
return nodeType(node, exactMatch(nodeTypes.INHERITANCESPECIFIER))
}
function isAssignment (node) {
return nodeType(node, exactMatch(nodeTypes.ASSIGNMENT))
}
function isContractDefinition (node) {
return nodeType(node, exactMatch(nodeTypes.CONTRACTDEFINITION))
}
function isInlineAssembly (node) {
return nodeType(node, exactMatch(nodeTypes.INLINEASSEMBLY))
}
// #################### Complex Node Identification
function isStorageVariableDeclaration (node) {
return isVariableDeclaration(node) && expressionType(node, basicRegex.REFTYPE)
}
function isInteraction (node) {
return isLLCall(node) || isLLSend(node) || isExternalDirectCall(node)
}
function isEffect (node) {
return isAssignment(node) || isPlusPlusUnaryOperation(node) || isMinusMinusUnaryOperation(node) || isInlineAssembly(node)
}
function isWriteOnStateVariable (effectNode, stateVariables) {
return isEffect(effectNode) && !isInlineAssembly(effectNode) && isStateVariable(getEffectedVariableName(effectNode), stateVariables)
}
function isStateVariable (name, stateVariables) {
return stateVariables.some((item) => name === getDeclaredVariableName(item))
}
function isConstantFunction (node) {
return isFunctionDefinition(node) && node.attributes.constant === true
}
function isCallToNonConstLocalFunction (node) {
return isLocalCall(node) && !expressionType(node.children[0], basicRegex.CONSTANTFUNCTIONTYPE)
}
function isExternalDirectCall (node) {
return isMemberAccess(node, basicRegex.EXTERNALFUNCTIONTYPE, undefined, basicRegex.CONTRACTTYPE, undefined) && !isThisLocalCall(node)
}
// usage of now special variable // usage of now special variable
function isNowAccess (node) { function isNowAccess (node) {
return nodeType(node, nodeTypes.IDENTIFIER) && return nodeType(node, exactMatch(nodeTypes.IDENTIFIER)) &&
expressionType(node, basicTypes.UINT) && expressionType(node, exactMatch(basicTypes.UINT)) &&
name(node, 'now') name(node, exactMatch('now'))
}
function isPlusPlusUnaryOperation (node) {
return nodeType(node, exactMatch(nodeTypes.UNARYOPERATION)) && operator(node, exactMatch(utils.escapeRegExp('++')))
}
function isMinusMinusUnaryOperation (node) {
return nodeType(node, exactMatch(nodeTypes.UNARYOPERATION)) && operator(node, exactMatch('--'))
}
function isFullyImplementedContract (node) {
return nodeType(node, exactMatch(nodeTypes.CONTRACTDEFINITION)) && node.attributes.fullyImplemented === true
} }
// usage of block timestamp // usage of block timestamp
@ -59,7 +238,16 @@ function isSpecialVariableAccess (node, varType) {
} }
function isThisLocalCall (node) { function isThisLocalCall (node) {
return isMemberAccess(node, basicRegex.FUNCTIONTYPE, 'this', basicRegex.CONTRACTTYPE, undefined) return isMemberAccess(node, basicRegex.FUNCTIONTYPE, exactMatch('this'), basicRegex.CONTRACTTYPE, undefined)
}
function isLocalCall (node) {
return nodeType(node, exactMatch(nodeTypes.FUNCTIONCALL)) &&
minNrOfChildren(node, 1) &&
nodeType(node.children[0], exactMatch(nodeTypes.IDENTIFIER)) &&
expressionType(node.children[0], basicRegex.FUNCTIONTYPE) &&
!expressionType(node.children[0], basicRegex.EXTERNALFUNCTIONTYPE) &&
nrOfChildren(node.children[0], 0)
} }
function isLowLevelCall (node) { function isLowLevelCall (node) {
@ -71,30 +259,30 @@ function isLowLevelCall (node) {
function isLLSend (node) { function isLLSend (node) {
return isMemberAccess(node, return isMemberAccess(node,
utils.escapeRegExp(lowLevelCallTypes.SEND.type), exactMatch(utils.escapeRegExp(lowLevelCallTypes.SEND.type)),
undefined, basicTypes.ADDRESS, lowLevelCallTypes.SEND.ident) undefined, exactMatch(basicTypes.ADDRESS), exactMatch(lowLevelCallTypes.SEND.ident))
} }
function isLLCall (node) { function isLLCall (node) {
return isMemberAccess(node, return isMemberAccess(node,
utils.escapeRegExp(lowLevelCallTypes.CALL.type), exactMatch(utils.escapeRegExp(lowLevelCallTypes.CALL.type)),
undefined, basicTypes.ADDRESS, lowLevelCallTypes.CALL.ident) undefined, exactMatch(basicTypes.ADDRESS), exactMatch(lowLevelCallTypes.CALL.ident))
} }
function isLLCallcode (node) { function isLLCallcode (node) {
return isMemberAccess(node, return isMemberAccess(node,
utils.escapeRegExp(lowLevelCallTypes.CALLCODE.type), exactMatch(utils.escapeRegExp(lowLevelCallTypes.CALLCODE.type)),
undefined, basicTypes.ADDRESS, lowLevelCallTypes.CALLCODE.ident) undefined, exactMatch(basicTypes.ADDRESS), exactMatch(lowLevelCallTypes.CALLCODE.ident))
} }
function isLLDelegatecall (node) { function isLLDelegatecall (node) {
return isMemberAccess(node, return isMemberAccess(node,
utils.escapeRegExp(lowLevelCallTypes.DELEGATECALL.type), exactMatch(utils.escapeRegExp(lowLevelCallTypes.DELEGATECALL.type)),
undefined, basicTypes.ADDRESS, lowLevelCallTypes.DELEGATECALL.ident) undefined, exactMatch(basicTypes.ADDRESS), exactMatch(lowLevelCallTypes.DELEGATECALL.ident))
} }
function isMemberAccess (node, retType, accessor, accessorType, memberName) { function isMemberAccess (node, retType, accessor, accessorType, memberName) {
return nodeType(node, nodeTypes.MEMBERACCESS) && return nodeType(node, exactMatch(nodeTypes.MEMBERACCESS)) &&
expressionType(node, retType) && expressionType(node, retType) &&
name(node, memberName) && name(node, memberName) &&
nrOfChildren(node, 1) && nrOfChildren(node, 1) &&
@ -102,8 +290,14 @@ function isMemberAccess (node, retType, accessor, accessorType, memberName) {
expressionType(node.children[0], accessorType) expressionType(node.children[0], accessorType)
} }
// #################### Node Identification Primitives
function nrOfChildren (node, nr) { function nrOfChildren (node, nr) {
return (node && (nr === undefined || nr === null)) || (node && node.children && node.children.length === nr) return (node && (nr === undefined || nr === null)) || (node && nr === 0 && !node.children) || (node && node.children && node.children.length === nr)
}
function minNrOfChildren (node, nr) {
return (node && (nr === undefined || nr === null)) || (node && nr === 0 && !node.children) || (node && node.children && node.children.length >= nr)
} }
function expressionType (node, typeRegex) { function expressionType (node, typeRegex) {
@ -119,6 +313,16 @@ function name (node, nameRegex) {
return (node && !nameRegex) || (node && node.attributes && (regex.test(node.attributes.value) || regex.test(node.attributes.member_name))) return (node && !nameRegex) || (node && node.attributes && (regex.test(node.attributes.value) || regex.test(node.attributes.member_name)))
} }
function operator (node, opRegex) {
return (node && !opRegex) || (node && new RegExp(opRegex).test(node.attributes.operator))
}
// #################### Helpers
function exactMatch (regexStr) {
return '^' + regexStr + '$'
}
/** /**
* Builds an function signature as used in the AST of the solc-json AST * Builds an function signature as used in the AST of the solc-json AST
* @param {Array} paramTypes * @param {Array} paramTypes
@ -132,15 +336,69 @@ function buildFunctionSignature (paramTypes, returnTypes, isPayable) {
return 'function (' + utils.concatWithSeperator(paramTypes, ',') + ')' + ((isPayable) ? ' payable' : '') + ((returnTypes.length) ? ' returns (' + utils.concatWithSeperator(returnTypes, ',') + ')' : '') return 'function (' + utils.concatWithSeperator(paramTypes, ',') + ')' + ((isPayable) ? ' payable' : '') + ((returnTypes.length) ? ' returns (' + utils.concatWithSeperator(returnTypes, ',') + ')' : '')
} }
function findFirstSubNodeLTR (node, type) {
for (let i = 0; i < node.children.length; ++i) {
var item = node.children[i]
if (nodeType(item, type)) return item
else {
var res = findFirstSubNodeLTR(item, type)
if (res) return res
}
}
return null
}
module.exports = { module.exports = {
// #################### Trivial Getters
getType: getType,
// #################### Complex Getters
getThisLocalCallName: getThisLocalCallName,
getFunctionCallType: getFunctionCallType,
getContractName: getContractName,
getEffectedVariableName: getEffectedVariableName,
getDeclaredVariableName: getDeclaredVariableName,
getLocalCallName: getLocalCallName,
getInheritsFromName: getInheritsFromName,
getExternalDirectCallContractName: getExternalDirectCallContractName,
getExternalDirectCallMemberName: getExternalDirectCallMemberName,
getFunctionDefinitionName: getFunctionDefinitionName,
getFunctionCallTypeParameterType: getFunctionCallTypeParameterType,
getFullQualifiedFunctionCallIdent: getFullQualifiedFunctionCallIdent,
getFullQuallyfiedFuncDefinitionIdent: getFullQuallyfiedFuncDefinitionIdent,
getStateVariableDeclarationsFormContractNode: getStateVariableDeclarationsFormContractNode,
getFunctionOrModifierDefinitionParameterPart: getFunctionOrModifierDefinitionParameterPart,
// #################### Complex Node Identification
isInteraction: isInteraction,
isEffect: isEffect,
isNowAccess: isNowAccess, isNowAccess: isNowAccess,
isBlockTimestampAccess: isBlockTimestampAccess, isBlockTimestampAccess: isBlockTimestampAccess,
isThisLocalCall: isThisLocalCall, isThisLocalCall: isThisLocalCall,
isLocalCall: isLocalCall,
isWriteOnStateVariable: isWriteOnStateVariable,
isStateVariable: isStateVariable,
isLowLevelCall: isLowLevelCall, isLowLevelCall: isLowLevelCall,
isLowLevelCallInst: isLLCall, isLowLevelCallInst: isLLCall,
isLowLevelCallcodeInst: isLLCallcode, isLowLevelCallcodeInst: isLLCallcode,
isLowLevelDelegatecallInst: isLLDelegatecall, isLowLevelDelegatecallInst: isLLDelegatecall,
isLowLevelSendInst: isLLSend, isLowLevelSendInst: isLLSend,
isExternalDirectCall: isExternalDirectCall,
isFullyImplementedContract: isFullyImplementedContract,
isCallToNonConstLocalFunction: isCallToNonConstLocalFunction,
// #################### Trivial Node Identification
isFunctionDefinition: isFunctionDefinition,
isModifierDefinition: isModifierDefinition,
isInheritanceSpecifier: isInheritanceSpecifier,
isModifierInvocation: isModifierInvocation,
isVariableDeclaration: isVariableDeclaration,
isStorageVariableDeclaration: isStorageVariableDeclaration,
isAssignment: isAssignment,
isContractDefinition: isContractDefinition,
isConstantFunction: isConstantFunction,
isInlineAssembly: isInlineAssembly,
// #################### Constants
nodeTypes: nodeTypes, nodeTypes: nodeTypes,
basicTypes: basicTypes, basicTypes: basicTypes,
basicFunctionTypes: basicFunctionTypes, basicFunctionTypes: basicFunctionTypes,

@ -12,7 +12,6 @@ thisLocal.prototype.visit = function (node) {
} }
thisLocal.prototype.report = function (compilationResults) { thisLocal.prototype.report = function (compilationResults) {
this.warningNowNodes = []
return this.warningNodes.map(function (item, i) { return this.warningNodes.map(function (item, i) {
return { 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.`, 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.`,

@ -12,6 +12,10 @@ staticAnalysisRunner.prototype.run = function (compilationResult, toRun, callbac
return { 'name': m.name, 'mod': new m.Module() } 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. // Also provide convenience analysis via the AST walker.
var walker = new AstWalker() var walker = new AstWalker()
for (var k in compilationResult.sources) { for (var k in compilationResult.sources) {

@ -5,3 +5,4 @@ require('./gist-handler-test')
require('./query-params-test') require('./query-params-test')
require('./util-test') require('./util-test')
require('./staticanalysis/staticAnalysisCommon-test') require('./staticanalysis/staticAnalysisCommon-test')
require('./staticanalysis/staticAnalysisIntegration-test')

@ -80,7 +80,7 @@ test('staticAnalysisCommon.helpers.nrOfChildren', function (t) {
t.ok(common.helpers.nrOfChildren(node, 2), 'should work for 2 children') t.ok(common.helpers.nrOfChildren(node, 2), 'should work for 2 children')
t.notOk(common.helpers.nrOfChildren(node, '1+2'), 'regex should not work') t.notOk(common.helpers.nrOfChildren(node, '1+2'), 'regex should not work')
t.ok(common.helpers.nrOfChildren(node2, 0), 'should work for 0 children') t.ok(common.helpers.nrOfChildren(node2, 0), 'should work for 0 children')
t.notOk(common.helpers.nrOfChildren(node3, 0), 'should not work without children arr') t.ok(common.helpers.nrOfChildren(node3, 0), 'should work without children arr')
lowlevelAccessersCommon(t, common.helpers.nrOfChildren, node) lowlevelAccessersCommon(t, common.helpers.nrOfChildren, node)
}) })
@ -94,8 +94,8 @@ function lowlevelAccessersCommon (t, f, someNode) {
t.notOk(f(), 'false on no params') t.notOk(f(), 'false on no params')
} }
test('staticAnalysisCommon.helpers.isLowLevelCall', function (t) { test('staticAnalysisCommon.isLowLevelCall', function (t) {
t.plan(4) t.plan(6)
var sendAst = { name: 'MemberAccess', children: [{attributes: { value: 'd', type: 'address' }}], attributes: { value: 'send', type: 'function (uint256) returns (bool)' } } var sendAst = { name: 'MemberAccess', children: [{attributes: { value: 'd', type: 'address' }}], attributes: { value: 'send', type: 'function (uint256) returns (bool)' } }
var callAst = { name: 'MemberAccess', children: [{attributes: { value: 'f', type: 'address' }}], attributes: { member_name: 'call', type: 'function () payable returns (bool)' } } var callAst = { name: 'MemberAccess', children: [{attributes: { value: 'f', type: 'address' }}], attributes: { member_name: 'call', type: 'function () payable returns (bool)' } }
var callcodeAst = { name: 'MemberAccess', children: [{attributes: { value: 'f', type: 'address' }}], attributes: { member_name: 'callcode', type: 'function () payable returns (bool)' } } var callcodeAst = { name: 'MemberAccess', children: [{attributes: { value: 'f', type: 'address' }}], attributes: { member_name: 'callcode', type: 'function () payable returns (bool)' } }
@ -103,11 +103,13 @@ test('staticAnalysisCommon.helpers.isLowLevelCall', function (t) {
t.ok(common.isLowLevelSendInst(sendAst) && common.isLowLevelCall(sendAst), 'send is llc should work') t.ok(common.isLowLevelSendInst(sendAst) && common.isLowLevelCall(sendAst), 'send is llc should work')
t.ok(common.isLowLevelCallInst(callAst) && common.isLowLevelCall(callAst), 'call is llc should work') t.ok(common.isLowLevelCallInst(callAst) && common.isLowLevelCall(callAst), 'call is llc should work')
t.notOk(common.isLowLevelCallInst(callcodeAst), 'callcode is not call')
t.ok(common.isLowLevelCallcodeInst(callcodeAst) && common.isLowLevelCall(callcodeAst), 'callcode is llc should work') t.ok(common.isLowLevelCallcodeInst(callcodeAst) && common.isLowLevelCall(callcodeAst), 'callcode is llc should work')
t.notOk(common.isLowLevelCallcodeInst(callAst), 'call is not callcode')
t.ok(common.isLowLevelDelegatecallInst(delegatecallAst) && common.isLowLevelCall(delegatecallAst), 'delegatecall is llc should work') t.ok(common.isLowLevelDelegatecallInst(delegatecallAst) && common.isLowLevelCall(delegatecallAst), 'delegatecall is llc should work')
}) })
test('staticAnalysisCommon.helpers.isThisLocalCall', function (t) { test('staticAnalysisCommon.isThisLocalCall', function (t) {
t.plan(3) t.plan(3)
var node = { name: 'MemberAccess', children: [{attributes: { value: 'this', type: 'contract test' }}], attributes: { value: 'b', type: 'function (bytes32,address) returns (bool)' } } var node = { name: 'MemberAccess', children: [{attributes: { value: 'this', type: 'contract test' }}], attributes: { value: 'b', type: 'function (bytes32,address) returns (bool)' } }
t.ok(common.isThisLocalCall(node), 'is this.local_method() used should work') t.ok(common.isThisLocalCall(node), 'is this.local_method() used should work')
@ -115,7 +117,7 @@ test('staticAnalysisCommon.helpers.isThisLocalCall', function (t) {
t.notOk(common.isNowAccess(node), 'is now used should not work') t.notOk(common.isNowAccess(node), 'is now used should not work')
}) })
test('staticAnalysisCommon.helpers.isBlockTimestampAccess', function (t) { test('staticAnalysisCommon.isBlockTimestampAccess', function (t) {
t.plan(3) t.plan(3)
var node = { name: 'MemberAccess', children: [{attributes: { value: 'block', type: 'block' }}], attributes: { value: 'timestamp', type: 'uint256' } } var node = { name: 'MemberAccess', children: [{attributes: { value: 'block', type: 'block' }}], attributes: { value: 'timestamp', type: 'uint256' } }
t.notOk(common.isThisLocalCall(node), 'is this.local_method() used should not work') t.notOk(common.isThisLocalCall(node), 'is this.local_method() used should not work')
@ -123,10 +125,41 @@ test('staticAnalysisCommon.helpers.isBlockTimestampAccess', function (t) {
t.notOk(common.isNowAccess(node), 'is now used should not work') t.notOk(common.isNowAccess(node), 'is now used should not work')
}) })
test('staticAnalysisCommon.helpers.isNowAccess', function (t) { test('staticAnalysisCommon.isNowAccess', function (t) {
t.plan(3) t.plan(3)
var node = { name: 'Identifier', attributes: { value: 'now', type: 'uint256' } } var node = { name: 'Identifier', attributes: { value: 'now', type: 'uint256' } }
t.notOk(common.isThisLocalCall(node), 'is this.local_method() used should not work') t.notOk(common.isThisLocalCall(node), 'is this.local_method() used should not work')
t.notOk(common.isBlockTimestampAccess(node), 'is block.timestamp used should not work') t.notOk(common.isBlockTimestampAccess(node), 'is block.timestamp used should not work')
t.ok(common.isNowAccess(node), 'is now used should work') t.ok(common.isNowAccess(node), 'is now used should work')
}) })
test('staticAnalysisCommon.isExternalDirectCall', function (t) {
t.plan(5)
var node = {
attributes: {
member_name: 'info',
type: 'function () payable external returns (uint256)'
},
children: [
{
attributes: {
type: 'contract InfoFeed',
value: 'f'
},
id: 30,
name: 'Identifier',
src: '405:1:0'
}
],
id: 32,
name: 'MemberAccess',
src: '405:6:0'
}
var node2 = { name: 'MemberAccess', children: [{attributes: { value: 'this', type: 'contract test' }}], attributes: { value: 'b', type: 'function (bytes32,address) returns (bool)' } }
t.notOk(common.isThisLocalCall(node), 'is this.local_method() used should not work')
t.notOk(common.isBlockTimestampAccess(node), 'is block.timestamp used should not work')
t.notOk(common.isNowAccess(node), 'is now used should not work')
t.ok(common.isExternalDirectCall(node), 'f.info() should be external direct call')
t.notOk(common.isExternalDirectCall(node2), 'local call is not an exernal call')
})

@ -0,0 +1,47 @@
// var test = require('tape')
// var common = require('../../babelify-src/app/staticanalysis/modules/staticAnalysisCommon')
// var StatRunner = require('../../babelify-src/app/staticanalysis/staticAnalysisRunner')
// var utils = require('../../babelify-src/app/utils')
// var Compiler = require('../../babelify-src/app/compiler')
// var fs = require('fs')
// var path = require('path')
// var testFiles = [
// '/test-contracts/KingOfTheEtherThrone.sol',
// '/test-contracts/assembly.sol',
// '/test-contracts/ballot.sol',
// '/test-contracts/ballot_reentrant.sol',
// '/test-contracts/ballot_withoutWarning.sol',
// '/test-contracts/cross_contract.sol',
// '/test-contracts/inheritance.sol',
// '/test-contracts/notReentrant.sol',
// '/test-contracts/structReentrant.sol',
// '/test-contracts/thisLocal.sol',
// '/test-contracts/modifier1.sol',
// '/test-contracts/modifier2.sol'
// ]
// test('thisLocal.js', function (t) {
// t.plan(0)
// var module = require('../../babelify-src/app/staticanalysis/modules/thisLocal')
// runModuleOnFiles(module, t)
// })
// function runModuleOnFiles (module, t) {
// var fakeImport = function (url, cb) { cb('Not implemented') }
// var compiler = new Compiler(fakeImport)
// var statRunner = new StatRunner()
// testFiles.map((fileName) => {
// var contents = fs.readFileSync(path.join(__dirname, fileName), 'utf8')
// var compres = compiler.compile({ 'test': contents }, 'test')
// statRunner.runWithModuleList(compres, [{ name: module.name, mod: new module.Module() }], (reports) => {
// reports.map((r) => t.comment(r.warning))
// })
// })
// }

@ -0,0 +1,23 @@
// 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);
}
}

@ -0,0 +1,26 @@
pragma solidity ^0.4.9;
contract test {
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() {
msg.sender.send(19);
assembly {
}
}
}

@ -0,0 +1,145 @@
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;
}
}

@ -0,0 +1,101 @@
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;
}
}
}

@ -0,0 +1,31 @@
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;
}
}

@ -0,0 +1,19 @@
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();
}
}

@ -0,0 +1,40 @@
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);
}
}

@ -0,0 +1,17 @@
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) {
}
}

@ -0,0 +1,28 @@
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;
}
}

@ -0,0 +1,13 @@
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;
}
}

@ -0,0 +1,49 @@
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();
}
}

@ -0,0 +1,36 @@
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++;
}
}

@ -0,0 +1,16 @@
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) {
}
}
Loading…
Cancel
Save