-
Notifications
You must be signed in to change notification settings - Fork 55
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
955dc68
commit c328bcd
Showing
12 changed files
with
955 additions
and
1,009 deletions.
There are no files selected for viewing
210 changes: 96 additions & 114 deletions
210
crates/solc-expressions/src/func_call/intrinsic_call/abi.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,128 +1,110 @@ | ||
use crate::{ | ||
ContextBuilder, ExprErr, IntoExprErr, | ||
}; | ||
use crate::{ContextBuilder, ExprErr, IntoExprErr}; | ||
|
||
use graph::{ | ||
nodes::{ | ||
Builtin, ContextNode, ContextVar, ExprRet, | ||
}, | ||
nodes::{Builtin, ContextNode, ContextVar, ExprRet}, | ||
AnalyzerBackend, ContextEdge, Edge, Node, | ||
}; | ||
|
||
use solang_parser::pt::{Expression, Loc}; | ||
|
||
impl<T> AbiCaller for T where T: AnalyzerBackend<Expr = Expression, ExprErr = ExprErr> + Sized {} | ||
pub trait AbiCaller: AnalyzerBackend<Expr = Expression, ExprErr = ExprErr> + Sized { | ||
fn abi_call(&mut self, func_name: String, input_exprs: &[Expression], loc: Loc, ctx: ContextNode) -> Result<(), ExprErr> { | ||
fn abi_call( | ||
&mut self, | ||
func_name: String, | ||
input_exprs: &[Expression], | ||
loc: Loc, | ||
ctx: ContextNode, | ||
) -> Result<(), ExprErr> { | ||
match &*func_name { | ||
"abi.decode" => { | ||
// we skip the first because that is what is being decoded. | ||
// TODO: check if we have a concrete bytes value | ||
fn match_decode( | ||
ctx: ContextNode, | ||
loc: &Loc, | ||
ret: ExprRet, | ||
analyzer: &mut impl AnalyzerBackend, | ||
) -> Result<(), ExprErr> { | ||
match ret { | ||
ExprRet::Single(expect_builtin) => { | ||
match analyzer.node(expect_builtin) { | ||
Node::Builtin(_) => { | ||
let var = ContextVar::new_from_builtin( | ||
*loc, | ||
expect_builtin.into(), | ||
analyzer, | ||
) | ||
.into_expr_err(*loc)?; | ||
let node = analyzer.add_node(Node::ContextVar(var)); | ||
ctx.add_var(node.into(), analyzer) | ||
.into_expr_err(*loc)?; | ||
analyzer.add_edge( | ||
node, | ||
ctx, | ||
Edge::Context(ContextEdge::Variable), | ||
); | ||
ctx.push_expr(ExprRet::Single(node), analyzer) | ||
.into_expr_err(*loc)?; | ||
Ok(()) | ||
} | ||
Node::ContextVar(cvar) => { | ||
let bn = analyzer | ||
.builtin_or_add( | ||
cvar.ty | ||
.as_builtin(analyzer) | ||
.into_expr_err(*loc)?, | ||
) | ||
.into(); | ||
let var = ContextVar::new_from_builtin( | ||
*loc, bn, analyzer, | ||
) | ||
.into_expr_err(*loc)?; | ||
let node = analyzer.add_node(Node::ContextVar(var)); | ||
ctx.add_var(node.into(), analyzer) | ||
.into_expr_err(*loc)?; | ||
analyzer.add_edge( | ||
node, | ||
ctx, | ||
Edge::Context(ContextEdge::Variable), | ||
); | ||
ctx.push_expr(ExprRet::Single(node), analyzer) | ||
.into_expr_err(*loc)?; | ||
Ok(()) | ||
} | ||
e => todo!("Unhandled type in abi.decode: {e:?}"), | ||
} | ||
} | ||
ExprRet::Multi(inner) => inner.iter().try_for_each(|i| { | ||
match_decode(ctx, loc, i.clone(), analyzer) | ||
}), | ||
ExprRet::CtxKilled(kind) => { | ||
ctx.kill(analyzer, *loc, kind).into_expr_err(*loc) | ||
} | ||
e => panic!("This is invalid solidity: {:?}", e), | ||
} | ||
} | ||
self.parse_ctx_expr(&input_exprs[1], ctx)?; | ||
self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { | ||
let Some(ret) = | ||
ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? | ||
else { | ||
return Err(ExprErr::NoRhs( | ||
loc, | ||
"abi.decode was not given the types for decoding" | ||
.to_string(), | ||
)); | ||
}; | ||
if matches!(ret, ExprRet::CtxKilled(_)) { | ||
ctx.push_expr(ret, analyzer).into_expr_err(loc)?; | ||
return Ok(()); | ||
} | ||
match_decode(ctx, &loc, ret, analyzer) | ||
}) | ||
} | ||
"abi.encode" | ||
| "abi.encodePacked" | ||
| "abi.encodeCall" | ||
| "abi.encodeWithSignature" | ||
| "abi.encodeWithSelector" => { | ||
// currently we dont support concrete abi encoding, TODO | ||
let bn = self.builtin_or_add(Builtin::DynamicBytes); | ||
let cvar = ContextVar::new_from_builtin(loc, bn.into(), self) | ||
.into_expr_err(loc)?; | ||
let node = self.add_node(Node::ContextVar(cvar)); | ||
ctx.add_var(node.into(), self).into_expr_err(loc)?; | ||
self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); | ||
ctx.push_expr(ExprRet::Single(node), self) | ||
.into_expr_err(loc)?; | ||
Ok(()) | ||
} | ||
_ => Err(ExprErr::FunctionNotFound( | ||
"abi.decode" => { | ||
// we skip the first because that is what is being decoded. | ||
// TODO: check if we have a concrete bytes value | ||
fn match_decode( | ||
ctx: ContextNode, | ||
loc: &Loc, | ||
ret: ExprRet, | ||
analyzer: &mut impl AnalyzerBackend, | ||
) -> Result<(), ExprErr> { | ||
match ret { | ||
ExprRet::Single(expect_builtin) => match analyzer.node(expect_builtin) { | ||
Node::Builtin(_) => { | ||
let var = ContextVar::new_from_builtin( | ||
*loc, | ||
expect_builtin.into(), | ||
analyzer, | ||
) | ||
.into_expr_err(*loc)?; | ||
let node = analyzer.add_node(Node::ContextVar(var)); | ||
ctx.add_var(node.into(), analyzer).into_expr_err(*loc)?; | ||
analyzer.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); | ||
ctx.push_expr(ExprRet::Single(node), analyzer) | ||
.into_expr_err(*loc)?; | ||
Ok(()) | ||
} | ||
Node::ContextVar(cvar) => { | ||
let bn = analyzer | ||
.builtin_or_add( | ||
cvar.ty.as_builtin(analyzer).into_expr_err(*loc)?, | ||
) | ||
.into(); | ||
let var = ContextVar::new_from_builtin(*loc, bn, analyzer) | ||
.into_expr_err(*loc)?; | ||
let node = analyzer.add_node(Node::ContextVar(var)); | ||
ctx.add_var(node.into(), analyzer).into_expr_err(*loc)?; | ||
analyzer.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); | ||
ctx.push_expr(ExprRet::Single(node), analyzer) | ||
.into_expr_err(*loc)?; | ||
Ok(()) | ||
} | ||
e => todo!("Unhandled type in abi.decode: {e:?}"), | ||
}, | ||
ExprRet::Multi(inner) => inner | ||
.iter() | ||
.try_for_each(|i| match_decode(ctx, loc, i.clone(), analyzer)), | ||
ExprRet::CtxKilled(kind) => { | ||
ctx.kill(analyzer, *loc, kind).into_expr_err(*loc) | ||
} | ||
e => panic!("This is invalid solidity: {:?}", e), | ||
} | ||
} | ||
self.parse_ctx_expr(&input_exprs[1], ctx)?; | ||
self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { | ||
let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { | ||
return Err(ExprErr::NoRhs( | ||
loc, | ||
"abi.decode was not given the types for decoding".to_string(), | ||
)); | ||
}; | ||
if matches!(ret, ExprRet::CtxKilled(_)) { | ||
ctx.push_expr(ret, analyzer).into_expr_err(loc)?; | ||
return Ok(()); | ||
} | ||
match_decode(ctx, &loc, ret, analyzer) | ||
}) | ||
} | ||
"abi.encode" | ||
| "abi.encodePacked" | ||
| "abi.encodeCall" | ||
| "abi.encodeWithSignature" | ||
| "abi.encodeWithSelector" => { | ||
// currently we dont support concrete abi encoding, TODO | ||
let bn = self.builtin_or_add(Builtin::DynamicBytes); | ||
let cvar = ContextVar::new_from_builtin(loc, bn.into(), self).into_expr_err(loc)?; | ||
let node = self.add_node(Node::ContextVar(cvar)); | ||
ctx.add_var(node.into(), self).into_expr_err(loc)?; | ||
self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); | ||
ctx.push_expr(ExprRet::Single(node), self) | ||
.into_expr_err(loc)?; | ||
Ok(()) | ||
} | ||
_ => Err(ExprErr::FunctionNotFound( | ||
loc, | ||
format!( | ||
"Could not find abi function: \"{func_name}\", context: {}", | ||
ctx.path(self), | ||
) | ||
)) | ||
} | ||
} | ||
} | ||
), | ||
)), | ||
} | ||
} | ||
} |
124 changes: 60 additions & 64 deletions
124
crates/solc-expressions/src/func_call/intrinsic_call/address.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,79 +1,75 @@ | ||
use crate::{ | ||
ExprErr, IntoExprErr, | ||
}; | ||
use crate::{ExprErr, IntoExprErr}; | ||
|
||
use graph::{ | ||
nodes::{ | ||
Builtin, ContextNode, ContextVar, ExprRet, | ||
}, | ||
nodes::{Builtin, ContextNode, ContextVar, ExprRet}, | ||
AnalyzerBackend, ContextEdge, Edge, Node, | ||
}; | ||
|
||
use solang_parser::pt::{Expression, Loc}; | ||
|
||
impl<T> AddressCaller for T where T: AnalyzerBackend<Expr = Expression, ExprErr = ExprErr> + Sized {} | ||
pub trait AddressCaller: AnalyzerBackend<Expr = Expression, ExprErr = ExprErr> + Sized { | ||
fn address_call(&mut self, func_name: String, _input_exprs: &[Expression], loc: Loc, ctx: ContextNode) -> Result<(), ExprErr> { | ||
fn address_call( | ||
&mut self, | ||
func_name: String, | ||
_input_exprs: &[Expression], | ||
loc: Loc, | ||
ctx: ContextNode, | ||
) -> Result<(), ExprErr> { | ||
match &*func_name { | ||
"delegatecall" | "staticcall" | "call" => { | ||
// TODO: Check if we have the code for the address | ||
// if we dont, model it as a unrestricted call that can make other calls | ||
ctx.pop_expr_latest(loc, self).into_expr_err(loc)?; | ||
// TODO: try to be smarter based on the address input | ||
let booln = self.builtin_or_add(Builtin::Bool); | ||
let bool_cvar = ContextVar::new_from_builtin(loc, booln.into(), self) | ||
.into_expr_err(loc)?; | ||
let bool_node = self.add_node(Node::ContextVar(bool_cvar)); | ||
ctx.add_var(bool_node.into(), self).into_expr_err(loc)?; | ||
self.add_edge(bool_node, ctx, Edge::Context(ContextEdge::Variable)); | ||
"delegatecall" | "staticcall" | "call" => { | ||
// TODO: Check if we have the code for the address | ||
// if we dont, model it as a unrestricted call that can make other calls | ||
ctx.pop_expr_latest(loc, self).into_expr_err(loc)?; | ||
// TODO: try to be smarter based on the address input | ||
let booln = self.builtin_or_add(Builtin::Bool); | ||
let bool_cvar = | ||
ContextVar::new_from_builtin(loc, booln.into(), self).into_expr_err(loc)?; | ||
let bool_node = self.add_node(Node::ContextVar(bool_cvar)); | ||
ctx.add_var(bool_node.into(), self).into_expr_err(loc)?; | ||
self.add_edge(bool_node, ctx, Edge::Context(ContextEdge::Variable)); | ||
|
||
let bn = self.builtin_or_add(Builtin::DynamicBytes); | ||
let cvar = ContextVar::new_from_builtin(loc, bn.into(), self) | ||
.into_expr_err(loc)?; | ||
let node = self.add_node(Node::ContextVar(cvar)); | ||
ctx.add_var(node.into(), self).into_expr_err(loc)?; | ||
self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); | ||
ctx.push_expr( | ||
ExprRet::Multi(vec![ | ||
ExprRet::Single(bool_node), | ||
ExprRet::Single(node), | ||
]), | ||
self, | ||
) | ||
.into_expr_err(loc)?; | ||
Ok(()) | ||
} | ||
"code" => { | ||
// TODO: try to be smarter based on the address input | ||
let bn = self.builtin_or_add(Builtin::DynamicBytes); | ||
let cvar = ContextVar::new_from_builtin(loc, bn.into(), self) | ||
.into_expr_err(loc)?; | ||
let node = self.add_node(Node::ContextVar(cvar)); | ||
ctx.add_var(node.into(), self).into_expr_err(loc)?; | ||
self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); | ||
ctx.push_expr(ExprRet::Single(node), self) | ||
.into_expr_err(loc)?; | ||
Ok(()) | ||
} | ||
"balance" => { | ||
// TODO: try to be smarter based on the address input | ||
let bn = self.builtin_or_add(Builtin::Uint(256)); | ||
let cvar = ContextVar::new_from_builtin(loc, bn.into(), self) | ||
.into_expr_err(loc)?; | ||
let node = self.add_node(Node::ContextVar(cvar)); | ||
ctx.add_var(node.into(), self).into_expr_err(loc)?; | ||
self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); | ||
ctx.push_expr(ExprRet::Single(node), self) | ||
.into_expr_err(loc)?; | ||
Ok(()) | ||
} | ||
_ => Err(ExprErr::FunctionNotFound( | ||
let bn = self.builtin_or_add(Builtin::DynamicBytes); | ||
let cvar = ContextVar::new_from_builtin(loc, bn.into(), self).into_expr_err(loc)?; | ||
let node = self.add_node(Node::ContextVar(cvar)); | ||
ctx.add_var(node.into(), self).into_expr_err(loc)?; | ||
self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); | ||
ctx.push_expr( | ||
ExprRet::Multi(vec![ExprRet::Single(bool_node), ExprRet::Single(node)]), | ||
self, | ||
) | ||
.into_expr_err(loc)?; | ||
Ok(()) | ||
} | ||
"code" => { | ||
// TODO: try to be smarter based on the address input | ||
let bn = self.builtin_or_add(Builtin::DynamicBytes); | ||
let cvar = ContextVar::new_from_builtin(loc, bn.into(), self).into_expr_err(loc)?; | ||
let node = self.add_node(Node::ContextVar(cvar)); | ||
ctx.add_var(node.into(), self).into_expr_err(loc)?; | ||
self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); | ||
ctx.push_expr(ExprRet::Single(node), self) | ||
.into_expr_err(loc)?; | ||
Ok(()) | ||
} | ||
"balance" => { | ||
// TODO: try to be smarter based on the address input | ||
let bn = self.builtin_or_add(Builtin::Uint(256)); | ||
let cvar = ContextVar::new_from_builtin(loc, bn.into(), self).into_expr_err(loc)?; | ||
let node = self.add_node(Node::ContextVar(cvar)); | ||
ctx.add_var(node.into(), self).into_expr_err(loc)?; | ||
self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); | ||
ctx.push_expr(ExprRet::Single(node), self) | ||
.into_expr_err(loc)?; | ||
Ok(()) | ||
} | ||
_ => Err(ExprErr::FunctionNotFound( | ||
loc, | ||
format!( | ||
"Could not find builtin address function: \"{func_name}\", context: {}", | ||
ctx.path(self), | ||
) | ||
)) | ||
} | ||
} | ||
} | ||
), | ||
)), | ||
} | ||
} | ||
} |
Oops, something went wrong.