Merge pull request #1411 from ConsenSys/feature/execution_info

Execution info
pull/1417/head
JoranHonig 4 years ago committed by GitHub
commit 727d5f3049
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 28
      mythril/analysis/report.py
  2. 5
      mythril/analysis/symbolic.py
  3. 4
      mythril/laser/ethereum/svm.py
  4. 11
      mythril/laser/execution_info.py
  5. 10
      mythril/mythril/mythril_analyzer.py
  6. 5
      tests/mythril/mythril_analyzer_test.py

@ -3,9 +3,10 @@ import logging
import json
import operator
from jinja2 import PackageLoader, Environment
from typing import Dict, List
from typing import Dict, List, Any, Optional
import hashlib
from mythril.laser.execution_info import ExecutionInfo
from mythril.solidity.soliditycontract import SolidityContract
from mythril.analysis.swc_data import SWC_TO_TITLE
from mythril.support.source_support import Source
@ -184,18 +185,24 @@ class Report:
loader=PackageLoader("mythril.analysis"), trim_blocks=True
)
def __init__(self, contracts=None, exceptions=None):
def __init__(
self,
contracts=None,
exceptions=None,
execution_info: Optional[List[ExecutionInfo]] = None,
):
"""
:param contracts:
:param exceptions:
"""
self.issues = {}
self.issues = {} # type: Dict[bytes, Issue]
self.solc_version = ""
self.meta = {}
self.meta = {} # type: Dict[str, Any]
self.source = Source()
self.source.get_source_from_contracts_list(contracts)
self.exceptions = exceptions or []
self.execution_info = execution_info or []
def sorted_issues(self):
"""
@ -246,6 +253,7 @@ class Report:
:return:
"""
# Setup issues
_issues = []
for key, issue in self.issues.items():
@ -272,7 +280,17 @@ class Report:
"extra": extra,
}
)
meta_data = self._get_exception_data()
# Setup meta
meta_data = self.meta
# Add logs to meta
meta_data.update(self._get_exception_data())
# Add execution info to meta
meta_data["mythril_execution_info"] = {}
for execution_info in self.execution_info:
meta_data["mythril_execution_info"].update(execution_info.as_dict())
result = [
{
"issues": _issues,

@ -2,6 +2,7 @@
purposes."""
from mythril.analysis.module import EntryPoint, ModuleLoader, get_detection_module_hooks
from mythril.laser.execution_info import ExecutionInfo
from mythril.laser.ethereum import svm
from mythril.laser.ethereum.state.account import Account
from mythril.laser.ethereum.state.world_state import WorldState
@ -300,3 +301,7 @@ class SymExecWrapper:
)
state_index += 1
@property
def execution_info(self) -> List[ExecutionInfo]:
return self.laser.execution_info

@ -7,6 +7,7 @@ from typing import Callable, Dict, DefaultDict, List, Tuple, Optional
from mythril.support.opcodes import opcodes as OPCODES
from mythril.analysis.potential_issues import check_potential_issues
from mythril.laser.execution_info import ExecutionInfo
from mythril.laser.ethereum.cfg import NodeFlags, Node, Edge, JumpType
from mythril.laser.ethereum.evm_exceptions import StackUnderflowException
from mythril.laser.ethereum.evm_exceptions import VmException
@ -72,8 +73,9 @@ class LaserEVM:
:param requires_statespace: Variable indicating whether the statespace should be recorded
:param iprof: Instruction Profiler
"""
self.open_states = [] # type: List[WorldState]
self.execution_info = [] # type: List[ExecutionInfo]
self.open_states = [] # type: List[WorldState]
self.total_states = 0
self.dynamic_loader = dynamic_loader

@ -0,0 +1,11 @@
from abc import ABC, abstractmethod
class ExecutionInfo(ABC):
@abstractmethod
def as_dict(self):
"""Returns a dictionary with the execution info contained in this object
The returned dictionary only uses primitive types.
"""
pass

@ -19,6 +19,7 @@ from mythril.ethereum.evmcontract import EVMContract
from mythril.laser.smt import SolverStatistics
from mythril.support.start_time import StartTime
from mythril.exceptions import DetectorNotFoundError
from mythril.laser.execution_info import ExecutionInfo
log = logging.getLogger(__name__)
@ -139,6 +140,7 @@ class MythrilAnalyzer:
all_issues = [] # type: List[Issue]
SolverStatistics().enabled = True
exceptions = []
execution_info = None # type: Optional[List[ExecutionInfo]]
for contract in self.contracts:
StartTime() # Reinitialize start time for new contracts
try:
@ -158,6 +160,7 @@ class MythrilAnalyzer:
custom_modules_directory=self.custom_modules_directory,
)
issues = fire_lasers(sym, modules)
execution_info = sym.execution_info
except DetectorNotFoundError as e:
# Bubble up
raise e
@ -179,8 +182,13 @@ class MythrilAnalyzer:
source_data = Source()
source_data.get_source_from_contracts_list(self.contracts)
# Finally, output the results
report = Report(contracts=self.contracts, exceptions=exceptions)
report = Report(
contracts=self.contracts,
exceptions=exceptions,
execution_info=execution_info,
)
for issue in all_issues:
report.append_issue(issue)

@ -1,7 +1,7 @@
from pathlib import Path
from mythril.mythril import MythrilDisassembler, MythrilAnalyzer
from mythril.analysis.report import Issue
from mock import patch
from mock import patch, PropertyMock
@patch("mythril.analysis.report.Issue.add_code_info", return_value=None)
@ -9,8 +9,9 @@ from mock import patch
"mythril.mythril.mythril_analyzer.fire_lasers",
return_value=[Issue("", "", "234", "101", "title", "0x02445")],
)
@patch("mythril.mythril.mythril_analyzer.SymExecWrapper", return_value=None)
@patch("mythril.mythril.mythril_analyzer.SymExecWrapper")
def test_fire_lasers(mock_sym, mock_fire_lasers, mock_code_info):
type(mock_sym.return_value).execution_info = PropertyMock(return_value=[])
disassembler = MythrilDisassembler(eth=None)
disassembler.load_from_solidity(
[

Loading…
Cancel
Save