Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
B
baas-ide
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
JIRA
JIRA
Merge Requests
1
Merge Requests
1
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
guxukai
baas-ide
Commits
44327da2
Commit
44327da2
authored
Apr 03, 2017
by
Michael Fröwis
Committed by
chriseth
May 17, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Static Analysis: integration tests
parent
d68814df
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
276 additions
and
52 deletions
+276
-52
astWalker.js
src/app/staticanalysis/astWalker.js
+54
-0
abstractAstView.js
src/app/staticanalysis/modules/abstractAstView.js
+2
-1
checksEffectsInteraction.js
src/app/staticanalysis/modules/checksEffectsInteraction.js
+2
-0
constantFunctions.js
src/app/staticanalysis/modules/constantFunctions.js
+2
-0
list.js
src/app/staticanalysis/modules/list.js
+3
-0
staticAnalysisCommon.js
src/app/staticanalysis/modules/staticAnalysisCommon.js
+6
-2
staticAnalysisRunner.js
src/app/staticanalysis/staticAnalysisRunner.js
+2
-1
staticAnalysisCommon-test.js
test/staticanalysis/staticAnalysisCommon-test.js
+9
-0
staticAnalysisIntegration-test.js
test/staticanalysis/staticAnalysisIntegration-test.js
+192
-47
assembly.sol
test/staticanalysis/test-contracts/assembly.sol
+4
-1
No files found.
src/app/staticanalysis/astWalker.js
0 → 100644
View file @
44327da2
'use strict'
/**
* Crawl the given AST through the function walk(ast, callback)
*/
function
AstWalker
()
{
}
/**
* visit all the AST nodes
*
* @param {Object} ast - AST node
* @param {Object or Function} callback - if (Function) the function will be called for every node.
* - if (Object) callback[<Node Type>] will be called for
* every node of type <Node Type>. callback["*"] will be called fo all other nodes.
* in each case, if the callback returns false it does not descend into children.
* If no callback for the current type, children are visited.
*/
AstWalker
.
prototype
.
walk
=
function
(
ast
,
callback
)
{
if
(
callback
instanceof
Function
)
{
callback
=
{
'*'
:
callback
}
}
if
(
!
(
'*'
in
callback
))
{
callback
[
'*'
]
=
function
()
{
return
true
}
}
if
(
manageCallBack
(
ast
,
callback
)
&&
ast
.
children
&&
ast
.
children
.
length
>
0
)
{
for
(
var
k
in
ast
.
children
)
{
var
child
=
ast
.
children
[
k
]
this
.
walk
(
child
,
callback
)
}
}
}
/**
* walk the given @astList
*
* @param {Object} sourcesList - sources list (containing root AST node)
* @param {Function} - callback used by AstWalker to compute response
*/
AstWalker
.
prototype
.
walkAstList
=
function
(
sourcesList
,
callback
)
{
var
walker
=
new
AstWalker
()
for
(
var
k
in
sourcesList
)
{
walker
.
walk
(
sourcesList
[
k
].
AST
,
callback
)
}
}
function
manageCallBack
(
node
,
callback
)
{
if
(
node
.
name
in
callback
)
{
return
callback
[
node
.
name
](
node
)
}
else
{
return
callback
[
'*'
](
node
)
}
}
module
.
exports
=
AstWalker
src/app/staticanalysis/modules/abstractAstView.js
View file @
44327da2
var
common
=
require
(
'./staticAnalysisCommon'
)
var
common
=
require
(
'./staticAnalysisCommon'
)
var
AstWalker
=
require
(
'ethereum-remix'
).
util
.
AstWalker
// var AstWalker = require('ethereum-remix').util.AstWalker
var
AstWalker
=
require
(
'../astWalker'
)
function
abstractAstView
()
{
function
abstractAstView
()
{
this
.
contracts
=
null
this
.
contracts
=
null
...
...
src/app/staticanalysis/modules/checksEffectsInteraction.js
View file @
44327da2
...
@@ -19,6 +19,8 @@ checksEffectsInteraction.prototype.report = function (compilationResults) {
...
@@ -19,6 +19,8 @@ checksEffectsInteraction.prototype.report = function (compilationResults) {
var
cg
=
callGraph
.
buildGlobalFuncCallGraph
(
this
.
contracts
)
var
cg
=
callGraph
.
buildGlobalFuncCallGraph
(
this
.
contracts
)
if
(
this
.
contracts
.
some
((
item
)
=>
item
.
modifiers
.
length
>
0
))
this
.
warning
.
push
({
warning
:
`Modifiers are currently not supported by this analysis.`
})
this
.
contracts
.
forEach
((
contract
)
=>
{
this
.
contracts
.
forEach
((
contract
)
=>
{
contract
.
functions
.
forEach
((
func
)
=>
{
contract
.
functions
.
forEach
((
func
)
=>
{
func
.
changesState
=
checkIfChangesState
(
common
.
getFullQuallyfiedFuncDefinitionIdent
(
contract
.
node
,
func
.
node
,
func
.
parameters
),
func
.
changesState
=
checkIfChangesState
(
common
.
getFullQuallyfiedFuncDefinitionIdent
(
contract
.
node
,
func
.
node
,
func
.
parameters
),
...
...
src/app/staticanalysis/modules/constantFunctions.js
View file @
44327da2
...
@@ -19,6 +19,8 @@ constantFunctions.prototype.report = function (compilationResults) {
...
@@ -19,6 +19,8 @@ constantFunctions.prototype.report = function (compilationResults) {
var
cg
=
callGraph
.
buildGlobalFuncCallGraph
(
this
.
contracts
)
var
cg
=
callGraph
.
buildGlobalFuncCallGraph
(
this
.
contracts
)
if
(
this
.
contracts
.
some
((
item
)
=>
item
.
modifiers
.
length
>
0
))
this
.
warning
.
push
({
warning
:
`Modifiers are currently not supported by this analysis.`
})
this
.
contracts
.
forEach
((
contract
)
=>
{
this
.
contracts
.
forEach
((
contract
)
=>
{
if
(
!
common
.
isFullyImplementedContract
(
contract
.
node
))
return
if
(
!
common
.
isFullyImplementedContract
(
contract
.
node
))
return
...
...
src/app/staticanalysis/modules/list.js
View file @
44327da2
...
@@ -5,4 +5,7 @@ module.exports = [
...
@@ -5,4 +5,7 @@ module.exports = [
require
(
'./checksEffectsInteraction'
),
require
(
'./checksEffectsInteraction'
),
require
(
'./constantFunctions'
),
require
(
'./constantFunctions'
),
require
(
'./inlineAssembly'
)
require
(
'./inlineAssembly'
)
// require('./blockTimestamp'),
// require('./lowLevelCalls'),
// require('./blockBlockhash')
]
]
src/app/staticanalysis/modules/staticAnalysisCommon.js
View file @
44327da2
...
@@ -226,18 +226,21 @@ function isExternalDirectCall (node) {
...
@@ -226,18 +226,21 @@ function isExternalDirectCall (node) {
return
isMemberAccess
(
node
,
basicRegex
.
EXTERNALFUNCTIONTYPE
,
undefined
,
basicRegex
.
CONTRACTTYPE
,
undefined
)
&&
!
isThisLocalCall
(
node
)
return
isMemberAccess
(
node
,
basicRegex
.
EXTERNALFUNCTIONTYPE
,
undefined
,
basicRegex
.
CONTRACTTYPE
,
undefined
)
&&
!
isThisLocalCall
(
node
)
}
}
// usage of now special variable
function
isNowAccess
(
node
)
{
function
isNowAccess
(
node
)
{
return
nodeType
(
node
,
exactMatch
(
nodeTypes
.
IDENTIFIER
))
&&
return
nodeType
(
node
,
exactMatch
(
nodeTypes
.
IDENTIFIER
))
&&
expressionType
(
node
,
exactMatch
(
basicTypes
.
UINT
))
&&
expressionType
(
node
,
exactMatch
(
basicTypes
.
UINT
))
&&
name
(
node
,
exactMatch
(
'now'
))
name
(
node
,
exactMatch
(
'now'
))
}
}
// usage of block timestamp
function
isBlockTimestampAccess
(
node
)
{
function
isBlockTimestampAccess
(
node
)
{
return
isSpecialVariableAccess
(
node
,
specialVariables
.
BLOCKTIMESTAMP
)
return
isSpecialVariableAccess
(
node
,
specialVariables
.
BLOCKTIMESTAMP
)
}
}
// usage of block timestamp
function
isBlockBlockHashAccess
(
node
)
{
return
isSpecialVariableAccess
(
node
,
specialVariables
.
BLOCKHASH
)
}
function
isThisLocalCall
(
node
)
{
function
isThisLocalCall
(
node
)
{
return
isMemberAccess
(
node
,
basicRegex
.
FUNCTIONTYPE
,
exactMatch
(
'this'
),
basicRegex
.
CONTRACTTYPE
,
undefined
)
return
isMemberAccess
(
node
,
basicRegex
.
FUNCTIONTYPE
,
exactMatch
(
'this'
),
basicRegex
.
CONTRACTTYPE
,
undefined
)
}
}
...
@@ -382,6 +385,7 @@ module.exports = {
...
@@ -382,6 +385,7 @@ module.exports = {
isEffect
:
isEffect
,
isEffect
:
isEffect
,
isNowAccess
:
isNowAccess
,
isNowAccess
:
isNowAccess
,
isBlockTimestampAccess
:
isBlockTimestampAccess
,
isBlockTimestampAccess
:
isBlockTimestampAccess
,
isBlockBlockHashAccess
:
isBlockBlockHashAccess
,
isThisLocalCall
:
isThisLocalCall
,
isThisLocalCall
:
isThisLocalCall
,
isLocalCall
:
isLocalCall
,
isLocalCall
:
isLocalCall
,
isWriteOnStateVariable
:
isWriteOnStateVariable
,
isWriteOnStateVariable
:
isWriteOnStateVariable
,
...
...
src/app/staticanalysis/staticAnalysisRunner.js
View file @
44327da2
'use strict'
'use strict'
var
AstWalker
=
require
(
'ethereum-remix'
).
util
.
AstWalker
// var AstWalker = require('ethereum-remix').util.AstWalker
var
AstWalker
=
require
(
'./astWalker'
)
var
list
=
require
(
'./modules/list'
)
var
list
=
require
(
'./modules/list'
)
function
staticAnalysisRunner
()
{
function
staticAnalysisRunner
()
{
...
...
test/staticanalysis/staticAnalysisCommon-test.js
View file @
44327da2
...
@@ -1593,6 +1593,15 @@ test('staticAnalysisCommon.isBlockTimestampAccess', function (t) {
...
@@ -1593,6 +1593,15 @@ test('staticAnalysisCommon.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.isBlockBlockhashAccess'
,
function
(
t
)
{
t
.
plan
(
4
)
var
node
=
{
name
:
'MemberAccess'
,
children
:
[{
attributes
:
{
value
:
'block'
,
type
:
'block'
}}],
attributes
:
{
value
:
'blockhash'
,
type
:
'bytes32'
}
}
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
.
ok
(
common
.
isBlockBlockHashAccess
(
node
),
'blockhash should work'
)
t
.
notOk
(
common
.
isNowAccess
(
node
),
'is now used should not work'
)
})
test
(
'staticAnalysisCommon.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)'
}
}
...
...
test/staticanalysis/staticAnalysisIntegration-test.js
View file @
44327da2
// var test = require('tape')
var
test
=
require
(
'tape'
)
// var common = require('../../babelify-src/app/staticanalysis/modules/staticAnalysisCommon')
var
StatRunner
=
require
(
'../../babelify-src/app/staticanalysis/staticAnalysisRunner'
)
// var StatRunner = require('../../babelify-src/app/staticanalysis/staticAnalysisRunner')
// const util = require('util')
// var utils = require('../../babelify-src/app/utils')
// var Compiler = require('../../babelify-src/app/compiler')
var
solc
=
require
(
'solc'
)
// var fs = require('fs')
var
fs
=
require
(
'fs'
)
// var path = require('path')
var
path
=
require
(
'path'
)
// var testFiles = [
var
testFiles
=
[
// '/test-contracts/KingOfTheEtherThrone.sol',
'KingOfTheEtherThrone.sol'
,
// '/test-contracts/assembly.sol',
'assembly.sol'
,
// '/test-contracts/ballot.sol',
'ballot.sol'
,
// '/test-contracts/ballot_reentrant.sol',
'ballot_reentrant.sol'
,
// '/test-contracts/ballot_withoutWarning.sol',
'ballot_withoutWarnings.sol'
,
// '/test-contracts/cross_contract.sol',
'cross_contract.sol'
,
// '/test-contracts/inheritance.sol',
'inheritance.sol'
,
// '/test-contracts/notReentrant.sol',
'modifier1.sol'
,
// '/test-contracts/structReentrant.sol',
'modifier2.sol'
,
// '/test-contracts/thisLocal.sol',
'notReentrant.sol'
,
// '/test-contracts/modifier1.sol',
'structReentrant.sol'
,
// '/test-contracts/modifier2.sol'
'thisLocal.sol'
// ]
]
// test('thisLocal.js', function (t) {
var
testFileAsts
=
{}
// t.plan(0)
testFiles
.
forEach
((
fileName
)
=>
{
// var module = require('../../babelify-src/app/staticanalysis/modules/thisLocal')
var
contents
=
fs
.
readFileSync
(
path
.
join
(
__dirname
,
'test-contracts'
,
fileName
),
'utf8'
)
testFileAsts
[
fileName
]
=
solc
.
compile
(
contents
,
0
)
// runModuleOnFiles(module, t)
})
// })
test
(
'Integration test thisLocal.js'
,
function
(
t
)
{
// function runModuleOnFiles (module, t) {
t
.
plan
(
testFiles
.
length
)
// var fakeImport = function (url, cb) { cb('Not implemented') }
// var compiler = new Compiler(fakeImport)
var
module
=
require
(
'../../babelify-src/app/staticanalysis/modules/thisLocal'
)
// var statRunner = new StatRunner()
var
lengthCheck
=
{
// testFiles.map((fileName) => {
'KingOfTheEtherThrone.sol'
:
0
,
// var contents = fs.readFileSync(path.join(__dirname, fileName), 'utf8')
'assembly.sol'
:
0
,
// var compres = compiler.compile({ 'test': contents }, 'test')
'ballot.sol'
:
0
,
'ballot_reentrant.sol'
:
1
,
// statRunner.runWithModuleList(compres, [{ name: module.name, mod: new module.Module() }], (reports) => {
'ballot_withoutWarnings.sol'
:
0
,
// reports.map((r) => t.comment(r.warning))
'cross_contract.sol'
:
0
,
// })
'inheritance.sol'
:
0
,
// })
'modifier1.sol'
:
0
,
// }
'modifier2.sol'
:
0
,
'notReentrant.sol'
:
0
,
'structReentrant.sol'
:
0
,
'thisLocal.sol'
:
1
}
runModuleOnFiles
(
module
,
t
,
(
file
,
report
)
=>
{
t
.
equal
(
report
.
length
,
lengthCheck
[
file
],
`
${
file
}
has right amount of this local warnings`
)
})
})
test
(
'Integration test checksEffectsInteraction.js'
,
function
(
t
)
{
t
.
plan
(
testFiles
.
length
)
var
module
=
require
(
'../../babelify-src/app/staticanalysis/modules/checksEffectsInteraction'
)
var
lengthCheck
=
{
'KingOfTheEtherThrone.sol'
:
1
,
'assembly.sol'
:
0
,
'ballot.sol'
:
0
,
'ballot_reentrant.sol'
:
1
,
'ballot_withoutWarnings.sol'
:
0
,
'cross_contract.sol'
:
0
,
'inheritance.sol'
:
1
,
'modifier1.sol'
:
0
,
'modifier2.sol'
:
0
,
'notReentrant.sol'
:
0
,
'structReentrant.sol'
:
1
,
'thisLocal.sol'
:
0
}
runModuleOnFiles
(
module
,
t
,
(
file
,
report
)
=>
{
t
.
equal
(
report
.
length
,
lengthCheck
[
file
],
`
${
file
}
has right amount of checks-effects-interaction warnings`
)
})
})
test
(
'Integration test constatnFunctions.js'
,
function
(
t
)
{
t
.
plan
(
testFiles
.
length
)
var
module
=
require
(
'../../babelify-src/app/staticanalysis/modules/constantFunctions'
)
var
lengthCheck
=
{
'KingOfTheEtherThrone.sol'
:
0
,
'assembly.sol'
:
0
,
'ballot.sol'
:
0
,
'ballot_reentrant.sol'
:
0
,
'ballot_withoutWarnings.sol'
:
0
,
'cross_contract.sol'
:
1
,
'inheritance.sol'
:
0
,
'modifier1.sol'
:
1
,
'modifier2.sol'
:
0
,
'notReentrant.sol'
:
0
,
'structReentrant.sol'
:
0
,
'thisLocal.sol'
:
1
}
runModuleOnFiles
(
module
,
t
,
(
file
,
report
)
=>
{
t
.
equal
(
report
.
length
,
lengthCheck
[
file
],
`
${
file
}
has right amount of constant warnings`
)
})
})
test
(
'Integration test constantFunctions.js'
,
function
(
t
)
{
t
.
plan
(
testFiles
.
length
)
var
module
=
require
(
'../../babelify-src/app/staticanalysis/modules/inlineAssembly'
)
var
lengthCheck
=
{
'KingOfTheEtherThrone.sol'
:
0
,
'assembly.sol'
:
2
,
'ballot.sol'
:
0
,
'ballot_reentrant.sol'
:
0
,
'ballot_withoutWarnings.sol'
:
0
,
'cross_contract.sol'
:
0
,
'inheritance.sol'
:
0
,
'modifier1.sol'
:
0
,
'modifier2.sol'
:
0
,
'notReentrant.sol'
:
0
,
'structReentrant.sol'
:
0
,
'thisLocal.sol'
:
0
}
runModuleOnFiles
(
module
,
t
,
(
file
,
report
)
=>
{
t
.
equal
(
report
.
length
,
lengthCheck
[
file
],
`
${
file
}
has right amount of inline assembly warnings`
)
})
})
test
(
'Integration test txOrigin.js'
,
function
(
t
)
{
t
.
plan
(
testFiles
.
length
)
var
module
=
require
(
'../../babelify-src/app/staticanalysis/modules/txOrigin'
)
var
lengthCheck
=
{
'KingOfTheEtherThrone.sol'
:
0
,
'assembly.sol'
:
1
,
'ballot.sol'
:
0
,
'ballot_reentrant.sol'
:
0
,
'ballot_withoutWarnings.sol'
:
0
,
'cross_contract.sol'
:
0
,
'inheritance.sol'
:
0
,
'modifier1.sol'
:
0
,
'modifier2.sol'
:
0
,
'notReentrant.sol'
:
0
,
'structReentrant.sol'
:
0
,
'thisLocal.sol'
:
0
}
runModuleOnFiles
(
module
,
t
,
(
file
,
report
)
=>
{
t
.
equal
(
report
.
length
,
lengthCheck
[
file
],
`
${
file
}
has right amount of tx.origin warnings`
)
})
})
test
(
'Integration test gasCosts.js'
,
function
(
t
)
{
t
.
plan
(
testFiles
.
length
)
var
module
=
require
(
'../../babelify-src/app/staticanalysis/modules/gasCosts'
)
var
lengthCheck
=
{
'KingOfTheEtherThrone.sol'
:
2
,
'assembly.sol'
:
2
,
'ballot.sol'
:
3
,
'ballot_reentrant.sol'
:
2
,
'ballot_withoutWarnings.sol'
:
0
,
'cross_contract.sol'
:
1
,
'inheritance.sol'
:
1
,
'modifier1.sol'
:
0
,
'modifier2.sol'
:
1
,
'notReentrant.sol'
:
1
,
'structReentrant.sol'
:
1
,
'thisLocal.sol'
:
2
}
runModuleOnFiles
(
module
,
t
,
(
file
,
report
)
=>
{
t
.
equal
(
report
.
length
,
lengthCheck
[
file
],
`
${
file
}
has right amount of gasCost warnings`
)
})
})
// #################### Helpers
function
runModuleOnFiles
(
module
,
t
,
cb
)
{
var
statRunner
=
new
StatRunner
()
testFiles
.
forEach
((
fileName
)
=>
{
statRunner
.
runWithModuleList
(
testFileAsts
[
fileName
],
[{
name
:
module
.
name
,
mod
:
new
module
.
Module
()
}],
(
reports
)
=>
{
cb
(
fileName
,
reports
[
0
].
report
)
})
})
}
test/staticanalysis/test-contracts/assembly.sol
View file @
44327da2
pragma solidity ^0.4.9;
pragma solidity ^0.4.9;
contract test {
contract test {
address owner;
function at(address _addr) returns (bytes o_code) {
function at(address _addr) returns (bytes o_code) {
assembly {
assembly {
// retrieve the size of the code, this needs assembly
// retrieve the size of the code, this needs assembly
...
@@ -18,6 +20,7 @@ pragma solidity ^0.4.9;
...
@@ -18,6 +20,7 @@ pragma solidity ^0.4.9;
}
}
function bla() {
function bla() {
if(tx.origin == owner)
msg.sender.send(19);
msg.sender.send(19);
assembly {
assembly {
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment