1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
use crate::{
function_data_builder::FunctionDataBuilder,
function_target::FunctionData,
function_target_pipeline::{FunctionTargetProcessor, FunctionTargetsHolder},
stackless_bytecode::PropKind,
usage_analysis::UsageProcessor,
};
use move_model::{
ast::{Operation, QuantKind},
exp_generator::ExpGenerator,
model::FunctionEnv,
ty::BOOL_TYPE,
};
use num::{BigUint, Zero};
pub struct WellFormedInstrumentationProcessor {}
impl WellFormedInstrumentationProcessor {
pub fn new() -> Box<Self> {
Box::new(Self {})
}
}
impl FunctionTargetProcessor for WellFormedInstrumentationProcessor {
fn process(
&self,
targets: &mut FunctionTargetsHolder,
fun_env: &FunctionEnv<'_>,
data: FunctionData,
) -> FunctionData {
if !data.variant.is_verified() {
return data;
}
let usage = UsageProcessor::analyze(targets, fun_env, &data);
let mut builder = FunctionDataBuilder::new(fun_env, data);
builder.set_loc(fun_env.get_loc().at_start());
let old_code = std::mem::take(&mut builder.data.code);
for param in 0..builder.fun_env.get_parameter_count() {
let exp = builder.mk_call(
&BOOL_TYPE,
Operation::WellFormed,
vec![builder.mk_temporary(param)],
);
builder.emit_prop(PropKind::Assume, exp);
}
for mem in usage.accessed.all {
let struct_env = builder.global_env().get_struct_qid(mem.to_qualified_id());
if struct_env.is_native_or_intrinsic() {
continue;
}
let exp = builder
.mk_inst_mem_quant_opt(QuantKind::Forall, &mem, &mut |val| {
Some(builder.mk_call(&BOOL_TYPE, Operation::WellFormed, vec![val]))
})
.expect("quant defined");
builder.emit_prop(PropKind::Assume, exp);
if let Some(spec_var) = struct_env.get_ghost_memory_spec_var() {
let mem_ty = mem.to_type();
let zero_addr = builder.mk_address_const(BigUint::zero());
let exists = builder.mk_call_with_inst(
&BOOL_TYPE,
vec![mem_ty.clone()],
Operation::Exists(None),
vec![zero_addr.clone()],
);
builder.emit_prop(PropKind::Assume, exists);
let svar_module = builder.global_env().get_module(spec_var.module_id);
let svar = svar_module.get_spec_var(spec_var.id);
if let Some(init) = &svar.init {
let mem_val = builder.mk_call_with_inst(
&mem_ty,
mem.inst.clone(),
Operation::Pack(mem.module_id, mem.id),
vec![init.clone()],
);
let mem_access = builder.mk_call_with_inst(
&mem_ty,
vec![mem_ty.clone()],
Operation::Global(None),
vec![zero_addr],
);
let eq_with_init = builder.mk_identical(mem_access, mem_val);
builder.emit_prop(PropKind::Assume, eq_with_init);
}
}
}
for bc in old_code {
builder.emit(bc);
}
builder.data
}
fn name(&self) -> String {
"entry_point_instrumenter".to_string()
}
}