Merge pull request #971 from ConsenSys/jsonv2fix

Fix the jsonv2 output for the type of the contract
pull/997/head
Nikhil Parasaram 6 years ago committed by GitHub
commit d42153f592
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 35
      mythril/analysis/report.py
  2. 29
      mythril/ethereum/evmcontract.py
  3. 4
      mythril/mythril.py
  4. 2
      mythril/mythril/mythril_analyzer.py
  5. 20
      mythril/support/source_support.py
  6. 19
      mythril/support/support_utils.py
  7. 2
      tests/report_test.py
  8. 10
      tests/testdata/outputs_expected/ether_send.sol.o.jsonv2
  9. 10
      tests/testdata/outputs_expected/metacoin.sol.o.jsonv2
  10. 10
      tests/testdata/outputs_expected/nonascii.sol.o.jsonv2

@ -4,13 +4,13 @@ import json
import operator import operator
from jinja2 import PackageLoader, Environment from jinja2 import PackageLoader, Environment
from typing import Dict, List from typing import Dict, List
import _pysha3 as sha3
import hashlib import hashlib
from mythril.solidity.soliditycontract import SolidityContract from mythril.solidity.soliditycontract import SolidityContract
from mythril.analysis.swc_data import SWC_TO_TITLE from mythril.analysis.swc_data import SWC_TO_TITLE
from mythril.support.source_support import Source from mythril.support.source_support import Source
from mythril.support.start_time import StartTime from mythril.support.start_time import StartTime
from mythril.support.support_utils import get_code_hash
from time import time from time import time
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -63,20 +63,7 @@ class Issue:
self.lineno = None self.lineno = None
self.source_mapping = None self.source_mapping = None
self.discovery_time = time() - StartTime().global_start_time self.discovery_time = time() - StartTime().global_start_time
self.bytecode_hash = get_code_hash(bytecode)
try:
keccak = sha3.keccak_256()
keccak.update(
bytes.fromhex(bytecode[2:])
if bytecode[:2] == "0x"
else bytes.fromhex(bytecode)
)
self.bytecode_hash = "0x" + keccak.hexdigest()
except ValueError:
log.debug(
"Unable to change the bytecode to bytes. Bytecode: {}".format(bytecode)
)
self.bytecode_hash = ""
@property @property
def as_dict(self): def as_dict(self):
@ -144,7 +131,7 @@ class Report:
loader=PackageLoader("mythril.analysis"), trim_blocks=True loader=PackageLoader("mythril.analysis"), trim_blocks=True
) )
def __init__(self, verbose=False, source=None, exceptions=None): def __init__(self, verbose=False, contracts=None, exceptions=None):
""" """
:param verbose: :param verbose:
@ -153,7 +140,8 @@ class Report:
self.verbose = verbose self.verbose = verbose
self.solc_version = "" self.solc_version = ""
self.meta = {} self.meta = {}
self.source = source or Source() self.source = Source()
self.source.get_source_from_contracts_list(contracts)
self.exceptions = exceptions or [] self.exceptions = exceptions or []
def sorted_issues(self): def sorted_issues(self):
@ -210,12 +198,7 @@ class Report:
for key, issue in self.issues.items(): for key, issue in self.issues.items():
if issue.bytecode_hash not in source_list: idx = self.source.get_source_index(issue.bytecode_hash)
idx = len(source_list)
source_list.append(issue.bytecode_hash)
else:
idx = source_list.index(issue.bytecode_hash)
try: try:
title = SWC_TO_TITLE[issue.swc_id] title = SWC_TO_TITLE[issue.swc_id]
except KeyError: except KeyError:
@ -238,9 +221,9 @@ class Report:
result = [ result = [
{ {
"issues": _issues, "issues": _issues,
"sourceType": "raw-bytecode", "sourceType": self.source.source_type,
"sourceFormat": "evm-byzantium-bytecode", "sourceFormat": self.source.source_format,
"sourceList": source_list, "sourceList": self.source.source_list,
"meta": meta_data, "meta": meta_data,
} }
] ]

@ -1,15 +1,14 @@
"""This module contains the class representing EVM contracts, aka Smart """This module contains the class representing EVM contracts, aka Smart
Contracts.""" Contracts."""
import re import re
import _pysha3 as sha3
import logging import logging
log = logging.getLogger(__name__)
import persistent import persistent
from ethereum import utils
from ethereum import utils
from mythril.disassembler.disassembly import Disassembly from mythril.disassembler.disassembly import Disassembly
from mythril.support.support_utils import get_code_hash
log = logging.getLogger(__name__)
class EVMContract(persistent.Persistent): class EVMContract(persistent.Persistent):
@ -47,7 +46,7 @@ class EVMContract(persistent.Persistent):
:return: runtime bytecode hash :return: runtime bytecode hash
""" """
return self._get_hash(self.code[2:]) return get_code_hash(self.code)
@property @property
def creation_bytecode_hash(self): def creation_bytecode_hash(self):
@ -55,23 +54,7 @@ class EVMContract(persistent.Persistent):
:return: Creation bytecode hash :return: Creation bytecode hash
""" """
return self._get_hash(self.creation_code[2:]) return get_code_hash(self.creation_code)
@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): def as_dict(self):
""" """

@ -608,10 +608,8 @@ class Mythril(object):
all_issues += issues all_issues += issues
log.info("Solver statistics: \n{}".format(str(SolverStatistics()))) log.info("Solver statistics: \n{}".format(str(SolverStatistics())))
source_data = Source()
source_data.get_source_from_contracts_list(self.contracts)
# Finally, output the results # Finally, output the results
report = Report(verbose_report, source_data, exceptions=exceptions) report = Report(verbose_report, self.contracts, exceptions=exceptions)
for issue in all_issues: for issue in all_issues:
report.append_issue(issue) report.append_issue(issue)

