Skip to content

Commit

Permalink
Rename father/son to predecessor/successor
Browse files Browse the repository at this point in the history
This is a breaking change in the API but for the moment, we keep the compatibility layer in the cfg/node.py.
  • Loading branch information
DarkaMaul committed Apr 12, 2024
1 parent 118c916 commit b90371d
Show file tree
Hide file tree
Showing 30 changed files with 326 additions and 260 deletions.
4 changes: 2 additions & 2 deletions examples/scripts/taint_mapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ def visit_node(node, visited):

node.function.compilation_unit.context[KEY] = list(set(taints))

for son in node.sons:
visit_node(son, visited)
for successor in node.successors:
visit_node(successor, visited)


def check_call(func, taints):
Expand Down
8 changes: 4 additions & 4 deletions slither/analyses/write/are_variables_written.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,18 +86,18 @@ def _visit(
lvalue = refs_lvalues

ret: List[Variable] = []
if not node.sons and node.type not in [NodeType.THROW, NodeType.RETURN]:
if not node.successors and node.type not in [NodeType.THROW, NodeType.RETURN]:
ret += [v for v in variables_to_write if v not in variables_written]

# Explore sons if
# Explore successors if
# - Before is none: its the first time we explored the node
# - variables_written is not before: it means that this path has a configuration of set variables
# that we haven't seen yet
before = state.nodes[node] if node in state.nodes else None
if before is None or variables_written not in before:
state.nodes[node].append(variables_written)
for son in node.sons:
ret += _visit(son, state, variables_written, variables_to_write)
for successor in node.successors:
ret += _visit(successor, state, variables_written, variables_to_write)
return ret


Expand Down
156 changes: 98 additions & 58 deletions slither/core/cfg/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
Node module
"""
from enum import Enum
import logging
from typing import Optional, List, Set, Dict, Tuple, Union, TYPE_CHECKING

from slither.all_exceptions import SlitherException
Expand Down Expand Up @@ -64,6 +65,8 @@
###################################################################################
###################################################################################

logger = logging.getLogger("SlitherNode")


class NodeType(Enum):
ENTRYPOINT = "ENTRY_POINT" # no expression
Expand Down Expand Up @@ -125,8 +128,8 @@ def __init__(
self._node_type = node_type

# TODO: rename to explicit CFG
self._sons: List["Node"] = []
self._fathers: List["Node"] = []
self._successors: List["Node"] = []
self._predecessors: List["Node"] = []

## Dominators info
# Dominators nodes
Expand Down Expand Up @@ -225,7 +228,7 @@ def type(self, new_type: NodeType) -> None:

@property
def will_return(self) -> bool:
if not self.sons and self.type != NodeType.THROW:
if not self.successors and self.type != NodeType.THROW:
if SolidityFunction("revert()") not in self.solidity_calls:
if SolidityFunction("revert(string)") not in self.solidity_calls:
return True
Expand Down Expand Up @@ -582,97 +585,97 @@ def add_inline_asm(self, asm: Union[str, Dict]) -> None:
###################################################################################
###################################################################################

def add_father(self, father: "Node") -> None:
"""Add a father node
def add_predecessor(self, predecessor: "Node") -> None:
"""Add a predecessor node
Args:
father: father to add
predecessor: predecessor to add
"""
self._fathers.append(father)
self._predecessors.append(predecessor)

def set_fathers(self, fathers: List["Node"]) -> None:
"""Set the father nodes
def set_predecessors(self, predecessors: List["Node"]) -> None:
"""Set the predecessors nodes
Args:
fathers: list of fathers to add
predecessors: list of predecessors to add
"""
self._fathers = fathers
self._predecessors = predecessors

@property
def fathers(self) -> List["Node"]:
"""Returns the father nodes
def predecessors(self) -> List["Node"]:
"""Returns the predecessor nodes
Returns:
list(Node): list of fathers
list(Node): list of predecessor
"""
return list(self._fathers)
return list(self._predecessors)

def remove_father(self, father: "Node") -> None:
"""Remove the father node. Do nothing if the node is not a father
def remove_predecessor(self, predecessor: "Node") -> None:
"""Remove the predecessor node. Do nothing if the node is not a predecessor
Args:
:param father:
:param predecessor:
"""
self._fathers = [x for x in self._fathers if x.node_id != father.node_id]
self._predecessors = [x for x in self._predecessors if x.node_id != predecessor.node_id]

def remove_son(self, son: "Node") -> None:
"""Remove the son node. Do nothing if the node is not a son
def remove_successor(self, successor: "Node") -> None:
"""Remove the successor node. Do nothing if the node is not a successor
Args:
:param son:
:param successor:
"""
self._sons = [x for x in self._sons if x.node_id != son.node_id]
self._successors = [x for x in self._successors if x.node_id != successor.node_id]

def add_son(self, son: "Node") -> None:
"""Add a son node
def add_successor(self, successor: "Node") -> None:
"""Add a successor node
Args:
son: son to add
successor: successor to add
"""
self._sons.append(son)
self._successors.append(successor)

def replace_son(self, ori_son: "Node", new_son: "Node") -> None:
"""Replace a son node. Do nothing if the node to replace is not a son
def replace_successor(self, old_successor: "Node", new_successor: "Node") -> None:
"""Replace a successor node. Do nothing if the node to replace is not a successor
Args:
ori_son: son to replace
new_son: son to replace with
old_successor: successor to replace
new_successor: successor to replace with
"""
for i, s in enumerate(self._sons):
if s.node_id == ori_son.node_id:
for i, s in enumerate(self._successors):
if s.node_id == old_successor.node_id:
idx = i
break
else:
return
self._sons[idx] = new_son
self._successors[idx] = new_successor

def set_sons(self, sons: List["Node"]) -> None:
"""Set the son nodes
def set_successors(self, successors: List["Node"]) -> None:
"""Set the successor nodes
Args:
sons: list of fathers to add
successors: list of successors to add
"""
self._sons = sons
self._successors = successors

@property
def sons(self) -> List["Node"]:
"""Returns the son nodes
def successors(self) -> List["Node"]:
"""Returns the successors nodes
Returns:
list(Node): list of sons
list(Node): list of successors
"""
return list(self._sons)
return list(self._successors)

@property
def son_true(self) -> Optional["Node"]:
def successor_true(self) -> Optional["Node"]:
if self.type in [NodeType.IF, NodeType.IFLOOP]:
return self._sons[0]
return self._successors[0]
return None

@property
def son_false(self) -> Optional["Node"]:
if self.type in [NodeType.IF, NodeType.IFLOOP] and len(self._sons) >= 1:
return self._sons[1]
def successor_false(self) -> Optional["Node"]:
if self.type in [NodeType.IF, NodeType.IFLOOP] and len(self._successors) >= 1:
return self._successors[1]
return None

# endregion
Expand Down Expand Up @@ -1046,6 +1049,43 @@ def __str__(self) -> str:
txt = str(self._node_type.value) + additional_info
return txt

def __getattr__(self, item: str):
"""Get attribute wrapper.
Used for the breaking change to deprecate the usage of sons/fathers and use predecessors
and successors.
"""
replaced_functions = {
"add_son",
"remove_son",
"replace_son",
"son_false",
"son_true",
"sons",
"add_father",
"fathers",
"remove_father",
"set_fathers",
}

if item not in replaced_functions:
raise AttributeError(item)

if "son" in item:
new_function = item.replace("son", "successor")
elif "father" in item:
new_function = item.replace("father", "predecessor")
else:
raise AttributeError(item)

proxied_function = getattr(self, new_function)
logger.warning(
"Function %s is deprecated and will be removed in a future version. Please use %s instead.",
item,
new_function,
)
return proxied_function


# endregion
###################################################################################
Expand All @@ -1056,18 +1096,18 @@ def __str__(self) -> str:


def link_nodes(node1: Node, node2: Node) -> None:
node1.add_son(node2)
node2.add_father(node1)
node1.add_successor(node2)
node2.add_predecessor(node1)


def insert_node(origin: Node, node_inserted: Node) -> None:
sons = origin.sons
successors = origin.successors
link_nodes(origin, node_inserted)
for son in sons:
son.remove_father(origin)
origin.remove_son(son)
for successor in successors:
successor.remove_predecessor(origin)
origin.remove_successor(successor)

link_nodes(node_inserted, son)
link_nodes(node_inserted, successor)


def recheable(node: Node) -> Set[Node]:
Expand All @@ -1076,16 +1116,16 @@ def recheable(node: Node) -> Set[Node]:
:param node:
:return: set(Node)
"""
nodes = node.sons
nodes = node.successors
visited = set()
while nodes:
next_node = nodes[0]
nodes = nodes[1:]
if next_node not in visited:
visited.add(next_node)
for son in next_node.sons:
if son not in visited:
nodes.append(son)
for successor in next_node.successors:
if successor not in visited:
nodes.append(successor)
return visited


Expand Down
8 changes: 4 additions & 4 deletions slither/core/declarations/contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -1480,8 +1480,8 @@ def add_constructor_variables(self) -> None:
constructor_variable, counter, v, prev_node.scope
)
v.node_initialization = next_node
prev_node.add_son(next_node)
next_node.add_father(prev_node)
prev_node.add_successor(next_node)
next_node.add_predecessor(prev_node)
prev_node = next_node
counter += 1
break
Expand Down Expand Up @@ -1512,8 +1512,8 @@ def add_constructor_variables(self) -> None:
constructor_variable, counter, v, prev_node.scope
)
v.node_initialization = next_node
prev_node.add_son(next_node)
next_node.add_father(prev_node)
prev_node.add_successor(next_node)
next_node.add_predecessor(prev_node)
prev_node = next_node
counter += 1

Expand Down
16 changes: 8 additions & 8 deletions slither/core/declarations/function.py
Original file line number Diff line number Diff line change
Expand Up @@ -1397,8 +1397,8 @@ def cfg_to_dot(self, filename: str):
f.write("digraph{\n")
for node in self.nodes:
f.write(f'{node.node_id}[label="{str(node)}"];\n')
for son in node.sons:
f.write(f"{node.node_id}->{son.node_id};\n")
for successor in node.successors:
f.write(f"{node.node_id}->{successor.node_id};\n")

f.write("}\n")

Expand Down Expand Up @@ -1453,15 +1453,15 @@ def slithir_cfg_to_dot_str(self, skip_expressions: bool = False) -> str:
label += "\nIRs:\n" + "\n".join([str(ir) for ir in node.irs])
content += f'{node.node_id}[label="{label}"];\n'
if node.type in [NodeType.IF, NodeType.IFLOOP]:
true_node = node.son_true
true_node = node.successor_true
if true_node:
content += f'{node.node_id}->{true_node.node_id}[label="True"];\n'
false_node = node.son_false
false_node = node.successor_false
if false_node:
content += f'{node.node_id}->{false_node.node_id}[label="False"];\n'
else:
for son in node.sons:
content += f"{node.node_id}->{son.node_id};\n"
for successor in node.successors:
content += f"{node.node_id}->{successor.node_id};\n"

content += "}\n"
return content
Expand Down Expand Up @@ -1761,8 +1761,8 @@ def _get_last_ssa_variable_instances(
ret[name] = set()
ret[name] |= instances

for son in node.sons:
to_explore.append((son, dict(values)))
for successor in node.successors:
to_explore.append((successor, dict(values)))

return ret

Expand Down
Loading

0 comments on commit b90371d

Please sign in to comment.