Skip to content

Commit

Permalink
Memoize calls to __str__
Browse files Browse the repository at this point in the history
  • Loading branch information
DarkaMaul committed Apr 19, 2024
1 parent 6074ab1 commit 6afe440
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 57 deletions.
10 changes: 9 additions & 1 deletion slither/core/slither_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ def _relative_path_format(path: str) -> str:
return path.split("..")[-1].strip(".").strip("/")


def empty_tuple_list():
return [(-1, -1)]


def tuple_dict():
return defaultdict(empty_tuple_list)


# pylint: disable=too-many-instance-attributes,too-many-public-methods
class SlitherCore(Context):
"""
Expand Down Expand Up @@ -80,7 +88,7 @@ def __init__(self) -> None:
# Maps from file to detector name to the start/end ranges for that detector.
# Infinity is used to signal a detector has no end range.
self._ignore_ranges: Dict[str, Dict[str, List[Tuple[int, ...]]]] = defaultdict(
lambda: defaultdict(lambda: [(-1, -1)])
tuple_dict
)

self._compilation_units: List[SlitherCompilationUnit] = []
Expand Down
4 changes: 3 additions & 1 deletion slither/core/solidity_types/array_type.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from functools import cache
from typing import Union, Optional, Tuple, Any, TYPE_CHECKING

from slither.core.expressions.expression import Expression
Expand Down Expand Up @@ -66,6 +67,7 @@ def storage_size(self) -> Tuple[int, bool]:
return elem_size * int(str(self._length_value)), True
return 32, True

@cache
def __str__(self) -> str:
if self._length:
return str(self._type) + f"[{str(self._length_value)}]"
Expand All @@ -77,4 +79,4 @@ def __eq__(self, other: Any) -> bool:
return self._type == other.type and self._length_value == other.length_value

def __hash__(self) -> int:
return hash(str(self))
return hash(self._type)
4 changes: 3 additions & 1 deletion slither/core/solidity_types/elementary_type.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import itertools
from functools import cache
from typing import Tuple, Optional, Any

from slither.core.solidity_types.type import Type
Expand Down Expand Up @@ -216,6 +217,7 @@ def max(self) -> int:
return MaxValues[self.name]
raise SlitherException(f"{self.name} does not have a max value")

@cache
def __str__(self) -> str:
return self._type

Expand All @@ -225,4 +227,4 @@ def __eq__(self, other: Any) -> bool:
return self.type == other.type

def __hash__(self) -> int:
return hash(str(self))
return hash(self._type)
4 changes: 3 additions & 1 deletion slither/core/solidity_types/mapping_type.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from functools import cache
from typing import Union, Tuple, TYPE_CHECKING, Any

from slither.core.solidity_types.type import Type
Expand Down Expand Up @@ -35,6 +36,7 @@ def storage_size(self) -> Tuple[int, bool]:
def is_dynamic(self) -> bool:
return True

@cache
def __str__(self) -> str:
return f"mapping({str(self._from)} => {str(self._to)})"

Expand All @@ -44,4 +46,4 @@ def __eq__(self, other: Any) -> bool:
return self.type_from == other.type_from and self.type_to == other.type_to

def __hash__(self) -> int:
return hash(str(self))
return hash(f"{self._from}.{self._to}")
127 changes: 74 additions & 53 deletions slither/solc_parsing/slither_compilation_unit_solc.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import concurrent.futures
from collections import defaultdict
import json
import logging
Expand Down Expand Up @@ -73,6 +74,64 @@ def _handle_import_aliases(
)


def generate_slithir_contract(contract):
contract.add_constructor_variables()

for func in contract.functions + contract.modifiers:
try:
func.generate_slithir_and_analyze()

except AttributeError as e:
# This can happen for example if there is a call to an interface
# And the interface is redefined due to contract's name reuse
# But the available version misses some functions
# self._underlying_contract_to_parser[contract].log_incorrect_parsing(
# f"Impossible to generate IR for {contract.name}.{func.name} ({func.source_mapping}):\n {e}"
# )
# TODO(dm)
pass
except Exception as e:
func_expressions = "\n".join([f"\t{ex}" for ex in func.expressions])
logger.error(
f"\nFailed to generate IR for {contract.name}.{func.name}. Please open an issue https://github.com/crytic/slither/issues.\n{contract.name}.{func.name} ({func.source_mapping}):\n "
f"{func_expressions}"
)
raise e
try:
contract.convert_expression_to_slithir_ssa()
except Exception as exc:
logger.error(
f"\nFailed to convert IR to SSA for {contract.name} contract. Please open an issue https://github.com/crytic/slither/issues.\n "
)
raise exc


def generate_slithir_function(func):
try:
func.generate_slithir_and_analyze()
except AttributeError as e:
logger.error(
f"Impossible to generate IR for top level function {func.name} ({func.source_mapping}):\n {e}"
)
except Exception as e:
func_expressions = "\n".join([f"\t{ex}" for ex in func.expressions])
logger.error(
f"\nFailed to generate IR for top level function {func.name}. Please open an issue https://github.com/crytic/slither/issues.\n{func.name} ({func.source_mapping}):\n "
f"{func_expressions}"
)
raise e

try:
func.generate_slithir_ssa({})
except Exception as e:
func_expressions = "\n".join([f"\t{ex}" for ex in func.expressions])
logger.error(
f"\nFailed to convert IR to SSA for top level function {func.name}. Please open an issue https://github.com/crytic/slither/issues.\n{func.name} ({func.source_mapping}):\n "
f"{func_expressions}"
)
raise e


class SlitherCompilationUnitSolc(CallerContextExpression):
# pylint: disable=too-many-instance-attributes
def __init__(self, compilation_unit: SlitherCompilationUnit) -> None:
Expand Down Expand Up @@ -803,60 +862,22 @@ def _analyze_variables_modifiers_functions(self, contract: ContractSolc) -> None
contract.set_is_analyzed(True)

def _convert_to_slithir(self) -> None:

for contract in self._compilation_unit.contracts:
contract.add_constructor_variables()

for func in contract.functions + contract.modifiers:
try:
func.generate_slithir_and_analyze()

except AttributeError as e:
# This can happens for example if there is a call to an interface
# And the interface is redefined due to contract's name reuse
# But the available version misses some functions
self._underlying_contract_to_parser[contract].log_incorrect_parsing(
f"Impossible to generate IR for {contract.name}.{func.name} ({func.source_mapping}):\n {e}"
)
except Exception as e:
func_expressions = "\n".join([f"\t{ex}" for ex in func.expressions])
logger.error(
f"\nFailed to generate IR for {contract.name}.{func.name}. Please open an issue https://github.com/crytic/slither/issues.\n{contract.name}.{func.name} ({func.source_mapping}):\n "
f"{func_expressions}"
)
raise e
try:
contract.convert_expression_to_slithir_ssa()
except Exception as e:
logger.error(
f"\nFailed to convert IR to SSA for {contract.name} contract. Please open an issue https://github.com/crytic/slither/issues.\n "
)
raise e

for func in self._compilation_unit.functions_top_level:
try:
func.generate_slithir_and_analyze()
except AttributeError as e:
logger.error(
f"Impossible to generate IR for top level function {func.name} ({func.source_mapping}):\n {e}"
)
except Exception as e:
func_expressions = "\n".join([f"\t{ex}" for ex in func.expressions])
logger.error(
f"\nFailed to generate IR for top level function {func.name}. Please open an issue https://github.com/crytic/slither/issues.\n{func.name} ({func.source_mapping}):\n "
f"{func_expressions}"
)
raise e

try:
func.generate_slithir_ssa({})
except Exception as e:
func_expressions = "\n".join([f"\t{ex}" for ex in func.expressions])
logger.error(
f"\nFailed to convert IR to SSA for top level function {func.name}. Please open an issue https://github.com/crytic/slither/issues.\n{func.name} ({func.source_mapping}):\n "
f"{func_expressions}"
)
raise e
generate_slithir_contract(contract)

for function in self._compilation_unit.functions_top_level:
generate_slithir_function(function)
#
# with concurrent.futures.ProcessPoolExecutor() as executor:
#
# futures = [
# executor.submit(generate_slithir_contract, contract) for contract in self._compilation_unit.contracts
# ] + [
# executor.submit(generate_slithir_function, function) for function in self._compilation_unit.functions_top_level
# ]
#
# for future in concurrent.futures.as_completed(futures):
# future.result()

self._compilation_unit.propagate_function_calls()
for contract in self._compilation_unit.contracts:
Expand Down

0 comments on commit 6afe440

Please sign in to comment.