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 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}