Merge branch 'develop' of github.com:ConsenSys/mythril-classic into dependence

pull/1029/head
Bernhard Mueller 6 years ago
commit c8aad25921
  1. 2
      mythril/ethereum/util.py
  2. 54
      mythril/solidity/soliditycontract.py

@ -33,7 +33,7 @@ def get_solc_json(file, solc_binary="solc", solc_args=None):
:return: :return:
""" """
cmd = [solc_binary, "--combined-json", "bin,bin-runtime,srcmap,srcmap-runtime"] cmd = [solc_binary, "--combined-json", "bin,bin-runtime,srcmap,srcmap-runtime,ast"]
if solc_args: if solc_args:
cmd.extend(solc_args.split()) cmd.extend(solc_args.split())

@ -1,5 +1,7 @@
"""This module contains representation classes for Solidity files, contracts """This module contains representation classes for Solidity files, contracts
and source mappings.""" and source mappings."""
from typing import Dict, Set
import mythril.laser.ethereum.util as helper import mythril.laser.ethereum.util as helper
from mythril.ethereum.evmcontract import EVMContract from mythril.ethereum.evmcontract import EVMContract
from mythril.ethereum.util import get_solc_json from mythril.ethereum.util import get_solc_json
@ -20,9 +22,16 @@ class SourceMapping:
class SolidityFile: class SolidityFile:
"""Representation of a file containing Solidity code.""" """Representation of a file containing Solidity code."""
def __init__(self, filename, data): def __init__(self, filename: str, data: str, full_contract_source: Set[str]):
"""
Metadata class containing data regarding a specific solidity file
:param filename: The filename of the solidity file
:param data: The code of the solidity file
:param full_contract_source: The set of contract source mappings of all the contracts in the file
"""
self.filename = filename self.filename = filename
self.data = data self.data = data
self.full_contract_source = full_contract_source
class SourceCodeInfo: class SourceCodeInfo:
@ -69,7 +78,12 @@ class SolidityContract(EVMContract):
for filename in data["sourceList"]: for filename in data["sourceList"]:
with open(filename, "r", encoding="utf-8") as file: with open(filename, "r", encoding="utf-8") as file:
code = file.read() code = file.read()
self.solidity_files.append(SolidityFile(filename, code)) full_contract_sources = self.get_full_contract_sources(
data["sources"][filename]["AST"]
)
self.solidity_files.append(
SolidityFile(filename, code, full_contract_sources)
)
has_contract = False has_contract = False
@ -117,6 +131,19 @@ class SolidityContract(EVMContract):
super().__init__(code, creation_code, name=name) super().__init__(code, creation_code, name=name)
@staticmethod
def get_full_contract_sources(ast: Dict) -> Set[str]:
"""
Takes a solc AST and gets the src mappings for all the contracts defined in the top level of the ast
:param ast: AST of the contract
:return: The source map
"""
source_map = set()
for child in ast["children"]:
if "contractKind" in child["attributes"]:
source_map.add(child["src"])
return source_map
def get_source_info(self, address, constructor=False): def get_source_info(self, address, constructor=False):
""" """
@ -140,6 +167,26 @@ class SolidityContract(EVMContract):
lineno = mappings[index].lineno lineno = mappings[index].lineno
return SourceCodeInfo(filename, lineno, code, mappings[index].solc_mapping) return SourceCodeInfo(filename, lineno, code, mappings[index].solc_mapping)
def _is_autogenerated_code(self, offset: int, length: int, file_index: int) -> bool:
"""
Checks whether the code is autogenerated or not
:param offset: offset of the code
:param length: length of the code
:param file_index: file the code corresponds to
:return: True if the code is internally generated, else false
"""
# Handle internal compiler files
if file_index == -1:
return True
# Handle the common code src map for the entire code.
if (
"{}:{}:{}".format(offset, length, file_index)
in self.solidity_files[file_index].full_contract_source
):
return True
return False
def _get_solc_mappings(self, srcmap, constructor=False): def _get_solc_mappings(self, srcmap, constructor=False):
""" """
@ -161,7 +208,8 @@ class SolidityContract(EVMContract):
if len(mapping) > 2 and len(mapping[2]) > 0: if len(mapping) > 2 and len(mapping[2]) > 0:
idx = int(mapping[2]) idx = int(mapping[2])
if idx == -1:
if self._is_autogenerated_code(offset, length, idx):
lineno = None lineno = None
else: else:
lineno = ( lineno = (

Loading…
Cancel
Save