neo_solidity/cli/cli_parts/cli_manifest/permissions/
abstract.rs

1fn pop_value(stack: &mut Vec<AbstractValue>) -> Result<AbstractValue, ()> {
2    stack.pop().ok_or(())
3}
4
5fn pop_n(stack: &mut Vec<AbstractValue>, n: usize) -> Result<(), ()> {
6    if stack.len() < n {
7        return Err(());
8    }
9    for _ in 0..n {
10        stack.pop();
11    }
12    Ok(())
13}
14
15fn apply_instruction(state: &mut AbstractState, instr: &ir::Instruction) -> Result<(), ()> {
16    use ir::Instruction::*;
17
18    match instr {
19        Drop(_) => {
20            pop_value(&mut state.stack)?;
21        }
22        LoadParameter(_) => state.stack.push(AbstractValue::Unknown),
23        PushLiteral(lit) => state.stack.push(AbstractValue::Literal(lit.clone())),
24        Return | ReturnVoid | ReturnDefault(_) | Abort => {}
25        AbortMsg | Throw => {
26            pop_value(&mut state.stack)?;
27        }
28        BinaryOp(_) => {
29            pop_n(&mut state.stack, 2)?;
30            state.stack.push(AbstractValue::Unknown);
31        }
32        LoadState(_) => state.stack.push(AbstractValue::Unknown),
33        StoreState(_) => {
34            pop_value(&mut state.stack)?;
35        }
36        LoadStorageDynamic => {
37            pop_value(&mut state.stack)?;
38            state.stack.push(AbstractValue::Unknown);
39        }
40        LoadLocal(index) => {
41            let value = state
42                .locals
43                .get(*index)
44                .cloned()
45                .unwrap_or(AbstractValue::Unknown);
46            state.stack.push(value);
47        }
48        StoreLocal(index) => {
49            let value = pop_value(&mut state.stack)?;
50            if let Some(slot) = state.locals.get_mut(*index) {
51                *slot = value;
52            }
53        }
54        LoadMappingElement { key_types, .. } => {
55            pop_n(&mut state.stack, key_types.len())?;
56            state.stack.push(AbstractValue::Unknown);
57        }
58        StoreMappingElement { key_types, .. } => {
59            pop_n(&mut state.stack, key_types.len() + 1)?;
60        }
61        LoadStructField { key_types, .. } => {
62            pop_n(&mut state.stack, key_types.len())?;
63            state.stack.push(AbstractValue::Unknown);
64        }
65        StoreStructField { key_types, .. } => {
66            pop_n(&mut state.stack, key_types.len() + 1)?;
67        }
68        LoadStructArrayElement { key_types, .. } => {
69            pop_n(&mut state.stack, key_types.len() + 1)?;
70            state.stack.push(AbstractValue::Unknown);
71        }
72        StoreStructArrayElement { key_types, .. } => {
73            pop_n(&mut state.stack, key_types.len() + 2)?;
74        }
75        LoadRuntimeValue(_) => state.stack.push(AbstractValue::Unknown),
76        GetSize => {
77            pop_value(&mut state.stack)?;
78            state.stack.push(AbstractValue::Unknown);
79        }
80        CallFunction { arg_count, .. } => {
81            pop_n(&mut state.stack, *arg_count)?;
82            // For manifest inference we conservatively treat internal calls as producing a
83            // single stack item (e.g., `null`, a value, or an array-wrapped tuple).
84            state.stack.push(AbstractValue::Unknown);
85        }
86        CallBuiltin { builtin, arg_count } => {
87            pop_n(&mut state.stack, *arg_count)?;
88            match builtin {
89                // Track `this` / `address(this)` values so we can avoid emitting
90                // impossible manifest permissions for self-calls.
91                ir::BuiltinCall::Syscall(name)
92                    if name == "System.Runtime.GetExecutingScriptHash" =>
93                {
94                    state.stack.push(AbstractValue::ExecutingScriptHash);
95                }
96                _ => state.stack.push(AbstractValue::Unknown),
97            }
98        }
99        EmitEvent { arg_count, .. } | EmitEventByName { arg_count, .. } => {
100            pop_n(&mut state.stack, arg_count + 1)?;
101        }
102        Convert { .. } => {
103            pop_value(&mut state.stack)?;
104            state.stack.push(AbstractValue::Unknown);
105        }
106        IsType { .. } => {
107            pop_value(&mut state.stack)?;
108            state.stack.push(AbstractValue::Unknown);
109        }
110        NewBuffer => {
111            pop_value(&mut state.stack)?;
112            state.stack.push(AbstractValue::Unknown);
113        }
114        NewArray { .. } => {
115            pop_value(&mut state.stack)?;
116            state.stack.push(AbstractValue::Unknown);
117        }
118        ArrayGet => {
119            pop_n(&mut state.stack, 2)?;
120            state.stack.push(AbstractValue::Unknown);
121        }
122        ArraySet => {
123            pop_n(&mut state.stack, 3)?;
124        }
125        MemCpy => {
126            // Stack order: [dst, dst_offset, src, src_offset, count]
127            pop_n(&mut state.stack, 5)?;
128            state.stack.push(AbstractValue::Unknown);
129        }
130        ReverseItems => {
131            pop_value(&mut state.stack)?;
132        }
133        BitwiseNot | LogicalNot => {
134            pop_value(&mut state.stack)?;
135            state.stack.push(AbstractValue::Unknown);
136        }
137        Try { .. } | EndTry { .. } | Jump { .. } | Label(_) => {}
138        JumpIf { .. } => {
139            pop_value(&mut state.stack)?;
140        }
141        Dup => {
142            let value = state.stack.last().cloned().unwrap_or(AbstractValue::Unknown);
143            state.stack.push(value);
144        }
145        Swap => {
146            let len = state.stack.len();
147            if len >= 2 {
148                state.stack.swap(len - 1, len - 2);
149            }
150        }
151    }
152
153    Ok(())
154}