Skip to content

Commit

Permalink
Full refactoring of dependencies to fix some bugs in the interval checks
Browse files Browse the repository at this point in the history
  • Loading branch information
alexcere committed Oct 7, 2024
1 parent b49015b commit 144a1cb
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 99 deletions.
16 changes: 15 additions & 1 deletion src/global_params/types.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,28 @@
"""
Module that contains the declaration of common types used throughout the project
"""
from typing import Dict, Union, Any
from typing import Dict, Union, Any, List, Tuple

# Type for the stack variables that are introduced in the stack as args of other expressions
var_id_T = str

# An expression consists of either a variable, a constant or an op and their subexpressions
# Its grammar:
# exp -> int_val | input_var | (op, [exp1, ..., expn])
expression_T = Union[int, var_id_T, Tuple[str, List['expression_T']]]

# Representation of an interval formed by an expression and an offset
memory_instr_interval_T = Tuple[expression_T, expression_T]

# Type for the id of instructions in the SMS
instr_id_T = str

# Id for block ids
block_id_T = str

# How dependencies among instructions are represented
dependencies_T = List[List[instr_id_T]]

ASM_bytecode_T = Dict[str, Union[int, str]]

# SMS refers to the JSON representation of a block, with the initial and final stacks and the operations
Expand Down
48 changes: 33 additions & 15 deletions src/parser/cfg_block.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import logging

from global_params.types import instr_id_T
from global_params.types import instr_id_T, dependencies_T
from parser.cfg_instruction import CFGInstruction, build_push_spec, build_pushtag_spec
from parser.utils_parser import is_in_input_stack, is_in_output_stack, are_dependent_interval, get_empty_spec, \
get_expression, are_dependent_accesses, replace_pos_instrsid, generate_dep, get_interval
Expand Down Expand Up @@ -217,7 +217,11 @@ def check_validity_arguments(self):
print("[WARNING]: Aliasing between variables!")

def _process_dependences(self, instructions: List[CFGInstruction],
map_positions: Dict[int, instr_id_T]) -> List[Tuple[instr_id_T, instr_id_T]]:
map_positions: Dict[int, instr_id_T]) -> Tuple[dependencies_T, dependencies_T]:
"""
Given the list of instructions and a dict that maps each position in a sequence to the instruction id, generates
a list of dependencies
"""
sto_dep = self._compute_storage_dependences(instructions)
sto_dep = self._simplify_dependences(sto_dep)
sto_deps = replace_pos_instrsid(sto_dep, map_positions)
Expand All @@ -227,20 +231,32 @@ def _process_dependences(self, instructions: List[CFGInstruction],
mem_deps = replace_pos_instrsid(mem_dep, map_positions)
return sto_deps, mem_deps

def _compute_storage_dependences(self, instructions: List[CFGInstruction]):
def _compute_storage_dependences(self, instructions: List[CFGInstruction]) -> List[List[int]]:
"""
Returns a list with the positions that have storage dependencies
"""
sto_ins = []
# print(instructions)
for i in range(len(instructions)):
ins = instructions[i]
for i, ins in enumerate(instructions):

if ins.get_op_name() in ["sload", "sstore"]:
v = ins.get_in_args()[0]
input_val = get_expression(v, instructions[:i])
sto_ins.append([i, input_val, ins.get_type_mem_op()])

# Store instructions have an empty offset
interval = (input_val, 0)

# We store the position of the store access, the position accessed and the type (whether write or read)
sto_ins.append([i, interval, ins.get_type_mem_op()])

# elif ins.get_op_name() in ["call","delegatecall","staticcall","callcode"]:
# sto_ins.append([i,["inf"],"write"])

deps = [[sto_ins[i][0], j[0]] for i in range(len(sto_ins)) for j in sto_ins[i + 1:] if
are_dependent_accesses(sto_ins[i][1], j[1]) and generate_dep(sto_ins[i][2], j[2])]
deps = [[first_sto_access[0], second_sto_access[0]]
for i, first_sto_access in enumerate(sto_ins) for second_sto_access in sto_ins[i + 1:]
if are_dependent_accesses(first_sto_access[1], second_sto_access[1])
and generate_dep(first_sto_access[2], second_sto_access[2])]

# print("DEPS: "+str(deps))
# print("******")
return deps
Expand All @@ -252,22 +268,21 @@ def _compute_memory_dependences(self, instructions: List[CFGInstruction]):
mem_instrs_offset = [
"keccak256"] # , "codecopy","extcodecopy","calldatacopy","returndatacopy","mcopy","log0","log1","log2","log3","log4","create","create2","call","delegatecall","staticcall","callcode"]

for i in range(len(instructions)):
ins = instructions[i]
for i, ins in enumerate(instructions):

if ins.get_op_name() in mem_instrs_access:
v = ins.get_in_args()[0]
input_val = get_expression(v, instructions[:i])
interval = [input_val, ["0x20"]]
interval = (input_val, 32)
mem_ins.append([i, interval, ins.get_type_mem_op()])

elif ins.get_op_name() in mem_instrs_offset:
values = ins.get_in_args()

interval_args = get_interval(ins.get_op_name(), values)

if ins.get_op_name() not in ["call", "callcode", "delegatecall", "staticcall"]:
input_vals = list(map(lambda x: get_expression(x, instructions[:i]), interval_args))
interval = [input_vals[0], input_vals[1]]
interval = (input_vals[0], input_vals[1])
mem_ins.append([i, interval, ins.get_type_mem_op()])

# else:
Expand All @@ -280,8 +295,11 @@ def _compute_memory_dependences(self, instructions: List[CFGInstruction]):
# interval = [input_vals[0],input_vals[1]]
# mem_ins.append([i,interval, "write"])

deps = [[mem_ins[i][0], j[0]] for i in range(len(mem_ins)) for j in mem_ins[i + 1:] if
are_dependent_interval(mem_ins[i][1], j[1]) and generate_dep(mem_ins[i][2], j[2])]
deps = [[first_mem_ins[0], second_mem_ins[0]]
for i, first_mem_ins in enumerate(mem_ins) for second_mem_ins in mem_ins[i + 1:]
if generate_dep(first_mem_ins[2], second_mem_ins[2]) and
are_dependent_interval(first_mem_ins[1], second_mem_ins[1])]

# print("DEPS: "+str(deps))
# print("******")
return deps
Expand Down
Loading

0 comments on commit 144a1cb

Please sign in to comment.