From 499bce16f75ec4299c40a229a8b69e95b844ee23 Mon Sep 17 00:00:00 2001 From: A23187 <41769181+A-23187@users.noreply.github.com> Date: Mon, 5 Jun 2023 18:00:36 +0800 Subject: [PATCH] some fixes (#1721) * some fixes - add cli option --enable-mutation-pruner to control if to enable MutationPrunerBuilder - let cli option --enable-coverage-strategy to control if to load CoveragePluginBuilder - let cli option --enable-iprof to control if to load InstructionProfilerBuilder - remove the redundant print in MythrilDisassembler.hash_for_function_signature - fix the bug of non-hexadecimal numbers found when converting hex(func_hash)[2:] to bytes - other fixes * some fixes - add cli option --disable-mutation-pruner to disable MutationPrunerBuilder - let cli option --disable-coverage-strategy to disable CoveragePluginBuilder - let cli option --disable-iprof to disable InstructionProfilerBuilder - remove the redundant print in MythrilDisassembler.hash_for_function_signature - other fixes * Fix tests --------- Co-authored-by: norhh --- mythril/analysis/symbolic.py | 10 +++++++--- mythril/analysis/traceexplore.py | 1 - mythril/interfaces/cli.py | 25 ++++++++++++------------- mythril/mythril/mythril_analyzer.py | 4 +++- mythril/mythril/mythril_disassembler.py | 1 - mythril/support/support_args.py | 4 +++- tests/cmd_line_test.py | 11 +++++++++-- tests/graph_test.py | 4 +++- tests/mythril/mythril_analyzer_test.py | 4 +++- tests/statespace_test.py | 4 +++- 10 files changed, 43 insertions(+), 25 deletions(-) diff --git a/mythril/analysis/symbolic.py b/mythril/analysis/symbolic.py index 103a0b64..6aeed770 100644 --- a/mythril/analysis/symbolic.py +++ b/mythril/analysis/symbolic.py @@ -136,10 +136,14 @@ class SymExecWrapper: ) plugin_loader = LaserPluginLoader() - plugin_loader.load(CoveragePluginBuilder()) - plugin_loader.load(MutationPrunerBuilder()) + if not args.disable_coverage_strategy: + plugin_loader.load(CoveragePluginBuilder()) + if not args.disable_mutation_pruner: + plugin_loader.load(MutationPrunerBuilder()) + if not args.disable_iprof: + plugin_loader.load(InstructionProfilerBuilder()) + plugin_loader.load(CallDepthLimitBuilder()) - plugin_loader.load(InstructionProfilerBuilder()) plugin_loader.add_args( "call-depth-limit", call_depth_limit=args.call_depth_limit ) diff --git a/mythril/analysis/traceexplore.py b/mythril/analysis/traceexplore.py index 6c694199..fbc5befc 100644 --- a/mythril/analysis/traceexplore.py +++ b/mythril/analysis/traceexplore.py @@ -149,7 +149,6 @@ def get_serializable_statespace(statespace): label = re.sub( "([^_])([\d]{2}\d+)", lambda m: m.group(1) + hex(int(m.group(2))), label ) - code = re.sub("([0-9a-f]{8})[0-9a-f]+", lambda m: m.group(1) + "(...)", code) s_edge = { "from": str(edge.as_dict["from"]), diff --git a/mythril/interfaces/cli.py b/mythril/interfaces/cli.py index a5ef8721..1aaa248b 100644 --- a/mythril/interfaces/cli.py +++ b/mythril/interfaces/cli.py @@ -328,7 +328,7 @@ def main() -> None: help="Lists available detection modules", ) read_storage_parser = subparsers.add_parser( - "read-storage", + READ_STORAGE_COMNAND, help="Retrieves storage slots from a given address through rpc", parents=[rpc_parser], ) @@ -546,7 +546,7 @@ def add_analysis_args(options): "--phrack", action="store_true", help="Phrack-style call graph" ) options.add_argument( - "--enable-physics", action="store_true", help="enable graph physics simulation" + "--enable-physics", action="store_true", help="Enable graph physics simulation" ) options.add_argument( "-q", @@ -555,7 +555,7 @@ def add_analysis_args(options): help="Lookup function signatures through www.4byte.directory", ) options.add_argument( - "--enable-iprof", action="store_true", help="enable the instruction profiler" + "--disable-iprof", action="store_true", help="Disable the instruction profiler" ) options.add_argument( "--disable-dependency-pruning", @@ -563,13 +563,18 @@ def add_analysis_args(options): help="Deactivate dependency-based pruning", ) options.add_argument( - "--enable-coverage-strategy", + "--disable-coverage-strategy", + action="store_true", + help="Disable coverage based search strategy", + ) + options.add_argument( + "--disable-mutation-pruner", action="store_true", - help="enable coverage based search strategy", + help="Disable mutation pruner", ) options.add_argument( "--custom-modules-directory", - help="designates a separate directory to search for custom analysis modules", + help="Designates a separate directory to search for custom analysis modules", metavar="CUSTOM_MODULES_DIRECTORY", ) options.add_argument( @@ -660,12 +665,6 @@ def validate_args(args: Namespace): "The --query-signature function requires the python package ethereum-input-decoder", ) - if args.enable_iprof and args.v < 4: - exit_with_error( - args.outform, - "--enable-iprof must be used with -v LOG_LEVEL where LOG_LEVEL >= 4", - ) - def set_config(args: Namespace): """ @@ -771,7 +770,7 @@ def execute_command( else: strategy = args.__dict__.get("strategy") - if args.command == "read-storage": + if args.command == READ_STORAGE_COMNAND: storage = disassembler.get_state_variable_from_storage( address=address, params=[a.strip() for a in args.storage_slots.strip().split(",")], diff --git a/mythril/mythril/mythril_analyzer.py b/mythril/mythril/mythril_analyzer.py index 2f73736f..1f6556c2 100644 --- a/mythril/mythril/mythril_analyzer.py +++ b/mythril/mythril/mythril_analyzer.py @@ -67,9 +67,11 @@ class MythrilAnalyzer: args.parallel_solving = cmd_args.parallel_solving args.unconstrained_storage = cmd_args.unconstrained_storage args.call_depth_limit = cmd_args.call_depth_limit - args.iprof = cmd_args.enable_iprof + args.disable_iprof = cmd_args.disable_iprof args.solver_log = cmd_args.solver_log args.transaction_sequences = cmd_args.transaction_sequences + args.disable_coverage_strategy = cmd_args.disable_coverage_strategy + args.disable_mutation_pruner = cmd_args.disable_mutation_pruner if args.pruning_factor is None: if self.execution_timeout > LARGE_TIME: diff --git a/mythril/mythril/mythril_disassembler.py b/mythril/mythril/mythril_disassembler.py index 96fc269f..bcee5550 100644 --- a/mythril/mythril/mythril_disassembler.py +++ b/mythril/mythril/mythril_disassembler.py @@ -313,7 +313,6 @@ class MythrilDisassembler: :param func: function name :return: Its hash signature """ - print(sha3(func)) return "0x%s" % sha3(func)[:4].hex() def get_state_variable_from_storage( diff --git a/mythril/support/support_args.py b/mythril/support/support_args.py index 82df7e34..5722a8e2 100644 --- a/mythril/support/support_args.py +++ b/mythril/support/support_args.py @@ -14,12 +14,14 @@ class Args(object, metaclass=Singleton): self.unconstrained_storage = False self.parallel_solving = False self.call_depth_limit = 3 - self.iprof = True + self.disable_iprof = False self.solver_log = None self.transaction_sequences: List[List[str]] = None self.use_integer_module = True self.use_issue_annotations = False self.solc_args = None + self.disable_coverage_strategy = False + self.disable_mutation_pruner = False args = Args() diff --git a/tests/cmd_line_test.py b/tests/cmd_line_test.py index b534947f..40fb2643 100644 --- a/tests/cmd_line_test.py +++ b/tests/cmd_line_test.py @@ -1,4 +1,4 @@ -from subprocess import check_output, CalledProcessError +from subprocess import check_output, CalledProcessError, STDOUT from tests import BaseTestCase, TESTDATA, PROJECT_DIR, TESTS_DIR from mock import patch @@ -17,6 +17,13 @@ def output_of(command): return exc.output.decode("UTF-8") +def total_output(command): + try: + return check_output(command, shell=True, stderr=STDOUT).decode("UTF-8") + except CalledProcessError as exc: + return exc.output.decode("UTF-8") + + class CommandLineToolTestCase(BaseTestCase): def test_disassemble_code_correctly(self): command = "python3 {} disassemble --bin-runtime -c 0x5050".format(MYTH) @@ -59,7 +66,7 @@ class CommandLineToolTestCase(BaseTestCase): command = "python3 {} analyze {} --enable-iprof -o json".format( MYTH, solidity_file ) - self.assertIn(""""success": false""", output_of(command)) + self.assertIn("""unrecognized arguments""", total_output(command)) def test_only_epic(self): command = "python3 {} --epic".format(MYTH) diff --git a/tests/graph_test.py b/tests/graph_test.py index 1beaa3cc..a76ee531 100644 --- a/tests/graph_test.py +++ b/tests/graph_test.py @@ -29,9 +29,11 @@ def test_generate_graph(): parallel_solving=True, unconstrained_storage=True, call_depth_limit=3, - enable_iprof=False, + disable_iprof=True, solver_log=None, transaction_sequences=None, + disable_coverage_strategy=False, + disable_mutation_pruner=False, ) analyzer = MythrilAnalyzer( disassembler=disassembler, diff --git a/tests/mythril/mythril_analyzer_test.py b/tests/mythril/mythril_analyzer_test.py index 45608231..39ec3dfc 100644 --- a/tests/mythril/mythril_analyzer_test.py +++ b/tests/mythril/mythril_analyzer_test.py @@ -36,9 +36,11 @@ def test_fire_lasers(mock_sym, mock_fire_lasers, mock_code_info): parallel_solving=True, unconstrained_storage=True, call_depth_limit=3, - enable_iprof=False, + disable_iprof=True, solver_log=None, transaction_sequences=None, + disable_coverage_strategy=False, + disable_mutation_pruner=False, ) analyzer = MythrilAnalyzer(disassembler, cmd_args=args) diff --git a/tests/statespace_test.py b/tests/statespace_test.py index c3db4635..e51523d5 100644 --- a/tests/statespace_test.py +++ b/tests/statespace_test.py @@ -26,9 +26,11 @@ def test_statespace_dump(): parallel_solving=True, unconstrained_storage=True, call_depth_limit=3, - enable_iprof=False, + disable_iprof=True, solver_log=None, transaction_sequences=None, + disable_coverage_strategy=False, + disable_mutation_pruner=False, ) analyzer = MythrilAnalyzer( disassembler=disassembler,