Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix issues with statespace on solc 0.8.26 #1863

Merged
merged 7 commits into from
Aug 29, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 22 additions & 24 deletions mythril/analysis/callgraph.py
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@
graphs."""

import re
from typing import Dict, List

from jinja2 import Environment, PackageLoader, select_autoescape
from z3 import Z3Exception
@@ -125,63 +126,60 @@
}


def extract_nodes(statespace):
def extract_nodes(statespace) -> List[Dict]:
"""
Extract nodes from the given statespace and create a list of node dictionaries
with visual attributes for graph representation.

:param statespace:
:param color_map:
:return:
:param statespace: The statespace object containing nodes and states information.
:return: A list of dictionaries representing each node with its attributes.
"""
nodes = []
color_map = {}
for node_key in statespace.nodes:
node = statespace.nodes[node_key]
for node_key, node in statespace.nodes.items():
instructions = [state.get_current_instruction() for state in node.states]
code_split = []

for instruction in instructions:
if instruction["opcode"].startswith("PUSH"):
code_line = "%d %s %s" % (
instruction["address"],
instruction["opcode"],
instruction["argument"],
)
address = instruction["address"]
opcode = instruction["opcode"]
if opcode.startswith("PUSH"):
code_line = f"{address} {opcode} {instruction.get('argument', '')}"
elif (
instruction["opcode"].startswith("JUMPDEST")
opcode.startswith("JUMPDEST")
and NodeFlags.FUNC_ENTRY in node.flags
and instruction["address"] == node.start_addr
and address == node.start_addr
):
code_line = node.function_name
else:
code_line = "%d %s" % (instruction["address"], instruction["opcode"])
code_line = f"{address} {opcode}"

code_line = re.sub(
"([0-9a-f]{8})[0-9a-f]+", lambda m: m.group(1) + "(...)", code_line
)
code_line = re.sub(r"([0-9a-f]{8})[0-9a-f]+", r"\1(...)", code_line)
code_split.append(code_line)

truncated_code = (
"\n".join(code_split)
if (len(code_split) < 7)
if len(code_split) < 7
else "\n".join(code_split[:6]) + "\n(click to expand +)"
)

if node.get_cfg_dict()["contract_name"] not in color_map.keys():
contract_name = node.get_cfg_dict()["contract_name"]
if contract_name not in color_map:
color = default_colors[len(color_map) % len(default_colors)]
color_map[node.get_cfg_dict()["contract_name"]] = color
color_map[contract_name] = color

nodes.append(
{
"id": str(node_key),
"color": color_map.get(
node.get_cfg_dict()["contract_name"], default_colors[0]
),
"color": color_map.get(contract_name, default_colors[0]),
"size": 150,
"fullLabel": "\n".join(code_split),
"label": truncated_code,
"truncLabel": truncated_code,
"isExpanded": False,
}
)

return nodes


38 changes: 21 additions & 17 deletions mythril/laser/ethereum/cfg.py
Original file line number Diff line number Diff line change
@@ -59,25 +59,29 @@ def __init__(

def get_cfg_dict(self) -> Dict:
"""
Generate a configuration dictionary for the current state of the contract.

:return:
:return: A dictionary containing the contract's configuration details.
"""
code = ""
for state in self.states:
instruction = state.get_current_instruction()

code += str(instruction["address"]) + " " + instruction["opcode"]
if instruction["opcode"].startswith("PUSH"):
code += " " + "".join(str(instruction["argument"]))

code += "\\n"

return dict(
contract_name=self.contract_name,
start_addr=self.start_addr,
function_name=self.function_name,
code=code,
)
code_lines = [
f"{instruction['address']} {instruction['opcode']}"
+ (
f" {instruction['argument']}"
if instruction["opcode"].startswith("PUSH")
and "argument" in instruction
else ""
)
for state in self.states
for instruction in [state.get_current_instruction()]
]
code = "\\n".join(code_lines)

return {
"contract_name": self.contract_name,
"start_addr": self.start_addr,
"function_name": self.function_name,
"code": code,
}


class Edge: