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 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 read_from_memory(
70        &self,
71        cx: &mut SymCx,
72        memory: &SymMemory,
73        offset: SymExpr,
74    ) -> SymBytes {
75        match self {
76            Self::Concrete(size) => memory.read_bytes_offset(cx, offset, *size),
77            Self::Symbolic { size, max_size } => {
78                memory.read_bytes_symbolic_size(cx, offset, size.clone(), *max_size)
79            }
80        }
81    }
82
83    pub(crate) fn size_word(&self, cx: &mut SymCx) -> SymExpr {
84        match self {
85            Self::Concrete(size) => SymExpr::constant(cx, U256::from(*size)),
86            Self::Symbolic { size, .. } => size.clone(),
87        }
88    }
89
90    pub(crate) fn parts(&self, cx: &mut SymCx) -> (SymExpr, usize, bool) {
91        match self {
92            Self::Concrete(size) => (SymExpr::constant(cx, U256::from(*size)), *size, false),
93            Self::Symbolic { size, max_size } => (size.clone(), *max_size, true),
94        }
95    }
96
97    pub(crate) fn calldata(&self, cx: &mut SymCx, input: SymBytes) -> SymCalldata {
98        match self {
99            Self::Concrete(_) => SymCalldata::from_bytes(cx, input),
100            Self::Symbolic { size, .. } => SymCalldata::from_bytes_with_size(input, size.clone()),
101        }
102    }
103}