@ -166,7 +166,7 @@ class MythrilAnalyzer:
source_data = Source() source_data = Source()
source_data.get_source_from_contracts_list(self.contracts) source_data.get_source_from_contracts_list(self.contracts)
# Finally, output the results # Finally, output the results
report = Report(verbose_report, source_data, exceptions=exceptions) report = Report(verbose_report, contracts=self.contracts, exceptions=exceptions)
for issue in all_issues: for issue in all_issues:
report.append_issue(issue) report.append_issue(issue)

@ -5,9 +5,7 @@ from mythril.ethereum.evmcontract import EVMContract
class Source: class Source:
"""Class to handle to source data""" """Class to handle to source data"""
def __init__( def __init__(self, source_type=None, source_format=None, source_list=None):
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_type: whether it is a solidity-file or evm-bytecode
:param source_format: whether it is bytecode, ethereum-address or text :param source_format: whether it is bytecode, ethereum-address or text
@ -17,7 +15,7 @@ class Source:
self.source_type = source_type self.source_type = source_type
self.source_format = source_format self.source_format = source_format
self.source_list = source_list or [] self.source_list = source_list or []
self.meta = meta self._source_hash = []
def get_source_from_contracts_list(self, contracts): def get_source_from_contracts_list(self, contracts):
""" """
@ -32,16 +30,28 @@ class Source:
self.source_format = "text" self.source_format = "text"
for contract in contracts: for contract in contracts:
self.source_list += [file.filename for file in contract.solidity_files] self.source_list += [file.filename for file in contract.solidity_files]
self._source_hash.append(contract.bytecode_hash)
elif isinstance(contracts[0], EVMContract): elif isinstance(contracts[0], EVMContract):
self.source_format = "evm-byzantium-bytecode" self.source_format = "evm-byzantium-bytecode"
self.source_type = ( self.source_type = (
"raw-bytecode" if contracts[0].name == "MAIN" else "ethereum-address" "ethereum-address"
if len(contracts[0].name) == 42 and contracts[0].name[0:2] == "0x"
else "raw-bytecode"
) )
for contract in contracts: for contract in contracts:
if contract.creation_code: if contract.creation_code:
self.source_list.append(contract.creation_bytecode_hash) self.source_list.append(contract.creation_bytecode_hash)
if contract.code: if contract.code:
self.source_list.append(contract.bytecode_hash) self.source_list.append(contract.bytecode_hash)
self._source_hash = self.source_list
else: else:
assert False # Fail hard assert False # Fail hard
def get_source_index(self, bytecode_hash: str) -> int:
"""
Find the contract index in the list
:param bytecode_hash: The contract hash
:return: The index of the contract in the _source_hash list
"""
return self._source_hash.index(bytecode_hash)

@ -1,5 +1,9 @@
"""This module contains utility functions for the Mythril support package.""" """This module contains utility functions for the Mythril support package."""
from typing import Dict from typing import Dict
import logging
import _pysha3 as sha3
log = logging.getLogger(__name__)
class Singleton(type): class Singleton(type):
@ -20,3 +24,18 @@ class Singleton(type):
if cls not in cls._instances: if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs) cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls] return cls._instances[cls]
def get_code_hash(code: str) -> str:
"""
:param code: bytecode
:return: Returns hash of the given bytecode
"""
code = code[2:] if code[:2] == "0x" else code
try:
keccak = sha3.keccak_256()
keccak.update(bytes.fromhex(code))
return "0x" + keccak.hexdigest()
except ValueError:
log.debug("Unable to change the bytecode to bytes. Bytecode: {}".format(code))
return ""

@ -39,7 +39,7 @@ def _generate_report(input_file):
) )
issues = fire_lasers(sym) issues = fire_lasers(sym)
report = Report() report = Report(contracts=[contract])
for issue in issues: for issue in issues:
issue.filename = "test-filename.sol" issue.filename = "test-filename.sol"
report.append_issue(issue) report.append_issue(issue)

@ -1,9 +1 @@
[ [{"issues": [], "meta": {}, "sourceFormat": "evm-byzantium-bytecode", "sourceList": ["0x3746c7c2ae7b0d4c3f8b1905df9a7ea169b9f93bec68a10a00b4c9d27a18c6fb"], "sourceType": "raw-bytecode"}]
{
"issues": [],
"meta": {},
"sourceFormat": "evm-byzantium-bytecode",
"sourceList": [],
"sourceType": "raw-bytecode"
}
]

@ -1,9 +1 @@
[ [{"issues": [], "meta": {}, "sourceFormat": "evm-byzantium-bytecode", "sourceList": ["0x0e6f727bb3301e02d3be831bf34357522fd2f1d40e90dff8e2214553b06b5f6c"], "sourceType": "raw-bytecode"}]
{
"issues": [],
"meta": {},
"sourceFormat": "evm-byzantium-bytecode",
"sourceList": [],
"sourceType": "raw-bytecode"
}
]

@ -1,9 +1 @@
[ [{"issues": [], "meta": {}, "sourceFormat": "evm-byzantium-bytecode", "sourceList": ["0x11a78eb09819f505ba4f10747e6d1f7a44480e602c67573b7abac2f733a85d93"], "sourceType": "raw-bytecode"}]
{
"issues": [],
"meta": {},
"sourceFormat": "evm-byzantium-bytecode",
"sourceList": [],
"sourceType": "raw-bytecode"
}
]

Loading…
Cancel
Save