mirror of https://github.com/crytic/slither
Merge pull request #823 from crytic/dev-multiple-compilation-units
Add the support for multiple compilation units.pull/836/head
commit
76c5cb2602
@ -1,17 +0,0 @@ |
|||||||
from typing import TYPE_CHECKING |
|
||||||
|
|
||||||
if TYPE_CHECKING: |
|
||||||
from slither import Slither |
|
||||||
|
|
||||||
|
|
||||||
class ChildSlither: |
|
||||||
def __init__(self): |
|
||||||
super().__init__() |
|
||||||
self._slither = None |
|
||||||
|
|
||||||
def set_slither(self, slither: "Slither"): |
|
||||||
self._slither = slither |
|
||||||
|
|
||||||
@property |
|
||||||
def slither(self) -> "Slither": |
|
||||||
return self._slither |
|
@ -0,0 +1,267 @@ |
|||||||
|
import math |
||||||
|
from collections import defaultdict |
||||||
|
from typing import Optional, Dict, List, Set, Union, TYPE_CHECKING, Tuple |
||||||
|
|
||||||
|
from crytic_compile import CompilationUnit, CryticCompile |
||||||
|
from crytic_compile.compiler.compiler import CompilerVersion |
||||||
|
|
||||||
|
from slither.core.context.context import Context |
||||||
|
from slither.core.declarations import ( |
||||||
|
Contract, |
||||||
|
Pragma, |
||||||
|
Import, |
||||||
|
Function, |
||||||
|
Modifier, |
||||||
|
) |
||||||
|
from slither.core.declarations.enum_top_level import EnumTopLevel |
||||||
|
from slither.core.declarations.function_top_level import FunctionTopLevel |
||||||
|
from slither.core.declarations.structure_top_level import StructureTopLevel |
||||||
|
from slither.core.variables.state_variable import StateVariable |
||||||
|
from slither.core.variables.top_level_variable import TopLevelVariable |
||||||
|
from slither.slithir.operations import InternalCall |
||||||
|
from slither.slithir.variables import Constant |
||||||
|
|
||||||
|
if TYPE_CHECKING: |
||||||
|
from slither.core.slither_core import SlitherCore |
||||||
|
|
||||||
|
# pylint: disable=too-many-instance-attributes,too-many-public-methods |
||||||
|
class SlitherCompilationUnit(Context): |
||||||
|
def __init__(self, core: "SlitherCore", crytic_compilation_unit: CompilationUnit): |
||||||
|
super().__init__() |
||||||
|
|
||||||
|
self._core = core |
||||||
|
self._crytic_compile_compilation_unit = crytic_compilation_unit |
||||||
|
|
||||||
|
# Top level object |
||||||
|
self._contracts: Dict[str, Contract] = {} |
||||||
|
self._structures_top_level: List[StructureTopLevel] = [] |
||||||
|
self._enums_top_level: List[EnumTopLevel] = [] |
||||||
|
self._variables_top_level: List[TopLevelVariable] = [] |
||||||
|
self._functions_top_level: List[FunctionTopLevel] = [] |
||||||
|
self._pragma_directives: List[Pragma] = [] |
||||||
|
self._import_directives: List[Import] = [] |
||||||
|
|
||||||
|
self._all_functions: Set[Function] = set() |
||||||
|
self._all_modifiers: Set[Modifier] = set() |
||||||
|
|
||||||
|
# Memoize |
||||||
|
self._all_state_variables: Optional[Set[StateVariable]] = None |
||||||
|
|
||||||
|
self._storage_layouts: Dict[str, Dict[str, Tuple[int, int]]] = {} |
||||||
|
|
||||||
|
self._contract_name_collisions = defaultdict(list) |
||||||
|
self._contract_with_missing_inheritance = set() |
||||||
|
|
||||||
|
self._source_units: Dict[int, str] = {} |
||||||
|
|
||||||
|
self.counter_slithir_tuple = 0 |
||||||
|
self.counter_slithir_temporary = 0 |
||||||
|
self.counter_slithir_reference = 0 |
||||||
|
|
||||||
|
@property |
||||||
|
def core(self) -> "SlitherCore": |
||||||
|
return self._core |
||||||
|
|
||||||
|
@property |
||||||
|
def source_units(self) -> Dict[int, str]: |
||||||
|
return self._source_units |
||||||
|
|
||||||
|
# endregion |
||||||
|
################################################################################### |
||||||
|
################################################################################### |
||||||
|
# region Compiler |
||||||
|
################################################################################### |
||||||
|
################################################################################### |
||||||
|
|
||||||
|
@property |
||||||
|
def compiler_version(self) -> CompilerVersion: |
||||||
|
return self._crytic_compile_compilation_unit.compiler_version |
||||||
|
|
||||||
|
@property |
||||||
|
def solc_version(self) -> str: |
||||||
|
return self._crytic_compile_compilation_unit.compiler_version.version |
||||||
|
|
||||||
|
@property |
||||||
|
def crytic_compile_compilation_unit(self) -> CompilationUnit: |
||||||
|
return self._crytic_compile_compilation_unit |
||||||
|
|
||||||
|
@property |
||||||
|
def crytic_compile(self) -> CryticCompile: |
||||||
|
return self._crytic_compile_compilation_unit.crytic_compile |
||||||
|
|
||||||
|
# endregion |
||||||
|
################################################################################### |
||||||
|
################################################################################### |
||||||
|
# region Pragma attributes |
||||||
|
################################################################################### |
||||||
|
################################################################################### |
||||||
|
|
||||||
|
@property |
||||||
|
def pragma_directives(self) -> List[Pragma]: |
||||||
|
""" list(core.declarations.Pragma): Pragma directives.""" |
||||||
|
return self._pragma_directives |
||||||
|
|
||||||
|
@property |
||||||
|
def import_directives(self) -> List[Import]: |
||||||
|
""" list(core.declarations.Import): Import directives""" |
||||||
|
return self._import_directives |
||||||
|
|
||||||
|
# endregion |
||||||
|
################################################################################### |
||||||
|
################################################################################### |
||||||
|
# region Contracts |
||||||
|
################################################################################### |
||||||
|
################################################################################### |
||||||
|
|
||||||
|
@property |
||||||
|
def contracts(self) -> List[Contract]: |
||||||
|
"""list(Contract): List of contracts.""" |
||||||
|
return list(self._contracts.values()) |
||||||
|
|
||||||
|
@property |
||||||
|
def contracts_derived(self) -> List[Contract]: |
||||||
|
"""list(Contract): List of contracts that are derived and not inherited.""" |
||||||
|
inheritances = [x.inheritance for x in self.contracts] |
||||||
|
inheritance = [item for sublist in inheritances for item in sublist] |
||||||
|
return [c for c in self._contracts.values() if c not in inheritance and not c.is_top_level] |
||||||
|
|
||||||
|
@property |
||||||
|
def contracts_as_dict(self) -> Dict[str, Contract]: |
||||||
|
"""list(dict(str: Contract): List of contracts as dict: name -> Contract.""" |
||||||
|
return self._contracts |
||||||
|
|
||||||
|
def get_contract_from_name(self, contract_name: Union[str, Constant]) -> Optional[Contract]: |
||||||
|
""" |
||||||
|
Return a contract from a name |
||||||
|
Args: |
||||||
|
contract_name (str): name of the contract |
||||||
|
Returns: |
||||||
|
Contract |
||||||
|
""" |
||||||
|
return next((c for c in self.contracts if c.name == contract_name), None) |
||||||
|
|
||||||
|
# endregion |
||||||
|
################################################################################### |
||||||
|
################################################################################### |
||||||
|
# region Functions and modifiers |
||||||
|
################################################################################### |
||||||
|
################################################################################### |
||||||
|
|
||||||
|
@property |
||||||
|
def functions(self) -> List[Function]: |
||||||
|
return list(self._all_functions) |
||||||
|
|
||||||
|
def add_function(self, func: Function): |
||||||
|
self._all_functions.add(func) |
||||||
|
|
||||||
|
@property |
||||||
|
def modifiers(self) -> List[Modifier]: |
||||||
|
return list(self._all_modifiers) |
||||||
|
|
||||||
|
def add_modifier(self, modif: Modifier): |
||||||
|
self._all_modifiers.add(modif) |
||||||
|
|
||||||
|
@property |
||||||
|
def functions_and_modifiers(self) -> List[Function]: |
||||||
|
return self.functions + self.modifiers |
||||||
|
|
||||||
|
def propagate_function_calls(self): |
||||||
|
for f in self.functions_and_modifiers: |
||||||
|
for node in f.nodes: |
||||||
|
for ir in node.irs_ssa: |
||||||
|
if isinstance(ir, InternalCall): |
||||||
|
ir.function.add_reachable_from_node(node, ir) |
||||||
|
|
||||||
|
# endregion |
||||||
|
################################################################################### |
||||||
|
################################################################################### |
||||||
|
# region Variables |
||||||
|
################################################################################### |
||||||
|
################################################################################### |
||||||
|
|
||||||
|
@property |
||||||
|
def state_variables(self) -> List[StateVariable]: |
||||||
|
if self._all_state_variables is None: |
||||||
|
state_variables = [c.state_variables for c in self.contracts] |
||||||
|
state_variables = [item for sublist in state_variables for item in sublist] |
||||||
|
self._all_state_variables = set(state_variables) |
||||||
|
return list(self._all_state_variables) |
||||||
|
|
||||||
|
# endregion |
||||||
|
################################################################################### |
||||||
|
################################################################################### |
||||||
|
# region Top level |
||||||
|
################################################################################### |
||||||
|
################################################################################### |
||||||
|
|
||||||
|
@property |
||||||
|
def structures_top_level(self) -> List[StructureTopLevel]: |
||||||
|
return self._structures_top_level |
||||||
|
|
||||||
|
@property |
||||||
|
def enums_top_level(self) -> List[EnumTopLevel]: |
||||||
|
return self._enums_top_level |
||||||
|
|
||||||
|
@property |
||||||
|
def variables_top_level(self) -> List[TopLevelVariable]: |
||||||
|
return self._variables_top_level |
||||||
|
|
||||||
|
@property |
||||||
|
def functions_top_level(self) -> List[FunctionTopLevel]: |
||||||
|
return self._functions_top_level |
||||||
|
|
||||||
|
# endregion |
||||||
|
################################################################################### |
||||||
|
################################################################################### |
||||||
|
# region Internals |
||||||
|
################################################################################### |
||||||
|
################################################################################### |
||||||
|
|
||||||
|
@property |
||||||
|
def contract_name_collisions(self) -> Dict: |
||||||
|
return self._contract_name_collisions |
||||||
|
|
||||||
|
@property |
||||||
|
def contracts_with_missing_inheritance(self) -> Set: |
||||||
|
return self._contract_with_missing_inheritance |
||||||
|
|
||||||
|
# endregion |
||||||
|
################################################################################### |
||||||
|
################################################################################### |
||||||
|
# region Storage Layouts |
||||||
|
################################################################################### |
||||||
|
################################################################################### |
||||||
|
|
||||||
|
def compute_storage_layout(self): |
||||||
|
for contract in self.contracts_derived: |
||||||
|
self._storage_layouts[contract.name] = {} |
||||||
|
|
||||||
|
slot = 0 |
||||||
|
offset = 0 |
||||||
|
for var in contract.state_variables_ordered: |
||||||
|
if var.is_constant: |
||||||
|
continue |
||||||
|
|
||||||
|
size, new_slot = var.type.storage_size |
||||||
|
|
||||||
|
if new_slot: |
||||||
|
if offset > 0: |
||||||
|
slot += 1 |
||||||
|
offset = 0 |
||||||
|
elif size + offset > 32: |
||||||
|
slot += 1 |
||||||
|
offset = 0 |
||||||
|
|
||||||
|
self._storage_layouts[contract.name][var.canonical_name] = ( |
||||||
|
slot, |
||||||
|
offset, |
||||||
|
) |
||||||
|
if new_slot: |
||||||
|
slot += math.ceil(size / 32) |
||||||
|
else: |
||||||
|
offset += size |
||||||
|
|
||||||
|
def storage_layout_of(self, contract, var) -> Tuple[int, int]: |
||||||
|
return self._storage_layouts[contract.name][var.canonical_name] |
||||||
|
|
||||||
|
# endregion |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue