首先,我要感谢Rustan和整个社区为您在Dafny上所做的工作。这是一种很棒的语言!
我正在研究硕士论文,该论文涉及使用Dafny对虚拟机进行形式验证。
这是我定义虚拟机(剥离后的版本)的方式:
class VM
{
var v: array<bv8>;
var I: bv16;
var memory: array<bv8>;
predicate Valid()
reads this
{
v.Length == 16
&& memory.Length == 0x0FFF
}
constructor Init()
ensures Valid()
{
v := new bv8[16];
I := 0;
memory := new bv8[0x0FFF];
}
}
到目前为止一切顺利。我有几种方法可以改变此计算机的状态。特别是,这是一个:
method parse_opcode_registers(vm: VM, opcode: bv16)
requires vm.Valid()
modifies vm`I, vm.v
{
var i: int := 0;
var bound := ((opcode & 0x0F00) >> 8) as int;
if opcode & 0xF0FF == 0xF065
{
while i < bound && vm.I as int < vm.memory.Length
decreases bound - i
{
vm.v[i] := vm.memory[vm.I];
i := i + 1;
vm.I := vm.I + 1;
}
}
}
这通过了达芙妮的验证。但是,当存在此方法的调用方时,就会发生此问题。即,以下代码将产生错误call may violate context's modifies clause
:
method Main() {
var vm := new VM.Init();
parse_opcode_registers(vm, 0xF018);
}
任何提示将不胜感激。
答案 0 :(得分:1)
您需要将ensures fresh(v)
添加到Init
的{{1}}构造函数中。
基本上,问题在于Dafny很担心,因为VM
声称要修改parse_opcode_register
,但是Dafny不确定vm.v
的来源。请记住,Dafny一次只分析一种方法,因此在分析vm.v
时它不会在构造函数Init
内查看。相反,Dafny仅查看先决条件。这就是为什么在后置条件中添加Main
可以解决问题的原因。
fresh(v)
的含义是fresh(blah)
是在方法执行期间重新分配的。
有关更多信息,请参见FAQ question about modifies clauses。