Skip to main content

foundry_evm_symbolic/runtime/
calldata.rs

1use 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 size_word(&self) -> SymExpr {
17        self.size_word.clone()
18    }
19
20    pub(crate) fn load_word(&self, cx: &mut SymCx, offset: SymExpr) -> SymExpr {
21        if let Some(offset) = offset.as_const() {
22            let Ok(offset) = usize::try_from(offset) else {
23                return SymExpr::zero(cx);
24            };
25            self.bytes.word_at(cx, offset)
26        } else {
27            self.load_dynamic(cx, &offset)
28        }
29    }
30
31    fn load_dynamic(&self, cx: &mut SymCx, offset: &SymExpr) -> SymExpr {
32        let mut result = SymExpr::zero(cx);
33        for candidate in (0..self.size).rev() {
34            let candidate_expr = SymExpr::constant(cx, U256::from(candidate));
35            let condition = SymBoolExpr::eq(cx, offset.clone(), candidate_expr);
36            let word = self.bytes.word_at(cx, candidate);
37            result = SymExpr::ite(cx, condition, word, result);
38        }
39        result
40    }
41
42    pub(crate) fn read_bytes_offset(
43        &self,
44        cx: &mut SymCx,
45        offset: SymExpr,
46        size: usize,
47    ) -> SymBytes {
48        self.bytes.read_offset(cx, offset, size)
49    }
50}
51
52impl BoundedCopySize {
53    pub(crate) fn expand_memory(&self, cx: &mut SymCx, memory: &mut SymMemory, offset: SymExpr) {
54        let size = self.size_word(cx);
55        memory.expand_range(cx, offset, size);
56    }
57
58    pub(crate) fn read_from_memory(
59        &self,
60        cx: &mut SymCx,
61        memory: &SymMemory,
62        offset: SymExpr,
63    ) -> SymBytes {
64        match self {
65            Self::Concrete(size) => memory.read_bytes_offset(cx, offset, *size),
66            Self::Symbolic { size, max_size } => {
67                memory.read_bytes_symbolic_size(cx, offset, size.clone(), *max_size)
68            }
69        }
70    }
71
72    pub(crate) fn size_word(&self, cx: &mut SymCx) -> SymExpr {
73        match self {
74            Self::Concrete(size) => SymExpr::constant(cx, U256::from(*size)),
75            Self::Symbolic { size, .. } => size.clone(),
76        }
77    }
78
79    pub(crate) fn parts(&self, cx: &mut SymCx) -> (SymExpr, usize, bool) {
80        match self {
81            Self::Concrete(size) => (SymExpr::constant(cx, U256::from(*size)), *size, false),
82            Self::Symbolic { size, max_size } => (size.clone(), *max_size, true),
83        }
84    }
85
86    pub(crate) fn calldata(&self, cx: &mut SymCx, input: SymBytes) -> SymCalldata {
87        match self {
88            Self::Concrete(_) => SymCalldata::from_bytes(cx, input),
89            Self::Symbolic { size, .. } => {
90                SymCalldata { size: input.len(), size_word: size.clone(), bytes: input }
91            }
92        }
93    }
94}