Skip to content

Commit

Permalink
fix issue 69
Browse files Browse the repository at this point in the history
Cleans up wrapping subtraction and when an assign occurs, the assignee inherits tmp_of from assignor
  • Loading branch information
brockelmore committed Dec 9, 2023
1 parent 18ebcda commit 486b3dc
Show file tree
Hide file tree
Showing 8 changed files with 765 additions and 657 deletions.
2 changes: 1 addition & 1 deletion crates/graph/src/nodes/context/solving.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ impl ContextNode {
dep: ContextVarNode,
analyzer: &mut (impl GraphBackend + AnalyzerBackend),
) -> Result<(), GraphError> {
tracing::trace!("Adding ctx dependency: {}", dep.display_name(analyzer)?);
tracing::trace!("Adding ctx dependency: {}, is_controllable: {}", dep.display_name(analyzer)?, dep.is_controllable(analyzer)?);
if dep.is_controllable(analyzer)? {
let range = dep.ref_range(analyzer)?.unwrap();
let r = range.into_flattened_range(analyzer)?;
Expand Down
21 changes: 6 additions & 15 deletions crates/graph/src/nodes/context/var/typing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ impl ContextVarNode {
Ok(global_first.is_storage(analyzer)? || global_first.is_calldata_input(analyzer))
}

pub fn is_independent_and_storage_or_calldata(
pub fn is_fundamental(
&self,
analyzer: &impl GraphBackend,
) -> Result<bool, GraphError> {
Expand Down Expand Up @@ -86,22 +86,13 @@ impl ContextVarNode {
}

pub fn is_controllable(&self, analyzer: &impl GraphBackend) -> Result<bool, GraphError> {
if self.is_storage_or_calldata_input(analyzer)?
|| self.is_msg(analyzer)?
|| self.is_block(analyzer)?
{
Ok(true)
} else if let Some(tmp) = self.tmp_of(analyzer)? {
let rhs_controllable = if let Some(rhs) = tmp.rhs {
rhs.is_controllable(analyzer)?
Ok(self.dependent_on(analyzer, true)?.iter().any(|dependent_on| {
if let Ok(t) = dependent_on.is_fundamental(analyzer) {
t
} else {
false
};
let lhs_controllable = tmp.lhs.is_controllable(analyzer)?;
Ok(lhs_controllable || rhs_controllable)
} else {
Ok(false)
}
}
}))
}

pub fn is_calldata_input(&self, analyzer: &impl GraphBackend) -> bool {
Expand Down
6 changes: 3 additions & 3 deletions crates/graph/src/range/elem/reference.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ impl RangeElem<Concrete> for Reference<Concrete> {
analyzer: &impl GraphBackend,
) -> Result<Elem<Concrete>, GraphError> {
let cvar = ContextVarNode::from(self.idx);
if cvar.is_independent_and_storage_or_calldata(analyzer)? {
if cvar.is_fundamental(analyzer)? {
return Ok(Elem::Reference(Reference::new(
cvar.global_first_version(analyzer).into(),
)));
Expand Down Expand Up @@ -142,7 +142,7 @@ impl RangeElem<Concrete> for Reference<Concrete> {
) -> Result<Elem<Concrete>, GraphError> {
let cvar = ContextVarNode::from(self.idx);

let independent = cvar.is_independent_and_storage_or_calldata(analyzer)?;
let independent = cvar.is_fundamental(analyzer)?;
if independent {
Ok(Elem::Reference(Reference::new(
cvar.global_first_version(analyzer).into(),
Expand All @@ -159,7 +159,7 @@ impl RangeElem<Concrete> for Reference<Concrete> {
analyzer: &impl GraphBackend,
) -> Result<Elem<Concrete>, GraphError> {
let cvar = ContextVarNode::from(self.idx);
if cvar.is_independent_and_storage_or_calldata(analyzer)? {
if cvar.is_fundamental(analyzer)? {
Ok(Elem::Reference(Reference::new(
cvar.global_first_version(analyzer).into(),
)))
Expand Down
100 changes: 98 additions & 2 deletions crates/graph/src/range/exec/exec_op.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,12 +204,108 @@ impl ExecOp<Concrete> for RangeExpr<Concrete> {
}
RangeOp::Sub(unchecked) => {
if unchecked {
let candidates = vec![
let mut candidates = vec![];
// check if rhs contains zero, if so add lhs_min and max as candidates
let zero = Elem::from(Concrete::from(U256::from(0)));
let one = Elem::from(Concrete::from(U256::from(1)));
let rhs_min_contains_zero = matches!(
rhs_min.range_ord(&zero),
Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal)
);

let rhs_max_contains_zero = matches!(
rhs_max.range_ord(&zero),
Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal)
);

if rhs_min_contains_zero && rhs_max_contains_zero {
candidates.push(Some(lhs_min.clone()));
candidates.push(Some(lhs_max.clone()));
}

// If we have the below case, where the lhs
// contains the rhs, we can add zero. Futher more, if
// the lhs contains rhs - 1, we can add max as it
// would overflow to uint256.max
// zero min max uint256.max
// lhs: | - - |----------------------------| - - |
// rhs: | - - |--| - - - - - - - - - - - - - - - |
match lhs_max.range_ord(&rhs_min) {
Some(std::cmp::Ordering::Less) => {
// We are going to overflow, zero not possible
}
Some(std::cmp::Ordering::Equal) => {
// We are going to at least be zero,
// we may overflow. check if rhs is const, otherwise
// add uint256.max as a candidate
candidates.push(Some(zero.clone()));
if !consts.1 {
candidates.push(zero.range_wrapping_sub(&one));
}
}
Some(std::cmp::Ordering::Greater) => {
// No guarantees on overflow, check lhs_min
match lhs_min.range_ord(&rhs_min) {
Some(std::cmp::Ordering::Less) => {
// fully contained, add zero and max
candidates.push(Some(zero.clone()));
candidates.push(zero.range_wrapping_sub(&one));
}
Some(std::cmp::Ordering::Equal) => {
// We are going to at least be zero,
// we may overflow. check if rhs is const, otherwise
// add uint256.max as a candidate
candidates.push(Some(zero.clone()));
if !consts.1 {
candidates.push(zero.range_wrapping_sub(&one));
}
}
Some(std::cmp::Ordering::Greater) => {
// current info:
// zero min max uint256.max
// lhs: | - - |----------------------------| - - |
// rhs: | - |----? - - - - - - - - - - - - - - - |
// figure out where rhs max is
match lhs_min.range_ord(&rhs_max) {
Some(std::cmp::Ordering::Less) => {
// zero min
// lhs: | - - |---?
// rhs: | - |----|
// min max
// Add both
candidates.push(Some(zero.clone()));
candidates.push(zero.range_wrapping_sub(&one));
}
Some(std::cmp::Ordering::Equal) => {
// zero min
// lhs: | - - |---?
// rhs: | |---|
// min max
// Add zero
candidates.push(Some(zero.clone()));
}
Some(std::cmp::Ordering::Greater) => {
// zero min
// lhs: | - - |---?
// rhs: |-----|
// min max
// Add nothing
}
_ => {}
}
}
_ => {}
}
}
_ => {}
}

candidates.extend(vec![
lhs_min.range_wrapping_sub(&rhs_min),
lhs_min.range_wrapping_sub(&rhs_max),
lhs_max.range_wrapping_sub(&rhs_min),
lhs_max.range_wrapping_sub(&rhs_max),
];
]);
let mut candidates = candidates.into_iter().flatten().collect::<Vec<_>>();
candidates.sort_by(|a, b| match a.range_ord(b) {
Some(r) => r,
Expand Down
44 changes: 22 additions & 22 deletions crates/pyrometer/src/graph_backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -519,14 +519,14 @@ flowchart BT
)?)
}
Node::ContextVar(_) => None,
_n => {
n => {
handled_nodes.lock().unwrap().insert(*node);
Some(format!(
" {}(\"{}\")", //\n style {} stroke:{}",
" {}(\"{}\")\n style {} stroke:{}",
petgraph::graph::GraphIndex::index(node),
as_dot_str(*node, self).replace('\"', "\'"),
// petgraph::graph::GraphIndex::index(node),
// n.dot_str_color()
petgraph::graph::GraphIndex::index(node),
n.dot_str_color()
))
}
}
Expand All @@ -546,9 +546,9 @@ flowchart BT
}
let from = from.index();
let to = to.index();
let _edge_idx = edge.index();
let edge_idx = edge.index();
Some(format!(
" {from:} -->|\"{:?}\"| {to:}", // class {to} linkSource{edge_idx}\n class {from} linkTarget{edge_idx}",
" {from:} -->|\"{:?}\"| {to:}\n class {to} linkSource{edge_idx}\n class {from} linkTarget{edge_idx}",
self.graph().edge_weight(edge).unwrap()
))
} else {
Expand Down Expand Up @@ -585,29 +585,29 @@ pub fn mermaid_node(
g: &impl GraphBackend,
indent: &str,
node: NodeIdx,
_style: bool,
_class: Option<&str>,
style: bool,
class: Option<&str>,
) -> String {
let node_str = format!(
let mut node_str = format!(
"{indent}{}(\"{}\")",
petgraph::graph::GraphIndex::index(&node),
as_dot_str(node, g).replace('\"', "\'"),
);

// if style {
// node_str.push_str(&format!(
// "\n{indent}style {} stroke:{}",
// petgraph::graph::GraphIndex::index(&node),
// g.node(node).dot_str_color()
// ));
// }
if style {
node_str.push_str(&format!(
"\n{indent}style {} stroke:{}",
petgraph::graph::GraphIndex::index(&node),
g.node(node).dot_str_color()
));
}

// if let Some(class) = class {
// node_str.push_str(&format!(
// "\n{indent}class {} {class}",
// petgraph::graph::GraphIndex::index(&node),
// ));
// }
if let Some(class) = class {
node_str.push_str(&format!(
"\n{indent}class {} {class}",
petgraph::graph::GraphIndex::index(&node),
));
}

node_str
}
Loading

0 comments on commit 486b3dc

Please sign in to comment.