From 3afdf31ec1bf7a93d13af0946794b6aaa8b1ac70 Mon Sep 17 00:00:00 2001 From: Nikhil Parasaram Date: Tue, 5 Mar 2019 21:19:23 +0530 Subject: [PATCH 01/22] Handle -1 case in solidity file mapping --- mythril/analysis/report.py | 14 ++++++++++++++ mythril/solidity/soliditycontract.py | 15 +++++++++------ mythril/support/truffle.py | 5 ++++- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/mythril/analysis/report.py b/mythril/analysis/report.py index 075dbdb1..b30f9553 100644 --- a/mythril/analysis/report.py +++ b/mythril/analysis/report.py @@ -103,6 +103,18 @@ class Issue: return issue + def _add_false_positive_tags(self): + """ + Adds the false positive to description and changes severity to low + """ + self.severity = "Low" + self.description_tail += ( + " This happened in the internal compiler generated code, " + "so it might possibly be a false positive." + ) + self.description = "%s\n%s" % (self.description_head, self.description_tail) + self.code = "" + def add_code_info(self, contract): """ @@ -115,6 +127,8 @@ class Issue: self.filename = codeinfo.filename self.code = codeinfo.code self.lineno = codeinfo.lineno + if self.lineno is None: + self._add_false_positive_tags() self.source_mapping = codeinfo.solc_mapping else: self.source_mapping = self.address diff --git a/mythril/solidity/soliditycontract.py b/mythril/solidity/soliditycontract.py index d2669e7f..6f83ead7 100644 --- a/mythril/solidity/soliditycontract.py +++ b/mythril/solidity/soliditycontract.py @@ -161,11 +161,14 @@ class SolidityContract(EVMContract): if len(mapping) > 2 and len(mapping[2]) > 0: idx = int(mapping[2]) - lineno = ( - self.solidity_files[idx] - .data.encode("utf-8")[0:offset] - .count("\n".encode("utf-8")) - + 1 - ) + if idx == -1: + lineno = None + else: + lineno = ( + self.solidity_files[idx] + .data.encode("utf-8")[0:offset] + .count("\n".encode("utf-8")) + + 1 + ) prev_item = item mappings.append(SourceMapping(idx, offset, length, lineno, item)) diff --git a/mythril/support/truffle.py b/mythril/support/truffle.py index 800b6fca..58b00b06 100644 --- a/mythril/support/truffle.py +++ b/mythril/support/truffle.py @@ -181,7 +181,10 @@ def get_mappings(source, deployed_source_map): if len(mapping) > 2 and len(mapping[2]) > 0: idx = int(mapping[2]) - lineno = source.encode("utf-8")[0:offset].count("\n".encode("utf-8")) + 1 + if idx == -1: + lineno = None + else: + lineno = source.encode("utf-8")[0:offset].count("\n".encode("utf-8")) + 1 prev_item = item mappings.append(SourceMapping(idx, offset, length, lineno, item)) From 7b80c759102e0fbd416b40591480db6182f8d2ce Mon Sep 17 00:00:00 2001 From: Nikhil Parasaram Date: Wed, 6 Mar 2019 16:40:25 +0530 Subject: [PATCH 02/22] Change the error message and function name --- mythril/analysis/report.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/mythril/analysis/report.py b/mythril/analysis/report.py index b30f9553..99fd58bf 100644 --- a/mythril/analysis/report.py +++ b/mythril/analysis/report.py @@ -103,14 +103,13 @@ class Issue: return issue - def _add_false_positive_tags(self): + def _set_internal_compiler_error(self): """ Adds the false positive to description and changes severity to low """ self.severity = "Low" self.description_tail += ( - " This happened in the internal compiler generated code, " - "so it might possibly be a false positive." + " This issue is reported for internal compiler generated code." ) self.description = "%s\n%s" % (self.description_head, self.description_tail) self.code = "" @@ -128,7 +127,7 @@ class Issue: self.code = codeinfo.code self.lineno = codeinfo.lineno if self.lineno is None: - self._add_false_positive_tags() + self._set_internal_compiler_error() self.source_mapping = codeinfo.solc_mapping else: self.source_mapping = self.address From 85b749fa0cea13a981b8c4bd47cd3a50a8fcd018 Mon Sep 17 00:00:00 2001 From: Nikhil Parasaram Date: Wed, 6 Mar 2019 20:13:45 +0530 Subject: [PATCH 03/22] add support for logs --- mythril/analysis/report.py | 16 +++++++++++++--- mythril/interfaces/cli.py | 20 ++++++++++++++++++-- mythril/mythril.py | 5 +++-- 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/mythril/analysis/report.py b/mythril/analysis/report.py index 075dbdb1..14836046 100644 --- a/mythril/analysis/report.py +++ b/mythril/analysis/report.py @@ -3,6 +3,7 @@ import logging import json import operator from jinja2 import PackageLoader, Environment +from typing import Dict, List import _pysha3 as sha3 import hashlib @@ -127,7 +128,7 @@ class Report: loader=PackageLoader("mythril.analysis"), trim_blocks=True ) - def __init__(self, verbose=False, source=None): + def __init__(self, verbose=False, source=None, exceptions=None): """ :param verbose: @@ -137,6 +138,7 @@ class Report: self.solc_version = "" self.meta = {} self.source = source or Source() + self.exceptions = exceptions or [] def sorted_issues(self): """ @@ -174,6 +176,14 @@ class Report: result = {"success": True, "error": None, "issues": self.sorted_issues()} return json.dumps(result, sort_keys=True) + def _get_exception_data(self) -> dict: + if not self.exceptions: + return {} + logs = [] # type: List[Dict] + for exception in self.exceptions: + logs += [{"level": "error", "hidden": "true", "error": exception}] + return {"logs": logs} + def as_swc_standard_format(self): """Format defined for integration and correlation. @@ -208,14 +218,14 @@ class Report: "extra": {}, } ) - + meta_data = self._get_exception_data() result = [ { "issues": _issues, "sourceType": "raw-bytecode", "sourceFormat": "evm-byzantium-bytecode", "sourceList": source_list, - "meta": {}, + "meta": meta_data, } ] diff --git a/mythril/interfaces/cli.py b/mythril/interfaces/cli.py index 7ea614b8..9b668d37 100644 --- a/mythril/interfaces/cli.py +++ b/mythril/interfaces/cli.py @@ -10,9 +10,11 @@ import json import logging import os import sys +import traceback import coloredlogs +from mythril.analysis.report import Report import mythril.support.signatures as sigs from mythril.exceptions import AddressNotFoundError, CriticalError from mythril.mythril import Mythril @@ -31,9 +33,22 @@ def exit_with_error(format_, message): """ if format_ == "text" or format_ == "markdown": log.error(message) - else: + elif format_ == "json": result = {"success": False, "error": str(message), "issues": []} print(json.dumps(result)) + else: + result = [ + { + "issues": [], + "sourceType": "", + "sourceFormat": "", + "sourceList": [], + "meta": { + "logs": [{"level": "error", "hidden": "true", "error": message}] + }, + } + ] + print(json.dumps(result)) sys.exit() @@ -243,7 +258,6 @@ def main(): else: print("Mythril version {}".format(VERSION)) sys.exit() - # Parse cmdline args if not ( @@ -486,6 +500,8 @@ def main(): except CriticalError as ce: exit_with_error(args.outform, str(ce)) + except Exception: + exit_with_error(args.outform, traceback.format_exc()) if __name__ == "__main__": diff --git a/mythril/mythril.py b/mythril/mythril.py index 2f082ba0..8eb49956 100644 --- a/mythril/mythril.py +++ b/mythril/mythril.py @@ -568,6 +568,7 @@ class Mythril(object): """ all_issues = [] SolverStatistics().enabled = True + exceptions = [] for contract in contracts or self.contracts: try: sym = SymExecWrapper( @@ -597,7 +598,7 @@ class Mythril(object): + traceback.format_exc() ) issues = retrieve_callback_issues(modules) - + exceptions.append(traceback.format_exc()) for issue in issues: issue.add_code_info(contract) @@ -607,7 +608,7 @@ class Mythril(object): source_data = Source() source_data.get_source_from_contracts_list(self.contracts) # Finally, output the results - report = Report(verbose_report, source_data) + report = Report(verbose_report, source_data, exceptions=exceptions) for issue in all_issues: report.append_issue(issue) From fa13ef86506920aeed999e8987b1bca8353930fc Mon Sep 17 00:00:00 2001 From: Nikhil Parasaram Date: Wed, 6 Mar 2019 20:39:51 +0530 Subject: [PATCH 04/22] Refactor cli.py --- mythril/analysis/report.py | 2 +- mythril/interfaces/cli.py | 375 ++++++++++++++++++++----------------- 2 files changed, 204 insertions(+), 173 deletions(-) diff --git a/mythril/analysis/report.py b/mythril/analysis/report.py index 14836046..6761a209 100644 --- a/mythril/analysis/report.py +++ b/mythril/analysis/report.py @@ -179,7 +179,7 @@ class Report: def _get_exception_data(self) -> dict: if not self.exceptions: return {} - logs = [] # type: List[Dict] + logs = [] # type: List[Dict] for exception in self.exceptions: logs += [{"level": "error", "hidden": "true", "error": exception}] return {"logs": logs} diff --git a/mythril/interfaces/cli.py b/mythril/interfaces/cli.py index 9b668d37..198d4388 100644 --- a/mythril/interfaces/cli.py +++ b/mythril/interfaces/cli.py @@ -14,7 +14,6 @@ import traceback import coloredlogs -from mythril.analysis.report import Report import mythril.support.signatures as sigs from mythril.exceptions import AddressNotFoundError, CriticalError from mythril.mythril import Mythril @@ -52,11 +51,28 @@ def exit_with_error(format_, message): sys.exit() -def main(): +def main() -> None: """The main CLI interface entry point.""" parser = argparse.ArgumentParser( description="Security analysis of Ethereum smart contracts" ) + create_parser(parser) + + # Get config values + + args = parser.parse_args() + parse_args(parser=parser, args=args) + + +if __name__ == "__main__": + main() + + +def create_parser(parser: argparse.ArgumentParser) -> None: + """ + Creates the parser by setting all the possible arguments + :param parser: The parser + """ parser.add_argument("solidity_file", nargs="*") commands = parser.add_argument_group("commands") @@ -180,14 +196,14 @@ def main(): options.add_argument( "--max-depth", type=int, - default=50, + default=22, help="Maximum recursion depth for symbolic execution", ) options.add_argument( "--strategy", choices=["dfs", "bfs", "naive-random", "weighted-random"], - default="bfs", + default="dfs", help="Symbolic execution strategy", ) options.add_argument( @@ -242,24 +258,8 @@ def main(): ) parser.add_argument("--epic", action="store_true", help=argparse.SUPPRESS) - # Get config values - - args = parser.parse_args() - - if args.epic: - path = os.path.dirname(os.path.realpath(__file__)) - sys.argv.remove("--epic") - os.system(" ".join(sys.argv) + " | python3 " + path + "/epic.py") - sys.exit() - - if args.version: - if args.outform == "json": - print(json.dumps({"version_str": VERSION})) - else: - print("Mythril version {}".format(VERSION)) - sys.exit() - # Parse cmdline args +def validate_args(parser: argparse.ArgumentParser, args: argparse.Namespace): if not ( args.search or args.hash @@ -312,177 +312,119 @@ def main(): "--enable-iprof must be used with one of -g, --graph, -x, --fire-lasers, -j and --statespace-json", ) - # -- commands -- + +def quick_commands(args: argparse.Namespace): if args.hash: print(Mythril.hash_for_function_signature(args.hash)) sys.exit() - try: - # the mythril object should be our main interface - # infura = None, rpc = None, rpctls = None - # solc_args = None, dynld = None, max_recursion_depth = 12): - - mythril = Mythril( - solv=args.solv, - dynld=args.dynld, - onchain_storage_access=(not args.no_onchain_storage_access), - solc_args=args.solc_args, - enable_online_lookup=args.query_signature, + +def set_config(args: argparse.Namespace): + mythril = Mythril( + solv=args.solv, + dynld=args.dynld, + onchain_storage_access=(not args.no_onchain_storage_access), + solc_args=args.solc_args, + enable_online_lookup=args.query_signature, + ) + if args.dynld or not args.no_onchain_storage_access and not (args.rpc or args.i): + mythril.set_api_from_config_path() + + if args.address: + # Establish RPC connection if necessary + mythril.set_api_rpc(rpc=args.rpc, rpctls=args.rpctls) + elif args.search or args.contract_hash_to_address: + # Open LevelDB if necessary + mythril.set_api_leveldb( + mythril.leveldb_dir if not args.leveldb_dir else args.leveldb_dir ) - if ( - args.dynld - or not args.no_onchain_storage_access - and not (args.rpc or args.i) - ): - mythril.set_api_from_config_path() - - if args.address: - # Establish RPC connection if necessary - mythril.set_api_rpc(rpc=args.rpc, rpctls=args.rpctls) - elif args.search or args.contract_hash_to_address: - # Open LevelDB if necessary - mythril.set_api_leveldb( - mythril.leveldb_dir if not args.leveldb_dir else args.leveldb_dir - ) + return mythril - if args.search: - # Database search ops - mythril.search_db(args.search) - sys.exit() - if args.contract_hash_to_address: - # search corresponding address - try: - mythril.contract_hash_to_address(args.contract_hash_to_address) - except AddressNotFoundError: - print("Address not found.") +def leveldb_search(mythril: Mythril, args: argparse.Namespace): + if args.search: + # Database search ops + mythril.search_db(args.search) + sys.exit() - sys.exit() + if args.contract_hash_to_address: + # search corresponding address + try: + mythril.contract_hash_to_address(args.contract_hash_to_address) + except AddressNotFoundError: + print("Address not found.") - if args.truffle: - try: - # not really pythonic atm. needs refactoring - mythril.analyze_truffle_project(args) - except FileNotFoundError: - print( - "Build directory not found. Make sure that you start the analysis from the project root, and that 'truffle compile' has executed successfully." - ) - sys.exit() + sys.exit() - # Load / compile input contracts - address = None - - if args.code: - # Load from bytecode - code = args.code[2:] if args.code.startswith("0x") else args.code - address, _ = mythril.load_from_bytecode(code, args.bin_runtime) - elif args.codefile: - bytecode = "".join([l.strip() for l in args.codefile if len(l.strip()) > 0]) - bytecode = bytecode[2:] if bytecode.startswith("0x") else bytecode - address, _ = mythril.load_from_bytecode(bytecode, args.bin_runtime) - elif args.address: - # Get bytecode from a contract address - address, _ = mythril.load_from_address(args.address) - elif args.solidity_file: - # Compile Solidity source file(s) - if args.graph and len(args.solidity_file) > 1: - exit_with_error( - args.outform, - "Cannot generate call graphs from multiple input files. Please do it one at a time.", - ) - address, _ = mythril.load_from_solidity(args.solidity_file) # list of files - else: + +def get_code(mythril: Mythril, args: argparse.Namespace): + address = None + if args.code: + # Load from bytecode + code = args.code[2:] if args.code.startswith("0x") else args.code + address, _ = mythril.load_from_bytecode(code, args.bin_runtime) + elif args.codefile: + bytecode = "".join([l.strip() for l in args.codefile if len(l.strip()) > 0]) + bytecode = bytecode[2:] if bytecode.startswith("0x") else bytecode + address, _ = mythril.load_from_bytecode(bytecode, args.bin_runtime) + elif args.address: + # Get bytecode from a contract address + address, _ = mythril.load_from_address(args.address) + elif args.solidity_file: + # Compile Solidity source file(s) + if args.graph and len(args.solidity_file) > 1: exit_with_error( args.outform, - "No input bytecode. Please provide EVM code via -c BYTECODE, -a ADDRESS, or -i SOLIDITY_FILES", + "Cannot generate call graphs from multiple input files. Please do it one at a time.", ) + address, _ = mythril.load_from_solidity(args.solidity_file) # list of files + else: + exit_with_error( + args.outform, + "No input bytecode. Please provide EVM code via -c BYTECODE, -a ADDRESS, or -i SOLIDITY_FILES", + ) + return address - # Commands - if args.storage: - if not args.address: - exit_with_error( - args.outform, - "To read storage, provide the address of a deployed contract with the -a option.", - ) - - storage = mythril.get_state_variable_from_storage( - address=address, - params=[a.strip() for a in args.storage.strip().split(",")], +def execute_command( + mythril: Mythril, + address: str, + parser: argparse.ArgumentParser, + args: argparse.Namespace, +): + if args.storage: + if not args.address: + exit_with_error( + args.outform, + "To read storage, provide the address of a deployed contract with the -a option.", ) - print(storage) - elif args.disassemble: - # or mythril.disassemble(mythril.contracts[0]) - - if mythril.contracts[0].code: - print("Runtime Disassembly: \n" + mythril.contracts[0].get_easm()) - if mythril.contracts[0].creation_code: - print("Disassembly: \n" + mythril.contracts[0].get_creation_easm()) + storage = mythril.get_state_variable_from_storage( + address=address, params=[a.strip() for a in args.storage.strip().split(",")] + ) + print(storage) - elif args.graph or args.fire_lasers: - if not mythril.contracts: - exit_with_error( - args.outform, "input files do not contain any valid contracts" - ) + elif args.disassemble: + # or mythril.disassemble(mythril.contracts[0]) - if args.graph: - html = mythril.graph_html( - strategy=args.strategy, - contract=mythril.contracts[0], - address=address, - enable_physics=args.enable_physics, - phrackify=args.phrack, - max_depth=args.max_depth, - execution_timeout=args.execution_timeout, - create_timeout=args.create_timeout, - enable_iprof=args.enable_iprof, - ) + if mythril.contracts[0].code: + print("Runtime Disassembly: \n" + mythril.contracts[0].get_easm()) + if mythril.contracts[0].creation_code: + print("Disassembly: \n" + mythril.contracts[0].get_creation_easm()) - try: - with open(args.graph, "w") as f: - f.write(html) - except Exception as e: - exit_with_error(args.outform, "Error saving graph: " + str(e)) - - else: - try: - report = mythril.fire_lasers( - strategy=args.strategy, - address=address, - modules=[m.strip() for m in args.modules.strip().split(",")] - if args.modules - else [], - verbose_report=args.verbose_report, - max_depth=args.max_depth, - execution_timeout=args.execution_timeout, - create_timeout=args.create_timeout, - transaction_count=args.transaction_count, - enable_iprof=args.enable_iprof, - ) - outputs = { - "json": report.as_json(), - "jsonv2": report.as_swc_standard_format(), - "text": report.as_text(), - "markdown": report.as_markdown(), - } - print(outputs[args.outform]) - except ModuleNotFoundError as e: - exit_with_error( - args.outform, "Error loading analyis modules: " + format(e) - ) - - elif args.statespace_json: - - if not mythril.contracts: - exit_with_error( - args.outform, "input files do not contain any valid contracts" - ) + elif args.graph or args.fire_lasers: + if not mythril.contracts: + exit_with_error( + args.outform, "input files do not contain any valid contracts" + ) - statespace = mythril.dump_statespace( + if args.graph: + html = mythril.graph_html( strategy=args.strategy, contract=mythril.contracts[0], address=address, + enable_physics=args.enable_physics, + phrackify=args.phrack, max_depth=args.max_depth, execution_timeout=args.execution_timeout, create_timeout=args.create_timeout, @@ -490,14 +432,103 @@ def main(): ) try: - with open(args.statespace_json, "w") as f: - json.dump(statespace, f) + with open(args.graph, "w") as f: + f.write(html) except Exception as e: - exit_with_error(args.outform, "Error saving json: " + str(e)) + exit_with_error(args.outform, "Error saving graph: " + str(e)) else: - parser.print_help() + try: + report = mythril.fire_lasers( + strategy=args.strategy, + address=address, + modules=[m.strip() for m in args.modules.strip().split(",")] + if args.modules + else [], + verbose_report=args.verbose_report, + max_depth=args.max_depth, + execution_timeout=args.execution_timeout, + create_timeout=args.create_timeout, + transaction_count=args.transaction_count, + enable_iprof=args.enable_iprof, + ) + outputs = { + "json": report.as_json(), + "jsonv2": report.as_swc_standard_format(), + "text": report.as_text(), + "markdown": report.as_markdown(), + } + print(outputs[args.outform]) + except ModuleNotFoundError as e: + exit_with_error( + args.outform, "Error loading analyis modules: " + format(e) + ) + + elif args.statespace_json: + + if not mythril.contracts: + exit_with_error( + args.outform, "input files do not contain any valid contracts" + ) + + statespace = mythril.dump_statespace( + strategy=args.strategy, + contract=mythril.contracts[0], + address=address, + max_depth=args.max_depth, + execution_timeout=args.execution_timeout, + create_timeout=args.create_timeout, + enable_iprof=args.enable_iprof, + ) + + try: + with open(args.statespace_json, "w") as f: + json.dump(statespace, f) + except Exception as e: + exit_with_error(args.outform, "Error saving json: " + str(e)) + + else: + parser.print_help() + + +def parse_args(parser: argparse.ArgumentParser, args: argparse.Namespace) -> None: + """ + Parses the arguments + :param parser: The parser + :param args: The args + """ + + if args.epic: + path = os.path.dirname(os.path.realpath(__file__)) + sys.argv.remove("--epic") + os.system(" ".join(sys.argv) + " | python3 " + path + "/epic.py") + sys.exit() + + if args.version: + if args.outform == "json": + print(json.dumps({"version_str": VERSION})) + else: + print("Mythril version {}".format(VERSION)) + sys.exit() + + # Parse cmdline args + validate_args(parser, args) + try: + quick_commands(args) + mythril = set_config(args) + leveldb_search(mythril, args) + + if args.truffle: + try: + mythril.analyze_truffle_project(args) + except FileNotFoundError: + print( + "Build directory not found. Make sure that you start the analysis from the project root, and that 'truffle compile' has executed successfully." + ) + sys.exit() + address = get_code(mythril, args) + execute_command(mythril=mythril, address=address, parser=parser, args=args) except CriticalError as ce: exit_with_error(args.outform, str(ce)) except Exception: From 1a0ead5eac29f0c4b26ff7211829662ee7ca4864 Mon Sep 17 00:00:00 2001 From: Nikhil Parasaram Date: Fri, 8 Mar 2019 00:05:57 +0530 Subject: [PATCH 05/22] Add deprecation warning for truffle --- mythril/support/truffle.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/mythril/support/truffle.py b/mythril/support/truffle.py index 800b6fca..de33b596 100644 --- a/mythril/support/truffle.py +++ b/mythril/support/truffle.py @@ -5,6 +5,7 @@ import logging import os import re import sys +import warnings from pathlib import PurePath from ethereum.utils import sha3 @@ -20,12 +21,24 @@ from mythril.solidity.soliditycontract import SourceMapping log = logging.getLogger(__name__) +def format_Warning(message, category, filename, lineno, line=""): + return "{}: {}\n\n".format(str(filename), str(message)) + + +warnings.formatwarning = format_Warning + + def analyze_truffle_project(sigs, args): """ :param sigs: :param args: """ + warnings.warn( + "The option --truffle is being deprecated, Please use the truffle-security plugin, https://github.com/ConsenSys/truffle-security", + FutureWarning, + ) + project_root = os.getcwd() build_dir = os.path.join(project_root, "build", "contracts") From 80fa123639525bed5bdedad1de25ea00b063b2d2 Mon Sep 17 00:00:00 2001 From: Nikhil Parasaram Date: Fri, 8 Mar 2019 00:37:14 +0530 Subject: [PATCH 06/22] Fix rubixi.sol and walletlibrary.sol --- solidity_examples/WalletLibrary.sol | 2 +- solidity_examples/rubixi.sol | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/solidity_examples/WalletLibrary.sol b/solidity_examples/WalletLibrary.sol index d972cdd6..df10b56b 100644 --- a/solidity_examples/WalletLibrary.sol +++ b/solidity_examples/WalletLibrary.sol @@ -212,7 +212,7 @@ contract WalletLibrary is WalletEvents { } // throw unless the contract is not yet initialized. - modifier only_uninitialized { require(m_numOwners > 0); _; } + modifier only_uninitialized { require(m_numOwners == 0); _; } // constructor - just pass on the owner array to the multiowned and // the limit to daylimit diff --git a/solidity_examples/rubixi.sol b/solidity_examples/rubixi.sol index 8e1567c6..948a07eb 100644 --- a/solidity_examples/rubixi.sol +++ b/solidity_examples/rubixi.sol @@ -34,7 +34,7 @@ contract Rubixi { //Fee functions for creator function collectAllFees() public onlyowner { - require(collectedFees == 0); + require(collectedFees > 0); creator.transfer(collectedFees); collectedFees = 0; } From 420a16e08e43d9be28dc36108c78592720e93bc5 Mon Sep 17 00:00:00 2001 From: Nikhil Parasaram Date: Mon, 11 Mar 2019 21:33:14 +0530 Subject: [PATCH 07/22] Fix more require statements in rubixi --- solidity_examples/rubixi.sol | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/solidity_examples/rubixi.sol b/solidity_examples/rubixi.sol index 948a07eb..2a4f75fb 100644 --- a/solidity_examples/rubixi.sol +++ b/solidity_examples/rubixi.sol @@ -43,14 +43,14 @@ contract Rubixi { _amt *= 1 ether; if (_amt > collectedFees) collectAllFees(); - require(collectedFees == 0); + require(collectedFees > 0); creator.transfer(_amt); collectedFees -= _amt; } function collectPercentOfFees(uint _pcent) public onlyowner { - require(collectedFees == 0 || _pcent > 100); + require(collectedFees > 0 && _pcent <= 100); uint feesToCollect = collectedFees / 100 * _pcent; creator.transfer(feesToCollect); @@ -63,12 +63,12 @@ contract Rubixi { } function changeMultiplier(uint _mult) public onlyowner { - require(_mult > 300 || _mult < 120); + require(_mult <= 300 && _mult >= 120); pyramidMultiplier = _mult; } function changeFeePercentage(uint _fee) public onlyowner { - require(_fee > 10); + require(_fee <= 10); feePercent = _fee; } From fc0c63d3685d8b9508d69396ef229c569107698b Mon Sep 17 00:00:00 2001 From: Bernhard Mueller Date: Tue, 12 Mar 2019 21:26:34 +0700 Subject: [PATCH 08/22] Update README.md --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 67127df9..0df13776 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,10 @@ Mythril Classic is an open-source security analysis tool for Ethereum smart contracts. It uses symbolic analysis, taint analysis and control flow checking to detect a variety of security vulnerabilities. -This is an experimental tool designed for security guys. If you a smart contract developer you might prefer [Truffle Security](https://github.com/ConsenSys/truffle-security) or other convenient tools built on the [MythX API](https://mythx.io). +This is an experimental tool designed for security pros. If you a smart contract developer you might prefer MythX tools such as: + +- [Mythos](https://github.com/cleanunicorn/mythos) +- [Truffle Security](https://github.com/ConsenSys/truffle-security) Whether you want to contribute, need support, or want to learn what we have cooking for the future, our [Discord server](https://discord.gg/E3YrVtG) will serve your needs. From 87fc786888da931ed7c1c7acef1920e1af429417 Mon Sep 17 00:00:00 2001 From: Bernhard Mueller Date: Tue, 12 Mar 2019 22:38:38 +0700 Subject: [PATCH 09/22] Update README.md --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 0df13776..a017d155 100644 --- a/README.md +++ b/README.md @@ -12,9 +12,7 @@ [![Sonarcloud - Maintainability](https://sonarcloud.io/api/project_badges/measure?project=mythril&metric=sqale_rating)](https://sonarcloud.io/dashboard?id=mythril) [![Downloads](https://pepy.tech/badge/mythril)](https://pepy.tech/project/mythril) -Mythril Classic is an open-source security analysis tool for Ethereum smart contracts. It uses symbolic analysis, taint analysis and control flow checking to detect a variety of security vulnerabilities. - -This is an experimental tool designed for security pros. If you a smart contract developer you might prefer MythX tools such as: +Mythril Classic is an open-source security analysis tool for Ethereum smart contracts. It uses symbolic analysis, taint analysis and control flow checking to detect a variety of security vulnerabilities. It's also an experimental tool designed for security pros. If you a smart contract developer you might prefer smoother tools such as: - [Mythos](https://github.com/cleanunicorn/mythos) - [Truffle Security](https://github.com/ConsenSys/truffle-security) From fcf35781587ebf420868301a28e5172922221ebc Mon Sep 17 00:00:00 2001 From: Nikhil Parasaram Date: Thu, 14 Mar 2019 21:12:47 +0530 Subject: [PATCH 10/22] Update the defaults cli.py --- mythril/interfaces/cli.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mythril/interfaces/cli.py b/mythril/interfaces/cli.py index 198d4388..c51e8b2a 100644 --- a/mythril/interfaces/cli.py +++ b/mythril/interfaces/cli.py @@ -196,14 +196,14 @@ def create_parser(parser: argparse.ArgumentParser) -> None: options.add_argument( "--max-depth", type=int, - default=22, + default=50, help="Maximum recursion depth for symbolic execution", ) options.add_argument( "--strategy", choices=["dfs", "bfs", "naive-random", "weighted-random"], - default="dfs", + default="bfs", help="Symbolic execution strategy", ) options.add_argument( From dfea10193f2aebca4b03818db5280106aef75d72 Mon Sep 17 00:00:00 2001 From: Joran Honig Date: Fri, 15 Mar 2019 12:23:04 +0100 Subject: [PATCH 11/22] make copy take a slice of the memory vs the ref to the memory array This can cause some concurrency issues --- mythril/laser/ethereum/state/memory.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mythril/laser/ethereum/state/memory.py b/mythril/laser/ethereum/state/memory.py index 4fac4120..0f3283a5 100644 --- a/mythril/laser/ethereum/state/memory.py +++ b/mythril/laser/ethereum/state/memory.py @@ -29,6 +29,11 @@ class Memory: """ return len(self._memory) + def __copy__(self): + copy = Memory() + copy._memory = self._memory[:] + return copy + def extend(self, size): """ From 074557b624f7c56295ca9e0961ed7f3fc470c5a1 Mon Sep 17 00:00:00 2001 From: Joran Honig Date: Fri, 15 Mar 2019 12:23:14 +0100 Subject: [PATCH 12/22] use shallow copy versus deepcopy --- mythril/analysis/symbolic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mythril/analysis/symbolic.py b/mythril/analysis/symbolic.py index e2a0d1a2..f4477fad 100644 --- a/mythril/analysis/symbolic.py +++ b/mythril/analysis/symbolic.py @@ -193,7 +193,7 @@ class SymExecWrapper: ) elif op == "SSTORE": - stack = copy.deepcopy(state.mstate.stack) + stack = copy.copy(state.mstate.stack) address = state.environment.active_account.address index, value = stack.pop(), stack.pop() From e2e86aa1be5c08689db525e2574f436c00725d07 Mon Sep 17 00:00:00 2001 From: Nikhil Parasaram Date: Sat, 16 Mar 2019 10:15:24 +0530 Subject: [PATCH 13/22] Add create2 stub --- mythril/laser/ethereum/instructions.py | 14 ++++++++++++++ mythril/laser/ethereum/taint_analysis.py | 1 + 2 files changed, 15 insertions(+) diff --git a/mythril/laser/ethereum/instructions.py b/mythril/laser/ethereum/instructions.py index 161e742a..cd5e5cfa 100644 --- a/mythril/laser/ethereum/instructions.py +++ b/mythril/laser/ethereum/instructions.py @@ -1671,6 +1671,20 @@ class Instruction: state.stack.append(0) return [global_state] + @StateTransition() + def create2_(self, global_state: GlobalState) -> List[GlobalState]: + """ + + :param global_state: + :return: + """ + # TODO: implement me + state = global_state.mstate + state.stack.pop(), state.stack.pop(), state.stack.pop() + # Not supported + state.stack.append(0) + return [global_state] + @StateTransition() def return_(self, global_state: GlobalState): """ diff --git a/mythril/laser/ethereum/taint_analysis.py b/mythril/laser/ethereum/taint_analysis.py index 394069b1..daf82c31 100644 --- a/mythril/laser/ethereum/taint_analysis.py +++ b/mythril/laser/ethereum/taint_analysis.py @@ -449,5 +449,6 @@ class TaintRunner: "MSIZE": (0, 1), "GAS": (0, 1), "CREATE": (3, 1), + "CREATE2": (4, 1), "RETURN": (2, 0), } From 7cc9a3de8fd7ec73da620405d2295c9d3d5dc303 Mon Sep 17 00:00:00 2001 From: Nikhil Parasaram Date: Sat, 16 Mar 2019 13:05:41 +0530 Subject: [PATCH 14/22] Add the BitWise instructions --- mythril/laser/ethereum/gas.py | 8 ++ mythril/laser/ethereum/instructions.py | 42 +++++++ mythril/laser/smt/__init__.py | 1 + mythril/laser/smt/bitvec.py | 21 ++++ tests/instructions/sar_test.py | 148 +++++++++++++++++++++++++ tests/instructions/shl_test.py | 123 ++++++++++++++++++++ tests/instructions/shr_test.py | 125 +++++++++++++++++++++ 7 files changed, 468 insertions(+) create mode 100644 tests/instructions/sar_test.py create mode 100644 tests/instructions/shl_test.py create mode 100644 tests/instructions/shr_test.py diff --git a/mythril/laser/ethereum/gas.py b/mythril/laser/ethereum/gas.py index 8fae5f53..7e283d15 100644 --- a/mythril/laser/ethereum/gas.py +++ b/mythril/laser/ethereum/gas.py @@ -62,6 +62,9 @@ OPCODE_GAS = { "XOR": (3, 3), "NOT": (3, 3), "BYTE": (3, 3), + "SHL": (3, 3), + "SHR": (3, 3), + "SAR": (3, 3), "SHA3": ( 30, 30 + 6 * 8, @@ -80,6 +83,7 @@ OPCODE_GAS = { "GASPRICE": (2, 2), "EXTCODESIZE": (700, 700), "EXTCODECOPY": (700, 700 + 3 * 768), # https://ethereum.stackexchange.com/a/47556 + "EXTCODEHASH": (400, 400), "RETURNDATASIZE": (2, 2), "RETURNDATACOPY": (3, 3), "BLOCKHASH": (20, 20), @@ -176,6 +180,10 @@ OPCODE_GAS = { "LOG3": (4 * 375, 4 * 375 + 8 * 32), "LOG4": (5 * 375, 5 * 375 + 8 * 32), "CREATE": (32000, 32000), + "CREATE2": ( + 32000, + 32000, + ), # TODO: The gas value is dynamic, to be done while implementing create2 "CALL": (700, 700 + 9000 + 25000), "NATIVE_COST": calculate_native_gas, "CALLCODE": (700, 700 + 9000 + 25000), diff --git a/mythril/laser/ethereum/instructions.py b/mythril/laser/ethereum/instructions.py index cd5e5cfa..e7d9ebc4 100644 --- a/mythril/laser/ethereum/instructions.py +++ b/mythril/laser/ethereum/instructions.py @@ -26,6 +26,7 @@ from mythril.laser.smt import ( Bool, Or, Not, + LShR, ) from mythril.laser.smt import symbol_factory @@ -464,6 +465,33 @@ class Instruction: global_state.mstate.stack.append(0 if s1 == 0 else URem(s0, s1)) return [global_state] + @StateTransition() + def shl_(self, global_state: GlobalState) -> List[GlobalState]: + shift, value = ( + util.pop_bitvec(global_state.mstate), + util.pop_bitvec(global_state.mstate), + ) + global_state.mstate.stack.append(value << shift) + return [global_state] + + @StateTransition() + def shr_(self, global_state: GlobalState) -> List[GlobalState]: + shift, value = ( + util.pop_bitvec(global_state.mstate), + util.pop_bitvec(global_state.mstate), + ) + global_state.mstate.stack.append(LShR(value, shift)) + return [global_state] + + @StateTransition() + def sar_(self, global_state: GlobalState) -> List[GlobalState]: + shift, value = ( + util.pop_bitvec(global_state.mstate), + util.pop_bitvec(global_state.mstate), + ) + global_state.mstate.stack.append(value >> shift) + return [global_state] + @StateTransition() def smod_(self, global_state: GlobalState) -> List[GlobalState]: """ @@ -1082,6 +1110,20 @@ class Instruction: return [global_state] + @StateTransition + def extcodehash_(self, global_state: GlobalState) -> List[GlobalState]: + """ + + :param global_state: + :return: List of global states possible, list of size 1 in this case + """ + # TODO: To be implemented + address = global_state.mstate.stack.pop() + global_state.mstate.stack.append( + global_state.new_bitvec("extcodehash_{}".format(str(address)), 256) + ) + return [global_state] + @StateTransition() def extcodecopy_(self, global_state: GlobalState) -> List[GlobalState]: """ diff --git a/mythril/laser/smt/__init__.py b/mythril/laser/smt/__init__.py index f46a8968..d849d0c4 100644 --- a/mythril/laser/smt/__init__.py +++ b/mythril/laser/smt/__init__.py @@ -13,6 +13,7 @@ from mythril.laser.smt.bitvec import ( BVAddNoOverflow, BVMulNoOverflow, BVSubNoUnderflow, + LShR, ) from mythril.laser.smt.bitvecfunc import BitVecFunc from mythril.laser.smt.expression import Expression, simplify diff --git a/mythril/laser/smt/bitvec.py b/mythril/laser/smt/bitvec.py index 00b519a7..381dc03f 100644 --- a/mythril/laser/smt/bitvec.py +++ b/mythril/laser/smt/bitvec.py @@ -211,6 +211,22 @@ class BitVec(Expression[z3.BitVecRef]): # MYPY: fix complaints due to z3 overriding __eq__ return Bool(cast(z3.BoolRef, self.raw != other.raw), annotations=union) + def __lshift__(self, other: Union[int, "BitVec"]) -> "BitVec": + if not isinstance(other, BitVec): + return BitVec( + self.raw << other, annotations=self.annotations + ) + union = self.annotations + other.annotations + return BitVec(self.raw << other.raw, annotations=union) + + def __rshift__(self, other: Union[int, "BitVec"]) -> "BitVec": + if not isinstance(other, BitVec): + return BitVec( + self.raw >> other, annotations=self.annotations + ) + union = self.annotations + other.annotations + return BitVec(self.raw >> other.raw, annotations=union) + def _comparison_helper( a: BitVec, b: BitVec, operation: Callable, default_value: bool, inputs_equal: bool @@ -254,6 +270,11 @@ def _arithmetic_helper(a: BitVec, b: BitVec, operation: Callable) -> BitVec: return BitVec(raw, annotations=union) +def LShR(a, b): + union = a.annotations + b.annotations + return BitVec(z3.LShR(a.raw, b.raw), annotations=union) + + def If(a: Union[Bool, bool], b: Union[BitVec, int], c: Union[BitVec, int]) -> BitVec: """Create an if-then-else expression. diff --git a/tests/instructions/sar_test.py b/tests/instructions/sar_test.py new file mode 100644 index 00000000..b618582f --- /dev/null +++ b/tests/instructions/sar_test.py @@ -0,0 +1,148 @@ +import pytest + +from mythril.disassembler.disassembly import Disassembly +from mythril.laser.ethereum.state.environment import Environment +from mythril.laser.ethereum.state.account import Account +from mythril.laser.ethereum.state.machine_state import MachineState +from mythril.laser.ethereum.state.global_state import GlobalState +from mythril.laser.ethereum.state.world_state import WorldState +from mythril.laser.ethereum.instructions import Instruction +from mythril.laser.ethereum.transaction.transaction_models import MessageCallTransaction +from mythril.laser.smt import symbol_factory, simplify + + +def get_state(): + active_account = Account("0x0", code=Disassembly("60606040")) + environment = Environment(active_account, None, None, None, None, None) + state = GlobalState(None, environment, None, MachineState(gas_limit=8000000)) + state.transaction_stack.append( + (MessageCallTransaction(world_state=WorldState(), gas_limit=8000000), None) + ) + return state + + +BVV = symbol_factory.BitVecVal +BV = symbol_factory.BitVecSym + +test_data = ( + ([BVV(-1, 256), BVV(1, 256)], BVV(-1, 256)), + ([BVV(23, 256), BVV(257, 256)], BVV(0, 256)), + ([BVV(23, 256), BVV(30, 256)], BVV(23 >> 30, 256)), + ([BVV(-10, 256), BVV(10, 256)], BVV(-1, 256)), + ([BV("a", 256), BV("b", 256)], BV("a", 256) >> BV("b", 256)), +) + + +@pytest.mark.parametrize("inputs,output", test_data) +def test_sar(inputs, output): + # Arrange + state = get_state() + + state.mstate.stack = inputs + instruction = Instruction("sar", dynamic_loader=None) + + # Act + new_state = instruction.evaluate(state)[0] + + # Assert + assert simplify(new_state.mstate.stack[-1]) == output + + +@pytest.mark.parametrize( + # Test cases from https://github.com/ethereum/EIPs/blob/master/EIPS/eip-145.md#sar-arithmetic-shift-right + "val1, val2, expected ", + ( + ( + "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x00", + "0x0000000000000000000000000000000000000000000000000000000000000001", + ), + ( + "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x01", + "0x0000000000000000000000000000000000000000000000000000000000000000", + ), + ( + "0x8000000000000000000000000000000000000000000000000000000000000000", + "0x01", + "0xc000000000000000000000000000000000000000000000000000000000000000", + ), + ( + "0x8000000000000000000000000000000000000000000000000000000000000000", + "0xff", + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + ), + ( + "0x8000000000000000000000000000000000000000000000000000000000000000", + "0x0100", + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + ), + ( + "0x8000000000000000000000000000000000000000000000000000000000000000", + "0x0101", + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + ), + ( + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "0x00", + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + ), + ( + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "0x01", + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + ), + ( + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "0xff", + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + ), + ( + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "0x0100", + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + ), + ( + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x01", + "0x0000000000000000000000000000000000000000000000000000000000000000", + ), + ( + "0x4000000000000000000000000000000000000000000000000000000000000000", + "0xfe", + "0x0000000000000000000000000000000000000000000000000000000000000001", + ), + ( + "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "0xf8", + "0x000000000000000000000000000000000000000000000000000000000000007f", + ), + ( + "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "0xfe", + "0x0000000000000000000000000000000000000000000000000000000000000001", + ), + ( + "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "0xff", + "0x0000000000000000000000000000000000000000000000000000000000000000", + ), + ( + "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "0x0100", + "0x0000000000000000000000000000000000000000000000000000000000000000", + ), + ), +) +def test_concrete_sar(val1, val2, expected): + # Arrange + state = get_state() + state.mstate.stack = [BVV(int(val1, 16), 256), BVV(int(val2, 16), 256)] + expected = BVV(int(expected, 16), 256) + instruction = Instruction("sar", dynamic_loader=None) + + # Act + new_state = instruction.evaluate(state)[0] + + # Assert + assert simplify(new_state.mstate.stack[-1]) == expected diff --git a/tests/instructions/shl_test.py b/tests/instructions/shl_test.py new file mode 100644 index 00000000..0e36c088 --- /dev/null +++ b/tests/instructions/shl_test.py @@ -0,0 +1,123 @@ +import pytest + +from mythril.disassembler.disassembly import Disassembly +from mythril.laser.ethereum.state.environment import Environment +from mythril.laser.ethereum.state.account import Account +from mythril.laser.ethereum.state.machine_state import MachineState +from mythril.laser.ethereum.state.global_state import GlobalState +from mythril.laser.ethereum.state.world_state import WorldState +from mythril.laser.ethereum.instructions import Instruction +from mythril.laser.ethereum.transaction.transaction_models import MessageCallTransaction +from mythril.laser.smt import symbol_factory, simplify + + +def get_state(): + active_account = Account("0x0", code=Disassembly("60606040")) + environment = Environment(active_account, None, None, None, None, None) + state = GlobalState(None, environment, None, MachineState(gas_limit=8000000)) + state.transaction_stack.append( + (MessageCallTransaction(world_state=WorldState(), gas_limit=8000000), None) + ) + return state + + +BVV = symbol_factory.BitVecVal +BV = symbol_factory.BitVecSym + +test_data = ( + ([BVV(2, 256), BVV(2, 256)], BVV(8, 256)), + ([BVV(23, 256), BVV(257, 256)], BVV(0, 256)), + ([BVV(23, 256), BVV(30, 256)], BVV(23 * (1 << 30), 256)), + ([BV("a", 256), BVV(270, 256)], 0), + ([BV("a", 256), BV("b", 256)], BV("a", 256) << BV("b", 256)), +) + + +@pytest.mark.parametrize("inputs,output,", test_data) +def test_shl(inputs, output): + # Arrange + state = get_state() + + state.mstate.stack = inputs + instruction = Instruction("shl", dynamic_loader=None) + + # Act + new_state = instruction.evaluate(state)[0] + + # Assert + assert simplify(new_state.mstate.stack[-1]) == output + + +@pytest.mark.parametrize( + # Testcases from https://github.com/ethereum/EIPs/blob/master/EIPS/eip-145.md#shl-shift-left + "val1, val2, expected", + ( + ( + "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x00", + "0x0000000000000000000000000000000000000000000000000000000000000001", + ), + ( + "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x01", + "0x0000000000000000000000000000000000000000000000000000000000000002", + ), + ( + "0x0000000000000000000000000000000000000000000000000000000000000001", + "0xff", + "0x8000000000000000000000000000000000000000000000000000000000000000", + ), + ( + "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0100", + "0x0000000000000000000000000000000000000000000000000000000000000000", + ), + ( + "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0101", + "0x0000000000000000000000000000000000000000000000000000000000000000", + ), + ( + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "0x00", + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + ), + ( + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "0x01", + "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe", + ), + ( + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "0xff", + "0x8000000000000000000000000000000000000000000000000000000000000000", + ), + ( + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "0x0100", + "0x0000000000000000000000000000000000000000000000000000000000000000", + ), + ( + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x01", + "0x0000000000000000000000000000000000000000000000000000000000000000", + ), + ( + "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "0x01", + "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe", + ), + ), +) +def test_concrete_shl(val1, val2, expected): + # Arrange + state = get_state() + state.mstate.stack = [BVV(int(val1, 16), 256), BVV(int(val2, 16), 256)] + expected = BVV(int(expected, 16), 256) + instruction = Instruction("shl", dynamic_loader=None) + + # Act + new_state = instruction.evaluate(state)[0] + + # Assert + assert simplify(new_state.mstate.stack[-1]) == expected diff --git a/tests/instructions/shr_test.py b/tests/instructions/shr_test.py new file mode 100644 index 00000000..aaf370e2 --- /dev/null +++ b/tests/instructions/shr_test.py @@ -0,0 +1,125 @@ +import pytest + +from mythril.disassembler.disassembly import Disassembly +from mythril.laser.ethereum.state.environment import Environment +from mythril.laser.ethereum.state.account import Account +from mythril.laser.ethereum.state.machine_state import MachineState +from mythril.laser.ethereum.state.global_state import GlobalState +from mythril.laser.ethereum.state.world_state import WorldState +from mythril.laser.ethereum.instructions import Instruction +from mythril.laser.ethereum.transaction.transaction_models import MessageCallTransaction +from mythril.laser.smt import symbol_factory, simplify, LShR + + +def get_state(): + active_account = Account("0x0", code=Disassembly("60606040")) + environment = Environment(active_account, None, None, None, None, None) + state = GlobalState(None, environment, None, MachineState(gas_limit=8000000)) + state.transaction_stack.append( + (MessageCallTransaction(world_state=WorldState(), gas_limit=8000000), None) + ) + return state + + +BVV = symbol_factory.BitVecVal +BV = symbol_factory.BitVecSym + +test_data = ( + ([BVV(33, 256), BVV(4, 256)], BVV(2, 256)), + ([BVV(1 << 100, 256), BVV(257, 256)], BVV(0, 256)), + ([BVV(23233, 256), BVV(10, 256)], BVV(23233 // (1 << 10), 256)), + ([BV("a", 256), BVV(270, 256)], 0), + ( + [BV("a", 256), BV("b", 256)], + LShR(BV("a", 256), BV("b", 256)), + ), # Current approximate specs +) + + +@pytest.mark.parametrize("inputs,output,", test_data) +def test_shr(inputs, output): + # Arrange + state = get_state() + + state.mstate.stack = inputs + instruction = Instruction("shr", dynamic_loader=None) + + # Act + new_state = instruction.evaluate(state)[0] + + # Assert + assert simplify(new_state.mstate.stack[-1]) == output + + +@pytest.mark.parametrize( + # Cases: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-145.md#shr-logical-shift-right + "val1, val2, expected", + ( + ( + "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x00", + "0x0000000000000000000000000000000000000000000000000000000000000001", + ), + ( + "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x01", + "0x0000000000000000000000000000000000000000000000000000000000000000", + ), + ( + "0x8000000000000000000000000000000000000000000000000000000000000000", + "0x01", + "0x4000000000000000000000000000000000000000000000000000000000000000", + ), + ( + "0x8000000000000000000000000000000000000000000000000000000000000000", + "0xff", + "0x0000000000000000000000000000000000000000000000000000000000000001", + ), + ( + "0x8000000000000000000000000000000000000000000000000000000000000000", + "0x0100", + "0x0000000000000000000000000000000000000000000000000000000000000000", + ), + ( + "0x8000000000000000000000000000000000000000000000000000000000000000", + "0x0101", + "0x0000000000000000000000000000000000000000000000000000000000000000", + ), + ( + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "0x00", + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + ), + ( + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "0x01", + "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + ), + ( + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "0xff", + "0x0000000000000000000000000000000000000000000000000000000000000001", + ), + ( + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "0x0100", + "0x0000000000000000000000000000000000000000000000000000000000000000", + ), + ( + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x01", + "0x0000000000000000000000000000000000000000000000000000000000000000", + ), + ), +) +def test_concrete_shr(val1, val2, expected): + state = get_state() + state.mstate.stack = [BVV(int(val1, 16), 256), BVV(int(val2, 16), 256)] + expected = BVV(int(expected, 16), 256) + instruction = Instruction("shr", dynamic_loader=None) + + # Act + new_state = instruction.evaluate(state)[0] + + # Assert + assert simplify(new_state.mstate.stack[-1]) == expected From 8c1c054d417176cd42941393ad5b2a3aa762efae Mon Sep 17 00:00:00 2001 From: Nikhil Parasaram Date: Sat, 16 Mar 2019 13:14:34 +0530 Subject: [PATCH 15/22] Reuse code of leftshift and right shift --- mythril/laser/smt/bitvec.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/mythril/laser/smt/bitvec.py b/mythril/laser/smt/bitvec.py index 381dc03f..9e06a0b5 100644 --- a/mythril/laser/smt/bitvec.py +++ b/mythril/laser/smt/bitvec.py @@ -1,7 +1,7 @@ """This module provides classes for an SMT abstraction of bit vectors.""" from typing import Union, overload, List, cast, Any, Optional, Callable - +from operator import lshift, rshift import z3 from mythril.laser.smt.bool import Bool, And, Or @@ -211,21 +211,20 @@ class BitVec(Expression[z3.BitVecRef]): # MYPY: fix complaints due to z3 overriding __eq__ return Bool(cast(z3.BoolRef, self.raw != other.raw), annotations=union) - def __lshift__(self, other: Union[int, "BitVec"]) -> "BitVec": + def _handle_shift(self, other: Union[int, "BitVec"], operator: Callable): + # TODO: Handle BitVecFunc if not isinstance(other, BitVec): return BitVec( - self.raw << other, annotations=self.annotations + operator(self.raw, other), annotations=self.annotations ) union = self.annotations + other.annotations - return BitVec(self.raw << other.raw, annotations=union) + return BitVec(operator(self.raw, other.raw), annotations=union) + + def __lshift__(self, other: Union[int, "BitVec"]) -> "BitVec": + return self._handle_shift(other, lshift) def __rshift__(self, other: Union[int, "BitVec"]) -> "BitVec": - if not isinstance(other, BitVec): - return BitVec( - self.raw >> other, annotations=self.annotations - ) - union = self.annotations + other.annotations - return BitVec(self.raw >> other.raw, annotations=union) + return self._handle_shift(other, rshift) def _comparison_helper( @@ -271,6 +270,7 @@ def _arithmetic_helper(a: BitVec, b: BitVec, operation: Callable) -> BitVec: def LShR(a, b): + # TODO: Handle BitVecFunc union = a.annotations + b.annotations return BitVec(z3.LShR(a.raw, b.raw), annotations=union) From a1d79f3f1e89fc71b743e39faf3fd6f2f64919a7 Mon Sep 17 00:00:00 2001 From: Nikhil Parasaram Date: Sat, 16 Mar 2019 15:00:21 +0530 Subject: [PATCH 16/22] Support BitVecFuncs --- mythril/laser/ethereum/instructions.py | 2 +- mythril/laser/smt/bitvec.py | 27 ++++++++++++++++++++------ mythril/laser/smt/bitvecfunc.py | 16 +++++++++++++++ mythril/support/opcodes.py | 0 4 files changed, 38 insertions(+), 7 deletions(-) create mode 100644 mythril/support/opcodes.py diff --git a/mythril/laser/ethereum/instructions.py b/mythril/laser/ethereum/instructions.py index e7d9ebc4..ccbe649a 100644 --- a/mythril/laser/ethereum/instructions.py +++ b/mythril/laser/ethereum/instructions.py @@ -1722,7 +1722,7 @@ class Instruction: """ # TODO: implement me state = global_state.mstate - state.stack.pop(), state.stack.pop(), state.stack.pop() + endowment, memory_start, memory_length, salt = state.stack.pop(), state.stack.pop(), state.stack.pop(), state.stack.pop() # Not supported state.stack.append(0) return [global_state] diff --git a/mythril/laser/smt/bitvec.py b/mythril/laser/smt/bitvec.py index 9e06a0b5..5f53f4c0 100644 --- a/mythril/laser/smt/bitvec.py +++ b/mythril/laser/smt/bitvec.py @@ -211,8 +211,15 @@ class BitVec(Expression[z3.BitVecRef]): # MYPY: fix complaints due to z3 overriding __eq__ return Bool(cast(z3.BoolRef, self.raw != other.raw), annotations=union) - def _handle_shift(self, other: Union[int, "BitVec"], operator: Callable): - # TODO: Handle BitVecFunc + def _handle_shift(self, other: Union[int, "BitVec"], operator: Callable) -> "BitVec": + """ + Handle's shift + :param other: The other BitVector + :param operator: The shift operator + :return: the resulting output + """ + if isinstance(other, BitVecFunc): + return operator(other, self) if not isinstance(other, BitVec): return BitVec( operator(self.raw, other), annotations=self.annotations @@ -221,9 +228,19 @@ class BitVec(Expression[z3.BitVecRef]): return BitVec(operator(self.raw, other.raw), annotations=union) def __lshift__(self, other: Union[int, "BitVec"]) -> "BitVec": + """ + + :param other: + :return: + """ return self._handle_shift(other, lshift) def __rshift__(self, other: Union[int, "BitVec"]) -> "BitVec": + """ + + :param other: + :return: + """ return self._handle_shift(other, rshift) @@ -269,10 +286,8 @@ def _arithmetic_helper(a: BitVec, b: BitVec, operation: Callable) -> BitVec: return BitVec(raw, annotations=union) -def LShR(a, b): - # TODO: Handle BitVecFunc - union = a.annotations + b.annotations - return BitVec(z3.LShR(a.raw, b.raw), annotations=union) +def LShR(a: BitVec, b: BitVec): + return _arithmetic_helper(a, b, z3.LShR) def If(a: Union[Bool, bool], b: Union[BitVec, int], c: Union[BitVec, int]) -> BitVec: diff --git a/mythril/laser/smt/bitvecfunc.py b/mythril/laser/smt/bitvecfunc.py index d3e77601..f73ef504 100644 --- a/mythril/laser/smt/bitvecfunc.py +++ b/mythril/laser/smt/bitvecfunc.py @@ -207,3 +207,19 @@ class BitVecFunc(BitVec): return _comparison_helper( self, other, operator.eq, default_value=True, inputs_equal=False ) + + def __lshift__(self, other: Union[int, "BitVec"]) -> "BitVec": + """ + Left shift operation + :param other: The int or BitVec to shift on + :return The resulting left shifted output + """ + return _arithmetic_helper(self, other, operator.lshift) + + def __rshift__(self, other: Union[int, "BitVec"]) -> "BitVec": + """ + Right shift operation + :param other: The int or BitVec to shift on + :return The resulting right shifted output: + """ + return _arithmetic_helper(self, other, operator.rshift) diff --git a/mythril/support/opcodes.py b/mythril/support/opcodes.py new file mode 100644 index 00000000..e69de29b From 303891aed27c0d063723578ea48c3764d14e4bfd Mon Sep 17 00:00:00 2001 From: Nikhil Parasaram Date: Sat, 16 Mar 2019 15:01:54 +0530 Subject: [PATCH 17/22] Use new opcodes file over pyethereum --- mythril/analysis/security.py | 2 +- mythril/disassembler/asm.py | 2 +- mythril/support/opcodes.py | 91 ++++++++++++++++++++++++++++++++++++ 3 files changed, 93 insertions(+), 2 deletions(-) diff --git a/mythril/analysis/security.py b/mythril/analysis/security.py index d8e804db..abacf49a 100644 --- a/mythril/analysis/security.py +++ b/mythril/analysis/security.py @@ -1,7 +1,7 @@ """This module contains functionality for hooking in detection modules and executing them.""" from collections import defaultdict -from ethereum.opcodes import opcodes +from mythril.support.opcodes import opcodes from mythril.analysis import modules import pkgutil import importlib.util diff --git a/mythril/disassembler/asm.py b/mythril/disassembler/asm.py index cbbe1881..91b2721a 100644 --- a/mythril/disassembler/asm.py +++ b/mythril/disassembler/asm.py @@ -4,7 +4,7 @@ code disassembly.""" import re from collections import Generator -from ethereum.opcodes import opcodes +from mythril.support.opcodes import opcodes regex_PUSH = re.compile(r"^PUSH(\d*)$") diff --git a/mythril/support/opcodes.py b/mythril/support/opcodes.py index e69de29b..5fdd7885 100644 --- a/mythril/support/opcodes.py +++ b/mythril/support/opcodes.py @@ -0,0 +1,91 @@ +opcodes = { + 0x00: ['STOP', 0, 0, 0], + 0x01: ['ADD', 2, 1, 3], + 0x02: ['MUL', 2, 1, 5], + 0x03: ['SUB', 2, 1, 3], + 0x04: ['DIV', 2, 1, 5], + 0x05: ['SDIV', 2, 1, 5], + 0x06: ['MOD', 2, 1, 5], + 0x07: ['SMOD', 2, 1, 5], + 0x08: ['ADDMOD', 3, 1, 8], + 0x09: ['MULMOD', 3, 1, 8], + 0x0a: ['EXP', 2, 1, 10], + 0x0b: ['SIGNEXTEND', 2, 1, 5], + 0x10: ['LT', 2, 1, 3], + 0x11: ['GT', 2, 1, 3], + 0x12: ['SLT', 2, 1, 3], + 0x13: ['SGT', 2, 1, 3], + 0x14: ['EQ', 2, 1, 3], + 0x15: ['ISZERO', 1, 1, 3], + 0x16: ['AND', 2, 1, 3], + 0x17: ['OR', 2, 1, 3], + 0x18: ['XOR', 2, 1, 3], + 0x19: ['NOT', 1, 1, 3], + 0x1a: ['BYTE', 2, 1, 3], + 0x1b: ['SHL', 2, 1, 3], + 0x1c: ['SHR', 2, 1, 3], + 0x1d: ['SAR', 2, 1, 3], + 0x20: ['SHA3', 2, 1, 30], + 0x30: ['ADDRESS', 0, 1, 2], + 0x31: ['BALANCE', 1, 1, 20], # now 400 + 0x32: ['ORIGIN', 0, 1, 2], + 0x33: ['CALLER', 0, 1, 2], + 0x34: ['CALLVALUE', 0, 1, 2], + 0x35: ['CALLDATALOAD', 1, 1, 3], + 0x36: ['CALLDATASIZE', 0, 1, 2], + 0x37: ['CALLDATACOPY', 3, 0, 3], + 0x38: ['CODESIZE', 0, 1, 2], + 0x39: ['CODECOPY', 3, 0, 3], + 0x3a: ['GASPRICE', 0, 1, 2], + 0x3b: ['EXTCODESIZE', 1, 1, 20], # now 700 + 0x3c: ['EXTCODECOPY', 4, 0, 20], # now 700 + 0x3d: ['RETURNDATASIZE', 0, 1, 2], + 0x3e: ['RETURNDATACOPY', 3, 0, 3], + 0x3f: ['EXTCODEHASH', 3, 0, 3], + 0x40: ['BLOCKHASH', 1, 1, 20], + 0x41: ['COINBASE', 0, 1, 2], + 0x42: ['TIMESTAMP', 0, 1, 2], + 0x43: ['NUMBER', 0, 1, 2], + 0x44: ['DIFFICULTY', 0, 1, 2], + 0x45: ['GASLIMIT', 0, 1, 2], + 0x50: ['POP', 1, 0, 2], + 0x51: ['MLOAD', 1, 1, 3], + 0x52: ['MSTORE', 2, 0, 3], + 0x53: ['MSTORE8', 2, 0, 3], + 0x54: ['SLOAD', 1, 1, 50], # 200 now + 0x55: ['SSTORE', 2, 0, 0], + 0x56: ['JUMP', 1, 0, 8], + 0x57: ['JUMPI', 2, 0, 10], + 0x58: ['PC', 0, 1, 2], + 0x59: ['MSIZE', 0, 1, 2], + 0x5a: ['GAS', 0, 1, 2], + 0x5b: ['JUMPDEST', 0, 0, 1], + 0xa0: ['LOG0', 2, 0, 375], + 0xa1: ['LOG1', 3, 0, 750], + 0xa2: ['LOG2', 4, 0, 1125], + 0xa3: ['LOG3', 5, 0, 1500], + 0xa4: ['LOG4', 6, 0, 1875], + 0xf0: ['CREATE', 3, 1, 32000], + 0xf1: ['CALL', 7, 1, 40], # 700 now + 0xf2: ['CALLCODE', 7, 1, 40], # 700 now + 0xf3: ['RETURN', 2, 0, 0], + 0xf4: ['DELEGATECALL', 6, 1, 40], # 700 now + 0xf5: ['CREATE2', 3, 1, 32000], + 0xfa: ['STATICCALL', 6, 1, 40], + 0xfd: ['REVERT', 2, 0, 0], + 0xff: ['SUICIDE', 1, 0, 0], # 5000 now +} + +opcodesMetropolis = {0x3d, 0x3e, 0xfa, 0xfd} + +for i in range(1, 33): + opcodes[0x5f + i] = ['PUSH' + str(i), 0, 1, 3] + +for i in range(1, 17): + opcodes[0x7f + i] = ['DUP' + str(i), i, i + 1, 3] + opcodes[0x8f + i] = ['SWAP' + str(i), i + 1, i + 1, 3] + +reverse_opcodes = {} +for o in opcodes: + vars()[opcodes[o][0]] = opcodes[o] + reverse_opcodes[opcodes[o][0]] = o From d581a15131952c88816db86f149972fd2948192d Mon Sep 17 00:00:00 2001 From: Nikhil Parasaram Date: Sat, 16 Mar 2019 15:04:18 +0530 Subject: [PATCH 18/22] Refactor with black --- mythril/laser/ethereum/instructions.py | 7 +- mythril/support/opcodes.py | 158 ++++++++++++------------- 2 files changed, 85 insertions(+), 80 deletions(-) diff --git a/mythril/laser/ethereum/instructions.py b/mythril/laser/ethereum/instructions.py index ccbe649a..09152f80 100644 --- a/mythril/laser/ethereum/instructions.py +++ b/mythril/laser/ethereum/instructions.py @@ -1722,7 +1722,12 @@ class Instruction: """ # TODO: implement me state = global_state.mstate - endowment, memory_start, memory_length, salt = state.stack.pop(), state.stack.pop(), state.stack.pop(), state.stack.pop() + endowment, memory_start, memory_length, salt = ( + state.stack.pop(), + state.stack.pop(), + state.stack.pop(), + state.stack.pop(), + ) # Not supported state.stack.append(0) return [global_state] diff --git a/mythril/support/opcodes.py b/mythril/support/opcodes.py index 5fdd7885..d6e59231 100644 --- a/mythril/support/opcodes.py +++ b/mythril/support/opcodes.py @@ -1,89 +1,89 @@ opcodes = { - 0x00: ['STOP', 0, 0, 0], - 0x01: ['ADD', 2, 1, 3], - 0x02: ['MUL', 2, 1, 5], - 0x03: ['SUB', 2, 1, 3], - 0x04: ['DIV', 2, 1, 5], - 0x05: ['SDIV', 2, 1, 5], - 0x06: ['MOD', 2, 1, 5], - 0x07: ['SMOD', 2, 1, 5], - 0x08: ['ADDMOD', 3, 1, 8], - 0x09: ['MULMOD', 3, 1, 8], - 0x0a: ['EXP', 2, 1, 10], - 0x0b: ['SIGNEXTEND', 2, 1, 5], - 0x10: ['LT', 2, 1, 3], - 0x11: ['GT', 2, 1, 3], - 0x12: ['SLT', 2, 1, 3], - 0x13: ['SGT', 2, 1, 3], - 0x14: ['EQ', 2, 1, 3], - 0x15: ['ISZERO', 1, 1, 3], - 0x16: ['AND', 2, 1, 3], - 0x17: ['OR', 2, 1, 3], - 0x18: ['XOR', 2, 1, 3], - 0x19: ['NOT', 1, 1, 3], - 0x1a: ['BYTE', 2, 1, 3], - 0x1b: ['SHL', 2, 1, 3], - 0x1c: ['SHR', 2, 1, 3], - 0x1d: ['SAR', 2, 1, 3], - 0x20: ['SHA3', 2, 1, 30], - 0x30: ['ADDRESS', 0, 1, 2], - 0x31: ['BALANCE', 1, 1, 20], # now 400 - 0x32: ['ORIGIN', 0, 1, 2], - 0x33: ['CALLER', 0, 1, 2], - 0x34: ['CALLVALUE', 0, 1, 2], - 0x35: ['CALLDATALOAD', 1, 1, 3], - 0x36: ['CALLDATASIZE', 0, 1, 2], - 0x37: ['CALLDATACOPY', 3, 0, 3], - 0x38: ['CODESIZE', 0, 1, 2], - 0x39: ['CODECOPY', 3, 0, 3], - 0x3a: ['GASPRICE', 0, 1, 2], - 0x3b: ['EXTCODESIZE', 1, 1, 20], # now 700 - 0x3c: ['EXTCODECOPY', 4, 0, 20], # now 700 - 0x3d: ['RETURNDATASIZE', 0, 1, 2], - 0x3e: ['RETURNDATACOPY', 3, 0, 3], - 0x3f: ['EXTCODEHASH', 3, 0, 3], - 0x40: ['BLOCKHASH', 1, 1, 20], - 0x41: ['COINBASE', 0, 1, 2], - 0x42: ['TIMESTAMP', 0, 1, 2], - 0x43: ['NUMBER', 0, 1, 2], - 0x44: ['DIFFICULTY', 0, 1, 2], - 0x45: ['GASLIMIT', 0, 1, 2], - 0x50: ['POP', 1, 0, 2], - 0x51: ['MLOAD', 1, 1, 3], - 0x52: ['MSTORE', 2, 0, 3], - 0x53: ['MSTORE8', 2, 0, 3], - 0x54: ['SLOAD', 1, 1, 50], # 200 now - 0x55: ['SSTORE', 2, 0, 0], - 0x56: ['JUMP', 1, 0, 8], - 0x57: ['JUMPI', 2, 0, 10], - 0x58: ['PC', 0, 1, 2], - 0x59: ['MSIZE', 0, 1, 2], - 0x5a: ['GAS', 0, 1, 2], - 0x5b: ['JUMPDEST', 0, 0, 1], - 0xa0: ['LOG0', 2, 0, 375], - 0xa1: ['LOG1', 3, 0, 750], - 0xa2: ['LOG2', 4, 0, 1125], - 0xa3: ['LOG3', 5, 0, 1500], - 0xa4: ['LOG4', 6, 0, 1875], - 0xf0: ['CREATE', 3, 1, 32000], - 0xf1: ['CALL', 7, 1, 40], # 700 now - 0xf2: ['CALLCODE', 7, 1, 40], # 700 now - 0xf3: ['RETURN', 2, 0, 0], - 0xf4: ['DELEGATECALL', 6, 1, 40], # 700 now - 0xf5: ['CREATE2', 3, 1, 32000], - 0xfa: ['STATICCALL', 6, 1, 40], - 0xfd: ['REVERT', 2, 0, 0], - 0xff: ['SUICIDE', 1, 0, 0], # 5000 now + 0x00: ["STOP", 0, 0, 0], + 0x01: ["ADD", 2, 1, 3], + 0x02: ["MUL", 2, 1, 5], + 0x03: ["SUB", 2, 1, 3], + 0x04: ["DIV", 2, 1, 5], + 0x05: ["SDIV", 2, 1, 5], + 0x06: ["MOD", 2, 1, 5], + 0x07: ["SMOD", 2, 1, 5], + 0x08: ["ADDMOD", 3, 1, 8], + 0x09: ["MULMOD", 3, 1, 8], + 0x0A: ["EXP", 2, 1, 10], + 0x0B: ["SIGNEXTEND", 2, 1, 5], + 0x10: ["LT", 2, 1, 3], + 0x11: ["GT", 2, 1, 3], + 0x12: ["SLT", 2, 1, 3], + 0x13: ["SGT", 2, 1, 3], + 0x14: ["EQ", 2, 1, 3], + 0x15: ["ISZERO", 1, 1, 3], + 0x16: ["AND", 2, 1, 3], + 0x17: ["OR", 2, 1, 3], + 0x18: ["XOR", 2, 1, 3], + 0x19: ["NOT", 1, 1, 3], + 0x1A: ["BYTE", 2, 1, 3], + 0x1B: ["SHL", 2, 1, 3], + 0x1C: ["SHR", 2, 1, 3], + 0x1D: ["SAR", 2, 1, 3], + 0x20: ["SHA3", 2, 1, 30], + 0x30: ["ADDRESS", 0, 1, 2], + 0x31: ["BALANCE", 1, 1, 20], # now 400 + 0x32: ["ORIGIN", 0, 1, 2], + 0x33: ["CALLER", 0, 1, 2], + 0x34: ["CALLVALUE", 0, 1, 2], + 0x35: ["CALLDATALOAD", 1, 1, 3], + 0x36: ["CALLDATASIZE", 0, 1, 2], + 0x37: ["CALLDATACOPY", 3, 0, 3], + 0x38: ["CODESIZE", 0, 1, 2], + 0x39: ["CODECOPY", 3, 0, 3], + 0x3A: ["GASPRICE", 0, 1, 2], + 0x3B: ["EXTCODESIZE", 1, 1, 20], # now 700 + 0x3C: ["EXTCODECOPY", 4, 0, 20], # now 700 + 0x3D: ["RETURNDATASIZE", 0, 1, 2], + 0x3E: ["RETURNDATACOPY", 3, 0, 3], + 0x3F: ["EXTCODEHASH", 3, 0, 3], + 0x40: ["BLOCKHASH", 1, 1, 20], + 0x41: ["COINBASE", 0, 1, 2], + 0x42: ["TIMESTAMP", 0, 1, 2], + 0x43: ["NUMBER", 0, 1, 2], + 0x44: ["DIFFICULTY", 0, 1, 2], + 0x45: ["GASLIMIT", 0, 1, 2], + 0x50: ["POP", 1, 0, 2], + 0x51: ["MLOAD", 1, 1, 3], + 0x52: ["MSTORE", 2, 0, 3], + 0x53: ["MSTORE8", 2, 0, 3], + 0x54: ["SLOAD", 1, 1, 50], # 200 now + 0x55: ["SSTORE", 2, 0, 0], + 0x56: ["JUMP", 1, 0, 8], + 0x57: ["JUMPI", 2, 0, 10], + 0x58: ["PC", 0, 1, 2], + 0x59: ["MSIZE", 0, 1, 2], + 0x5A: ["GAS", 0, 1, 2], + 0x5B: ["JUMPDEST", 0, 0, 1], + 0xA0: ["LOG0", 2, 0, 375], + 0xA1: ["LOG1", 3, 0, 750], + 0xA2: ["LOG2", 4, 0, 1125], + 0xA3: ["LOG3", 5, 0, 1500], + 0xA4: ["LOG4", 6, 0, 1875], + 0xF0: ["CREATE", 3, 1, 32000], + 0xF1: ["CALL", 7, 1, 40], # 700 now + 0xF2: ["CALLCODE", 7, 1, 40], # 700 now + 0xF3: ["RETURN", 2, 0, 0], + 0xF4: ["DELEGATECALL", 6, 1, 40], # 700 now + 0xF5: ["CREATE2", 3, 1, 32000], + 0xFA: ["STATICCALL", 6, 1, 40], + 0xFD: ["REVERT", 2, 0, 0], + 0xFF: ["SUICIDE", 1, 0, 0], # 5000 now } -opcodesMetropolis = {0x3d, 0x3e, 0xfa, 0xfd} +opcodesMetropolis = {0x3D, 0x3E, 0xFA, 0xFD} for i in range(1, 33): - opcodes[0x5f + i] = ['PUSH' + str(i), 0, 1, 3] + opcodes[0x5F + i] = ["PUSH" + str(i), 0, 1, 3] for i in range(1, 17): - opcodes[0x7f + i] = ['DUP' + str(i), i, i + 1, 3] - opcodes[0x8f + i] = ['SWAP' + str(i), i + 1, i + 1, 3] + opcodes[0x7F + i] = ["DUP" + str(i), i, i + 1, 3] + opcodes[0x8F + i] = ["SWAP" + str(i), i + 1, i + 1, 3] reverse_opcodes = {} for o in opcodes: From 71f0d0f6258b67f15dc9bbe77f66cd7f60c5b253 Mon Sep 17 00:00:00 2001 From: Nikhil Parasaram Date: Sat, 16 Mar 2019 15:20:30 +0530 Subject: [PATCH 19/22] Fix typehints --- mythril/disassembler/asm.py | 2 +- mythril/support/opcodes.py | 161 ++++++++++++++++++------------------ 2 files changed, 83 insertions(+), 80 deletions(-) diff --git a/mythril/disassembler/asm.py b/mythril/disassembler/asm.py index 91b2721a..905b8d85 100644 --- a/mythril/disassembler/asm.py +++ b/mythril/disassembler/asm.py @@ -9,7 +9,7 @@ from mythril.support.opcodes import opcodes regex_PUSH = re.compile(r"^PUSH(\d*)$") # Additional mnemonic to catch failed assertions -opcodes[254] = ["ASSERT_FAIL", 0, 0, 0] +opcodes[254] = ("ASSERT_FAIL", 0, 0, 0) class EvmInstruction: diff --git a/mythril/support/opcodes.py b/mythril/support/opcodes.py index d6e59231..d70f0309 100644 --- a/mythril/support/opcodes.py +++ b/mythril/support/opcodes.py @@ -1,89 +1,92 @@ +# This pyethereum opcodes file with added opcodes +from typing import Dict, Tuple + opcodes = { - 0x00: ["STOP", 0, 0, 0], - 0x01: ["ADD", 2, 1, 3], - 0x02: ["MUL", 2, 1, 5], - 0x03: ["SUB", 2, 1, 3], - 0x04: ["DIV", 2, 1, 5], - 0x05: ["SDIV", 2, 1, 5], - 0x06: ["MOD", 2, 1, 5], - 0x07: ["SMOD", 2, 1, 5], - 0x08: ["ADDMOD", 3, 1, 8], - 0x09: ["MULMOD", 3, 1, 8], - 0x0A: ["EXP", 2, 1, 10], - 0x0B: ["SIGNEXTEND", 2, 1, 5], - 0x10: ["LT", 2, 1, 3], - 0x11: ["GT", 2, 1, 3], - 0x12: ["SLT", 2, 1, 3], - 0x13: ["SGT", 2, 1, 3], - 0x14: ["EQ", 2, 1, 3], - 0x15: ["ISZERO", 1, 1, 3], - 0x16: ["AND", 2, 1, 3], - 0x17: ["OR", 2, 1, 3], - 0x18: ["XOR", 2, 1, 3], - 0x19: ["NOT", 1, 1, 3], - 0x1A: ["BYTE", 2, 1, 3], - 0x1B: ["SHL", 2, 1, 3], - 0x1C: ["SHR", 2, 1, 3], - 0x1D: ["SAR", 2, 1, 3], - 0x20: ["SHA3", 2, 1, 30], - 0x30: ["ADDRESS", 0, 1, 2], - 0x31: ["BALANCE", 1, 1, 20], # now 400 - 0x32: ["ORIGIN", 0, 1, 2], - 0x33: ["CALLER", 0, 1, 2], - 0x34: ["CALLVALUE", 0, 1, 2], - 0x35: ["CALLDATALOAD", 1, 1, 3], - 0x36: ["CALLDATASIZE", 0, 1, 2], - 0x37: ["CALLDATACOPY", 3, 0, 3], - 0x38: ["CODESIZE", 0, 1, 2], - 0x39: ["CODECOPY", 3, 0, 3], - 0x3A: ["GASPRICE", 0, 1, 2], - 0x3B: ["EXTCODESIZE", 1, 1, 20], # now 700 - 0x3C: ["EXTCODECOPY", 4, 0, 20], # now 700 - 0x3D: ["RETURNDATASIZE", 0, 1, 2], - 0x3E: ["RETURNDATACOPY", 3, 0, 3], - 0x3F: ["EXTCODEHASH", 3, 0, 3], - 0x40: ["BLOCKHASH", 1, 1, 20], - 0x41: ["COINBASE", 0, 1, 2], - 0x42: ["TIMESTAMP", 0, 1, 2], - 0x43: ["NUMBER", 0, 1, 2], - 0x44: ["DIFFICULTY", 0, 1, 2], - 0x45: ["GASLIMIT", 0, 1, 2], - 0x50: ["POP", 1, 0, 2], - 0x51: ["MLOAD", 1, 1, 3], - 0x52: ["MSTORE", 2, 0, 3], - 0x53: ["MSTORE8", 2, 0, 3], - 0x54: ["SLOAD", 1, 1, 50], # 200 now - 0x55: ["SSTORE", 2, 0, 0], - 0x56: ["JUMP", 1, 0, 8], - 0x57: ["JUMPI", 2, 0, 10], - 0x58: ["PC", 0, 1, 2], - 0x59: ["MSIZE", 0, 1, 2], - 0x5A: ["GAS", 0, 1, 2], - 0x5B: ["JUMPDEST", 0, 0, 1], - 0xA0: ["LOG0", 2, 0, 375], - 0xA1: ["LOG1", 3, 0, 750], - 0xA2: ["LOG2", 4, 0, 1125], - 0xA3: ["LOG3", 5, 0, 1500], - 0xA4: ["LOG4", 6, 0, 1875], - 0xF0: ["CREATE", 3, 1, 32000], - 0xF1: ["CALL", 7, 1, 40], # 700 now - 0xF2: ["CALLCODE", 7, 1, 40], # 700 now - 0xF3: ["RETURN", 2, 0, 0], - 0xF4: ["DELEGATECALL", 6, 1, 40], # 700 now - 0xF5: ["CREATE2", 3, 1, 32000], - 0xFA: ["STATICCALL", 6, 1, 40], - 0xFD: ["REVERT", 2, 0, 0], - 0xFF: ["SUICIDE", 1, 0, 0], # 5000 now -} + 0x00: ("STOP", 0, 0, 0), + 0x01: ("ADD", 2, 1, 3), + 0x02: ("MUL", 2, 1, 5), + 0x03: ("SUB", 2, 1, 3), + 0x04: ("DIV", 2, 1, 5), + 0x05: ("SDIV", 2, 1, 5), + 0x06: ("MOD", 2, 1, 5), + 0x07: ("SMOD", 2, 1, 5), + 0x08: ("ADDMOD", 3, 1, 8), + 0x09: ("MULMOD", 3, 1, 8), + 0x0A: ("EXP", 2, 1, 10), + 0x0B: ("SIGNEXTEND", 2, 1, 5), + 0x10: ("LT", 2, 1, 3), + 0x11: ("GT", 2, 1, 3), + 0x12: ("SLT", 2, 1, 3), + 0x13: ("SGT", 2, 1, 3), + 0x14: ("EQ", 2, 1, 3), + 0x15: ("ISZERO", 1, 1, 3), + 0x16: ("AND", 2, 1, 3), + 0x17: ("OR", 2, 1, 3), + 0x18: ("XOR", 2, 1, 3), + 0x19: ("NOT", 1, 1, 3), + 0x1A: ("BYTE", 2, 1, 3), + 0x1B: ("SHL", 2, 1, 3), + 0x1C: ("SHR", 2, 1, 3), + 0x1D: ("SAR", 2, 1, 3), + 0x20: ("SHA3", 2, 1, 30), + 0x30: ("ADDRESS", 0, 1, 2), + 0x31: ("BALANCE", 1, 1, 20), # now 400 + 0x32: ("ORIGIN", 0, 1, 2), + 0x33: ("CALLER", 0, 1, 2), + 0x34: ("CALLVALUE", 0, 1, 2), + 0x35: ("CALLDATALOAD", 1, 1, 3), + 0x36: ("CALLDATASIZE", 0, 1, 2), + 0x37: ("CALLDATACOPY", 3, 0, 3), + 0x38: ("CODESIZE", 0, 1, 2), + 0x39: ("CODECOPY", 3, 0, 3), + 0x3A: ("GASPRICE", 0, 1, 2), + 0x3B: ("EXTCODESIZE", 1, 1, 20), # now 700 + 0x3C: ("EXTCODECOPY", 4, 0, 20), # now 700 + 0x3D: ("RETURNDATASIZE", 0, 1, 2), + 0x3E: ("RETURNDATACOPY", 3, 0, 3), + 0x3F: ("EXTCODEHASH", 3, 0, 3), + 0x40: ("BLOCKHASH", 1, 1, 20), + 0x41: ("COINBASE", 0, 1, 2), + 0x42: ("TIMESTAMP", 0, 1, 2), + 0x43: ("NUMBER", 0, 1, 2), + 0x44: ("DIFFICULTY", 0, 1, 2), + 0x45: ("GASLIMIT", 0, 1, 2), + 0x50: ("POP", 1, 0, 2), + 0x51: ("MLOAD", 1, 1, 3), + 0x52: ("MSTORE", 2, 0, 3), + 0x53: ("MSTORE8", 2, 0, 3), + 0x54: ("SLOAD", 1, 1, 50), # 200 now + 0x55: ("SSTORE", 2, 0, 0), + 0x56: ("JUMP", 1, 0, 8), + 0x57: ("JUMPI", 2, 0, 10), + 0x58: ("PC", 0, 1, 2), + 0x59: ("MSIZE", 0, 1, 2), + 0x5A: ("GAS", 0, 1, 2), + 0x5B: ("JUMPDEST", 0, 0, 1), + 0xA0: ("LOG0", 2, 0, 375), + 0xA1: ("LOG1", 3, 0, 750), + 0xA2: ("LOG2", 4, 0, 1125), + 0xA3: ("LOG3", 5, 0, 1500), + 0xA4: ("LOG4", 6, 0, 1875), + 0xF0: ("CREATE", 3, 1, 32000), + 0xF1: ("CALL", 7, 1, 40), # 700 now + 0xF2: ("CALLCODE", 7, 1, 40), # 700 now + 0xF3: ("RETURN", 2, 0, 0), + 0xF4: ("DELEGATECALL", 6, 1, 40), # 700 now + 0xF5: ("CREATE2", 3, 1, 32000), + 0xFA: ("STATICCALL", 6, 1, 40), + 0xFD: ("REVERT", 2, 0, 0), + 0xFF: ("SUICIDE", 1, 0, 0), # 5000 now +} # type: Dict[int, Tuple[str, int, int, int]] opcodesMetropolis = {0x3D, 0x3E, 0xFA, 0xFD} for i in range(1, 33): - opcodes[0x5F + i] = ["PUSH" + str(i), 0, 1, 3] + opcodes[0x5F + i] = ("PUSH" + str(i), 0, 1, 3) for i in range(1, 17): - opcodes[0x7F + i] = ["DUP" + str(i), i, i + 1, 3] - opcodes[0x8F + i] = ["SWAP" + str(i), i + 1, i + 1, 3] + opcodes[0x7F + i] = ("DUP" + str(i), i, i + 1, 3) + opcodes[0x8F + i] = ("SWAP" + str(i), i + 1, i + 1, 3) reverse_opcodes = {} for o in opcodes: From 910b366318e0d0e05e78d17dd5982a8947bf2a0b Mon Sep 17 00:00:00 2001 From: Joran Honig Date: Mon, 18 Mar 2019 09:47:39 +0100 Subject: [PATCH 20/22] update expected test results (pretty print & gas estimates) --- .../outputs_expected/calls.sol.o.jsonv2 | 151 +----------------- .../outputs_expected/ether_send.sol.o.jsonv2 | 10 +- .../outputs_expected/exceptions.sol.o.jsonv2 | 73 +-------- .../kinds_of_calls.sol.o.json | 12 +- .../kinds_of_calls.sol.o.jsonv2 | 68 +------- .../kinds_of_calls.sol.o.markdown | 6 +- .../kinds_of_calls.sol.o.text | 6 +- .../outputs_expected/metacoin.sol.o.jsonv2 | 10 +- .../multi_contracts.sol.o.jsonv2 | 28 +--- .../outputs_expected/nonascii.sol.o.jsonv2 | 10 +- .../outputs_expected/origin.sol.o.jsonv2 | 28 +--- .../outputs_expected/overflow.sol.o.json | 8 +- .../outputs_expected/overflow.sol.o.jsonv2 | 43 +---- .../outputs_expected/overflow.sol.o.markdown | 4 +- .../outputs_expected/overflow.sol.o.text | 4 +- .../outputs_expected/returnvalue.sol.o.jsonv2 | 58 +------ .../outputs_expected/suicide.sol.o.jsonv2 | 28 +--- .../outputs_expected/underflow.sol.o.json | 8 +- .../outputs_expected/underflow.sol.o.jsonv2 | 43 +---- .../outputs_expected/underflow.sol.o.markdown | 4 +- .../outputs_expected/underflow.sol.o.text | 4 +- 21 files changed, 40 insertions(+), 566 deletions(-) diff --git a/tests/testdata/outputs_expected/calls.sol.o.jsonv2 b/tests/testdata/outputs_expected/calls.sol.o.jsonv2 index 67c4957d..d42f0a1c 100644 --- a/tests/testdata/outputs_expected/calls.sol.o.jsonv2 +++ b/tests/testdata/outputs_expected/calls.sol.o.jsonv2 @@ -1,150 +1 @@ -[ - { - "issues": [ - { - "description": { - "head": "The contract executes an external message call.", - "tail": "An external function call to a fixed contract address is executed. Make sure that the callee contract has been reviewed carefully." - }, - "extra": { - - }, - "locations": [ - { - "sourceMap": "661:1:0" - } - ], - "severity": "Low", - "swcID": "SWC-107", - "swcTitle": "Reentrancy" - }, - { - "description": { - "head": "The contract executes an external message call.", - "tail": "An external function call to a fixed contract address is executed. Make sure that the callee contract has been reviewed carefully." - }, - "extra": { - - }, - "locations": [ - { - "sourceMap": "779:1:0" - } - ], - "severity": "Low", - "swcID": "SWC-107", - "swcTitle": "Reentrancy" - }, - { - "description": { - "head": "The contract executes an external message call.", - "tail": "An external function call to a fixed contract address is executed. Make sure that the callee contract has been reviewed carefully." - }, - "extra": { - - }, - "locations": [ - { - "sourceMap": "858:1:0" - } - ], - "severity": "Low", - "swcID": "SWC-107", - "swcTitle": "Reentrancy" - }, - { - "description": { - "head": "A call to a user-supplied address is executed.", - "tail": "The callee address of an external message call can be set by the caller. Note that the callee can contain arbitrary code and may re-enter any function in this contract. Review the business logic carefully to prevent averse effects on the contract state." - }, - "extra": { - - }, - "locations": [ - { - "sourceMap": "912:1:0" - } - ], - "severity": "Medium", - "swcID": "SWC-107", - "swcTitle": "Reentrancy" - }, - { - "description": { - "head": "The return value of a message call is not checked.", - "tail": "External calls return a boolean value. If the callee contract halts with an exception, 'false' is returned and execution continues in the caller. It is usually recommended to wrap external calls into a require statement to prevent unexpected states." - }, - "extra": { - - }, - "locations": [ - { - "sourceMap": "661:1:0" - } - ], - "severity": "Low", - "swcID": "SWC-104", - "swcTitle": "Unchecked Call Return Value" - }, - { - "description": { - "head": "The return value of a message call is not checked.", - "tail": "External calls return a boolean value. If the callee contract halts with an exception, 'false' is returned and execution continues in the caller. It is usually recommended to wrap external calls into a require statement to prevent unexpected states." - }, - "extra": { - - }, - "locations": [ - { - "sourceMap": "779:1:0" - } - ], - "severity": "Low", - "swcID": "SWC-104", - "swcTitle": "Unchecked Call Return Value" - }, - { - "description": { - "head": "The return value of a message call is not checked.", - "tail": "External calls return a boolean value. If the callee contract halts with an exception, 'false' is returned and execution continues in the caller. It is usually recommended to wrap external calls into a require statement to prevent unexpected states." - }, - "extra": { - - }, - "locations": [ - { - "sourceMap": "858:1:0" - } - ], - "severity": "Low", - "swcID": "SWC-104", - "swcTitle": "Unchecked Call Return Value" - }, - { - "description": { - "head": "The return value of a message call is not checked.", - "tail": "External calls return a boolean value. If the callee contract halts with an exception, 'false' is returned and execution continues in the caller. It is usually recommended to wrap external calls into a require statement to prevent unexpected states." - }, - "extra": { - - }, - "locations": [ - { - "sourceMap": "912:1:0" - } - ], - "severity": "Low", - "swcID": "SWC-104", - "swcTitle": "Unchecked Call Return Value" - } - ], - "meta": { - - }, - "sourceFormat": "evm-byzantium-bytecode", - "sourceList": [ - "0x7cbb77986c6b1bf6e945cd3fba06d3ea3d28cfc49cdfdc9571ec30703ac5862f" - ], - "sourceType": "raw-bytecode" - } -] +[{"issues": [{"description": {"head": "The contract executes an external message call.", "tail": "An external function call to a fixed contract address is executed. Make sure that the callee contract has been reviewed carefully."}, "extra": {}, "locations": [{"sourceMap": "661:1:0"}], "severity": "Low", "swcID": "SWC-107", "swcTitle": "Reentrancy"}, {"description": {"head": "The contract executes an external message call.", "tail": "An external function call to a fixed contract address is executed. Make sure that the callee contract has been reviewed carefully."}, "extra": {}, "locations": [{"sourceMap": "779:1:0"}], "severity": "Low", "swcID": "SWC-107", "swcTitle": "Reentrancy"}, {"description": {"head": "The contract executes an external message call.", "tail": "An external function call to a fixed contract address is executed. Make sure that the callee contract has been reviewed carefully."}, "extra": {}, "locations": [{"sourceMap": "858:1:0"}], "severity": "Low", "swcID": "SWC-107", "swcTitle": "Reentrancy"}, {"description": {"head": "A call to a user-supplied address is executed.", "tail": "The callee address of an external message call can be set by the caller. Note that the callee can contain arbitrary code and may re-enter any function in this contract. Review the business logic carefully to prevent averse effects on the contract state."}, "extra": {}, "locations": [{"sourceMap": "912:1:0"}], "severity": "Medium", "swcID": "SWC-107", "swcTitle": "Reentrancy"}, {"description": {"head": "The return value of a message call is not checked.", "tail": "External calls return a boolean value. If the callee contract halts with an exception, 'false' is returned and execution continues in the caller. It is usually recommended to wrap external calls into a require statement to prevent unexpected states."}, "extra": {}, "locations": [{"sourceMap": "661:1:0"}], "severity": "Low", "swcID": "SWC-104", "swcTitle": "Unchecked Call Return Value"}, {"description": {"head": "The return value of a message call is not checked.", "tail": "External calls return a boolean value. If the callee contract halts with an exception, 'false' is returned and execution continues in the caller. It is usually recommended to wrap external calls into a require statement to prevent unexpected states."}, "extra": {}, "locations": [{"sourceMap": "779:1:0"}], "severity": "Low", "swcID": "SWC-104", "swcTitle": "Unchecked Call Return Value"}, {"description": {"head": "The return value of a message call is not checked.", "tail": "External calls return a boolean value. If the callee contract halts with an exception, 'false' is returned and execution continues in the caller. It is usually recommended to wrap external calls into a require statement to prevent unexpected states."}, "extra": {}, "locations": [{"sourceMap": "858:1:0"}], "severity": "Low", "swcID": "SWC-104", "swcTitle": "Unchecked Call Return Value"}, {"description": {"head": "The return value of a message call is not checked.", "tail": "External calls return a boolean value. If the callee contract halts with an exception, 'false' is returned and execution continues in the caller. It is usually recommended to wrap external calls into a require statement to prevent unexpected states."}, "extra": {}, "locations": [{"sourceMap": "912:1:0"}], "severity": "Low", "swcID": "SWC-104", "swcTitle": "Unchecked Call Return Value"}], "meta": {}, "sourceFormat": "evm-byzantium-bytecode", "sourceList": ["0x7cbb77986c6b1bf6e945cd3fba06d3ea3d28cfc49cdfdc9571ec30703ac5862f"], "sourceType": "raw-bytecode"}] \ No newline at end of file diff --git a/tests/testdata/outputs_expected/ether_send.sol.o.jsonv2 b/tests/testdata/outputs_expected/ether_send.sol.o.jsonv2 index 0d1e9df5..0710acc2 100644 --- a/tests/testdata/outputs_expected/ether_send.sol.o.jsonv2 +++ b/tests/testdata/outputs_expected/ether_send.sol.o.jsonv2 @@ -1,9 +1 @@ -[ - { - "issues": [], - "meta": {}, - "sourceFormat": "evm-byzantium-bytecode", - "sourceList": [], - "sourceType": "raw-bytecode" - } -] \ No newline at end of file +[{"issues": [], "meta": {}, "sourceFormat": "evm-byzantium-bytecode", "sourceList": [], "sourceType": "raw-bytecode"}] \ No newline at end of file diff --git a/tests/testdata/outputs_expected/exceptions.sol.o.jsonv2 b/tests/testdata/outputs_expected/exceptions.sol.o.jsonv2 index c4f5f390..6f71bb6a 100644 --- a/tests/testdata/outputs_expected/exceptions.sol.o.jsonv2 +++ b/tests/testdata/outputs_expected/exceptions.sol.o.jsonv2 @@ -1,72 +1 @@ -[ - { - "issues": [ - { - "description": { - "head": "A reachable exception has been detected.", - "tail": "It is possible to trigger an exception (opcode 0xfe). Exceptions can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. Note that explicit `assert()` should only be used to check invariants. Use `require()` for regular input checking." - }, - "extra": {}, - "locations": [ - { - "sourceMap": "446:1:0" - } - ], - "severity": "Low", - "swcID": "SWC-110", - "swcTitle": "Assert Violation" - }, - { - "description": { - "head": "A reachable exception has been detected.", - "tail": "It is possible to trigger an exception (opcode 0xfe). Exceptions can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. Note that explicit `assert()` should only be used to check invariants. Use `require()` for regular input checking." - }, - "extra": {}, - "locations": [ - { - "sourceMap": "484:1:0" - } - ], - "severity": "Low", - "swcID": "SWC-110", - "swcTitle": "Assert Violation" - }, - { - "description": { - "head": "A reachable exception has been detected.", - "tail": "It is possible to trigger an exception (opcode 0xfe). Exceptions can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. Note that explicit `assert()` should only be used to check invariants. Use `require()` for regular input checking." - }, - "extra": {}, - "locations": [ - { - "sourceMap": "506:1:0" - } - ], - "severity": "Low", - "swcID": "SWC-110", - "swcTitle": "Assert Violation" - }, - { - "description": { - "head": "A reachable exception has been detected.", - "tail": "It is possible to trigger an exception (opcode 0xfe). Exceptions can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. Note that explicit `assert()` should only be used to check invariants. Use `require()` for regular input checking." - }, - "extra": {}, - "locations": [ - { - "sourceMap": "531:1:0" - } - ], - "severity": "Low", - "swcID": "SWC-110", - "swcTitle": "Assert Violation" - } - ], - "meta": {}, - "sourceFormat": "evm-byzantium-bytecode", - "sourceList": [ - "0x4a773a86bc6fb269f88bf09bb3094de29b6073cf13b1760e9d01d957f50a9dfd" - ], - "sourceType": "raw-bytecode" - } -] \ No newline at end of file +[{"issues": [{"description": {"head": "A reachable exception has been detected.", "tail": "It is possible to trigger an exception (opcode 0xfe). Exceptions can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. Note that explicit `assert()` should only be used to check invariants. Use `require()` for regular input checking."}, "extra": {}, "locations": [{"sourceMap": "446:1:0"}], "severity": "Low", "swcID": "SWC-110", "swcTitle": "Assert Violation"}, {"description": {"head": "A reachable exception has been detected.", "tail": "It is possible to trigger an exception (opcode 0xfe). Exceptions can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. Note that explicit `assert()` should only be used to check invariants. Use `require()` for regular input checking."}, "extra": {}, "locations": [{"sourceMap": "484:1:0"}], "severity": "Low", "swcID": "SWC-110", "swcTitle": "Assert Violation"}, {"description": {"head": "A reachable exception has been detected.", "tail": "It is possible to trigger an exception (opcode 0xfe). Exceptions can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. Note that explicit `assert()` should only be used to check invariants. Use `require()` for regular input checking."}, "extra": {}, "locations": [{"sourceMap": "506:1:0"}], "severity": "Low", "swcID": "SWC-110", "swcTitle": "Assert Violation"}, {"description": {"head": "A reachable exception has been detected.", "tail": "It is possible to trigger an exception (opcode 0xfe). Exceptions can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. Note that explicit `assert()` should only be used to check invariants. Use `require()` for regular input checking."}, "extra": {}, "locations": [{"sourceMap": "531:1:0"}], "severity": "Low", "swcID": "SWC-110", "swcTitle": "Assert Violation"}], "meta": {}, "sourceFormat": "evm-byzantium-bytecode", "sourceList": ["0x4a773a86bc6fb269f88bf09bb3094de29b6073cf13b1760e9d01d957f50a9dfd"], "sourceType": "raw-bytecode"}] \ No newline at end of file diff --git a/tests/testdata/outputs_expected/kinds_of_calls.sol.o.json b/tests/testdata/outputs_expected/kinds_of_calls.sol.o.json index 180eb4aa..b6bc99ac 100644 --- a/tests/testdata/outputs_expected/kinds_of_calls.sol.o.json +++ b/tests/testdata/outputs_expected/kinds_of_calls.sol.o.json @@ -33,8 +33,8 @@ "debug": "", "description": "The return value of a message call is not checked.\nExternal calls return a boolean value. If the callee contract halts with an exception, 'false' is returned and execution continues in the caller. It is usually recommended to wrap external calls into a require statement to prevent unexpected states.", "function": "_function_0x9b58bc26", - "max_gas_used": 35922, - "min_gas_used": 1170, + "max_gas_used": 35928, + "min_gas_used": 1176, "severity": "Low", "sourceMap": null, "swc-id": "104", @@ -46,8 +46,8 @@ "debug": "", "description": "A call to a user-supplied address is executed.\nThe callee address of an external message call can be set by the caller. Note that the callee can contain arbitrary code and may re-enter any function in this contract. Review the business logic carefully to prevent averse effects on the contract state.", "function": "_function_0xeea4c864", - "max_gas_used": 1223, - "min_gas_used": 471, + "max_gas_used": 1229, + "min_gas_used": 477, "severity": "Medium", "sourceMap": null, "swc-id": "107", @@ -59,8 +59,8 @@ "debug": "", "description": "The return value of a message call is not checked.\nExternal calls return a boolean value. If the callee contract halts with an exception, 'false' is returned and execution continues in the caller. It is usually recommended to wrap external calls into a require statement to prevent unexpected states.", "function": "_function_0xeea4c864", - "max_gas_used": 35947, - "min_gas_used": 1195, + "max_gas_used": 35953, + "min_gas_used": 1201, "severity": "Low", "sourceMap": null, "swc-id": "104", diff --git a/tests/testdata/outputs_expected/kinds_of_calls.sol.o.jsonv2 b/tests/testdata/outputs_expected/kinds_of_calls.sol.o.jsonv2 index e132d037..04cfe7f6 100644 --- a/tests/testdata/outputs_expected/kinds_of_calls.sol.o.jsonv2 +++ b/tests/testdata/outputs_expected/kinds_of_calls.sol.o.jsonv2 @@ -1,67 +1 @@ -[{ - "issues": [{ - "description": { - "head": "Use of callcode is deprecated.", - "tail": "The callcode method executes code of another contract in the context of the caller account. Due to a bug in the implementation it does not persist sender and value over the call. It was therefore deprecated and may be removed in the future. Use the delegatecall method instead." - }, - "extra": {}, - "locations": [{ - "sourceMap": "618:1:0" - }], - "severity": "Medium", - "swcID": "SWC-111", - "swcTitle": "Use of Deprecated Solidity Functions" - }, { - "description": { - "head": "A call to a user-supplied address is executed.", - "tail": "The callee address of an external message call can be set by the caller. Note that the callee can contain arbitrary code and may re-enter any function in this contract. Review the business logic carefully to prevent averse effects on the contract state." - }, - "extra": {}, - "locations": [{ - "sourceMap": "1038:1:0" - }], - "severity": "Medium", - "swcID": "SWC-107", - "swcTitle": "Reentrancy" - }, { - "description": { - "head": "The return value of a message call is not checked.", - "tail": "External calls return a boolean value. If the callee contract halts with an exception, 'false' is returned and execution continues in the caller. It is usually recommended to wrap external calls into a require statement to prevent unexpected states." - }, - "extra": {}, - "locations": [{ - "sourceMap": "618:1:0" - }], - "severity": "Low", - "swcID": "SWC-104", - "swcTitle": "Unchecked Call Return Value" - }, { - "description": { - "head": "The return value of a message call is not checked.", - "tail": "External calls return a boolean value. If the callee contract halts with an exception, 'false' is returned and execution continues in the caller. It is usually recommended to wrap external calls into a require statement to prevent unexpected states." - }, - "extra": {}, - "locations": [{ - "sourceMap": "849:1:0" - }], - "severity": "Low", - "swcID": "SWC-104", - "swcTitle": "Unchecked Call Return Value" - }, { - "description": { - "head": "The return value of a message call is not checked.", - "tail": "External calls return a boolean value. If the callee contract halts with an exception, 'false' is returned and execution continues in the caller. It is usually recommended to wrap external calls into a require statement to prevent unexpected states." - }, - "extra": {}, - "locations": [{ - "sourceMap": "1038:1:0" - }], - "severity": "Low", - "swcID": "SWC-104", - "swcTitle": "Unchecked Call Return Value" - }], - "meta": {}, - "sourceFormat": "evm-byzantium-bytecode", - "sourceList": ["0x6daec61d05d8f1210661e7e7d1ed6d72bd6ade639398fac1e867aff50abfc1c1"], - "sourceType": "raw-bytecode" -}] +[{"issues": [{"description": {"head": "Use of callcode is deprecated.", "tail": "The callcode method executes code of another contract in the context of the caller account. Due to a bug in the implementation it does not persist sender and value over the call. It was therefore deprecated and may be removed in the future. Use the delegatecall method instead."}, "extra": {}, "locations": [{"sourceMap": "618:1:0"}], "severity": "Medium", "swcID": "SWC-111", "swcTitle": "Use of Deprecated Solidity Functions"}, {"description": {"head": "A call to a user-supplied address is executed.", "tail": "The callee address of an external message call can be set by the caller. Note that the callee can contain arbitrary code and may re-enter any function in this contract. Review the business logic carefully to prevent averse effects on the contract state."}, "extra": {}, "locations": [{"sourceMap": "1038:1:0"}], "severity": "Medium", "swcID": "SWC-107", "swcTitle": "Reentrancy"}, {"description": {"head": "The return value of a message call is not checked.", "tail": "External calls return a boolean value. If the callee contract halts with an exception, 'false' is returned and execution continues in the caller. It is usually recommended to wrap external calls into a require statement to prevent unexpected states."}, "extra": {}, "locations": [{"sourceMap": "618:1:0"}], "severity": "Low", "swcID": "SWC-104", "swcTitle": "Unchecked Call Return Value"}, {"description": {"head": "The return value of a message call is not checked.", "tail": "External calls return a boolean value. If the callee contract halts with an exception, 'false' is returned and execution continues in the caller. It is usually recommended to wrap external calls into a require statement to prevent unexpected states."}, "extra": {}, "locations": [{"sourceMap": "849:1:0"}], "severity": "Low", "swcID": "SWC-104", "swcTitle": "Unchecked Call Return Value"}, {"description": {"head": "The return value of a message call is not checked.", "tail": "External calls return a boolean value. If the callee contract halts with an exception, 'false' is returned and execution continues in the caller. It is usually recommended to wrap external calls into a require statement to prevent unexpected states."}, "extra": {}, "locations": [{"sourceMap": "1038:1:0"}], "severity": "Low", "swcID": "SWC-104", "swcTitle": "Unchecked Call Return Value"}], "meta": {}, "sourceFormat": "evm-byzantium-bytecode", "sourceList": ["0x6daec61d05d8f1210661e7e7d1ed6d72bd6ade639398fac1e867aff50abfc1c1"], "sourceType": "raw-bytecode"}] \ No newline at end of file diff --git a/tests/testdata/outputs_expected/kinds_of_calls.sol.o.markdown b/tests/testdata/outputs_expected/kinds_of_calls.sol.o.markdown index 29001c95..4e222b18 100644 --- a/tests/testdata/outputs_expected/kinds_of_calls.sol.o.markdown +++ b/tests/testdata/outputs_expected/kinds_of_calls.sol.o.markdown @@ -32,7 +32,7 @@ The callcode method executes code of another contract in the context of the call - Contract: Unknown - Function name: `_function_0x9b58bc26` - PC address: 849 -- Estimated Gas Usage: 1170 - 35922 +- Estimated Gas Usage: 1176 - 35928 ### Description @@ -45,7 +45,7 @@ External calls return a boolean value. If the callee contract halts with an exce - Contract: Unknown - Function name: `_function_0xeea4c864` - PC address: 1038 -- Estimated Gas Usage: 471 - 1223 +- Estimated Gas Usage: 477 - 1229 ### Description @@ -58,7 +58,7 @@ The callee address of an external message call can be set by the caller. Note th - Contract: Unknown - Function name: `_function_0xeea4c864` - PC address: 1038 -- Estimated Gas Usage: 1195 - 35947 +- Estimated Gas Usage: 1201 - 35953 ### Description diff --git a/tests/testdata/outputs_expected/kinds_of_calls.sol.o.text b/tests/testdata/outputs_expected/kinds_of_calls.sol.o.text index 40db8117..9e9761c3 100644 --- a/tests/testdata/outputs_expected/kinds_of_calls.sol.o.text +++ b/tests/testdata/outputs_expected/kinds_of_calls.sol.o.text @@ -26,7 +26,7 @@ Severity: Low Contract: Unknown Function name: _function_0x9b58bc26 PC address: 849 -Estimated Gas Usage: 1170 - 35922 +Estimated Gas Usage: 1176 - 35928 The return value of a message call is not checked. External calls return a boolean value. If the callee contract halts with an exception, 'false' is returned and execution continues in the caller. It is usually recommended to wrap external calls into a require statement to prevent unexpected states. -------------------- @@ -37,7 +37,7 @@ Severity: Medium Contract: Unknown Function name: _function_0xeea4c864 PC address: 1038 -Estimated Gas Usage: 471 - 1223 +Estimated Gas Usage: 477 - 1229 A call to a user-supplied address is executed. The callee address of an external message call can be set by the caller. Note that the callee can contain arbitrary code and may re-enter any function in this contract. Review the business logic carefully to prevent averse effects on the contract state. -------------------- @@ -48,7 +48,7 @@ Severity: Low Contract: Unknown Function name: _function_0xeea4c864 PC address: 1038 -Estimated Gas Usage: 1195 - 35947 +Estimated Gas Usage: 1201 - 35953 The return value of a message call is not checked. External calls return a boolean value. If the callee contract halts with an exception, 'false' is returned and execution continues in the caller. It is usually recommended to wrap external calls into a require statement to prevent unexpected states. -------------------- diff --git a/tests/testdata/outputs_expected/metacoin.sol.o.jsonv2 b/tests/testdata/outputs_expected/metacoin.sol.o.jsonv2 index 0d1e9df5..0710acc2 100644 --- a/tests/testdata/outputs_expected/metacoin.sol.o.jsonv2 +++ b/tests/testdata/outputs_expected/metacoin.sol.o.jsonv2 @@ -1,9 +1 @@ -[ - { - "issues": [], - "meta": {}, - "sourceFormat": "evm-byzantium-bytecode", - "sourceList": [], - "sourceType": "raw-bytecode" - } -] \ No newline at end of file +[{"issues": [], "meta": {}, "sourceFormat": "evm-byzantium-bytecode", "sourceList": [], "sourceType": "raw-bytecode"}] \ No newline at end of file diff --git a/tests/testdata/outputs_expected/multi_contracts.sol.o.jsonv2 b/tests/testdata/outputs_expected/multi_contracts.sol.o.jsonv2 index 2afee3f5..dcd4c195 100644 --- a/tests/testdata/outputs_expected/multi_contracts.sol.o.jsonv2 +++ b/tests/testdata/outputs_expected/multi_contracts.sol.o.jsonv2 @@ -1,27 +1 @@ -[ - { - "issues": [ - { - "description": { - "head": "Anyone can withdraw ETH from the contract account.", - "tail": "Arbitrary senders other than the contract creator can withdraw ETH from the contract account without previously having sent an equivalent amount of ETH to it. This is likely to be a vulnerability." - }, - "extra": {}, - "locations": [ - { - "sourceMap": "142:1:0" - } - ], - "severity": "High", - "swcID": "SWC-105", - "swcTitle": "Unprotected Ether Withdrawal" - } - ], - "meta": {}, - "sourceFormat": "evm-byzantium-bytecode", - "sourceList": [ - "0xbc9c3d9db56d20cf4ca3b6fd88ff9215cf728a092cca1ed8edb83272b933ff5b" - ], - "sourceType": "raw-bytecode" - } -] \ No newline at end of file +[{"issues": [{"description": {"head": "Anyone can withdraw ETH from the contract account.", "tail": "Arbitrary senders other than the contract creator can withdraw ETH from the contract account without previously having sent an equivalent amount of ETH to it. This is likely to be a vulnerability."}, "extra": {}, "locations": [{"sourceMap": "142:1:0"}], "severity": "High", "swcID": "SWC-105", "swcTitle": "Unprotected Ether Withdrawal"}], "meta": {}, "sourceFormat": "evm-byzantium-bytecode", "sourceList": ["0xbc9c3d9db56d20cf4ca3b6fd88ff9215cf728a092cca1ed8edb83272b933ff5b"], "sourceType": "raw-bytecode"}] \ No newline at end of file diff --git a/tests/testdata/outputs_expected/nonascii.sol.o.jsonv2 b/tests/testdata/outputs_expected/nonascii.sol.o.jsonv2 index 0d1e9df5..0710acc2 100644 --- a/tests/testdata/outputs_expected/nonascii.sol.o.jsonv2 +++ b/tests/testdata/outputs_expected/nonascii.sol.o.jsonv2 @@ -1,9 +1 @@ -[ - { - "issues": [], - "meta": {}, - "sourceFormat": "evm-byzantium-bytecode", - "sourceList": [], - "sourceType": "raw-bytecode" - } -] \ No newline at end of file +[{"issues": [], "meta": {}, "sourceFormat": "evm-byzantium-bytecode", "sourceList": [], "sourceType": "raw-bytecode"}] \ No newline at end of file diff --git a/tests/testdata/outputs_expected/origin.sol.o.jsonv2 b/tests/testdata/outputs_expected/origin.sol.o.jsonv2 index b266a973..2d9efb87 100644 --- a/tests/testdata/outputs_expected/origin.sol.o.jsonv2 +++ b/tests/testdata/outputs_expected/origin.sol.o.jsonv2 @@ -1,27 +1 @@ -[ - { - "issues": [ - { - "description": { - "head": "Use of tx.origin is deprecated.", - "tail": "The smart contract retrieves the transaction origin (tx.origin) using msg.origin. Use of msg.origin is deprecated and the instruction may be removed in the future. Use msg.sender instead.\nSee also: https://solidity.readthedocs.io/en/develop/security-considerations.html#tx-origin" - }, - "extra": {}, - "locations": [ - { - "sourceMap": "317:1:0" - } - ], - "severity": "Medium", - "swcID": "SWC-111", - "swcTitle": "Use of Deprecated Solidity Functions" - } - ], - "meta": {}, - "sourceFormat": "evm-byzantium-bytecode", - "sourceList": [ - "0x25b20ef097dfc0aa56a932c4e09f06ee02a69c005767df86877f48c6c2412f03" - ], - "sourceType": "raw-bytecode" - } -] \ No newline at end of file +[{"issues": [{"description": {"head": "Use of tx.origin is deprecated.", "tail": "The smart contract retrieves the transaction origin (tx.origin) using msg.origin. Use of msg.origin is deprecated and the instruction may be removed in the future. Use msg.sender instead.\nSee also: https://solidity.readthedocs.io/en/develop/security-considerations.html#tx-origin"}, "extra": {}, "locations": [{"sourceMap": "317:1:0"}], "severity": "Medium", "swcID": "SWC-111", "swcTitle": "Use of Deprecated Solidity Functions"}], "meta": {}, "sourceFormat": "evm-byzantium-bytecode", "sourceList": ["0x25b20ef097dfc0aa56a932c4e09f06ee02a69c005767df86877f48c6c2412f03"], "sourceType": "raw-bytecode"}] \ No newline at end of file diff --git a/tests/testdata/outputs_expected/overflow.sol.o.json b/tests/testdata/outputs_expected/overflow.sol.o.json index 285fdf31..89fdb839 100644 --- a/tests/testdata/outputs_expected/overflow.sol.o.json +++ b/tests/testdata/outputs_expected/overflow.sol.o.json @@ -7,8 +7,8 @@ "debug": "", "description": "The binary subtraction can underflow.\nThe operands of the subtraction operation are not sufficiently constrained. The subtraction could therefore result in an integer underflow. Prevent the underflow by checking inputs or ensure sure that the underflow is caught by an assertion.", "function": "sendeth(address,uint256)", - "max_gas_used": 78152, - "min_gas_used": 17016, + "max_gas_used": 78155, + "min_gas_used": 17019, "severity": "High", "sourceMap": null, "swc-id": "101", @@ -20,8 +20,8 @@ "debug": "", "description": "The binary subtraction can underflow.\nThe operands of the subtraction operation are not sufficiently constrained. The subtraction could therefore result in an integer underflow. Prevent the underflow by checking inputs or ensure sure that the underflow is caught by an assertion.", "function": "sendeth(address,uint256)", - "max_gas_used": 78152, - "min_gas_used": 17016, + "max_gas_used": 78155, + "min_gas_used": 17019, "severity": "High", "sourceMap": null, "swc-id": "101", diff --git a/tests/testdata/outputs_expected/overflow.sol.o.jsonv2 b/tests/testdata/outputs_expected/overflow.sol.o.jsonv2 index ee33041a..9071dc3b 100644 --- a/tests/testdata/outputs_expected/overflow.sol.o.jsonv2 +++ b/tests/testdata/outputs_expected/overflow.sol.o.jsonv2 @@ -1,42 +1 @@ -[ - { - "issues": [ - { - "description": { - "head": "The binary subtraction can underflow.", - "tail": "The operands of the subtraction operation are not sufficiently constrained. The subtraction could therefore result in an integer underflow. Prevent the underflow by checking inputs or ensure sure that the underflow is caught by an assertion." - }, - "extra": {}, - "locations": [ - { - "sourceMap": "567:1:0" - } - ], - "severity": "High", - "swcID": "SWC-101", - "swcTitle": "Integer Overflow and Underflow" - }, - { - "description": { - "head": "The binary subtraction can underflow.", - "tail": "The operands of the subtraction operation are not sufficiently constrained. The subtraction could therefore result in an integer underflow. Prevent the underflow by checking inputs or ensure sure that the underflow is caught by an assertion." - }, - "extra": {}, - "locations": [ - { - "sourceMap": "649:1:0" - } - ], - "severity": "High", - "swcID": "SWC-101", - "swcTitle": "Integer Overflow and Underflow" - } - ], - "meta": {}, - "sourceFormat": "evm-byzantium-bytecode", - "sourceList": [ - "0xf230bec502569e8b7e7737616d0ad0f200c436624e3c223e5398c0615cd2d6b9" - ], - "sourceType": "raw-bytecode" - } -] \ No newline at end of file +[{"issues": [{"description": {"head": "The binary subtraction can underflow.", "tail": "The operands of the subtraction operation are not sufficiently constrained. The subtraction could therefore result in an integer underflow. Prevent the underflow by checking inputs or ensure sure that the underflow is caught by an assertion."}, "extra": {}, "locations": [{"sourceMap": "567:1:0"}], "severity": "High", "swcID": "SWC-101", "swcTitle": "Integer Overflow and Underflow"}, {"description": {"head": "The binary subtraction can underflow.", "tail": "The operands of the subtraction operation are not sufficiently constrained. The subtraction could therefore result in an integer underflow. Prevent the underflow by checking inputs or ensure sure that the underflow is caught by an assertion."}, "extra": {}, "locations": [{"sourceMap": "649:1:0"}], "severity": "High", "swcID": "SWC-101", "swcTitle": "Integer Overflow and Underflow"}], "meta": {}, "sourceFormat": "evm-byzantium-bytecode", "sourceList": ["0xf230bec502569e8b7e7737616d0ad0f200c436624e3c223e5398c0615cd2d6b9"], "sourceType": "raw-bytecode"}] \ No newline at end of file diff --git a/tests/testdata/outputs_expected/overflow.sol.o.markdown b/tests/testdata/outputs_expected/overflow.sol.o.markdown index 0d589f0d..8774d894 100644 --- a/tests/testdata/outputs_expected/overflow.sol.o.markdown +++ b/tests/testdata/outputs_expected/overflow.sol.o.markdown @@ -6,7 +6,7 @@ - Contract: Unknown - Function name: `sendeth(address,uint256)` - PC address: 567 -- Estimated Gas Usage: 17016 - 78152 +- Estimated Gas Usage: 17019 - 78155 ### Description @@ -19,7 +19,7 @@ The operands of the subtraction operation are not sufficiently constrained. The - Contract: Unknown - Function name: `sendeth(address,uint256)` - PC address: 649 -- Estimated Gas Usage: 17016 - 78152 +- Estimated Gas Usage: 17019 - 78155 ### Description diff --git a/tests/testdata/outputs_expected/overflow.sol.o.text b/tests/testdata/outputs_expected/overflow.sol.o.text index 934ccdd7..698665d8 100644 --- a/tests/testdata/outputs_expected/overflow.sol.o.text +++ b/tests/testdata/outputs_expected/overflow.sol.o.text @@ -4,7 +4,7 @@ Severity: High Contract: Unknown Function name: sendeth(address,uint256) PC address: 567 -Estimated Gas Usage: 17016 - 78152 +Estimated Gas Usage: 17019 - 78155 The binary subtraction can underflow. The operands of the subtraction operation are not sufficiently constrained. The subtraction could therefore result in an integer underflow. Prevent the underflow by checking inputs or ensure sure that the underflow is caught by an assertion. -------------------- @@ -15,7 +15,7 @@ Severity: High Contract: Unknown Function name: sendeth(address,uint256) PC address: 649 -Estimated Gas Usage: 17016 - 78152 +Estimated Gas Usage: 17019 - 78155 The binary subtraction can underflow. The operands of the subtraction operation are not sufficiently constrained. The subtraction could therefore result in an integer underflow. Prevent the underflow by checking inputs or ensure sure that the underflow is caught by an assertion. -------------------- diff --git a/tests/testdata/outputs_expected/returnvalue.sol.o.jsonv2 b/tests/testdata/outputs_expected/returnvalue.sol.o.jsonv2 index 8c6fa02a..00402e72 100644 --- a/tests/testdata/outputs_expected/returnvalue.sol.o.jsonv2 +++ b/tests/testdata/outputs_expected/returnvalue.sol.o.jsonv2 @@ -1,57 +1 @@ -[ - { - "issues": [ - { - "description": { - "head": "The contract executes an external message call.", - "tail": "An external function call to a fixed contract address is executed. Make sure that the callee contract has been reviewed carefully." - }, - "extra": {}, - "locations": [ - { - "sourceMap": "196:1:0" - } - ], - "severity": "Low", - "swcID": "SWC-107", - "swcTitle": "Reentrancy" - }, - { - "description": { - "head": "The contract executes an external message call.", - "tail": "An external function call to a fixed contract address is executed. Make sure that the callee contract has been reviewed carefully." - }, - "extra": {}, - "locations": [ - { - "sourceMap": "285:1:0" - } - ], - "severity": "Low", - "swcID": "SWC-107", - "swcTitle": "Reentrancy" - }, - { - "description": { - "head": "The return value of a message call is not checked.", - "tail": "External calls return a boolean value. If the callee contract halts with an exception, 'false' is returned and execution continues in the caller. It is usually recommended to wrap external calls into a require statement to prevent unexpected states." - }, - "extra": {}, - "locations": [ - { - "sourceMap": "285:1:0" - } - ], - "severity": "Low", - "swcID": "SWC-104", - "swcTitle": "Unchecked Call Return Value" - } - ], - "meta": {}, - "sourceFormat": "evm-byzantium-bytecode", - "sourceList": [ - "0xb191cf6cc0d8cc37a91c9d88019cc011b932169fb5776df616e2bb9cd93b4039" - ], - "sourceType": "raw-bytecode" - } -] \ No newline at end of file +[{"issues": [{"description": {"head": "The contract executes an external message call.", "tail": "An external function call to a fixed contract address is executed. Make sure that the callee contract has been reviewed carefully."}, "extra": {}, "locations": [{"sourceMap": "196:1:0"}], "severity": "Low", "swcID": "SWC-107", "swcTitle": "Reentrancy"}, {"description": {"head": "The contract executes an external message call.", "tail": "An external function call to a fixed contract address is executed. Make sure that the callee contract has been reviewed carefully."}, "extra": {}, "locations": [{"sourceMap": "285:1:0"}], "severity": "Low", "swcID": "SWC-107", "swcTitle": "Reentrancy"}, {"description": {"head": "The return value of a message call is not checked.", "tail": "External calls return a boolean value. If the callee contract halts with an exception, 'false' is returned and execution continues in the caller. It is usually recommended to wrap external calls into a require statement to prevent unexpected states."}, "extra": {}, "locations": [{"sourceMap": "285:1:0"}], "severity": "Low", "swcID": "SWC-104", "swcTitle": "Unchecked Call Return Value"}], "meta": {}, "sourceFormat": "evm-byzantium-bytecode", "sourceList": ["0xb191cf6cc0d8cc37a91c9d88019cc011b932169fb5776df616e2bb9cd93b4039"], "sourceType": "raw-bytecode"}] \ No newline at end of file diff --git a/tests/testdata/outputs_expected/suicide.sol.o.jsonv2 b/tests/testdata/outputs_expected/suicide.sol.o.jsonv2 index ee5c2c44..6516a9a6 100644 --- a/tests/testdata/outputs_expected/suicide.sol.o.jsonv2 +++ b/tests/testdata/outputs_expected/suicide.sol.o.jsonv2 @@ -1,27 +1 @@ -[ - { - "issues" : [ - { - "swcTitle" : "Unprotected SELFDESTRUCT Instruction", - "locations" : [ - { - "sourceMap" : "146:1:0" - } - ], - "extra" : {}, - "description" : { - "tail" : "Anyone can kill this contract and withdraw its balance to an arbitrary address.", - "head" : "The contract can be killed by anyone." - }, - "severity" : "High", - "swcID" : "SWC-106" - } - ], - "sourceFormat" : "evm-byzantium-bytecode", - "meta" : {}, - "sourceType" : "raw-bytecode", - "sourceList" : [ - "0x2fb801366b61a05b30550481a1c8f7d5f20de0b93d9f2f2ce2b28c4e322033c9" - ] - } -] \ No newline at end of file +[{"issues": [{"description": {"head": "The contract can be killed by anyone.", "tail": "Anyone can kill this contract and withdraw its balance to an arbitrary address."}, "extra": {}, "locations": [{"sourceMap": "146:1:0"}], "severity": "High", "swcID": "SWC-106", "swcTitle": "Unprotected SELFDESTRUCT Instruction"}], "meta": {}, "sourceFormat": "evm-byzantium-bytecode", "sourceList": ["0x2fb801366b61a05b30550481a1c8f7d5f20de0b93d9f2f2ce2b28c4e322033c9"], "sourceType": "raw-bytecode"}] \ No newline at end of file diff --git a/tests/testdata/outputs_expected/underflow.sol.o.json b/tests/testdata/outputs_expected/underflow.sol.o.json index 5761ec2e..6a2464d5 100644 --- a/tests/testdata/outputs_expected/underflow.sol.o.json +++ b/tests/testdata/outputs_expected/underflow.sol.o.json @@ -7,8 +7,8 @@ "debug": "", "description": "The binary subtraction can underflow.\nThe operands of the subtraction operation are not sufficiently constrained. The subtraction could therefore result in an integer underflow. Prevent the underflow by checking inputs or ensure sure that the underflow is caught by an assertion.", "function": "sendeth(address,uint256)", - "max_gas_used": 52858, - "min_gas_used": 11912, + "max_gas_used": 52861, + "min_gas_used": 11915, "severity": "High", "sourceMap": null, "swc-id": "101", @@ -20,8 +20,8 @@ "debug": "", "description": "The binary subtraction can underflow.\nThe operands of the subtraction operation are not sufficiently constrained. The subtraction could therefore result in an integer underflow. Prevent the underflow by checking inputs or ensure sure that the underflow is caught by an assertion.", "function": "sendeth(address,uint256)", - "max_gas_used": 52858, - "min_gas_used": 11912, + "max_gas_used": 52861, + "min_gas_used": 11915, "severity": "High", "sourceMap": null, "swc-id": "101", diff --git a/tests/testdata/outputs_expected/underflow.sol.o.jsonv2 b/tests/testdata/outputs_expected/underflow.sol.o.jsonv2 index eee3d146..548c0ec6 100644 --- a/tests/testdata/outputs_expected/underflow.sol.o.jsonv2 +++ b/tests/testdata/outputs_expected/underflow.sol.o.jsonv2 @@ -1,42 +1 @@ -[ - { - "issues": [ - { - "description": { - "head": "The binary subtraction can underflow.", - "tail": "The operands of the subtraction operation are not sufficiently constrained. The subtraction could therefore result in an integer underflow. Prevent the underflow by checking inputs or ensure sure that the underflow is caught by an assertion." - }, - "extra": {}, - "locations": [ - { - "sourceMap": "567:1:0" - } - ], - "severity": "High", - "swcID": "SWC-101", - "swcTitle": "Integer Overflow and Underflow" - }, - { - "description": { - "head": "The binary subtraction can underflow.", - "tail": "The operands of the subtraction operation are not sufficiently constrained. The subtraction could therefore result in an integer underflow. Prevent the underflow by checking inputs or ensure sure that the underflow is caught by an assertion." - }, - "extra": {}, - "locations": [ - { - "sourceMap": "649:1:0" - } - ], - "severity": "High", - "swcID": "SWC-101", - "swcTitle": "Integer Overflow and Underflow" - } - ], - "meta": {}, - "sourceFormat": "evm-byzantium-bytecode", - "sourceList": [ - "0xabef56740bf7795a9f8732e4781ebd27f2977f8a4997e3ff11cee79a4ba6c0ce" - ], - "sourceType": "raw-bytecode" - } -] \ No newline at end of file +[{"issues": [{"description": {"head": "The binary subtraction can underflow.", "tail": "The operands of the subtraction operation are not sufficiently constrained. The subtraction could therefore result in an integer underflow. Prevent the underflow by checking inputs or ensure sure that the underflow is caught by an assertion."}, "extra": {}, "locations": [{"sourceMap": "567:1:0"}], "severity": "High", "swcID": "SWC-101", "swcTitle": "Integer Overflow and Underflow"}, {"description": {"head": "The binary subtraction can underflow.", "tail": "The operands of the subtraction operation are not sufficiently constrained. The subtraction could therefore result in an integer underflow. Prevent the underflow by checking inputs or ensure sure that the underflow is caught by an assertion."}, "extra": {}, "locations": [{"sourceMap": "649:1:0"}], "severity": "High", "swcID": "SWC-101", "swcTitle": "Integer Overflow and Underflow"}], "meta": {}, "sourceFormat": "evm-byzantium-bytecode", "sourceList": ["0xabef56740bf7795a9f8732e4781ebd27f2977f8a4997e3ff11cee79a4ba6c0ce"], "sourceType": "raw-bytecode"}] \ No newline at end of file diff --git a/tests/testdata/outputs_expected/underflow.sol.o.markdown b/tests/testdata/outputs_expected/underflow.sol.o.markdown index 19f4ca9c..48399072 100644 --- a/tests/testdata/outputs_expected/underflow.sol.o.markdown +++ b/tests/testdata/outputs_expected/underflow.sol.o.markdown @@ -6,7 +6,7 @@ - Contract: Unknown - Function name: `sendeth(address,uint256)` - PC address: 567 -- Estimated Gas Usage: 11912 - 52858 +- Estimated Gas Usage: 11915 - 52861 ### Description @@ -19,7 +19,7 @@ The operands of the subtraction operation are not sufficiently constrained. The - Contract: Unknown - Function name: `sendeth(address,uint256)` - PC address: 649 -- Estimated Gas Usage: 11912 - 52858 +- Estimated Gas Usage: 11915 - 52861 ### Description diff --git a/tests/testdata/outputs_expected/underflow.sol.o.text b/tests/testdata/outputs_expected/underflow.sol.o.text index 84a35ab7..16701a04 100644 --- a/tests/testdata/outputs_expected/underflow.sol.o.text +++ b/tests/testdata/outputs_expected/underflow.sol.o.text @@ -4,7 +4,7 @@ Severity: High Contract: Unknown Function name: sendeth(address,uint256) PC address: 567 -Estimated Gas Usage: 11912 - 52858 +Estimated Gas Usage: 11915 - 52861 The binary subtraction can underflow. The operands of the subtraction operation are not sufficiently constrained. The subtraction could therefore result in an integer underflow. Prevent the underflow by checking inputs or ensure sure that the underflow is caught by an assertion. -------------------- @@ -15,7 +15,7 @@ Severity: High Contract: Unknown Function name: sendeth(address,uint256) PC address: 649 -Estimated Gas Usage: 11912 - 52858 +Estimated Gas Usage: 11915 - 52861 The binary subtraction can underflow. The operands of the subtraction operation are not sufficiently constrained. The subtraction could therefore result in an integer underflow. Prevent the underflow by checking inputs or ensure sure that the underflow is caught by an assertion. -------------------- From d62e777f90398b83cb7e4110206f62a0c873de08 Mon Sep 17 00:00:00 2001 From: JoranHonig Date: Mon, 18 Mar 2019 14:58:54 +0530 Subject: [PATCH 21/22] Update mythril/laser/smt/bitvec.py Co-Authored-By: norhh --- mythril/laser/smt/bitvec.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mythril/laser/smt/bitvec.py b/mythril/laser/smt/bitvec.py index 5f53f4c0..05081137 100644 --- a/mythril/laser/smt/bitvec.py +++ b/mythril/laser/smt/bitvec.py @@ -213,7 +213,7 @@ class BitVec(Expression[z3.BitVecRef]): def _handle_shift(self, other: Union[int, "BitVec"], operator: Callable) -> "BitVec": """ - Handle's shift + Handles shift :param other: The other BitVector :param operator: The shift operator :return: the resulting output From 0efe9f45376c16e8c5fee2b324dd32d85cdf1aee Mon Sep 17 00:00:00 2001 From: Nikhil Parasaram Date: Mon, 18 Mar 2019 23:27:54 +0530 Subject: [PATCH 22/22] Update version to v0.20.1 --- mythril/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mythril/version.py b/mythril/version.py index 5dcd9e2c..fbb49d37 100644 --- a/mythril/version.py +++ b/mythril/version.py @@ -4,4 +4,4 @@ This file is suitable for sourcing inside POSIX shell, e.g. bash as well as for importing into Python. """ -VERSION = "v0.20.0" # NOQA +VERSION = "v0.20.1" # NOQA