mirror of https://github.com/crytic/slither
parent
d33c3e8b83
commit
cacf3cf483
@ -0,0 +1,105 @@ |
|||||||
|
""" |
||||||
|
Compute the data depenency between all the SSA variables |
||||||
|
""" |
||||||
|
from slither.slithir.operations import Index, Member, OperationWithLValue |
||||||
|
from slither.slithir.variables import ReferenceVariable, Constant |
||||||
|
from slither.slithir.variables import (Constant, LocalIRVariable, StateIRVariable, |
||||||
|
ReferenceVariable, TemporaryVariable, |
||||||
|
TupleVariable) |
||||||
|
|
||||||
|
KEY = "DATA_DEPENDENCY_SSA" |
||||||
|
KEY_NON_SSA = "DATA_DEPENDENCY" |
||||||
|
|
||||||
|
def compute_dependency(slither): |
||||||
|
for contract in slither.contracts: |
||||||
|
compute_dependency_contract(contract) |
||||||
|
|
||||||
|
def compute_dependency_contract(contract): |
||||||
|
if KEY in contract.context: |
||||||
|
return |
||||||
|
|
||||||
|
contract.context[KEY] = dict() |
||||||
|
for function in contract.all_functions_called: |
||||||
|
compute_dependency_function(function) |
||||||
|
data_depencencies = function.context[KEY] |
||||||
|
|
||||||
|
for (key, values) in data_depencencies.items(): |
||||||
|
if not key in contract.context[KEY]: |
||||||
|
contract.context[KEY][key] = set(values) |
||||||
|
else: |
||||||
|
contract.context[KEY][key].union(values) |
||||||
|
|
||||||
|
# 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[KEY].items()} |
||||||
|
for key, items in data_depencencies.items(): |
||||||
|
for item in items: |
||||||
|
if item in data_depencencies: |
||||||
|
additional_items = contract.context[KEY][item] |
||||||
|
for additional_item in additional_items: |
||||||
|
if not additional_item in items and additional_item != key: |
||||||
|
changed = True |
||||||
|
contract.context[KEY][key].add(additional_item) |
||||||
|
|
||||||
|
|
||||||
|
contract.context[KEY_NON_SSA] = convert_to_non_ssa(contract.context[KEY]) |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def compute_dependency_function(function): |
||||||
|
if KEY in function.context: |
||||||
|
return function.context[KEY] |
||||||
|
|
||||||
|
function.context[KEY] = dict() |
||||||
|
for node in function.nodes: |
||||||
|
for ir in node.irs_ssa: |
||||||
|
if isinstance(ir, OperationWithLValue) and ir.lvalue: |
||||||
|
lvalue = ir.lvalue |
||||||
|
# if isinstance(ir.lvalue, ReferenceVariable): |
||||||
|
# lvalue = lvalue.points_to_origin |
||||||
|
# # TODO fix incorrect points_to for BALANCE |
||||||
|
# if not lvalue: |
||||||
|
# continue |
||||||
|
if not lvalue in function.context[KEY]: |
||||||
|
function.context[KEY][lvalue] = set() |
||||||
|
if isinstance(ir, Index): |
||||||
|
read = [ir.variable_left] |
||||||
|
else: |
||||||
|
read = ir.read |
||||||
|
[function.context[KEY][lvalue].add(v) for v in read if not isinstance(v, Constant)] |
||||||
|
|
||||||
|
function.context[KEY_NON_SSA] = convert_to_non_ssa(function.context[KEY]) |
||||||
|
|
||||||
|
def valid_non_ssa(v): |
||||||
|
if isinstance(v, (TemporaryVariable, |
||||||
|
ReferenceVariable, |
||||||
|
TupleVariable)): |
||||||
|
return False |
||||||
|
return True |
||||||
|
|
||||||
|
def convert_variable_to_non_ssa(v): |
||||||
|
if isinstance(v, (LocalIRVariable, StateIRVariable)): |
||||||
|
if isinstance(v, LocalIRVariable): |
||||||
|
function = v.function |
||||||
|
return function.get_local_variable_from_name(v.name) |
||||||
|
else: |
||||||
|
contract = v.contract |
||||||
|
return contract.get_state_variable_from_name(v.name) |
||||||
|
return v |
||||||
|
|
||||||
|
def convert_to_non_ssa(data_depencies): |
||||||
|
# Need to create new set() as its changed during iteration |
||||||
|
ret = dict() |
||||||
|
for (k, values) in data_depencies.items(): |
||||||
|
if not valid_non_ssa(k): |
||||||
|
continue |
||||||
|
var = convert_variable_to_non_ssa(k) |
||||||
|
if not var in ret: |
||||||
|
ret[var] = set() |
||||||
|
ret[var] = ret[var].union(set([convert_variable_to_non_ssa(v) for v in |
||||||
|
values if valid_non_ssa(v)])) |
||||||
|
|
||||||
|
return ret |
Loading…
Reference in new issue