Skip to content

Commit

Permalink
Data depencies: use fix point for function depenencies (fix #171)
Browse files Browse the repository at this point in the history
Add data_depencies.get_dependencies function
Add depencies printer
  • Loading branch information
montyly committed Feb 10, 2019
1 parent 02661eb commit 1757618
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 8 deletions.
39 changes: 31 additions & 8 deletions slither/analyses/data_dependency/data_dependency.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,21 @@ def is_tainted_ssa(variable, context, only_unprotected=False):
return variable in taints or any(is_dependent_ssa(variable, t, context, only_unprotected) for t in taints)


def get_dependencies(variable, context, only_unprotected=False):
'''
Args:
variable
context (Contract|Function)
only_unprotected (bool): True only unprotected function are considered
Returns:
list(Variable)
'''
assert isinstance(context, (Contract, Function))
assert isinstance(only_unprotected, bool)
if only_unprotected:
return context.context[KEY_NON_SSA].get(variable, [])
return context.context[KEY_NON_SSA_UNPROTECTED].get(variable, [])

# endregion
###################################################################################
###################################################################################
Expand Down Expand Up @@ -162,8 +177,11 @@ def compute_dependency_contract(contract, slither):
for function in contract.all_functions_called:
compute_dependency_function(function)

propagate_function(contract, function, KEY_SSA)
propagate_function(contract, function, KEY_SSA_UNPROTECTED)
propagate_function(contract, function, KEY_SSA, KEY_NON_SSA)
propagate_function(contract,
function,
KEY_SSA_UNPROTECTED,
KEY_NON_SSA_UNPROTECTED)

if function.visibility in ['public', 'external']:
[slither.context[KEY_INPUT].add(p) for p in function.parameters]
Expand All @@ -172,7 +190,8 @@ def compute_dependency_contract(contract, slither):
propagate_contract(contract, KEY_SSA, KEY_NON_SSA)
propagate_contract(contract, KEY_SSA_UNPROTECTED, KEY_NON_SSA_UNPROTECTED)

def propagate_function(contract, function, context_key):
def propagate_function(contract, function, context_key, context_key_non_ssa):
transitive_close_dependencies(function, context_key, context_key_non_ssa)
# Propage data dependency
data_depencencies = function.context[context_key]
for (key, values) in data_depencencies.items():
Expand All @@ -181,22 +200,26 @@ def propagate_function(contract, function, context_key):
else:
contract.context[context_key][key].union(values)

def propagate_contract(contract, context_key, context_key_non_ssa):
def transitive_close_dependencies(context, context_key, context_key_non_ssa):
# transitive closure
changed = True
while changed:
changed = False
# Need to create new set() as its changed during iteration
data_depencencies = {k: set([v for v in values]) for k, values in contract.context[context_key].items()}
data_depencencies = {k: set([v for v in values]) for k, values in context.context[context_key].items()}
for key, items in data_depencencies.items():
for item in items:
if item in data_depencencies:
additional_items = contract.context[context_key][item]
additional_items = context.context[context_key][item]
for additional_item in additional_items:
if not additional_item in items and additional_item != key:
changed = True
contract.context[context_key][key].add(additional_item)
contract.context[context_key_non_ssa] = convert_to_non_ssa(contract.context[context_key])
context.context[context_key][key].add(additional_item)
context.context[context_key_non_ssa] = convert_to_non_ssa(context.context[context_key])


def propagate_contract(contract, context_key, context_key_non_ssa):
transitive_close_dependencies(contract, context_key, context_key_non_ssa)

def add_dependency(lvalue, function, ir, is_protected):
if not lvalue in function.context[KEY_SSA]:
Expand Down
1 change: 1 addition & 0 deletions slither/printers/all_printers.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@
from .functions.cfg import CFG
from .summary.function_ids import FunctionIds
from .summary.variables_order import VariablesOrder
from .summary.data_depenency import DataDependency
46 changes: 46 additions & 0 deletions slither/printers/summary/data_depenency.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
"""
Module printing summary of the contract
"""

from prettytable import PrettyTable
from slither.printers.abstract_printer import AbstractPrinter
from slither.analyses.data_dependency.data_dependency import get_dependencies
from slither.slithir.variables import TemporaryVariable, ReferenceVariable

def _get(v, c):
return [d.name for d in get_dependencies(v, c) if not isinstance(d, (TemporaryVariable,
ReferenceVariable))]

class DataDependency(AbstractPrinter):

ARGUMENT = 'data-dependency'
HELP = 'Print the data dependencies of the variables'

WIKI = 'https://github.com/trailofbits/slither/wiki/Printer-documentation#data-dependencies'

def output(self, _filename):
"""
_filename is not used
Args:
_filename(string)
"""

txt = ''
for c in self.contracts:
txt += "\nContract %s\n"%c.name
table = PrettyTable(['Variable', 'Depenencies'])
for v in c.state_variables:
table.add_row([v.name, _get(v, c)])

txt += str(table)

txt += "\n"
for f in c.functions_and_modifiers_not_inherited:
txt += "\nFunction %s\n"%f.full_name
table = PrettyTable(['Variable', 'Depenencies'])
for v in f.variables:
table.add_row([v.name, _get(v, f)])
for v in c.state_variables:
table.add_row([v.canonical_name, _get(v, f)])
txt += str(table)
self.info(txt)

0 comments on commit 1757618

Please sign in to comment.