diff --git a/mythril/analysis/modules/base.py b/mythril/analysis/modules/base.py index 800f0437..072f74e9 100644 --- a/mythril/analysis/modules/base.py +++ b/mythril/analysis/modules/base.py @@ -34,7 +34,6 @@ class DetectionModule: ) self.entrypoint = entrypoint self._issues = [] - self._cache_addresses = {} @property def issues(self): @@ -45,10 +44,9 @@ class DetectionModule: def reset_module(self): """ - Resets issues and cache addresses + Resets issues """ self._issues = [] - self._cache_addresses = {} def execute(self, statespace): """The entry point for execution, which is being called by Mythril. diff --git a/mythril/analysis/modules/delegatecall.py b/mythril/analysis/modules/delegatecall.py index 3ed77a3a..596f8ce5 100644 --- a/mythril/analysis/modules/delegatecall.py +++ b/mythril/analysis/modules/delegatecall.py @@ -82,17 +82,16 @@ def _concrete_call( address=address, swc_id=DELEGATECALL_TO_UNTRUSTED_CONTRACT, bytecode=state.environment.code.bytecode, - title="Call data forwarded with delegatecall()", - _type="Informational", + title="Delegatecall Proxy", + severity="Low", + description_head="The contract implements a delegatecall proxy.", + description_tail="The smart contract forwards the received calldata via delegatecall. Note that callers" + "can execute arbitrary functions in the callee contract and that the callee contract " + "can access the storage of the calling contract. " + "Make sure that the callee contract is audited properly.", gas_used=(state.mstate.min_gas_used, state.mstate.max_gas_used), ) - issue.description = ( - "This contract forwards its call data via DELEGATECALL in its fallback function. " - "This means that any function in the called contract can be executed. Note that the callee contract will have " - "access to the storage of the calling contract.\n" - ) - target = hex(call.to.val) if call.to.type == VarType.CONCRETE else str(call.to) issue.description += "DELEGATECALL target: {}".format(target) diff --git a/mythril/analysis/modules/dependence_on_predictable_vars.py b/mythril/analysis/modules/dependence_on_predictable_vars.py index db6756fc..632672b8 100644 --- a/mythril/analysis/modules/dependence_on_predictable_vars.py +++ b/mythril/analysis/modules/dependence_on_predictable_vars.py @@ -8,7 +8,7 @@ from mythril.analysis.call_helpers import get_call_from_state from mythril.analysis.modules.base import DetectionModule from mythril.analysis.ops import Call, VarType from mythril.analysis.report import Issue -from mythril.analysis.swc_data import PREDICTABLE_VARS_DEPENDENCE, TIMESTAMP_DEPENDENCE +from mythril.analysis.swc_data import TIMESTAMP_DEPENDENCE, WEAK_RANDOMNESS from mythril.exceptions import UnsatError from mythril.laser.ethereum.state.global_state import GlobalState @@ -23,7 +23,7 @@ class PredictableDependenceModule(DetectionModule): """""" super().__init__( name="Dependence of Predictable Variables", - swc_id="{} {}".format(TIMESTAMP_DEPENDENCE, PREDICTABLE_VARS_DEPENDENCE), + swc_id="{} {}".format(TIMESTAMP_DEPENDENCE, WEAK_RANDOMNESS), description=( "Check for CALLs that send >0 Ether as a result of computation " "based on predictable variables such as block.coinbase, " @@ -67,8 +67,9 @@ def _analyze_states(state: GlobalState) -> list: address = call.state.get_current_instruction()["address"] - description = "In the function `" + call.node.function_name + "` " - description += "the following predictable state variables are used to determine Ether recipient:\n" + description = ( + "The contract sends Ether depending on the values of the following variables:\n" + ) # First check: look for predictable state variables in node & call recipient constraints @@ -84,20 +85,24 @@ def _analyze_states(state: GlobalState) -> list: for item in found: description += "- block.{}\n".format(item) if solve(call): - swc_type = ( - TIMESTAMP_DEPENDENCE - if item == "timestamp" - else PREDICTABLE_VARS_DEPENDENCE + swc_id = TIMESTAMP_DEPENDENCE if item == "timestamp" else WEAK_RANDOMNESS + + description += ( + "Note that the values of variables like coinbase, gaslimit, block number and timestamp " + "are predictable and/or can be manipulated by a malicious miner. " + "Don't use them for random number generation or to make critical decisions." ) + issue = Issue( contract=call.node.contract_name, function_name=call.node.function_name, address=address, - swc_id=swc_type, + swc_id=swc_id, bytecode=call.state.environment.code.bytecode, title="Dependence on predictable environment variable", - _type="Warning", - description=description, + severity="Low", + description_head="Sending of Ether depends on a predictable variable.", + description_tail=description, gas_used=( call.state.mstate.min_gas_used, call.state.mstate.max_gas_used, @@ -109,7 +114,6 @@ def _analyze_states(state: GlobalState) -> list: for constraint in call.node.constraints[:] + [call.to]: if "blockhash" in str(constraint): - description = "In the function `" + call.node.function_name + "` " if "number" in str(constraint): m = re.search(r"blockhash\w+(\s-\s(\d+))*", str(constraint)) if m and solve(call): @@ -117,8 +121,8 @@ def _analyze_states(state: GlobalState) -> list: found = m.group(1) if found: # block.blockhash(block.number - N) - description += ( - "predictable expression 'block.blockhash(block.number - " + description = ( + "The predictable expression 'block.blockhash(block.number - " + m.group(2) + ")' is used to determine Ether recipient" ) @@ -129,13 +133,13 @@ def _analyze_states(state: GlobalState) -> list: elif "storage" in str( constraint ): # block.blockhash(block.number - storage_0) - description += ( - "predictable expression 'block.blockhash(block.number - " + description = ( + "The predictable expression 'block.blockhash(block.number - " + "some_storage_var)' is used to determine Ether recipient" ) else: # block.blockhash(block.number) - description += ( - "predictable expression 'block.blockhash(block.number)'" + description = ( + "The predictable expression 'block.blockhash(block.number)'" + " is used to determine Ether recipient" ) description += ", this expression will always be equal to zero." @@ -145,10 +149,11 @@ def _analyze_states(state: GlobalState) -> list: function_name=call.node.function_name, address=address, bytecode=call.state.environment.code.bytecode, - title="Dependence on predictable variable", - _type="Warning", - description=description, - swc_id=PREDICTABLE_VARS_DEPENDENCE, + title="Dependence on Predictable Variable", + severity="Low", + description_head="Sending of Ether depends on the blockhash.", + description_tail=description, + swc_id=WEAK_RANDOMNESS, gas_used=( call.state.mstate.min_gas_used, call.state.mstate.max_gas_used, @@ -174,19 +179,22 @@ def _analyze_states(state: GlobalState) -> list: index = r.group(1) if index and solve(call): - description += ( - "block.blockhash() is calculated using a value from storage " - "at index {}".format(index) + description = ( + "A block hash is calculated using the block.blockhash(uint blockNumber) method. " + "The block number is obtained from storage index {}".format( + index + ) ) issue = Issue( contract=call.node.contract_name, function_name=call.node.function_name, address=address, bytecode=call.state.environment.code.bytecode, - title="Dependence on predictable variable", - _type="Informational", - description=description, - swc_id=PREDICTABLE_VARS_DEPENDENCE, + title="Dependence on Predictable Variable", + severity="Low", + description_head="Sending of Ether depends on the blockhash.", + description_tail=description, + swc_id=WEAK_RANDOMNESS, gas_used=( call.state.mstate.min_gas_used, call.state.mstate.max_gas_used, diff --git a/mythril/analysis/modules/deprecated_ops.py b/mythril/analysis/modules/deprecated_ops.py index f362edbf..9eca59c4 100644 --- a/mythril/analysis/modules/deprecated_ops.py +++ b/mythril/analysis/modules/deprecated_ops.py @@ -24,8 +24,10 @@ def _analyze_state(state): if instruction["opcode"] == "ORIGIN": log.debug("ORIGIN in function " + node.function_name) title = "Use of tx.origin" - description = ( - "The function `{}` retrieves the transaction origin (tx.origin) using the ORIGIN opcode. " + description_head = "Use of tx.origin is deprecated." + description_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".format( node.function_name @@ -36,9 +38,11 @@ def _analyze_state(state): elif instruction["opcode"] == "CALLCODE": log.debug("CALLCODE in function " + node.function_name) title = "Use of callcode" - description = ( - "The function `{}` uses callcode. Callcode does not persist sender or value over the call. " - "Use delegatecall instead.".format(node.function_name) + description_head = "Use of callcode is deprecated." + description_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." ) swc_id = DEPRICATED_FUNCTIONS_USAGE @@ -48,9 +52,10 @@ def _analyze_state(state): address=instruction["address"], title=title, bytecode=state.environment.code.bytecode, - _type="Warning", swc_id=swc_id, - description=description, + severity="Medium", + description_head=description_head, + description_tail=description_tail, gas_used=(state.mstate.min_gas_used, state.mstate.max_gas_used), ) return [issue] diff --git a/mythril/analysis/modules/ether_thief.py b/mythril/analysis/modules/ether_thief.py index 20258a71..ccdb5167 100644 --- a/mythril/analysis/modules/ether_thief.py +++ b/mythril/analysis/modules/ether_thief.py @@ -1,6 +1,7 @@ """This module contains the detection code for unauthorized ether withdrawal.""" import logging +import json from copy import copy from mythril.analysis import solver @@ -40,6 +41,15 @@ class EtherThief(DetectionModule): entrypoint="callback", pre_hooks=["CALL"], ) + self._cache_addresses = {} + + def reset_module(self): + """ + Resets the module by clearing everything + :return: + """ + super().reset_module() + self._cache_addresses = {} def execute(self, state: GlobalState): """ @@ -88,17 +98,18 @@ class EtherThief(DetectionModule): transaction_sequence = solver.get_transaction_sequence(state, constraints) - debug = str(transaction_sequence) + debug = json.dumps(transaction_sequence, indent=4) issue = Issue( contract=node.contract_name, function_name=node.function_name, - address=address, + address=instruction["address"], swc_id=UNPROTECTED_ETHER_WITHDRAWAL, - title="Ether thief", - _type="Warning", + title="Unprotected Ether Withdrawal", + severity="High", bytecode=state.environment.code.bytecode, - description="Arbitrary senders other than the contract creator can withdraw ETH from the contract" + description_head="Anyone can withdraw ETH from the contract account.", + description_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.", debug=debug, diff --git a/mythril/analysis/modules/exceptions.py b/mythril/analysis/modules/exceptions.py index 971f3fe4..d819d0ea 100644 --- a/mythril/analysis/modules/exceptions.py +++ b/mythril/analysis/modules/exceptions.py @@ -1,5 +1,6 @@ """This module contains the detection code for reachable exceptions.""" import logging +import json from mythril.analysis import solver from mythril.analysis.modules.base import DetectionModule @@ -25,24 +26,26 @@ def _analyze_state(state) -> list: try: address = state.get_current_instruction()["address"] - description = ( - "A reachable exception (opcode 0xfe) has been detected. " - "This can be caused by type errors, division by zero, " + description_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." ) - debug = str(solver.get_transaction_sequence(state, node.constraints)) + transaction_sequence = solver.get_transaction_sequence(state, node.constraints) + debug = json.dumps(transaction_sequence, indent=4) issue = Issue( contract=node.contract_name, function_name=node.function_name, address=address, swc_id=ASSERT_VIOLATION, - title="Exception state", - _type="Informational", - description=description, + title="Exception State", + severity="Low", + description_head="A reachable exception has been detected.", + description_tail=description_tail, bytecode=state.environment.code.bytecode, debug=debug, gas_used=(state.mstate.min_gas_used, state.mstate.max_gas_used), diff --git a/mythril/analysis/modules/external_calls.py b/mythril/analysis/modules/external_calls.py index 2cf7b6a0..09828267 100644 --- a/mythril/analysis/modules/external_calls.py +++ b/mythril/analysis/modules/external_calls.py @@ -9,6 +9,7 @@ from mythril.laser.smt import UGT, symbol_factory from mythril.laser.ethereum.state.global_state import GlobalState from mythril.exceptions import UnsatError import logging +import json log = logging.getLogger(__name__) @@ -45,11 +46,13 @@ def _analyze_state(state): constraints += [to == 0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF] transaction_sequence = solver.get_transaction_sequence(state, constraints) - debug = str(transaction_sequence) - description = ( - "The contract executes a function call with high gas to a user-supplied address. " - "Note that the callee can contain arbitrary code and may re-enter any function in this contract. " - "Review the business logic carefully to prevent unanticipated effects on the contract state." + debug = json.dumps(transaction_sequence, indent=4) + description_head = "A call to a user-supplied address is executed." + description_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." ) issue = Issue( @@ -57,10 +60,11 @@ def _analyze_state(state): function_name=node.function_name, address=address, swc_id=REENTRANCY, - title="External call to user-supplied address", - _type="Warning", + title="External Call To User-Supplied Address", bytecode=state.environment.code.bytecode, - description=description, + severity="Medium", + description_head=description_head, + description_tail=description_tail, debug=debug, gas_used=(state.mstate.min_gas_used, state.mstate.max_gas_used), ) @@ -71,10 +75,11 @@ def _analyze_state(state): "[EXTERNAL_CALLS] Callee address cannot be modified. Reporting informational issue." ) - debug = str(transaction_sequence) - description = ( - "The contract executes a function call to an external address. " - "Verify that the code at this address is trusted and immutable." + debug = json.dumps(transaction_sequence, indent=4) + description_head = "The contract executes an external message call." + description_tail = ( + "An external function call to a fixed contract address is executed. Make sure " + "that the callee contract has been reviewed carefully." ) issue = Issue( @@ -82,10 +87,11 @@ def _analyze_state(state): function_name=state.node.function_name, address=address, swc_id=REENTRANCY, - title="External call", - _type="Informational", + title="External Call To Fixed Address", bytecode=state.environment.code.bytecode, - description=description, + severity="Low", + description_head=description_head, + description_tail=description_tail, debug=debug, gas_used=(state.mstate.min_gas_used, state.mstate.max_gas_used), ) diff --git a/mythril/analysis/modules/integer.py b/mythril/analysis/modules/integer.py index 53265657..c11b40ed 100644 --- a/mythril/analysis/modules/integer.py +++ b/mythril/analysis/modules/integer.py @@ -1,14 +1,15 @@ """This module contains the detection code for integer overflows and underflows.""" + +import json + from mythril.analysis import solver from mythril.analysis.report import Issue from mythril.analysis.swc_data import INTEGER_OVERFLOW_AND_UNDERFLOW from mythril.exceptions import UnsatError from mythril.laser.ethereum.state.global_state import GlobalState -from mythril.laser.ethereum.taint_analysis import TaintRunner from mythril.analysis.modules.base import DetectionModule - from mythril.laser.smt import ( BVAddNoOverflow, BVSubNoUnderflow, @@ -19,7 +20,6 @@ from mythril.laser.smt import ( Expression, ) -import copy import logging @@ -49,6 +49,17 @@ class IntegerOverflowUnderflowModule(DetectionModule): entrypoint="callback", pre_hooks=["ADD", "MUL", "SUB", "SSTORE", "JUMPI"], ) + self._overflow_cache = {} + self._underflow_cache = {} + + def reset_module(self): + """ + Resets the module + :return: + """ + super().reset_module() + self._overflow_cache = {} + self._underflow_cache = {} def execute(self, state: GlobalState): """Executes analysis module for integer underflow and integer overflow. @@ -56,6 +67,11 @@ class IntegerOverflowUnderflowModule(DetectionModule): :param state: Statespace to analyse :return: Found issues """ + address = _get_address_from_state(state) + has_overflow = self._overflow_cache.get(address, False) + has_underflow = self._underflow_cache.get(address, False) + if has_overflow or has_underflow: + return if state.get_current_instruction()["opcode"] == "ADD": self._handle_add(state) elif state.get_current_instruction()["opcode"] == "MUL": @@ -80,7 +96,7 @@ class IntegerOverflowUnderflowModule(DetectionModule): if model is None: return - annotation = OverUnderflowAnnotation(state, "add", c) + annotation = OverUnderflowAnnotation(state, "addition", c) op0.annotate(annotation) def _handle_mul(self, state): @@ -97,7 +113,7 @@ class IntegerOverflowUnderflowModule(DetectionModule): if model is None: return - annotation = OverUnderflowAnnotation(state, "multiply", c) + annotation = OverUnderflowAnnotation(state, "multiplication", c) op0.annotate(annotation) def _handle_sub(self, state): @@ -124,46 +140,82 @@ class IntegerOverflowUnderflowModule(DetectionModule): stack[index] = symbol_factory.BitVecVal(value, 256) return stack[index] + @staticmethod + def _get_description_head(annotation, _type): + return "The binary {} can {}.".format(annotation.operator, _type.lower()) + + @staticmethod + def _get_description_tail(annotation, _type): + + return ( + "The operands of the {} operation are not sufficiently constrained. " + "The {} could therefore result in an integer {}. Prevent the {} by checking inputs " + "or ensure sure that the {} is caught by an assertion.".format( + annotation.operator, + annotation.operator, + _type.lower(), + _type.lower(), + _type.lower(), + ) + ) + + @staticmethod + def _get_title(_type): + return "Integer {}".format(_type) + def _handle_sstore(self, state): stack = state.mstate.stack value = stack[-2] if not isinstance(value, Expression): return - for annotation in value.annotations: if not isinstance(annotation, OverUnderflowAnnotation): continue - title = ( - "Integer Underflow" - if annotation.operator == "subtraction" - else "Integer Overflow" - ) + _type = "Underflow" if annotation.operator == "subtraction" else "Overflow" ostate = annotation.overflowing_state node = ostate.node + issue = Issue( contract=node.contract_name, function_name=node.function_name, address=ostate.get_current_instruction()["address"], swc_id=INTEGER_OVERFLOW_AND_UNDERFLOW, bytecode=ostate.environment.code.bytecode, - title=title, - _type="Warning", + title=self._get_title(_type), + severity="High", + description_head=self._get_description_head(annotation, _type), + description_tail=self._get_description_tail(annotation, _type), gas_used=(state.mstate.min_gas_used, state.mstate.max_gas_used), ) - issue.description = "This binary {} operation can result in {}.\n".format( - annotation.operator, title.lower() - ) + address = _get_address_from_state(ostate) + + if annotation.operator == "subtraction" and self._underflow_cache.get( + address, False + ): + continue + if annotation.operator != "subtraction" and self._overflow_cache.get( + address, False + ): + continue + try: - issue.debug = str( - solver.get_transaction_sequence( - state, node.constraints + [annotation.constraint] - ) + + transaction_sequence = solver.get_transaction_sequence( + state, node.constraints + [annotation.constraint] ) + + issue.debug = json.dumps(transaction_sequence, indent=4) + except UnsatError: - return + continue + if annotation.operator == "subtraction": + self._underflow_cache[address] = True + else: + self._overflow_cache[address] = True + self._issues.append(issue) def _handle_jumpi(self, state): @@ -175,34 +227,48 @@ class IntegerOverflowUnderflowModule(DetectionModule): continue ostate = annotation.overflowing_state node = ostate.node - title = ( - "Integer Underflow" - if annotation.operator == "subtraction" - else "Integer Overflow" - ) + _type = "Underflow" if annotation.operator == "subtraction" else "Overflow" issue = Issue( contract=node.contract_name, function_name=node.function_name, address=ostate.get_current_instruction()["address"], swc_id=INTEGER_OVERFLOW_AND_UNDERFLOW, bytecode=ostate.environment.code.bytecode, - title=title, - _type="Warning", + title=self._get_title(_type), + severity="High", + description_head=self._get_description_head(annotation, _type), + description_tail=self._get_description_tail(annotation, _type), gas_used=(state.mstate.min_gas_used, state.mstate.max_gas_used), ) - issue.description = "This binary {} operation can result in integer overflow.\n".format( - annotation.operator - ) + address = _get_address_from_state(ostate) + + if annotation.operator == "subtraction" and self._underflow_cache.get( + address, False + ): + continue + + if annotation.operator != "subtraction" and self._overflow_cache.get( + address, False + ): + continue + try: - issue.debug = str( - solver.get_transaction_sequence( - state, node.constraints + [annotation.constraint] - ) + + transaction_sequence = solver.get_transaction_sequence( + state, node.constraints + [annotation.constraint] ) + + issue.debug = json.dumps(transaction_sequence, indent=4) + except UnsatError: - return + continue + + if annotation.operator == "subtraction": + self._underflow_cache[address] = True + else: + self._overflow_cache[address] = True self._issues.append(issue) @staticmethod @@ -218,3 +284,7 @@ class IntegerOverflowUnderflowModule(DetectionModule): detector = IntegerOverflowUnderflowModule() + + +def _get_address_from_state(state): + return state.get_current_instruction()["address"] diff --git a/mythril/analysis/modules/multiple_sends.py b/mythril/analysis/modules/multiple_sends.py index da1a84c2..04a74bce 100644 --- a/mythril/analysis/modules/multiple_sends.py +++ b/mythril/analysis/modules/multiple_sends.py @@ -71,28 +71,34 @@ def _analyze_state(state: GlobalState): else: # RETURN or STOP if len(calls) > 1: + + description_tail = ( + "Consecutive calls are executed at the following bytecode offsets:\n" + ) + + for call in calls: + description_tail += "Offset: {}\n".format( + call.state.get_current_instruction()["address"] + ) + + description_tail += ( + "Try to isolate each external call into its own transaction," + " as external calls can fail accidentally or deliberately.\n" + ) + issue = Issue( contract=node.contract_name, function_name=node.function_name, address=instruction["address"], swc_id=MULTIPLE_SENDS, bytecode=state.environment.code.bytecode, - title="Multiple Calls", - _type="Informational", + title="Multiple Calls in a Single Transaction", + severity="Medium", + description_head="Multiple sends are executed in one transaction.", + description_tail=description_tail, gas_used=(state.mstate.min_gas_used, state.mstate.max_gas_used), ) - issue.description = ( - "Multiple sends are executed in a single transaction. " - "Try to isolate each external call into its own transaction," - " as external calls can fail accidentally or deliberately.\nConsecutive calls: \n" - ) - - for call in calls: - issue.description += "Call at address: {}\n".format( - call.state.get_current_instruction()["address"] - ) - return [issue] return [] diff --git a/mythril/analysis/modules/suicide.py b/mythril/analysis/modules/suicide.py index 4f5eb28f..62ea87eb 100644 --- a/mythril/analysis/modules/suicide.py +++ b/mythril/analysis/modules/suicide.py @@ -5,6 +5,7 @@ from mythril.exceptions import UnsatError from mythril.analysis.modules.base import DetectionModule from mythril.laser.ethereum.state.global_state import GlobalState import logging +import json log = logging.getLogger(__name__) @@ -14,62 +15,27 @@ For kill-able contracts, also check whether it is possible to direct the contrac """ -def _analyze_state(state): - log.info("Suicide module: Analyzing suicide instruction") - node = state.node - instruction = state.get_current_instruction() - to = state.mstate.stack[-1] - - log.debug("[SUICIDE] SUICIDE in function " + node.function_name) - - try: - try: - transaction_sequence = solver.get_transaction_sequence( - state, - node.constraints + [to == 0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF], - ) - description = "Anyone can kill this contract and withdraw its balance to their own account." - except UnsatError: - transaction_sequence = solver.get_transaction_sequence( - state, node.constraints - ) - description = ( - "The contract can be killed by anyone. Don't accidentally kill it." - ) - - debug = str(transaction_sequence) - - issue = Issue( - contract=node.contract_name, - function_name=node.function_name, - address=instruction["address"], - swc_id=UNPROTECTED_SELFDESTRUCT, - bytecode=state.environment.code.bytecode, - title="Unchecked SUICIDE", - _type="Warning", - description=description, - debug=debug, - gas_used=(state.mstate.min_gas_used, state.mstate.max_gas_used), - ) - return [issue] - except UnsatError: - log.info("[UNCHECKED_SUICIDE] no model found") - - return [] - - class SuicideModule(DetectionModule): """This module checks if the contact can be 'accidentally' killed by anyone.""" def __init__(self): super().__init__( - name="Unprotected Suicide", + name="Unprotected Selfdestruct", swc_id=UNPROTECTED_SELFDESTRUCT, description=DESCRIPTION, entrypoint="callback", pre_hooks=["SUICIDE"], ) + self._cache_address = {} + + def reset_module(self): + """ + Resets the module + :return: + """ + super().reset_module() + self._cache_address = {} def execute(self, state: GlobalState): """ @@ -77,8 +43,59 @@ class SuicideModule(DetectionModule): :param state: :return: """ - self._issues.extend(_analyze_state(state)) + self._issues.extend(self._analyze_state(state)) return self.issues + def _analyze_state(self, state): + log.info("Suicide module: Analyzing suicide instruction") + node = state.node + instruction = state.get_current_instruction() + if self._cache_address.get(instruction["address"], False): + return [] + to = state.mstate.stack[-1] + + log.debug("[SUICIDE] SUICIDE in function " + node.function_name) + + description_head = "The contract can be killed by anyone." + + try: + try: + transaction_sequence = solver.get_transaction_sequence( + state, + node.constraints + + [to == 0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF], + ) + description_tail = "Arbitrary senders can kill this contract and withdraw its balance to their own account." + except UnsatError: + transaction_sequence = solver.get_transaction_sequence( + state, node.constraints + ) + description_tail = ( + "Arbitrary senders can kill this contract but it is not possible to set the target address to which" + "the contract balance is sent." + ) + + debug = json.dumps(transaction_sequence, indent=4) + self._cache_address[instruction["address"]] = True + + issue = Issue( + contract=node.contract_name, + function_name=node.function_name, + address=instruction["address"], + swc_id=UNPROTECTED_SELFDESTRUCT, + bytecode=state.environment.code.bytecode, + title="Unprotected Selfdestruct", + severity="High", + description_head=description_head, + description_tail=description_tail, + debug=debug, + gas_used=(state.mstate.min_gas_used, state.mstate.max_gas_used), + ) + return [issue] + except UnsatError: + log.info("[UNCHECKED_SUICIDE] no model found") + + return [] + detector = SuicideModule() diff --git a/mythril/analysis/modules/transaction_order_dependence.py b/mythril/analysis/modules/transaction_order_dependence.py index 3f5eb4e0..4759d751 100644 --- a/mythril/analysis/modules/transaction_order_dependence.py +++ b/mythril/analysis/modules/transaction_order_dependence.py @@ -46,6 +46,11 @@ class TxOrderDependenceModule(DetectionModule): self._get_influencing_sstores(statespace, interesting_storages) ) + description_tail = ( + "A transaction order dependence vulnerability may exist in this contract. The value or " + "target of the call statement is loaded from a writable storage location." + ) + # Build issue if necessary if len(changing_sstores) > 0: node = call.node @@ -54,20 +59,18 @@ class TxOrderDependenceModule(DetectionModule): contract=node.contract_name, function_name=node.function_name, address=instruction["address"], - title="Transaction order dependence", + title="Transaction Order Dependence", bytecode=call.state.environment.code.bytecode, swc_id=TX_ORDER_DEPENDENCE, - _type="Warning", + severity="Medium", + description_head="The call outcome may depend on transaction order.", + description_tail=description_tail, gas_used=( call.state.mstate.min_gas_used, call.state.mstate.max_gas_used, ), ) - issue.description = ( - "Possible transaction order dependence vulnerability: The value or " - "direction of the call statement is determined from a tainted storage location." - ) issues.append(issue) return issues diff --git a/mythril/analysis/modules/unchecked_retval.py b/mythril/analysis/modules/unchecked_retval.py index dd8bdc04..70d7f0fd 100644 --- a/mythril/analysis/modules/unchecked_retval.py +++ b/mythril/analysis/modules/unchecked_retval.py @@ -71,24 +71,29 @@ def _analyze_state(state: GlobalState) -> list: issues = [] for retval in retvals: try: - model = solver.get_model(node.constraints + [retval["retval"] == 0]) + solver.get_model(node.constraints + [retval["retval"] == 0]) except UnsatError: continue + description_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." + ) + issue = Issue( contract=node.contract_name, function_name=node.function_name, address=retval["address"], bytecode=state.environment.code.bytecode, - title="Unchecked CALL return value", + title="Unchecked Call Return Value", swc_id=UNCHECKED_RET_VAL, + severity="Low", + description_head="The return value of a message call is not checked.", + description_tail=description_tail, gas_used=(state.mstate.min_gas_used, state.mstate.max_gas_used), ) - issue.description = ( - "The return value of an external call is not checked. " - "Note that execution continue even if the called contract throws." - ) issues.append(issue) return issues diff --git a/mythril/analysis/report.py b/mythril/analysis/report.py index 02656879..a8e77db5 100644 --- a/mythril/analysis/report.py +++ b/mythril/analysis/report.py @@ -6,6 +6,11 @@ from jinja2 import PackageLoader, Environment import _pysha3 as sha3 import hashlib +from mythril.solidity.soliditycontract import SolidityContract +from mythril.analysis.swc_data import SWC_TO_TITLE +from mythril.support.source_support import Source + + log = logging.getLogger(__name__) @@ -21,8 +26,9 @@ class Issue: title, bytecode, gas_used=(None, None), - _type="Informational", - description="", + severity=None, + description_head="", + description_tail="", debug="", ): """ @@ -42,14 +48,17 @@ class Issue: self.contract = contract self.function = function_name self.address = address - self.description = description - self.type = _type + self.description_head = description_head + self.description_tail = description_tail + self.description = "%s\n%s" % (description_head, description_tail) + self.severity = severity self.debug = debug self.swc_id = swc_id self.min_gas_used, self.max_gas_used = gas_used self.filename = None self.code = None self.lineno = None + self.source_mapping = None try: keccak = sha3.keccak_256() @@ -73,11 +82,12 @@ class Issue: "contract": self.contract, "description": self.description, "function": self.function, - "type": self.type, + "severity": self.severity, "address": self.address, "debug": self.debug, "min_gas_used": self.min_gas_used, "max_gas_used": self.max_gas_used, + "sourceMap": self.source_mapping, } if self.filename and self.lineno: @@ -94,13 +104,16 @@ class Issue: :param contract: """ - if self.address: + if self.address and isinstance(contract, SolidityContract): codeinfo = contract.get_source_info( self.address, constructor=(self.function == "constructor") ) self.filename = codeinfo.filename self.code = codeinfo.code self.lineno = codeinfo.lineno + self.source_mapping = codeinfo.solc_mapping + else: + self.source_mapping = self.address class Report: @@ -110,14 +123,16 @@ class Report: loader=PackageLoader("mythril.analysis"), trim_blocks=True ) - def __init__(self, verbose=False): + def __init__(self, verbose=False, source=None): """ :param verbose: """ self.issues = {} self.verbose = verbose - pass + self.solc_version = "" + self.meta = {} + self.source = source or Source() def sorted_issues(self): """ @@ -160,16 +175,44 @@ class Report: :return: """ - result = { - "issues": [ + _issues = [] + source_list = [] + + for key, issue in self.issues.items(): + + if issue.bytecode_hash not in source_list: + idx = len(source_list) + source_list.append(issue.bytecode_hash) + else: + idx = source_list.index(issue.bytecode_hash) + + try: + title = SWC_TO_TITLE[issue.swc_id] + except KeyError: + title = "Unspecified Security Issue" + + _issues.append( { - "swc-id": "SWC-{}".format(issue.swc_id), - "bytecodeOffset": issue.address, - "codeHash": issue.bytecode_hash, + "swcID": "SWC-" + issue.swc_id, + "swcTitle": title, + "description": { + "head": issue.description_head, + "tail": issue.description_tail, + }, + "severity": issue.severity, + "locations": [{"sourceMap": "%d:1:%d" % (issue.address, idx)}], + "extra": {}, } - for issue in self.issues.values() - ] + ) + + result = { + "issues": _issues, + "sourceType": "raw-bytecode", + "sourceFormat": "evm-byzantium-bytecode", + "sourceList": source_list, + "meta": {}, } + return json.dumps(result, sort_keys=True) def as_markdown(self): diff --git a/mythril/analysis/security.py b/mythril/analysis/security.py index 051da44d..d8e804db 100644 --- a/mythril/analysis/security.py +++ b/mythril/analysis/security.py @@ -28,6 +28,7 @@ def get_detection_module_hooks(modules, hook_type="pre"): if hook_type == "pre" else module.detector.post_hooks ) + for op_code in map(lambda x: x.upper(), hooks): if op_code in OPCODE_LIST: hook_dict[op_code].append(module.detector.execute) diff --git a/mythril/analysis/swc_data.py b/mythril/analysis/swc_data.py index 3a4f3bed..0462d482 100644 --- a/mythril/analysis/swc_data.py +++ b/mythril/analysis/swc_data.py @@ -17,13 +17,47 @@ MULTIPLE_SENDS = "113" TX_ORDER_DEPENDENCE = "114" TX_ORIGIN_USAGE = "115" TIMESTAMP_DEPENDENCE = "116" -# TODO: SWC ID 116 is missing, Add it if it's added to the https://github.com/SmartContractSecurity/SWC-registry INCORRECT_CONSTRUCTOR_NAME = "118" SHADOWING_STATE_VARIABLES = "119" WEAK_RANDOMNESS = "120" SIGNATURE_REPLAY = "121" IMPROPER_VERIFICATION_BASED_ON_MSG_SENDER = "122" +REQUIREMENT_VIOLATION = "123" +WRITE_TO_ARBITRARY_STORAGE = "124" +INCORRECT_INHERITANCE_ORDER = "125" +ARBITRARY_JUMP = "127" +DOS_WITH_BLOCK_GAS_LIMIT = "128" +TYPOGRAPHICAL_ERROR = "129" -PREDICTABLE_VARS_DEPENDENCE = ( - "N/A" -) # TODO: Add the swc id when this is added to the SWC Registry + +SWC_TO_TITLE = { + "100": "Function Default Visibility", + "101": "Integer Overflow and Underflow", + "102": "Outdated Compiler Version", + "103": "Floating Pragma", + "104": "Unchecked Call Return Value", + "105": "Unprotected Ether Withdrawal", + "106": "Unprotected SELFDESTRUCT Instruction", + "107": "Reentrancy", + "108": "State Variable Default Visibility", + "109": "Uninitialized Storage Pointer", + "110": "Assert Violation", + "111": "Use of Deprecated Solidity Functions", + "112": "Delegatecall to Untrusted Callee", + "113": "DoS with Failed Call", + "114": "Transaction Order Dependence", + "115": "Authorization through tx.origin", + "116": "Timestamp Dependence", + "117": "Signature Malleability", + "118": "Incorrect Constructor Name", + "119": "Shadowing State Variables", + "120": "Weak Sources of Randomness from Chain Attributes", + "121": "Missing Protection against Signature Replay Attacks", + "122": "Lack of Proper Signature Verification", + "123": "Requirement Violation", + "124": "Write to Arbitrary Storage Location", + "125": "Incorrect Inheritance Order", + "127": "Arbitrary Jump with Function Type Variable", + "128": "DoS With Block Gas Limit", + "129": "Typographical Error", +} diff --git a/mythril/analysis/templates/report_as_markdown.jinja2 b/mythril/analysis/templates/report_as_markdown.jinja2 index b3efd687..e6952535 100644 --- a/mythril/analysis/templates/report_as_markdown.jinja2 +++ b/mythril/analysis/templates/report_as_markdown.jinja2 @@ -4,7 +4,7 @@ ## {{ issue.title }} - SWC ID: {{ issue['swc-id'] }} -- Type: {{ issue.type }} +- Severity: {{ issue.severity }} - Contract: {{ issue.contract | default("Unknown") }} - Function name: `{{ issue.function }}` - PC address: {{ issue.address }} diff --git a/mythril/analysis/templates/report_as_text.jinja2 b/mythril/analysis/templates/report_as_text.jinja2 index 05adda1b..08edb6cb 100644 --- a/mythril/analysis/templates/report_as_text.jinja2 +++ b/mythril/analysis/templates/report_as_text.jinja2 @@ -2,7 +2,7 @@ {% for issue in issues %} ==== {{ issue.title }} ==== SWC ID: {{ issue['swc-id'] }} -Type: {{ issue.type }} +Severity: {{ issue.severity }} Contract: {{ issue.contract | default("Unknown") }} Function name: {{ issue.function }} PC address: {{ issue.address }} @@ -20,7 +20,7 @@ In file: {{ issue.filename }}:{{ issue.lineno }} {% endif %} {% if verbose and issue.debug %} -------------------- -DEBUGGING INFORMATION: +Transaction Sequence: {{ issue.debug }} {% endif %} diff --git a/mythril/disassembler/disassembly.py b/mythril/disassembler/disassembly.py index e69e07b7..0d4828fc 100644 --- a/mythril/disassembler/disassembly.py +++ b/mythril/disassembler/disassembly.py @@ -78,7 +78,6 @@ def get_function_info( # Append with missing 0s at the beginning function_hash = "0x" + instruction_list[index]["argument"][2:].rjust(8, "0") - function_names = signature_database.get(function_hash) if len(function_names) > 1: # In this case there was an ambiguous result diff --git a/mythril/ethereum/evmcontract.py b/mythril/ethereum/evmcontract.py index 1a9fdbf2..47a87f83 100644 --- a/mythril/ethereum/evmcontract.py +++ b/mythril/ethereum/evmcontract.py @@ -1,6 +1,10 @@ """This module contains the class representing EVM contracts, aka Smart Contracts.""" import re +import _pysha3 as sha3 +import logging + +log = logging.getLogger(__name__) import persistent from ethereum import utils @@ -37,6 +41,38 @@ class EVMContract(persistent.Persistent): creation_code, enable_online_lookup=enable_online_lookup ) + @property + def bytecode_hash(self): + """ + + :return: runtime bytecode hash + """ + return self._get_hash(self.code[2:]) + + @property + def creation_bytecode_hash(self): + """ + + :return: Creation bytecode hash + """ + return self._get_hash(self.creation_code[2:]) + + @staticmethod + def _get_hash(code): + """ + :param code: bytecode + :return: Returns hash of the given bytecode + """ + try: + keccak = sha3.keccak_256() + keccak.update(bytes.fromhex(code[2:])) + return "0x" + keccak.hexdigest() + except ValueError: + log.debug( + "Unable to change the bytecode to bytes. Bytecode: {}".format(code) + ) + return "" + def as_dict(self): """ diff --git a/mythril/ethereum/util.py b/mythril/ethereum/util.py index db5fd8e1..ac80863b 100644 --- a/mythril/ethereum/util.py +++ b/mythril/ethereum/util.py @@ -32,11 +32,11 @@ def get_solc_json(file, solc_binary="solc", solc_args=None): :param solc_args: :return: """ + cmd = [solc_binary, "--combined-json", "bin,bin-runtime,srcmap,srcmap-runtime"] if solc_args: cmd.extend(solc_args.split()) - if not "--allow-paths" in cmd: cmd.extend(["--allow-paths", "."]) else: diff --git a/mythril/interfaces/cli.py b/mythril/interfaces/cli.py index c75d1b2f..772f52b9 100644 --- a/mythril/interfaces/cli.py +++ b/mythril/interfaces/cli.py @@ -114,10 +114,10 @@ def main(): outputs.add_argument( "-o", "--outform", - choices=["text", "markdown", "json"], + choices=["text", "markdown", "json", "jsonv2"], default="text", help="report output format", - metavar="", + metavar="", ) outputs.add_argument( "--verbose-report", @@ -431,6 +431,7 @@ def main(): ) outputs = { "json": report.as_json(), + "jsonv2": report.as_swc_standard_format(), "text": report.as_text(), "markdown": report.as_markdown(), } diff --git a/mythril/laser/ethereum/call.py b/mythril/laser/ethereum/call.py index a376443c..e99e60cd 100644 --- a/mythril/laser/ethereum/call.py +++ b/mythril/laser/ethereum/call.py @@ -4,6 +4,7 @@ parameters for the new global state.""" import logging from typing import Union, List +from z3 import Z3Exception from mythril.laser.ethereum import natives from mythril.laser.ethereum.gas import OPCODE_GAS @@ -178,19 +179,23 @@ def get_call_data( else memory_size ) + uses_entire_calldata = simplify( + memory_size - global_state.environment.calldata.calldatasize == 0 + ) + + if uses_entire_calldata == True: + return global_state.environment.calldata + try: calldata_from_mem = state.memory[ util.get_concrete_int(memory_start) : util.get_concrete_int( memory_start + memory_size ) ] - call_data = ConcreteCalldata(transaction_id, calldata_from_mem) - log.debug("Calldata: " + str(call_data)) + return ConcreteCalldata(transaction_id, calldata_from_mem) except TypeError: log.debug("Unsupported symbolic calldata offset") - call_data = SymbolicCalldata("{}_internalcall".format(transaction_id)) - - return call_data + return SymbolicCalldata(transaction_id) def native_call( diff --git a/mythril/laser/ethereum/svm.py b/mythril/laser/ethereum/svm.py index c2397f3d..9e8c06af 100644 --- a/mythril/laser/ethereum/svm.py +++ b/mythril/laser/ethereum/svm.py @@ -262,6 +262,7 @@ class LaserEVM: :return: """ instructions = global_state.environment.code.instruction_list + try: op_code = instructions[global_state.mstate.pc]["opcode"] except IndexError: diff --git a/mythril/mythril.py b/mythril/mythril.py index ae1032c9..7c6e0887 100644 --- a/mythril/mythril.py +++ b/mythril/mythril.py @@ -32,6 +32,7 @@ from mythril.ethereum.interface.rpc.exceptions import ConnectionError from mythril.exceptions import CompilerError, CriticalError, NoContractFoundError from mythril.solidity.soliditycontract import SolidityContract, get_contracts_from_file from mythril.support import signatures +from mythril.support.source_support import Source from mythril.support.loader import DynLoader from mythril.exceptions import CompilerError, NoContractFoundError, CriticalError from mythril.analysis.symbolic import SymExecWrapper @@ -596,14 +597,15 @@ class Mythril(object): ) issues = retrieve_callback_issues(modules) - if type(contract) == SolidityContract: - for issue in issues: - issue.add_code_info(contract) + for issue in issues: + issue.add_code_info(contract) all_issues += issues + source_data = Source() + source_data.get_source_from_contracts_list(self.contracts) # Finally, output the results - report = Report(verbose_report) + report = Report(verbose_report, source_data) for issue in all_issues: report.append_issue(issue) diff --git a/mythril/solidity/soliditycontract.py b/mythril/solidity/soliditycontract.py index 6ec018f8..d2669e7f 100644 --- a/mythril/solidity/soliditycontract.py +++ b/mythril/solidity/soliditycontract.py @@ -7,13 +7,14 @@ from mythril.exceptions import NoContractFoundError class SourceMapping: - """Representation of a source mapping for a Solidity file.""" + def __init__(self, solidity_file_idx, offset, length, lineno, mapping): + """Representation of a source mapping for a Solidity file.""" - def __init__(self, solidity_file_idx, offset, length, lineno): self.solidity_file_idx = solidity_file_idx self.offset = offset self.length = length self.lineno = lineno + self.solc_mapping = mapping class SolidityFile: @@ -25,12 +26,13 @@ class SolidityFile: class SourceCodeInfo: - """Metadata class containing a code reference for a specific file.""" + def __init__(self, filename, lineno, code, mapping): + """Metadata class containing a code reference for a specific file.""" - def __init__(self, filename, lineno, code): self.filename = filename self.lineno = lineno self.code = code + self.solc_mapping = mapping def get_contracts_from_file(input_file, solc_args=None, solc_binary="solc"): @@ -60,7 +62,6 @@ class SolidityContract(EVMContract): """Representation of a Solidity contract.""" def __init__(self, input_file, name=None, solc_args=None, solc_binary="solc"): - data = get_solc_json(input_file, solc_args=solc_args, solc_binary=solc_binary) self.solidity_files = [] @@ -126,8 +127,8 @@ class SolidityContract(EVMContract): disassembly = self.creation_disassembly if constructor else self.disassembly mappings = self.constructor_mappings if constructor else self.mappings index = helper.get_instruction_index(disassembly.instruction_list, address) - solidity_file = self.solidity_files[mappings[index].solidity_file_idx] + solidity_file = self.solidity_files[mappings[index].solidity_file_idx] filename = solidity_file.filename offset = mappings[index].offset @@ -137,8 +138,7 @@ class SolidityContract(EVMContract): "utf-8", errors="ignore" ) lineno = mappings[index].lineno - - return SourceCodeInfo(filename, lineno, code) + return SourceCodeInfo(filename, lineno, code, mappings[index].solc_mapping) def _get_solc_mappings(self, srcmap, constructor=False): """ @@ -147,7 +147,10 @@ class SolidityContract(EVMContract): :param constructor: """ mappings = self.constructor_mappings if constructor else self.mappings + prev_item = "" for item in srcmap: + if item == "": + item = prev_item mapping = item.split(":") if len(mapping) > 0 and len(mapping[0]) > 0: @@ -164,5 +167,5 @@ class SolidityContract(EVMContract): .count("\n".encode("utf-8")) + 1 ) - - mappings.append(SourceMapping(idx, offset, length, lineno)) + prev_item = item + mappings.append(SourceMapping(idx, offset, length, lineno, item)) diff --git a/mythril/support/source_support.py b/mythril/support/source_support.py new file mode 100644 index 00000000..c774a425 --- /dev/null +++ b/mythril/support/source_support.py @@ -0,0 +1,47 @@ +from mythril.solidity.soliditycontract import SolidityContract +from mythril.ethereum.evmcontract import EVMContract + + +class Source: + """Class to handle to source data""" + + def __init__( + self, source_type=None, source_format=None, source_list=None, meta=None + ): + """ + :param source_type: whether it is a solidity-file or evm-bytecode + :param source_format: whether it is bytecode, ethereum-address or text + :param source_list: List of files + :param meta: meta data + """ + self.source_type = source_type + self.source_format = source_format + self.source_list = source_list or [] + self.meta = meta + + def get_source_from_contracts_list(self, contracts): + """ + get the source data from the contracts list + :param contracts: the list of contracts + :return: + """ + if contracts is None or len(contracts) == 0: + return + if isinstance(contracts[0], SolidityContract): + self.source_type = "solidity-file" + self.source_format = "text" + for contract in contracts: + self.source_list += [file.filename for file in contract.solidity_files] + elif isinstance(contracts[0], EVMContract): + self.source_format = "evm-byzantium-bytecode" + self.source_type = ( + "raw-bytecode" if contracts[0].name == "MAIN" else "ethereum-address" + ) + for contract in contracts: + if contract.creation_code: + self.source_list.append(contract.creation_bytecode_hash) + if contract.code: + self.source_list.append(contract.bytecode_hash) + + else: + assert False # Fail hard diff --git a/mythril/support/truffle.py b/mythril/support/truffle.py index 3cfd7406..800b6fca 100644 --- a/mythril/support/truffle.py +++ b/mythril/support/truffle.py @@ -165,7 +165,11 @@ def get_mappings(source, deployed_source_map): :return: """ mappings = [] + prev_item = "" for item in deployed_source_map: + if item == "": + item = prev_item + mapping = item.split(":") if len(mapping) > 0 and len(mapping[0]) > 0: @@ -178,7 +182,8 @@ def get_mappings(source, deployed_source_map): idx = int(mapping[2]) lineno = source.encode("utf-8")[0:offset].count("\n".encode("utf-8")) + 1 + prev_item = item - mappings.append(SourceMapping(idx, offset, length, lineno)) + mappings.append(SourceMapping(idx, offset, length, lineno, item)) return mappings diff --git a/tests/cmd_line_test.py b/tests/cmd_line_test.py index fde90517..0862cf9e 100644 --- a/tests/cmd_line_test.py +++ b/tests/cmd_line_test.py @@ -34,7 +34,7 @@ class TruffleTestCase(BaseTestCase): command = "cd {}; truffle compile; python3 {} --truffle -t 2".format( truffle_project_root, MYTH ) - self.assertIn("=== Ether thief ====", output_of(command)) + self.assertIn("=== Unprotected Ether Withdrawal ====", output_of(command)) class InfuraTestCase(BaseTestCase): diff --git a/tests/report_test.py b/tests/report_test.py index f5414534..09f2d3fc 100644 --- a/tests/report_test.py +++ b/tests/report_test.py @@ -76,10 +76,9 @@ def _assert_empty(changed_files, postfix): assert message == "", message -def _assert_empty_json(changed_files): +def _assert_empty_json(changed_files, postfix=".json"): """Asserts there are no changed files and otherwise builds error message.""" - postfix = ".json" expected = [] actual = [] @@ -124,14 +123,11 @@ def _get_changed_files(postfix, report_builder, reports): output_expected = TESTDATA_OUTPUTS_EXPECTED / (input_file.name + postfix) output_current = TESTDATA_OUTPUTS_CURRENT / (input_file.name + postfix) output_current.write_text(report_builder(report)) - if not (output_expected.read_text() == output_current.read_text()): yield input_file -def _get_changed_files_json(report_builder, reports): - postfix = ".json" - +def _get_changed_files_json(report_builder, reports, postfix=".json"): def ordered(obj): """ @@ -180,3 +176,14 @@ def test_text_report(reports): ), ".text", ) + + +def test_jsonv2_report(reports): + _assert_empty_json( + _get_changed_files_json( + lambda report: _fix_path(report.as_swc_standard_format()).strip(), + reports, + ".jsonv2", + ), + ".jsonv2", + ) diff --git a/tests/testdata/outputs_expected/calls.sol.o.json b/tests/testdata/outputs_expected/calls.sol.o.json index 404801ff..1342a258 100644 --- a/tests/testdata/outputs_expected/calls.sol.o.json +++ b/tests/testdata/outputs_expected/calls.sol.o.json @@ -1,102 +1 @@ -{ - "error": null, - "issues": [ - { - "address": 661, - "contract": "Unknown", - "debug": "", - "description": "The contract executes a function call to an external address. Verify that the code at this address is trusted and immutable.", - "function": "thisisfine()", - "max_gas_used": 1254, - "min_gas_used": 643, - "swc-id": "107", - "title": "External call", - "type": "Informational" - }, - { - "address": 661, - "contract": "Unknown", - "debug": "", - "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", - "function": "thisisfine()", - "max_gas_used": 35972, - "min_gas_used": 1361, - "swc-id": "104", - "title": "Unchecked CALL return value", - "type": "Informational" - }, - { - "address": 779, - "contract": "Unknown", - "debug": "", - "description": "The contract executes a function call to an external address. Verify that the code at this address is trusted and immutable.", - "function": "callstoredaddress()", - "max_gas_used": 1298, - "min_gas_used": 687, - "swc-id": "107", - "title": "External call", - "type": "Informational" - }, - { - "address": 779, - "contract": "Unknown", - "debug": "", - "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", - "function": "callstoredaddress()", - "max_gas_used": 36016, - "min_gas_used": 1405, - "swc-id": "104", - "title": "Unchecked CALL return value", - "type": "Informational" - }, - { - "address": 858, - "contract": "Unknown", - "debug": "", - "description": "The contract executes a function call to an external address. Verify that the code at this address is trusted and immutable.", - "function": "reentrancy()", - "max_gas_used": 1320, - "min_gas_used": 709, - "swc-id": "107", - "title": "External call", - "type": "Informational" - }, - { - "address": 858, - "contract": "Unknown", - "debug": "", - "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", - "function": "reentrancy()", - "max_gas_used": 61052, - "min_gas_used": 6441, - "swc-id": "104", - "title": "Unchecked CALL return value", - "type": "Informational" - }, - { - "address": 912, - "contract": "Unknown", - "debug": "", - "description": "The contract executes a function call with high gas to a user-supplied address. Note that the callee can contain arbitrary code and may re-enter any function in this contract. Review the business logic carefully to prevent unanticipated effects on the contract state.", - "function": "calluseraddress(address)", - "max_gas_used": 616, - "min_gas_used": 335, - "swc-id": "107", - "title": "External call to user-supplied address", - "type": "Warning" - }, - { - "address": 912, - "contract": "Unknown", - "debug": "", - "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", - "function": "calluseraddress(address)", - "max_gas_used": 35336, - "min_gas_used": 1055, - "swc-id": "104", - "title": "Unchecked CALL return value", - "type": "Informational" - } - ], - "success": true -} +{"error": null, "issues": [{"address": 661, "contract": "Unknown", "debug": "", "description": "The contract executes an external message call.\nAn external function call to a fixed contract address is executed. Make sure that the callee contract has been reviewed carefully.", "function": "thisisfine()", "max_gas_used": 1254, "min_gas_used": 643, "severity": "Low", "sourceMap": null, "swc-id": "107", "title": "External Call To Fixed Address"}, {"address": 661, "contract": "Unknown", "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": "thisisfine()", "max_gas_used": 35972, "min_gas_used": 1361, "severity": "Low", "sourceMap": null, "swc-id": "104", "title": "Unchecked Call Return Value"}, {"address": 779, "contract": "Unknown", "debug": "", "description": "The contract executes an external message call.\nAn external function call to a fixed contract address is executed. Make sure that the callee contract has been reviewed carefully.", "function": "callstoredaddress()", "max_gas_used": 1298, "min_gas_used": 687, "severity": "Low", "sourceMap": null, "swc-id": "107", "title": "External Call To Fixed Address"}, {"address": 779, "contract": "Unknown", "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": "callstoredaddress()", "max_gas_used": 36016, "min_gas_used": 1405, "severity": "Low", "sourceMap": null, "swc-id": "104", "title": "Unchecked Call Return Value"}, {"address": 858, "contract": "Unknown", "debug": "", "description": "The contract executes an external message call.\nAn external function call to a fixed contract address is executed. Make sure that the callee contract has been reviewed carefully.", "function": "reentrancy()", "max_gas_used": 1320, "min_gas_used": 709, "severity": "Low", "sourceMap": null, "swc-id": "107", "title": "External Call To Fixed Address"}, {"address": 858, "contract": "Unknown", "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": "reentrancy()", "max_gas_used": 61052, "min_gas_used": 6441, "severity": "Low", "sourceMap": null, "swc-id": "104", "title": "Unchecked Call Return Value"}, {"address": 912, "contract": "Unknown", "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 thecontract state.", "function": "calluseraddress(address)", "max_gas_used": 616, "min_gas_used": 335, "severity": "Medium", "sourceMap": null, "swc-id": "107", "title": "External Call To User-Supplied Address"}, {"address": 912, "contract": "Unknown", "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": "calluseraddress(address)", "max_gas_used": 35336, "min_gas_used": 1055, "severity": "Low", "sourceMap": null, "swc-id": "104", "title": "Unchecked Call Return Value"}], "success": true} \ No newline at end of file diff --git a/tests/testdata/outputs_expected/calls.sol.o.jsonv2 b/tests/testdata/outputs_expected/calls.sol.o.jsonv2 new file mode 100644 index 00000000..8a0aa0c7 --- /dev/null +++ b/tests/testdata/outputs_expected/calls.sol.o.jsonv2 @@ -0,0 +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 thecontract 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/calls.sol.o.markdown b/tests/testdata/outputs_expected/calls.sol.o.markdown index 34e48962..2edd13d7 100644 --- a/tests/testdata/outputs_expected/calls.sol.o.markdown +++ b/tests/testdata/outputs_expected/calls.sol.o.markdown @@ -1,8 +1,8 @@ # Analysis results for test-filename.sol -## External call +## External Call To Fixed Address - SWC ID: 107 -- Type: Informational +- Severity: Low - Contract: Unknown - Function name: `thisisfine()` - PC address: 661 @@ -10,11 +10,12 @@ ### Description -The contract executes a function call to an external address. Verify that the code at this address is trusted and immutable. +The contract executes an external message call. +An external function call to a fixed contract address is executed. Make sure that the callee contract has been reviewed carefully. -## Unchecked CALL return value +## Unchecked Call Return Value - SWC ID: 104 -- Type: Informational +- Severity: Low - Contract: Unknown - Function name: `thisisfine()` - PC address: 661 @@ -22,11 +23,12 @@ The contract executes a function call to an external address. Verify that the co ### Description -The return value of an external call is not checked. Note that execution continue even if the called contract throws. +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. -## External call +## External Call To Fixed Address - SWC ID: 107 -- Type: Informational +- Severity: Low - Contract: Unknown - Function name: `callstoredaddress()` - PC address: 779 @@ -34,11 +36,12 @@ The return value of an external call is not checked. Note that execution continu ### Description -The contract executes a function call to an external address. Verify that the code at this address is trusted and immutable. +The contract executes an external message call. +An external function call to a fixed contract address is executed. Make sure that the callee contract has been reviewed carefully. -## Unchecked CALL return value +## Unchecked Call Return Value - SWC ID: 104 -- Type: Informational +- Severity: Low - Contract: Unknown - Function name: `callstoredaddress()` - PC address: 779 @@ -46,11 +49,12 @@ The contract executes a function call to an external address. Verify that the co ### Description -The return value of an external call is not checked. Note that execution continue even if the called contract throws. +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. -## External call +## External Call To Fixed Address - SWC ID: 107 -- Type: Informational +- Severity: Low - Contract: Unknown - Function name: `reentrancy()` - PC address: 858 @@ -58,11 +62,12 @@ The return value of an external call is not checked. Note that execution continu ### Description -The contract executes a function call to an external address. Verify that the code at this address is trusted and immutable. +The contract executes an external message call. +An external function call to a fixed contract address is executed. Make sure that the callee contract has been reviewed carefully. -## Unchecked CALL return value +## Unchecked Call Return Value - SWC ID: 104 -- Type: Informational +- Severity: Low - Contract: Unknown - Function name: `reentrancy()` - PC address: 858 @@ -70,11 +75,12 @@ The contract executes a function call to an external address. Verify that the co ### Description -The return value of an external call is not checked. Note that execution continue even if the called contract throws. +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. -## External call to user-supplied address +## External Call To User-Supplied Address - SWC ID: 107 -- Type: Warning +- Severity: Medium - Contract: Unknown - Function name: `calluseraddress(address)` - PC address: 912 @@ -82,11 +88,12 @@ The return value of an external call is not checked. Note that execution continu ### Description -The contract executes a function call with high gas to a user-supplied address. Note that the callee can contain arbitrary code and may re-enter any function in this contract. Review the business logic carefully to prevent unanticipated effects on the contract state. +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 thecontract state. -## Unchecked CALL return value +## Unchecked Call Return Value - SWC ID: 104 -- Type: Informational +- Severity: Low - Contract: Unknown - Function name: `calluseraddress(address)` - PC address: 912 @@ -94,4 +101,5 @@ The contract executes a function call with high gas to a user-supplied address. ### Description -The return value of an external call is not checked. Note that execution continue even if the called contract throws. +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/calls.sol.o.text b/tests/testdata/outputs_expected/calls.sol.o.text index 69dc3d29..9e53ca4e 100644 --- a/tests/testdata/outputs_expected/calls.sol.o.text +++ b/tests/testdata/outputs_expected/calls.sol.o.text @@ -1,80 +1,88 @@ -==== External call ==== +==== External Call To Fixed Address ==== SWC ID: 107 -Type: Informational +Severity: Low Contract: Unknown Function name: thisisfine() PC address: 661 Estimated Gas Usage: 643 - 1254 -The contract executes a function call to an external address. Verify that the code at this address is trusted and immutable. +The contract executes an external message call. +An external function call to a fixed contract address is executed. Make sure that the callee contract has been reviewed carefully. -------------------- -==== Unchecked CALL return value ==== +==== Unchecked Call Return Value ==== SWC ID: 104 -Type: Informational +Severity: Low Contract: Unknown Function name: thisisfine() PC address: 661 Estimated Gas Usage: 1361 - 35972 -The return value of an external call is not checked. Note that execution continue even if the called contract throws. +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. -------------------- -==== External call ==== +==== External Call To Fixed Address ==== SWC ID: 107 -Type: Informational +Severity: Low Contract: Unknown Function name: callstoredaddress() PC address: 779 Estimated Gas Usage: 687 - 1298 -The contract executes a function call to an external address. Verify that the code at this address is trusted and immutable. +The contract executes an external message call. +An external function call to a fixed contract address is executed. Make sure that the callee contract has been reviewed carefully. -------------------- -==== Unchecked CALL return value ==== +==== Unchecked Call Return Value ==== SWC ID: 104 -Type: Informational +Severity: Low Contract: Unknown Function name: callstoredaddress() PC address: 779 Estimated Gas Usage: 1405 - 36016 -The return value of an external call is not checked. Note that execution continue even if the called contract throws. +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. -------------------- -==== External call ==== +==== External Call To Fixed Address ==== SWC ID: 107 -Type: Informational +Severity: Low Contract: Unknown Function name: reentrancy() PC address: 858 Estimated Gas Usage: 709 - 1320 -The contract executes a function call to an external address. Verify that the code at this address is trusted and immutable. +The contract executes an external message call. +An external function call to a fixed contract address is executed. Make sure that the callee contract has been reviewed carefully. -------------------- -==== Unchecked CALL return value ==== +==== Unchecked Call Return Value ==== SWC ID: 104 -Type: Informational +Severity: Low Contract: Unknown Function name: reentrancy() PC address: 858 Estimated Gas Usage: 6441 - 61052 -The return value of an external call is not checked. Note that execution continue even if the called contract throws. +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. -------------------- -==== External call to user-supplied address ==== +==== External Call To User-Supplied Address ==== SWC ID: 107 -Type: Warning +Severity: Medium Contract: Unknown Function name: calluseraddress(address) PC address: 912 Estimated Gas Usage: 335 - 616 -The contract executes a function call with high gas to a user-supplied address. Note that the callee can contain arbitrary code and may re-enter any function in this contract. Review the business logic carefully to prevent unanticipated effects on the contract state. +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 thecontract state. -------------------- -==== Unchecked CALL return value ==== +==== Unchecked Call Return Value ==== SWC ID: 104 -Type: Informational +Severity: Low Contract: Unknown Function name: calluseraddress(address) PC address: 912 Estimated Gas Usage: 1055 - 35336 -The return value of an external call is not checked. Note that execution continue even if the called contract throws. +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/environments.sol.o.json b/tests/testdata/outputs_expected/environments.sol.o.json index 5cd8f4db..d4ae2a37 100644 --- a/tests/testdata/outputs_expected/environments.sol.o.json +++ b/tests/testdata/outputs_expected/environments.sol.o.json @@ -9,7 +9,7 @@ "function": "_function_0x83f12fec", "swc-id": "101", "title": "Integer Overflow", - "type": "Warning", + "type": "Warning" }, { "address": 278, @@ -19,7 +19,7 @@ "function": "_function_0x83f12fec", "swc-id": "101", "title": "Integer Overflow", - "type": "Warning", + "type": "Warning" }, { "address": 378, @@ -29,8 +29,8 @@ "function": "_function_0x83f12fec", "swc-id": "101", "title": "Integer Underflow", - "type": "Warning", - }, + "type": "Warning" + } ], - "success": true, -} + "success": true +} \ No newline at end of file diff --git a/tests/testdata/outputs_expected/ether_send.sol.o.json b/tests/testdata/outputs_expected/ether_send.sol.o.json index 179ed787..237b1c1e 100644 --- a/tests/testdata/outputs_expected/ether_send.sol.o.json +++ b/tests/testdata/outputs_expected/ether_send.sol.o.json @@ -1,5 +1 @@ -{ - "error": null, - "issues": [], - "success": true -} +{"error": null, "issues": [], "success": true} \ 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 new file mode 100644 index 00000000..c1512195 --- /dev/null +++ b/tests/testdata/outputs_expected/ether_send.sol.o.jsonv2 @@ -0,0 +1 @@ +{"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.json b/tests/testdata/outputs_expected/exceptions.sol.o.json index c0324b17..de103061 100644 --- a/tests/testdata/outputs_expected/exceptions.sol.o.json +++ b/tests/testdata/outputs_expected/exceptions.sol.o.json @@ -1,54 +1 @@ -{ - "error": null, - "issues": [ - { - "address": 446, - "contract": "Unknown", - "debug": "", - "description": "A reachable exception (opcode 0xfe) has been detected. This 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.", - "function": "assert3(uint256)", - "max_gas_used": 301, - "min_gas_used": 206, - "swc-id": "110", - "title": "Exception state", - "type": "Informational" - }, - { - "address": 484, - "contract": "Unknown", - "debug": "", - "description": "A reachable exception (opcode 0xfe) has been detected. This 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.", - "function": "arrayaccess(uint256)", - "max_gas_used": 351, - "min_gas_used": 256, - "swc-id": "110", - "title": "Exception state", - "type": "Informational" - }, - { - "address": 506, - "contract": "Unknown", - "debug": "", - "description": "A reachable exception (opcode 0xfe) has been detected. This 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.", - "function": "divisionby0(uint256)", - "max_gas_used": 367, - "min_gas_used": 272, - "swc-id": "110", - "title": "Exception state", - "type": "Informational" - }, - { - "address": 531, - "contract": "Unknown", - "debug": "", - "description": "A reachable exception (opcode 0xfe) has been detected. This 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.", - "function": "assert1()", - "max_gas_used": 363, - "min_gas_used": 268, - "swc-id": "110", - "title": "Exception state", - "type": "Informational" - } - ], - "success": true -} +{"error": null, "issues": [{"address": 446, "contract": "Unknown", "debug": "", "description": "A reachable exception has been detected.\nIt 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.", "function": "assert3(uint256)", "max_gas_used": 301, "min_gas_used": 206, "severity": "Low", "sourceMap": null, "swc-id": "110", "title": "Exception State"}, {"address": 484, "contract": "Unknown", "debug": "", "description": "A reachable exception has been detected.\nIt 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.", "function": "arrayaccess(uint256)", "max_gas_used": 351, "min_gas_used": 256, "severity": "Low", "sourceMap": null, "swc-id": "110", "title": "Exception State"}, {"address": 506, "contract": "Unknown", "debug": "", "description": "A reachable exception has been detected.\nIt 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.", "function": "divisionby0(uint256)", "max_gas_used": 367, "min_gas_used": 272, "severity": "Low", "sourceMap": null, "swc-id": "110", "title": "Exception State"}, {"address": 531, "contract": "Unknown", "debug": "", "description": "A reachable exception has been detected.\nIt 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.", "function": "assert1()", "max_gas_used": 363, "min_gas_used": 268, "severity": "Low", "sourceMap": null, "swc-id": "110", "title": "Exception State"}], "success": true} \ 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 new file mode 100644 index 00000000..8a88b8d6 --- /dev/null +++ b/tests/testdata/outputs_expected/exceptions.sol.o.jsonv2 @@ -0,0 +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 diff --git a/tests/testdata/outputs_expected/exceptions.sol.o.markdown b/tests/testdata/outputs_expected/exceptions.sol.o.markdown index 64d4ed2b..c5da9834 100644 --- a/tests/testdata/outputs_expected/exceptions.sol.o.markdown +++ b/tests/testdata/outputs_expected/exceptions.sol.o.markdown @@ -1,8 +1,8 @@ # Analysis results for test-filename.sol -## Exception state +## Exception State - SWC ID: 110 -- Type: Informational +- Severity: Low - Contract: Unknown - Function name: `assert3(uint256)` - PC address: 446 @@ -10,11 +10,12 @@ ### Description -A reachable exception (opcode 0xfe) has been detected. This 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. +A reachable exception has been detected. +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. -## Exception state +## Exception State - SWC ID: 110 -- Type: Informational +- Severity: Low - Contract: Unknown - Function name: `arrayaccess(uint256)` - PC address: 484 @@ -22,11 +23,12 @@ A reachable exception (opcode 0xfe) has been detected. This can be caused by typ ### Description -A reachable exception (opcode 0xfe) has been detected. This 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. +A reachable exception has been detected. +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. -## Exception state +## Exception State - SWC ID: 110 -- Type: Informational +- Severity: Low - Contract: Unknown - Function name: `divisionby0(uint256)` - PC address: 506 @@ -34,11 +36,12 @@ A reachable exception (opcode 0xfe) has been detected. This can be caused by typ ### Description -A reachable exception (opcode 0xfe) has been detected. This 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. +A reachable exception has been detected. +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. -## Exception state +## Exception State - SWC ID: 110 -- Type: Informational +- Severity: Low - Contract: Unknown - Function name: `assert1()` - PC address: 531 @@ -46,4 +49,5 @@ A reachable exception (opcode 0xfe) has been detected. This can be caused by typ ### Description -A reachable exception (opcode 0xfe) has been detected. This 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. +A reachable exception has been detected. +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. diff --git a/tests/testdata/outputs_expected/exceptions.sol.o.text b/tests/testdata/outputs_expected/exceptions.sol.o.text index 6eaa9c6f..cfee4d39 100644 --- a/tests/testdata/outputs_expected/exceptions.sol.o.text +++ b/tests/testdata/outputs_expected/exceptions.sol.o.text @@ -1,40 +1,44 @@ -==== Exception state ==== +==== Exception State ==== SWC ID: 110 -Type: Informational +Severity: Low Contract: Unknown Function name: assert3(uint256) PC address: 446 Estimated Gas Usage: 206 - 301 -A reachable exception (opcode 0xfe) has been detected. This 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. +A reachable exception has been detected. +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. -------------------- -==== Exception state ==== +==== Exception State ==== SWC ID: 110 -Type: Informational +Severity: Low Contract: Unknown Function name: arrayaccess(uint256) PC address: 484 Estimated Gas Usage: 256 - 351 -A reachable exception (opcode 0xfe) has been detected. This 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. +A reachable exception has been detected. +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. -------------------- -==== Exception state ==== +==== Exception State ==== SWC ID: 110 -Type: Informational +Severity: Low Contract: Unknown Function name: divisionby0(uint256) PC address: 506 Estimated Gas Usage: 272 - 367 -A reachable exception (opcode 0xfe) has been detected. This 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. +A reachable exception has been detected. +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. -------------------- -==== Exception state ==== +==== Exception State ==== SWC ID: 110 -Type: Informational +Severity: Low Contract: Unknown Function name: assert1() PC address: 531 Estimated Gas Usage: 268 - 363 -A reachable exception (opcode 0xfe) has been detected. This 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. +A reachable exception has been detected. +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. -------------------- 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 26366268..b18d1c40 100644 --- a/tests/testdata/outputs_expected/kinds_of_calls.sol.o.json +++ b/tests/testdata/outputs_expected/kinds_of_calls.sol.o.json @@ -1,66 +1 @@ -{ - "error": null, - "issues": [ - { - "address": 618, - "contract": "Unknown", - "debug": "", - "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", - "function": "_function_0x141f32ff", - "max_gas_used": 35865, - "min_gas_used": 1113, - "swc-id": "104", - "title": "Unchecked CALL return value", - "type": "Informational" - }, - { - "address": 618, - "contract": "Unknown", - "debug": "", - "description": "The function `_function_0x141f32ff` uses callcode. Callcode does not persist sender or value over the call. Use delegatecall instead.", - "function": "_function_0x141f32ff", - "max_gas_used": 1141, - "min_gas_used": 389, - "swc-id": "111", - "title": "Use of callcode", - "type": "Warning" - }, - { - "address": 849, - "contract": "Unknown", - "debug": "", - "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", - "function": "_function_0x9b58bc26", - "max_gas_used": 35922, - "min_gas_used": 1170, - "swc-id": "104", - "title": "Unchecked CALL return value", - "type": "Informational" - }, - { - "address": 1038, - "contract": "Unknown", - "debug": "", - "description": "The contract executes a function call with high gas to a user-supplied address. Note that the callee can contain arbitrary code and may re-enter any function in this contract. Review the business logic carefully to prevent unanticipated effects on the contract state.", - "function": "_function_0xeea4c864", - "max_gas_used": 1223, - "min_gas_used": 471, - "swc-id": "107", - "title": "External call to user-supplied address", - "type": "Warning" - }, - { - "address": 1038, - "contract": "Unknown", - "debug": "", - "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", - "function": "_function_0xeea4c864", - "max_gas_used": 35947, - "min_gas_used": 1195, - "swc-id": "104", - "title": "Unchecked CALL return value", - "type": "Informational" - } - ], - "success": true -} +{"error": null, "issues": [{"address": 618, "contract": "Unknown", "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_0x141f32ff", "max_gas_used": 35865, "min_gas_used": 1113, "severity": "Low", "sourceMap": null, "swc-id": "104", "title": "Unchecked Call Return Value"}, {"address": 618, "contract": "Unknown", "debug": "", "description": "Use of callcode is deprecated.\nThe 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.", "function": "_function_0x141f32ff", "max_gas_used": 1141, "min_gas_used": 389, "severity": "Medium", "sourceMap": null, "swc-id": "111", "title": "Use of callcode"}, {"address": 849, "contract": "Unknown", "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, "severity": "Low", "sourceMap": null, "swc-id": "104", "title": "Unchecked Call Return Value"}, {"address": 1038, "contract": "Unknown", "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 thecontract state.", "function": "_function_0xeea4c864", "max_gas_used": 1223, "min_gas_used": 471, "severity": "Medium", "sourceMap": null, "swc-id": "107", "title": "External Call To User-Supplied Address"}, {"address": 1038, "contract": "Unknown", "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, "severity": "Low", "sourceMap": null, "swc-id": "104", "title": "Unchecked Call Return Value"}], "success": true} \ No newline at end of file diff --git a/tests/testdata/outputs_expected/kinds_of_calls.sol.o.jsonv2 b/tests/testdata/outputs_expected/kinds_of_calls.sol.o.jsonv2 new file mode 100644 index 00000000..ea5479c2 --- /dev/null +++ b/tests/testdata/outputs_expected/kinds_of_calls.sol.o.jsonv2 @@ -0,0 +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 thecontract 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 2b16432e..95011cec 100644 --- a/tests/testdata/outputs_expected/kinds_of_calls.sol.o.markdown +++ b/tests/testdata/outputs_expected/kinds_of_calls.sol.o.markdown @@ -1,8 +1,8 @@ # Analysis results for test-filename.sol -## Unchecked CALL return value +## Unchecked Call Return Value - SWC ID: 104 -- Type: Informational +- Severity: Low - Contract: Unknown - Function name: `_function_0x141f32ff` - PC address: 618 @@ -10,11 +10,12 @@ ### Description -The return value of an external call is not checked. Note that execution continue even if the called contract throws. +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. ## Use of callcode - SWC ID: 111 -- Type: Warning +- Severity: Medium - Contract: Unknown - Function name: `_function_0x141f32ff` - PC address: 618 @@ -22,11 +23,12 @@ The return value of an external call is not checked. Note that execution continu ### Description -The function `_function_0x141f32ff` uses callcode. Callcode does not persist sender or value over the call. Use delegatecall instead. +Use of callcode is deprecated. +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. -## Unchecked CALL return value +## Unchecked Call Return Value - SWC ID: 104 -- Type: Informational +- Severity: Low - Contract: Unknown - Function name: `_function_0x9b58bc26` - PC address: 849 @@ -34,11 +36,12 @@ The function `_function_0x141f32ff` uses callcode. Callcode does not persist sen ### Description -The return value of an external call is not checked. Note that execution continue even if the called contract throws. +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. -## External call to user-supplied address +## External Call To User-Supplied Address - SWC ID: 107 -- Type: Warning +- Severity: Medium - Contract: Unknown - Function name: `_function_0xeea4c864` - PC address: 1038 @@ -46,11 +49,12 @@ The return value of an external call is not checked. Note that execution continu ### Description -The contract executes a function call with high gas to a user-supplied address. Note that the callee can contain arbitrary code and may re-enter any function in this contract. Review the business logic carefully to prevent unanticipated effects on the contract state. +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 thecontract state. -## Unchecked CALL return value +## Unchecked Call Return Value - SWC ID: 104 -- Type: Informational +- Severity: Low - Contract: Unknown - Function name: `_function_0xeea4c864` - PC address: 1038 @@ -58,4 +62,5 @@ The contract executes a function call with high gas to a user-supplied address. ### Description -The return value of an external call is not checked. Note that execution continue even if the called contract throws. +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/kinds_of_calls.sol.o.text b/tests/testdata/outputs_expected/kinds_of_calls.sol.o.text index b4bba9ca..1c922c71 100644 --- a/tests/testdata/outputs_expected/kinds_of_calls.sol.o.text +++ b/tests/testdata/outputs_expected/kinds_of_calls.sol.o.text @@ -1,50 +1,55 @@ -==== Unchecked CALL return value ==== +==== Unchecked Call Return Value ==== SWC ID: 104 -Type: Informational +Severity: Low Contract: Unknown Function name: _function_0x141f32ff PC address: 618 Estimated Gas Usage: 1113 - 35865 -The return value of an external call is not checked. Note that execution continue even if the called contract throws. +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. -------------------- ==== Use of callcode ==== SWC ID: 111 -Type: Warning +Severity: Medium Contract: Unknown Function name: _function_0x141f32ff PC address: 618 Estimated Gas Usage: 389 - 1141 -The function `_function_0x141f32ff` uses callcode. Callcode does not persist sender or value over the call. Use delegatecall instead. +Use of callcode is deprecated. +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. -------------------- -==== Unchecked CALL return value ==== +==== Unchecked Call Return Value ==== SWC ID: 104 -Type: Informational +Severity: Low Contract: Unknown Function name: _function_0x9b58bc26 PC address: 849 Estimated Gas Usage: 1170 - 35922 -The return value of an external call is not checked. Note that execution continue even if the called contract throws. +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. -------------------- -==== External call to user-supplied address ==== +==== External Call To User-Supplied Address ==== SWC ID: 107 -Type: Warning +Severity: Medium Contract: Unknown Function name: _function_0xeea4c864 PC address: 1038 Estimated Gas Usage: 471 - 1223 -The contract executes a function call with high gas to a user-supplied address. Note that the callee can contain arbitrary code and may re-enter any function in this contract. Review the business logic carefully to prevent unanticipated effects on the contract state. +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 thecontract state. -------------------- -==== Unchecked CALL return value ==== +==== Unchecked Call Return Value ==== SWC ID: 104 -Type: Informational +Severity: Low Contract: Unknown Function name: _function_0xeea4c864 PC address: 1038 Estimated Gas Usage: 1195 - 35947 -The return value of an external call is not checked. Note that execution continue even if the called contract throws. +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.json b/tests/testdata/outputs_expected/metacoin.sol.o.json index 179ed787..237b1c1e 100644 --- a/tests/testdata/outputs_expected/metacoin.sol.o.json +++ b/tests/testdata/outputs_expected/metacoin.sol.o.json @@ -1,5 +1 @@ -{ - "error": null, - "issues": [], - "success": true -} +{"error": null, "issues": [], "success": true} \ No newline at end of file diff --git a/tests/testdata/outputs_expected/metacoin.sol.o.jsonv2 b/tests/testdata/outputs_expected/metacoin.sol.o.jsonv2 new file mode 100644 index 00000000..c1512195 --- /dev/null +++ b/tests/testdata/outputs_expected/metacoin.sol.o.jsonv2 @@ -0,0 +1 @@ +{"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.json b/tests/testdata/outputs_expected/multi_contracts.sol.o.json index c4d6e54c..64a7bee7 100644 --- a/tests/testdata/outputs_expected/multi_contracts.sol.o.json +++ b/tests/testdata/outputs_expected/multi_contracts.sol.o.json @@ -1,18 +1 @@ -{ - "error": null, - "issues": [ - { - "address": 142, - "contract": "Unknown", - "debug": "", - "description": "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.", - "function": "transfer()", - "max_gas_used": 467, - "min_gas_used": 186, - "swc-id": "105", - "title": "Ether thief", - "type": "Warning" - } - ], - "success": true -} +{"error": null, "issues": [{"address": 142, "contract": "Unknown", "debug": "", "description": "Anyone can withdraw ETH from the contract account.\nArbitrary 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.", "function": "transfer()", "max_gas_used": 467, "min_gas_used": 186, "severity": "High", "sourceMap": null, "swc-id": "105", "title": "Unprotected Ether Withdrawal"}], "success": true} \ 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 new file mode 100644 index 00000000..46747699 --- /dev/null +++ b/tests/testdata/outputs_expected/multi_contracts.sol.o.jsonv2 @@ -0,0 +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 diff --git a/tests/testdata/outputs_expected/multi_contracts.sol.o.markdown b/tests/testdata/outputs_expected/multi_contracts.sol.o.markdown index fdec9b80..a7eac008 100644 --- a/tests/testdata/outputs_expected/multi_contracts.sol.o.markdown +++ b/tests/testdata/outputs_expected/multi_contracts.sol.o.markdown @@ -1,8 +1,8 @@ # Analysis results for test-filename.sol -## Ether thief +## Unprotected Ether Withdrawal - SWC ID: 105 -- Type: Warning +- Severity: High - Contract: Unknown - Function name: `transfer()` - PC address: 142 @@ -10,4 +10,5 @@ ### Description +Anyone can withdraw ETH from the contract account. 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. diff --git a/tests/testdata/outputs_expected/multi_contracts.sol.o.text b/tests/testdata/outputs_expected/multi_contracts.sol.o.text index b229eda4..a8388020 100644 --- a/tests/testdata/outputs_expected/multi_contracts.sol.o.text +++ b/tests/testdata/outputs_expected/multi_contracts.sol.o.text @@ -1,10 +1,11 @@ -==== Ether thief ==== +==== Unprotected Ether Withdrawal ==== SWC ID: 105 -Type: Warning +Severity: High Contract: Unknown Function name: transfer() PC address: 142 Estimated Gas Usage: 186 - 467 +Anyone can withdraw ETH from the contract account. 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. -------------------- diff --git a/tests/testdata/outputs_expected/nonascii.sol.o.json b/tests/testdata/outputs_expected/nonascii.sol.o.json index 179ed787..237b1c1e 100644 --- a/tests/testdata/outputs_expected/nonascii.sol.o.json +++ b/tests/testdata/outputs_expected/nonascii.sol.o.json @@ -1,5 +1 @@ -{ - "error": null, - "issues": [], - "success": true -} +{"error": null, "issues": [], "success": true} \ 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 new file mode 100644 index 00000000..c1512195 --- /dev/null +++ b/tests/testdata/outputs_expected/nonascii.sol.o.jsonv2 @@ -0,0 +1 @@ +{"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.json b/tests/testdata/outputs_expected/origin.sol.o.json index 11a5212c..5b786178 100644 --- a/tests/testdata/outputs_expected/origin.sol.o.json +++ b/tests/testdata/outputs_expected/origin.sol.o.json @@ -1,18 +1 @@ -{ - "error": null, - "issues": [ - { - "address": 317, - "contract": "Unknown", - "debug": "", - "description": "The function `transferOwnership(address)` retrieves the transaction origin (tx.origin) using the ORIGIN opcode. Use msg.sender instead.\nSee also: https://solidity.readthedocs.io/en/develop/security-considerations.html#tx-origin", - "function": "transferOwnership(address)", - "max_gas_used": 1051, - "min_gas_used": 626, - "swc-id": "111", - "title": "Use of tx.origin", - "type": "Warning" - } - ], - "success": true -} +{"error": null, "issues": [{"address": 317, "contract": "Unknown", "debug": "", "description": "Use of tx.origin is deprecated.\nThe 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", "function": "transferOwnership(address)", "max_gas_used": 1051, "min_gas_used": 626, "severity": "Medium", "sourceMap": null, "swc-id": "111", "title": "Use of tx.origin"}], "success": true} \ 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 new file mode 100644 index 00000000..095427f1 --- /dev/null +++ b/tests/testdata/outputs_expected/origin.sol.o.jsonv2 @@ -0,0 +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 diff --git a/tests/testdata/outputs_expected/origin.sol.o.markdown b/tests/testdata/outputs_expected/origin.sol.o.markdown index 1e0ad30c..1f5f83ac 100644 --- a/tests/testdata/outputs_expected/origin.sol.o.markdown +++ b/tests/testdata/outputs_expected/origin.sol.o.markdown @@ -2,7 +2,7 @@ ## Use of tx.origin - SWC ID: 111 -- Type: Warning +- Severity: Medium - Contract: Unknown - Function name: `transferOwnership(address)` - PC address: 317 @@ -10,5 +10,6 @@ ### Description -The function `transferOwnership(address)` retrieves the transaction origin (tx.origin) using the ORIGIN opcode. Use msg.sender instead. +Use of tx.origin is deprecated. +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. See also: https://solidity.readthedocs.io/en/develop/security-considerations.html#tx-origin diff --git a/tests/testdata/outputs_expected/origin.sol.o.text b/tests/testdata/outputs_expected/origin.sol.o.text index acf08a93..b7ebc992 100644 --- a/tests/testdata/outputs_expected/origin.sol.o.text +++ b/tests/testdata/outputs_expected/origin.sol.o.text @@ -1,11 +1,12 @@ ==== Use of tx.origin ==== SWC ID: 111 -Type: Warning +Severity: Medium Contract: Unknown Function name: transferOwnership(address) PC address: 317 Estimated Gas Usage: 626 - 1051 -The function `transferOwnership(address)` retrieves the transaction origin (tx.origin) using the ORIGIN opcode. Use msg.sender instead. +Use of tx.origin is deprecated. +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. See also: https://solidity.readthedocs.io/en/develop/security-considerations.html#tx-origin -------------------- diff --git a/tests/testdata/outputs_expected/overflow.sol.o.json b/tests/testdata/outputs_expected/overflow.sol.o.json index 55606d81..f14878cc 100644 --- a/tests/testdata/outputs_expected/overflow.sol.o.json +++ b/tests/testdata/outputs_expected/overflow.sol.o.json @@ -4,24 +4,26 @@ "address": 567, "contract": "Unknown", "debug": "", - "description": "This binary subtraction operation can result in integer underflow.\n", + "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": 1774, - "min_gas_used": 1299, + "max_gas_used": 1053, + "min_gas_used": 768, + "severity": "High", + "sourceMap": null, "swc-id": "101", - "title": "Integer Underflow", - "type": "Warning" + "title": "Integer Underflow" }, { "address": 649, "contract": "Unknown", "debug": "", - "description": "This binary subtraction operation can result in integer underflow.\n", + "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": 1774, "min_gas_used": 1299, + "severity": "High", + "sourceMap": null, "swc-id": "101", - "title": "Integer Underflow", - "type": "Warning" + "title": "Integer Underflow" }], "success": true } diff --git a/tests/testdata/outputs_expected/overflow.sol.o.jsonv2 b/tests/testdata/outputs_expected/overflow.sol.o.jsonv2 new file mode 100644 index 00000000..9c2c320f --- /dev/null +++ b/tests/testdata/outputs_expected/overflow.sol.o.jsonv2 @@ -0,0 +1,40 @@ +{ + "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 d747f944..8ece5099 100644 --- a/tests/testdata/outputs_expected/overflow.sol.o.markdown +++ b/tests/testdata/outputs_expected/overflow.sol.o.markdown @@ -2,19 +2,20 @@ ## Integer Underflow - SWC ID: 101 -- Type: Warning +- Severity: High - Contract: Unknown - Function name: `sendeth(address,uint256)` - PC address: 567 -- Estimated Gas Usage: 1299 - 1774 +- Estimated Gas Usage: 768 - 1053 ### Description -This binary subtraction operation can result in integer underflow. +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. ## Integer Underflow - SWC ID: 101 -- Type: Warning +- Severity: High - Contract: Unknown - Function name: `sendeth(address,uint256)` - PC address: 649 @@ -22,4 +23,5 @@ This binary subtraction operation can result in integer underflow. ### Description -This binary subtraction operation can result in integer underflow. +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/overflow.sol.o.text b/tests/testdata/outputs_expected/overflow.sol.o.text index 6b35c666..745404aa 100644 --- a/tests/testdata/outputs_expected/overflow.sol.o.text +++ b/tests/testdata/outputs_expected/overflow.sol.o.text @@ -1,22 +1,22 @@ ==== Integer Underflow ==== SWC ID: 101 -Type: Warning +Severity: High Contract: Unknown Function name: sendeth(address,uint256) PC address: 567 -Estimated Gas Usage: 1299 - 1774 -This binary subtraction operation can result in integer underflow. - +Estimated Gas Usage: 768 - 1053 +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. -------------------- ==== Integer Underflow ==== SWC ID: 101 -Type: Warning +Severity: High Contract: Unknown Function name: sendeth(address,uint256) PC address: 649 Estimated Gas Usage: 1299 - 1774 -This binary subtraction operation can result in integer underflow. - +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.json b/tests/testdata/outputs_expected/returnvalue.sol.o.json index 17d61c3f..2c741ba2 100644 --- a/tests/testdata/outputs_expected/returnvalue.sol.o.json +++ b/tests/testdata/outputs_expected/returnvalue.sol.o.json @@ -1,42 +1 @@ -{ - "error": null, - "issues": [ - { - "address": 196, - "contract": "Unknown", - "debug": "", - "description": "The contract executes a function call to an external address. Verify that the code at this address is trusted and immutable.", - "function": "callchecked()", - "max_gas_used": 1210, - "min_gas_used": 599, - "swc-id": "107", - "title": "External call", - "type": "Informational" - }, - { - "address": 285, - "contract": "Unknown", - "debug": "", - "description": "The contract executes a function call to an external address. Verify that the code at this address is trusted and immutable.", - "function": "callnotchecked()", - "max_gas_used": 1232, - "min_gas_used": 621, - "swc-id": "107", - "title": "External call", - "type": "Informational" - }, - { - "address": 285, - "contract": "Unknown", - "debug": "", - "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", - "function": "callnotchecked()", - "max_gas_used": 35950, - "min_gas_used": 1339, - "swc-id": "104", - "title": "Unchecked CALL return value", - "type": "Informational" - } - ], - "success": true -} +{"error": null, "issues": [{"address": 196, "contract": "Unknown", "debug": "", "description": "The contract executes an external message call.\nAn external function call to a fixed contract address is executed. Make sure that the callee contract has been reviewed carefully.", "function": "callchecked()", "max_gas_used": 1210, "min_gas_used": 599, "severity": "Low", "sourceMap": null, "swc-id": "107", "title": "External Call To Fixed Address"}, {"address": 285, "contract": "Unknown", "debug": "", "description": "The contract executes an external message call.\nAn external function call to a fixed contract address is executed. Make sure that the callee contract has been reviewed carefully.", "function": "callnotchecked()", "max_gas_used": 1232, "min_gas_used": 621, "severity": "Low", "sourceMap": null, "swc-id": "107", "title": "External Call To Fixed Address"}, {"address": 285, "contract": "Unknown", "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": "callnotchecked()", "max_gas_used": 35950, "min_gas_used": 1339, "severity": "Low", "sourceMap": null, "swc-id": "104", "title": "Unchecked Call Return Value"}], "success": true} \ No newline at end of file diff --git a/tests/testdata/outputs_expected/returnvalue.sol.o.jsonv2 b/tests/testdata/outputs_expected/returnvalue.sol.o.jsonv2 new file mode 100644 index 00000000..6da3980c --- /dev/null +++ b/tests/testdata/outputs_expected/returnvalue.sol.o.jsonv2 @@ -0,0 +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 diff --git a/tests/testdata/outputs_expected/returnvalue.sol.o.markdown b/tests/testdata/outputs_expected/returnvalue.sol.o.markdown index 6b34840f..fcbd0a1b 100644 --- a/tests/testdata/outputs_expected/returnvalue.sol.o.markdown +++ b/tests/testdata/outputs_expected/returnvalue.sol.o.markdown @@ -1,8 +1,8 @@ # Analysis results for test-filename.sol -## External call +## External Call To Fixed Address - SWC ID: 107 -- Type: Informational +- Severity: Low - Contract: Unknown - Function name: `callchecked()` - PC address: 196 @@ -10,11 +10,12 @@ ### Description -The contract executes a function call to an external address. Verify that the code at this address is trusted and immutable. +The contract executes an external message call. +An external function call to a fixed contract address is executed. Make sure that the callee contract has been reviewed carefully. -## External call +## External Call To Fixed Address - SWC ID: 107 -- Type: Informational +- Severity: Low - Contract: Unknown - Function name: `callnotchecked()` - PC address: 285 @@ -22,11 +23,12 @@ The contract executes a function call to an external address. Verify that the co ### Description -The contract executes a function call to an external address. Verify that the code at this address is trusted and immutable. +The contract executes an external message call. +An external function call to a fixed contract address is executed. Make sure that the callee contract has been reviewed carefully. -## Unchecked CALL return value +## Unchecked Call Return Value - SWC ID: 104 -- Type: Informational +- Severity: Low - Contract: Unknown - Function name: `callnotchecked()` - PC address: 285 @@ -34,4 +36,5 @@ The contract executes a function call to an external address. Verify that the co ### Description -The return value of an external call is not checked. Note that execution continue even if the called contract throws. +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/returnvalue.sol.o.text b/tests/testdata/outputs_expected/returnvalue.sol.o.text index 320b0420..2678bf80 100644 --- a/tests/testdata/outputs_expected/returnvalue.sol.o.text +++ b/tests/testdata/outputs_expected/returnvalue.sol.o.text @@ -1,30 +1,33 @@ -==== External call ==== +==== External Call To Fixed Address ==== SWC ID: 107 -Type: Informational +Severity: Low Contract: Unknown Function name: callchecked() PC address: 196 Estimated Gas Usage: 599 - 1210 -The contract executes a function call to an external address. Verify that the code at this address is trusted and immutable. +The contract executes an external message call. +An external function call to a fixed contract address is executed. Make sure that the callee contract has been reviewed carefully. -------------------- -==== External call ==== +==== External Call To Fixed Address ==== SWC ID: 107 -Type: Informational +Severity: Low Contract: Unknown Function name: callnotchecked() PC address: 285 Estimated Gas Usage: 621 - 1232 -The contract executes a function call to an external address. Verify that the code at this address is trusted and immutable. +The contract executes an external message call. +An external function call to a fixed contract address is executed. Make sure that the callee contract has been reviewed carefully. -------------------- -==== Unchecked CALL return value ==== +==== Unchecked Call Return Value ==== SWC ID: 104 -Type: Informational +Severity: Low Contract: Unknown Function name: callnotchecked() PC address: 285 Estimated Gas Usage: 1339 - 35950 -The return value of an external call is not checked. Note that execution continue even if the called contract throws. +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/rubixi.sol.o.json b/tests/testdata/outputs_expected/rubixi.sol.o.json index bac935c7..d328ade0 100644 --- a/tests/testdata/outputs_expected/rubixi.sol.o.json +++ b/tests/testdata/outputs_expected/rubixi.sol.o.json @@ -8,7 +8,7 @@ "function": "_function_0x4229616d", "type": "Warning", "address": 1599, - "debug": "", + "debug": "" }, { "title": "Ether send", @@ -16,7 +16,7 @@ "function": "_function_0xb4022950", "type": "Warning", "address": 1940, - "debug": "", + "debug": "" }, { "title": "Ether send", @@ -24,7 +24,7 @@ "function": "_function_0xb4022950", "type": "Warning", "address": 2582, - "debug": "", + "debug": "" }, { "title": "Exception state", @@ -32,7 +32,7 @@ "function": "_function_0x57d4021b", "type": "Informational", "address": 1653, - "debug": "", + "debug": "" }, { "title": "Exception state", @@ -40,7 +40,7 @@ "function": "_function_0x9dbc4f9b", "type": "Informational", "address": 2085, - "debug": "", + "debug": "" }, { "title": "Invariant branch condition", @@ -48,7 +48,7 @@ "function": "fallback", "type": "Informational", "address": 3111, - "debug": "", + "debug": "" }, { "title": "Invariant branch condition", @@ -56,7 +56,7 @@ "function": "fallback", "type": "Informational", "address": 3140, - "debug": "", + "debug": "" }, { "title": "Invariant branch condition", @@ -64,7 +64,7 @@ "function": "fallback", "type": "Informational", "address": 2950, - "debug": "", + "debug": "" }, { "title": "Invariant branch condition", @@ -72,7 +72,7 @@ "function": "fallback", "type": "Informational", "address": 1268, - "debug": "", + "debug": "" }, { "title": "Invariant branch condition", @@ -80,7 +80,7 @@ "function": "_function_0x09dfdc71", "type": "Informational", "address": 310, - "debug": "", + "debug": "" }, { "title": "Invariant branch condition", @@ -88,7 +88,7 @@ "function": "_function_0x09dfdc71", "type": "Informational", "address": 1316, - "debug": "", + "debug": "" }, { "title": "Invariant branch condition", @@ -96,7 +96,7 @@ "function": "_function_0x253459e3", "type": "Informational", "address": 1375, - "debug": "", + "debug": "" }, { "title": "Invariant branch condition", @@ -104,7 +104,7 @@ "function": "_function_0x4229616d", "type": "Informational", "address": 1511, - "debug": "", + "debug": "" }, { "title": "Invariant branch condition", @@ -112,7 +112,7 @@ "function": "_function_0x57d4021b", "type": "Informational", "address": 1679, - "debug": "", + "debug": "" }, { "title": "Invariant branch condition", @@ -120,7 +120,7 @@ "function": "_function_0x6fbaaa1e", "type": "Informational", "address": 618, - "debug": "", + "debug": "" }, { "title": "Invariant branch condition", @@ -128,7 +128,7 @@ "function": "_function_0x8a5fb3ca", "type": "Informational", "address": 805, - "debug": "", + "debug": "" }, { "title": "Invariant branch condition", @@ -136,7 +136,7 @@ "function": "_function_0x9dbc4f9b", "type": "Informational", "address": 2187, - "debug": "", + "debug": "" }, { "title": "Unchecked CALL return value", @@ -144,7 +144,7 @@ "function": "_function_0x4229616d", "type": "Informational", "address": 1599, - "debug": "", + "debug": "" }, { "title": "Unchecked CALL return value", @@ -152,7 +152,7 @@ "function": "_function_0xb4022950", "type": "Informational", "address": 1940, - "debug": "", + "debug": "" }, { "title": "Unchecked CALL return value", @@ -160,7 +160,7 @@ "function": "_function_0xb4022950", "type": "Informational", "address": 2582, - "debug": "", - }, - ], -} + "debug": "" + } + ] +} \ No newline at end of file diff --git a/tests/testdata/outputs_expected/suicide.sol.o.json b/tests/testdata/outputs_expected/suicide.sol.o.json index 1cb84c82..5bb5eb13 100644 --- a/tests/testdata/outputs_expected/suicide.sol.o.json +++ b/tests/testdata/outputs_expected/suicide.sol.o.json @@ -1,18 +1 @@ -{ - "error": null, - "issues": [ - { - "address": 146, - "contract": "Unknown", - "debug": "", - "description": "Anyone can kill this contract and withdraw its balance to their own account.", - "function": "kill(address)", - "max_gas_used": 263, - "min_gas_used": 168, - "swc-id": "106", - "title": "Unchecked SUICIDE", - "type": "Warning" - } - ], - "success": true -} +{"error": null, "issues": [{"address": 146, "contract": "Unknown", "debug": "", "description": "The contract can be killed by anyone.\nArbitrary senders can kill this contract and withdraw its balance to their own account.", "function": "kill(address)", "max_gas_used": 263, "min_gas_used": 168, "severity": "High", "sourceMap": null, "swc-id": "106", "title": "Unprotected Selfdestruct"}], "success": true} \ 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 new file mode 100644 index 00000000..b3a966a1 --- /dev/null +++ b/tests/testdata/outputs_expected/suicide.sol.o.jsonv2 @@ -0,0 +1 @@ +{"issues": [{"description": {"head": "The contract can be killed by anyone.", "tail": "Arbitrary senders can kill this contract and withdraw its balance to their own account."}, "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/suicide.sol.o.markdown b/tests/testdata/outputs_expected/suicide.sol.o.markdown index cea3af81..3325269d 100644 --- a/tests/testdata/outputs_expected/suicide.sol.o.markdown +++ b/tests/testdata/outputs_expected/suicide.sol.o.markdown @@ -1,8 +1,8 @@ # Analysis results for test-filename.sol -## Unchecked SUICIDE +## Unprotected Selfdestruct - SWC ID: 106 -- Type: Warning +- Severity: High - Contract: Unknown - Function name: `kill(address)` - PC address: 146 @@ -10,4 +10,5 @@ ### Description -Anyone can kill this contract and withdraw its balance to their own account. +The contract can be killed by anyone. +Arbitrary senders can kill this contract and withdraw its balance to their own account. diff --git a/tests/testdata/outputs_expected/suicide.sol.o.text b/tests/testdata/outputs_expected/suicide.sol.o.text index 20a5bd24..5072a942 100644 --- a/tests/testdata/outputs_expected/suicide.sol.o.text +++ b/tests/testdata/outputs_expected/suicide.sol.o.text @@ -1,10 +1,11 @@ -==== Unchecked SUICIDE ==== +==== Unprotected Selfdestruct ==== SWC ID: 106 -Type: Warning +Severity: High Contract: Unknown Function name: kill(address) PC address: 146 Estimated Gas Usage: 168 - 263 -Anyone can kill this contract and withdraw its balance to their own account. +The contract can be killed by anyone. +Arbitrary senders can kill this contract and withdraw its balance to their own account. -------------------- diff --git a/tests/testdata/outputs_expected/underflow.sol.o.json b/tests/testdata/outputs_expected/underflow.sol.o.json index 55606d81..f14878cc 100644 --- a/tests/testdata/outputs_expected/underflow.sol.o.json +++ b/tests/testdata/outputs_expected/underflow.sol.o.json @@ -4,24 +4,26 @@ "address": 567, "contract": "Unknown", "debug": "", - "description": "This binary subtraction operation can result in integer underflow.\n", + "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": 1774, - "min_gas_used": 1299, + "max_gas_used": 1053, + "min_gas_used": 768, + "severity": "High", + "sourceMap": null, "swc-id": "101", - "title": "Integer Underflow", - "type": "Warning" + "title": "Integer Underflow" }, { "address": 649, "contract": "Unknown", "debug": "", - "description": "This binary subtraction operation can result in integer underflow.\n", + "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": 1774, "min_gas_used": 1299, + "severity": "High", + "sourceMap": null, "swc-id": "101", - "title": "Integer Underflow", - "type": "Warning" + "title": "Integer Underflow" }], "success": true } diff --git a/tests/testdata/outputs_expected/underflow.sol.o.jsonv2 b/tests/testdata/outputs_expected/underflow.sol.o.jsonv2 new file mode 100644 index 00000000..ab57bbd9 --- /dev/null +++ b/tests/testdata/outputs_expected/underflow.sol.o.jsonv2 @@ -0,0 +1,40 @@ +{ + "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 d747f944..8ece5099 100644 --- a/tests/testdata/outputs_expected/underflow.sol.o.markdown +++ b/tests/testdata/outputs_expected/underflow.sol.o.markdown @@ -2,19 +2,20 @@ ## Integer Underflow - SWC ID: 101 -- Type: Warning +- Severity: High - Contract: Unknown - Function name: `sendeth(address,uint256)` - PC address: 567 -- Estimated Gas Usage: 1299 - 1774 +- Estimated Gas Usage: 768 - 1053 ### Description -This binary subtraction operation can result in integer underflow. +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. ## Integer Underflow - SWC ID: 101 -- Type: Warning +- Severity: High - Contract: Unknown - Function name: `sendeth(address,uint256)` - PC address: 649 @@ -22,4 +23,5 @@ This binary subtraction operation can result in integer underflow. ### Description -This binary subtraction operation can result in integer underflow. +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/underflow.sol.o.text b/tests/testdata/outputs_expected/underflow.sol.o.text index 6b35c666..745404aa 100644 --- a/tests/testdata/outputs_expected/underflow.sol.o.text +++ b/tests/testdata/outputs_expected/underflow.sol.o.text @@ -1,22 +1,22 @@ ==== Integer Underflow ==== SWC ID: 101 -Type: Warning +Severity: High Contract: Unknown Function name: sendeth(address,uint256) PC address: 567 -Estimated Gas Usage: 1299 - 1774 -This binary subtraction operation can result in integer underflow. - +Estimated Gas Usage: 768 - 1053 +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. -------------------- ==== Integer Underflow ==== SWC ID: 101 -Type: Warning +Severity: High Contract: Unknown Function name: sendeth(address,uint256) PC address: 649 Estimated Gas Usage: 1299 - 1774 -This binary subtraction operation can result in integer underflow. - +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/weak_random.sol.o.json b/tests/testdata/outputs_expected/weak_random.sol.o.json index 681f8544..2338b178 100644 --- a/tests/testdata/outputs_expected/weak_random.sol.o.json +++ b/tests/testdata/outputs_expected/weak_random.sol.o.json @@ -8,7 +8,7 @@ "function": "_function_0xe9874106", "type": "Warning", "address": 1285, - "debug": "", + "debug": "" }, { "title": "Ether send", @@ -16,7 +16,7 @@ "function": "_function_0xe9874106", "type": "Warning", "address": 1285, - "debug": "", + "debug": "" }, { "title": "Exception state", @@ -24,7 +24,7 @@ "function": "fallback", "type": "Informational", "address": 356, - "debug": "", + "debug": "" }, { "title": "Exception state", @@ -32,7 +32,7 @@ "function": "_function_0xe9874106", "type": "Informational", "address": 146, - "debug": "", + "debug": "" }, { "title": "Transaction order dependence", @@ -40,7 +40,7 @@ "function": "_function_0xe9874106", "type": "Warning", "address": 1285, - "debug": "", - }, - ], -} + "debug": "" + } + ] +} \ No newline at end of file