diff --git a/mythril/analysis/module/loader.py b/mythril/analysis/module/loader.py index 11b1498e..4ed86b91 100644 --- a/mythril/analysis/module/loader.py +++ b/mythril/analysis/module/loader.py @@ -9,17 +9,21 @@ from mythril.analysis.module.modules.dependence_on_predictable_vars import ( ) from mythril.analysis.module.modules.deprecated_ops import DeprecatedOperations from mythril.analysis.module.modules.ether_thief import EtherThief -from mythril.analysis.module.modules.exceptions import ReachableExceptions +from mythril.analysis.module.modules.exceptions import Exceptions from mythril.analysis.module.modules.external_calls import ExternalCalls from mythril.analysis.module.modules.integer import IntegerArithmetics from mythril.analysis.module.modules.multiple_sends import MultipleSends -from mythril.analysis.module.modules.state_change_external_calls import StateChangeAfterCall +from mythril.analysis.module.modules.state_change_external_calls import ( + StateChangeAfterCall, +) from mythril.analysis.module.modules.suicide import AccidentallyKillable from mythril.analysis.module.modules.unchecked_retval import UncheckedRetval from mythril.analysis.module.modules.user_assertions import UserAssertions from mythril.analysis.module.base import EntryPoint +from mythril.exceptions import DetectorNotFoundError + from typing import Optional, List @@ -53,11 +57,28 @@ class ModuleLoader(object, metaclass=Singleton): :param white_list: If specified: only return whitelisted detection modules :return: The selected detection modules """ + result = self._modules[:] + + if white_list: + + # Sanity check + + available_names = [type(module).__name__ for module in result] + + for name in white_list: + if name not in available_names: + raise DetectorNotFoundError( + "Invalid detection module: {}".format(name) + ) + + result = [ + module for module in result if type(module).__name__ in white_list + ] + if entry_point: result = [module for module in result if module.entry_point == entry_point] - if white_list: - result = [module for module in result if module.name in white_list] + return result def _register_mythril_modules(self): @@ -69,7 +90,7 @@ class ModuleLoader(object, metaclass=Singleton): PredictableVariables(), DeprecatedOperations(), EtherThief(), - ReachableExceptions(), + Exceptions(), ExternalCalls(), IntegerArithmetics(), MultipleSends(), diff --git a/mythril/analysis/module/modules/exceptions.py b/mythril/analysis/module/modules/exceptions.py index 73b10803..7edcb0f3 100644 --- a/mythril/analysis/module/modules/exceptions.py +++ b/mythril/analysis/module/modules/exceptions.py @@ -11,7 +11,7 @@ from mythril.laser.ethereum.state.global_state import GlobalState log = logging.getLogger(__name__) -class ReachableExceptions(DetectionModule): +class Exceptions(DetectionModule): """""" name = "Reachable Exceptions" @@ -76,4 +76,4 @@ class ReachableExceptions(DetectionModule): return [] -detector = ReachableExceptions() +detector = Exceptions() diff --git a/mythril/exceptions.py b/mythril/exceptions.py index 7988759b..2f6ad04f 100644 --- a/mythril/exceptions.py +++ b/mythril/exceptions.py @@ -39,3 +39,10 @@ class AddressNotFoundError(MythrilBaseException): found.""" pass + + +class DetectorNotFoundError(MythrilBaseException): + """A Mythril exception denoting attempted usage of a non-existant + detection module.""" + + pass diff --git a/mythril/interfaces/cli.py b/mythril/interfaces/cli.py index d5cc5ed5..99187f6a 100644 --- a/mythril/interfaces/cli.py +++ b/mythril/interfaces/cli.py @@ -17,7 +17,11 @@ import traceback import mythril.support.signatures as sigs from argparse import ArgumentParser, Namespace, RawTextHelpFormatter from mythril import mythx -from mythril.exceptions import AddressNotFoundError, CriticalError +from mythril.exceptions import ( + AddressNotFoundError, + DetectorNotFoundError, + CriticalError, +) from mythril.laser.ethereum.transaction.symbolic import ACTORS from mythril.mythril import ( MythrilAnalyzer, @@ -729,9 +733,11 @@ def execute_command( "markdown": report.as_markdown(), } print(outputs[args.outform]) - except ModuleNotFoundError as e: + except DetectorNotFoundError as e: + exit_with_error(args.outform, format(e)) + except CriticalError as e: exit_with_error( - args.outform, "Error loading analysis modules: " + format(e) + args.outform, "Analysis error encountered: " + format(e) ) else: diff --git a/mythril/laser/ethereum/keccak_function_manager.py b/mythril/laser/ethereum/keccak_function_manager.py index 6fbbe583..29e421c8 100644 --- a/mythril/laser/ethereum/keccak_function_manager.py +++ b/mythril/laser/ethereum/keccak_function_manager.py @@ -141,7 +141,7 @@ class KeccakFunctionManager: ) concrete_cond = symbol_factory.Bool(False) for key, keccak in self.concrete_hashes.items(): - hash_eq = And(func(func_input) == keccak, key == func_input,) + hash_eq = And(func(func_input) == keccak, key == func_input) concrete_cond = Or(concrete_cond, hash_eq) return And(inv(func(func_input)) == func_input, Or(cond, concrete_cond)) diff --git a/mythril/mythril/mythril_analyzer.py b/mythril/mythril/mythril_analyzer.py index d94b2faf..844031af 100644 --- a/mythril/mythril/mythril_analyzer.py +++ b/mythril/mythril/mythril_analyzer.py @@ -18,6 +18,7 @@ from mythril.analysis.report import Report, Issue from mythril.ethereum.evmcontract import EVMContract from mythril.laser.smt import SolverStatistics from mythril.support.start_time import StartTime +from mythril.exceptions import DetectorNotFoundError log = logging.getLogger(__name__) @@ -172,6 +173,9 @@ class MythrilAnalyzer: custom_modules_directory=self.custom_modules_directory, ) issues = fire_lasers(sym, modules) + except DetectorNotFoundError as e: + # Bubble up + raise e except KeyboardInterrupt: log.critical("Keyboard Interrupt") if self.iprof is not None: