diff --git a/README.md b/README.md index 67127df9..a017d155 100644 --- a/README.md +++ b/README.md @@ -12,9 +12,10 @@ [![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. +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: -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). +- [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. diff --git a/mythril/analysis/report.py b/mythril/analysis/report.py index 46795b8d..06c15c30 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 @@ -106,6 +107,17 @@ class Issue: return issue + def _set_internal_compiler_error(self): + """ + Adds the false positive to description and changes severity to low + """ + self.severity = "Low" + self.description_tail += ( + " This issue is reported for internal compiler generated code." + ) + self.description = "%s\n%s" % (self.description_head, self.description_tail) + self.code = "" + def add_code_info(self, contract): """ @@ -118,6 +130,8 @@ class Issue: self.filename = codeinfo.filename self.code = codeinfo.code self.lineno = codeinfo.lineno + if self.lineno is None: + self._set_internal_compiler_error() self.source_mapping = codeinfo.solc_mapping else: self.source_mapping = self.address @@ -130,7 +144,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: @@ -140,6 +154,7 @@ class Report: self.solc_version = "" self.meta = {} self.source = source or Source() + self.exceptions = exceptions or [] def sorted_issues(self): """ @@ -177,6 +192,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. @@ -211,14 +234,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/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/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() diff --git a/mythril/disassembler/asm.py b/mythril/disassembler/asm.py index cbbe1881..905b8d85 100644 --- a/mythril/disassembler/asm.py +++ b/mythril/disassembler/asm.py @@ -4,12 +4,12 @@ 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*)$") # 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/interfaces/cli.py b/mythril/interfaces/cli.py index 7ea614b8..c51e8b2a 100644 --- a/mythril/interfaces/cli.py +++ b/mythril/interfaces/cli.py @@ -10,6 +10,7 @@ import json import logging import os import sys +import traceback import coloredlogs @@ -31,17 +32,47 @@ 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() -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") @@ -227,25 +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 @@ -298,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, @@ -476,16 +432,107 @@ 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: + exit_with_error(args.outform, traceback.format_exc()) if __name__ == "__main__": 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 161e742a..09152f80 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]: """ @@ -1671,6 +1713,25 @@ 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 + 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] + @StateTransition() def return_(self, global_state: GlobalState): """ 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): """ 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), } 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..05081137 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,6 +211,38 @@ 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) -> "BitVec": + """ + Handles 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 + ) + union = self.annotations + other.annotations + 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) + def _comparison_helper( a: BitVec, b: BitVec, operation: Callable, default_value: bool, inputs_equal: bool @@ -254,6 +286,10 @@ def _arithmetic_helper(a: BitVec, b: BitVec, operation: Callable) -> BitVec: return BitVec(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: """Create an if-then-else expression. 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/mythril.py b/mythril/mythril.py index 4654b235..872f23ae 100644 --- a/mythril/mythril.py +++ b/mythril/mythril.py @@ -570,6 +570,7 @@ class Mythril(object): """ all_issues = [] SolverStatistics().enabled = True + exceptions = [] for contract in contracts or self.contracts: StartTime() # Reinitialize start time for new contracts try: @@ -600,7 +601,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) @@ -610,7 +611,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) 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/opcodes.py b/mythril/support/opcodes.py new file mode 100644 index 00000000..d70f0309 --- /dev/null +++ b/mythril/support/opcodes.py @@ -0,0 +1,94 @@ +# 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 +} # 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) + +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 diff --git a/mythril/support/truffle.py b/mythril/support/truffle.py index 800b6fca..b42b1e10 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") @@ -181,7 +194,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)) 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 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..2a4f75fb 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; } @@ -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; } 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 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. --------------------