slither = Slither('data_dependency_simple_example.sol') myContract = slither.get_contract_from_name('MyContract') funcA = myContract.get_function_from_signature('foo()') a = myContract.get_state_variable_from_name('a') b = myContract.get_state_variable_from_name('b') c = myContract.get_state_variable_from_name('c') d = myContract.get_state_variable_from_name('d') D = Dependency() D.compute_contract(myContract, slither) D.dependencies = funcA.context[D.KEY_NON_SSA] R = Refinement() R.compute_contract(myContract, slither) guards = [] for var in R.types[R.Typ.GUARD]: if var in D.dependencies: guards += D.dependencies[var] R.types[R.Typ.GUARD] += guards for typ in R.types: for var in R.types[typ]: if var.name.startswith("REF") or var.name.startswith("TMP"): R.types[typ].remove(var)
def analyze(fname, cname='MyContract', funcname='foo()'): slither = Slither(fname) myContract = slither.get_contract_from_name(cname) funcA = myContract.get_function_from_signature(funcname) # Dependency Analysis D = Dependency() D.compute_contract(myContract, slither) D.dependencies = funcA.context[D.KEY_NON_SSA] # Refinement Analysis R = Refinement() R.compute_contract(myContract, slither, fname) # Lambda Analysis lambdas = get_lambda_analysis(fname, myContract, slither) # For Guard Types, use Dependency Analysis to fetch all vars which affect # the Guard (i.e. on which the guard depends) guards = [] for var in R.types[R.Typ.GUARD]: if var in D.dependencies: guards += D.dependencies[var] R.types[R.Typ.GUARD] += guards # Remove temporary variables and ref vars from types to_delete = {} for typ in R.types: to_delete[typ] = [] if typ != 6 and typ != 7: for var in R.types[typ]: if var.name.startswith("REF") or var.name.startswith("TMP"): to_delete[typ].append(var) for k,vals in to_delete.items(): for v in vals: R.types[k].remove(v) # Remove temporary variables and ref vars from dependencies to_delete = [] for var in D.dependencies: if var.name.startswith("REF") or var.name.startswith("TMP"): to_delete.append(var) else: to_delete2 = [] for var2 in D.dependencies[var]: if var2.name.startswith("REF") or var2.name.startswith("TMP"): to_delete2.append(var2) for x in to_delete2: D.dependencies[var].remove(x) if len(D.dependencies[var]) == 0: to_delete.append(var) for x in to_delete: D.dependencies.pop(x, None) # Fetch written and read types from dependencies R.types[R.Typ.WRITTEN] += D.dependencies.keys() R.types[R.Typ.READ] += [x for vals in D.dependencies.values() for x in vals] # Anything that is an index or guard is also read R.types[R.Typ.READ] += R.types[R.Typ.INDEX] R.types[R.Typ.READ] += R.types[R.Typ.GUARD] R.types[R.Typ.READ] += R.types[R.Typ.GUARDSTART] R.types[R.Typ.READ] += R.types[R.Typ.GUARDEND] # Reformat refinement type entries R_types_formatted = {} for typ, vrs in R.types.items(): # Special check for lower casing True and False constants rhs = set(map(lambda v: v.lower() if v=="True" or v=="False" else v, set(map(str, vrs)))) typ = typ.lower() if typ == "True" or typ == "False" else typ R_types_formatted[typ] = rhs R.types = R_types_formatted # Reformat dependencies entries dependencies_formatted = {} for v, vrs in D.dependencies.items(): # Special check for lower casing True and False constants lhs = str(v).lower() if str(v) == "True" or str(v) == "False" else str(v) rhs = set(map(lambda v: v.lower() if v=="True" or v=="False" else v, set(map(str, vrs)))) dependencies_formatted[lhs] = rhs D.dependencies = dependencies_formatted # Add lambdas to dependencies based on sub-parts dependencies_lambdas = {} for v, vrs in D.dependencies.items(): dependencies_lambdas[v] = vrs for lam in lambdas: lam_vrs = re.findall(r"[\w']+", lam[lam.index(":")+1:]) if any(map(lambda lv: lv in vrs, lam_vrs)): dependencies_lambdas[v].add(lam) D.dependencies = dependencies_lambdas # # Transitive Closure of Dependencies # D.dependencies = transitive_close(D.dependencies) return D, R