我正在尝试使用一些静态分析工具来检查程序,该程序广泛使用了递归调用。从概念上讲,它是这样的:
int counter = 0;
int access = 0;
extern int nd (); // a nondeterministic value
void compute1();
void compute2();
int get()
{
static int fpa[2] = {2, 2}; // each function can be called for twice
int k = nd() % 2;
if (fpa[k] > 0) {
fpa[k]--;
return k+1;
}
else
return 0;
}
void check_r(int* x) {
if (x == &counter) {
__VERIFIER_assert(!(access == 2));
access = 1;
}
}
void check_w(int* x) {
if (x == &counter) {
__VERIFIER_assert((access == 0));
access = 2;
}
}
void schedule() {
for (int i = 0; i < 5; i++) {
int fp = get();
if (fp == 0)
return;
elif (fp == 1)
compute1();
elif (fp == 2)
compute2();
}
}
void compute1()
{
// some computations
...
schedule(); // recursive call
check_w(&counter); // check write access
...
}
void compute2()
{
// some computations
...
schedule(); //recursive call
check_r(&counter);
...
}
int main()
{
schedule();
return 0;
}
我的初步测试表明,由于进行了递归调用,因此静态分析变得太慢而无法终止。
虽然从原则上讲,我可以将递归调用重写为switch statement左右,但是问题是在递归调用schedule
,compute1
和compute2
之前函数已经执行了大量的计算,因此很难保存程序上下文以备将来使用。
我已经被困了几天来优化这种情况,但只是无法提出一个特别的解决方案。有人可以提供一些评论和建议来摆脱此处的递归调用吗?非常感谢。
答案 0 :(得分:0)
在我看来,所有schedule函数正在做的事情是确定是调用compute1
还是compute2
,而get所做的只是确保单个函数的调用不会被重复两次。我认为从计算到调度的递归调用是没有必要的,因为不会有两个以上的调用。递归似乎暗示着,每当我们能够成功调用一个计算函数时,我们就不会再有机会再次调用计算
void schedule() {
int chances = 1;
for (int i = 0; i < 5 || chances > 0; i++) {
int fp = get();
if (fp == 0){
chances--;
if(chances < 0)
chances = 0;
continue;
}
elif (fp == 1){
compute1(); chances++;
}
elif (fp == 2){
compute2(); chances++;
}
}
}
void compute1()
{
// some computations
...
//schedule(); remove
check_w(&counter); // check write access
...
}
void compute2()
{
// some computations
...
//schedule(); remove
check_r(&counter);
...
}
此代码有点令人困惑,因此请澄清我是否做出了任何错误的假设