foundry_evm_symbolic/runtime/
calldata.rs1use super::*;
2
3#[derive(Clone, Debug)]
4pub(crate) struct SymCalldata {
5 size: usize,
6 size_word: SymExpr,
7 bytes: SymBytes,
8}
9
10impl SymCalldata {
11 pub(crate) fn from_bytes(cx: &mut SymCx, bytes: SymBytes) -> Self {
12 let size = bytes.len();
13 Self { size_word: SymExpr::constant(cx, U256::from(size)), size, bytes }
14 }
15
16 pub(crate) fn from_bytes_with_size(bytes: SymBytes, size_word: SymExpr) -> Self {
17 Self { size: bytes.len(), size_word, bytes }
18 }
19
20 pub(crate) fn size_word(&self) -> SymExpr {
21 self.size_word.clone()
22 }
23
24 pub(crate) fn load_word(
25 &self,
26 cx: &mut SymCx,
27 offset: SymExpr,
28 ) -> Result<SymExpr, SymbolicError> {
29 if let Some(offset) = offset.as_const() {
30 let Ok(offset) = usize::try_from(offset) else {
31 return Ok(SymExpr::zero(cx));
32 };
33 self.load(cx, offset)
34 } else {
35 self.load_dynamic(cx, &offset)
36 }
37 }
38
39 pub(crate) fn load(&self, cx: &mut SymCx, offset: usize) -> Result<SymExpr, SymbolicError> {
40 Ok(self.bytes.word_at(cx, offset))
41 }
42
43 pub(crate) fn load_dynamic(
44 &self,
45 cx: &mut SymCx,
46 offset: &SymExpr,
47 ) -> Result<SymExpr, SymbolicError> {
48 let mut result = SymExpr::zero(cx);
49 for candidate in (0..self.size).rev() {
50 let candidate_expr = SymExpr::constant(cx, U256::from(candidate));
51 let condition = SymBoolExpr::eq(cx, offset.clone(), candidate_expr);
52 let word = self.load(cx, candidate)?;
53 result = SymExpr::ite(cx, condition, word, result);
54 }
55 Ok(result)
56 }
57
58 pub(crate) fn read_bytes_offset(
59 &self,
60 cx: &mut SymCx,
61 offset: SymExpr,
62 size: usize,
63 ) -> SymBytes {
64 self.bytes.read_offset(cx, offset, size)
65 }
66}
67
68impl BoundedCopySize {
69 pub(crate) fn expand_memory(&self, cx: &mut SymCx, memory: &mut SymMemory, offset: SymExpr) {
70 let size = self.size_word(cx);
71 memory.expand_range(cx, offset, size);
72 }
73
74 pub(crate) fn read_from_memory(
75 &self,
76 cx: &mut SymCx,
77 memory: &SymMemory,
78 offset: SymExpr,
79 ) -> SymBytes {
80 match self {
81 Self::Concrete(size) => memory.read_bytes_offset(cx, offset, *size),
82 Self::Symbolic { size, max_size } => {
83 memory.read_bytes_symbolic_size(cx, offset, size.clone(), *max_size)
84 }
85 }
86 }
87
88 pub(crate) fn size_word(&self, cx: &mut SymCx) -> SymExpr {
89 match self {
90 Self::Concrete(size) => SymExpr::constant(cx, U256::from(*size)),
91 Self::Symbolic { size, .. } => size.clone(),
92 }
93 }
94
95 pub(crate) fn parts(&self, cx: &mut SymCx) -> (SymExpr, usize, bool) {
96 match self {
97 Self::Concrete(size) => (SymExpr::constant(cx, U256::from(*size)), *size, false),
98 Self::Symbolic { size, max_size } => (size.clone(), *max_size, true),
99 }
100 }
101
102 pub(crate) fn calldata(&self, cx: &mut SymCx, input: SymBytes) -> SymCalldata {
103 match self {
104 Self::Concrete(_) => SymCalldata::from_bytes(cx, input),
105 Self::Symbolic { size, .. } => SymCalldata::from_bytes_with_size(input, size.clone()),
106 }
107 }
108}