18、带别名的Ada程序的过程间符号评估与并发Ada程序的自动验证

带别名的Ada程序的过程间符号评估与并发Ada程序的自动验证

带别名的Ada程序的过程间符号评估

在Ada程序的分析中,别名和过程间分析是重要的研究内容。

别名问题
  • 别名的产生 :过程间的按引用传递参数会引入别名,即两个或多个左值在同一程序点引用同一存储位置。对于k > 1级指针的可能别名问题是不可判定的,但确定k = 1(即单级)指针几乎是微不足道的。
  • Ada95中的别名 :在Ada95中,参数要么按值传递,要么按引用传递。按值传递的参数类型是基本类型或私有类型的后代,其完整类型是按值传递类型。其他类型(如标记类型)要么按引用传递,要么参数传递机制未定义。访问类型也会导致别名的产生。
  • 别名的处理 :通过将程序进行符号评估的内存空间视为数组A(数组代数A的元素)来建模访问值的语义。变量V的地址用$V表示,引入∧运算符用于解引用访问值,∧$V = V。对⊕函数进行了略微修改:
a ⊕(α, β, γ) = (v1, ..., vβ−1, γ, vβ+1, ..., vn)

其中α表示要更新的实体,β表示相应的地址,γ表示更新值。

过程间分析

每个过程调用可能以两种方式改变符号上下文:
1. 通过从被调用者向调用者传递值(例如通过out参数)。
2. 通过被调用者内部的副作用(例如向非局部于被调用者的变量赋值)。

对于按值传递的参数,根据不同的模式有不同的处理方式:
| 参数模式 | 处理方式 |
| ---- | ---- |
| in | 该实体不允许用作左值,在表示调用点的CFG节点处,用相应的实际参数(或默认表达式)替换形式参数。 |
| out | 模式为out的形式参数在被调用者的程序上下文中引入一个新的左值,对于基本类型初始化为⊥。在调用点,将被调用者的符号描述中形式参数的左值出现替换为相应的实际参数。 |
| in out | 基本上是上述两种模式的总和,形式参数的左值出现以及在(右侧)表达式中的出现都被实际参数替换。 |

对于按引用传递的参数,涉及到指向参数本身实体的单级指针,可以使用前面介绍的方法处理。

示例

以下是一个示例程序:

-- 包规范 P1
package P1 is
    type Int Pointer is access all Integer;
    V: aliased Integer := 1;
    procedure Do It(P : Int Pointer);
end P1;

-- 包体 P1
package body P1 is
    I: Integer := 0;
    procedure Do It(P : Int Pointer) is
    begin
        P.all := P.all + 1;
        V := V + 1;
        I := I + 1;
        P.all := P.all + V + I;
    end Do It;
end P1;

-- 主程序
with P1, Text IO;
procedure Main is
    X: P1.Int Pointer := new Integer'(1);
    Y: P1.Int Pointer;
begin
    if False then
        Y := X;
    end if;
    P1.Do It(X);
    P1.Do It(P1.V'access);
end Main;

对于这个示例,给出了每个CFG节点的SymEval方程:

Do It
XExit = X1
= XEntry | {(A, A ⊕(∧P, P, ρ(A, P) + 1) ⊕(V, $V, ρ(A, $V ) + 1)),
(I, I + 1), (A, A ⊕(∧P, P, ρ(A, P) + ρ(A, $V ) + I)}

Main
X1 = XEntry | {(A, ⊥⊕(V, $V, 1) ⊕(∧X, X, 1) ⊕(∧Y, Y, ⊥)), (I, 0)}
X2 = False ⊙X1 | {(A, A ⊕(Y, $Y, X))}
X3 = (True ⊙X1 ∪False ⊙X2) | P1.Do It(X) = X1 | P1.Do It(X)
= X1 | {(A, A ⊕(∧X, X, ρ(A, X) + 1) ⊕(V, $V, ρ(A, $V ) + 1)),
(I, I + 1), (A, A ⊕(∧X, X, ρ(A, X) + ρ(A, $V ) + I)}
X4 = X3 | P1.Do It($V )
= X3 | {(A, A ⊕(∧$V, $V, ρ(A, $V ) + 1) ⊕(V, $V, ρ(A, $V ) + 1)),
(I, I + 1), (A, A ⊕(∧$V, $V, ρ(A, $V ) + ρ(A, $V ) + I)}

XEntry, X1, X2, X3, X4 →XExit
XExit = XEntry | {(A, ⊥⊕(V, $V, 1) ⊕(∧X, X, 1) ⊕(∧Y, Y, ⊥)), (I, 0)}
| {(A, A ⊕(∧X, X, ρ(A, X) + 1) ⊕(V, $V, ρ(A, $V ) + 1)), (I, I + 1),
(A, A ⊕(∧X, X, ρ(A, X) + ρ(A, $V ) + I)}
| {(A, A ⊕(∧$V, $V, ρ(A, $V ) + 1) ⊕(V, $V, ρ(A, $V ) + 1)),
(I, I + 1), (A, A ⊕(∧$V, $V, ρ(A, $V ) + ρ(A, $V ) + I)}
= XEntry | {(I, 2), (A, ⊥⊕(∧X, X, 5) ⊕(V, $V, 10) ⊕(∧Y, Y, ⊥))}

通过求解这些SymEval方程,可以得到执行Main过程后有效的程序上下文,这与在真实CPU上执行Main的结果完全一致。

下面是过程间分析的流程图:

graph TD;
    A[过程调用] --> B[传递值或副作用改变符号上下文];
    B --> C[按值传递参数处理];
    B --> D[按引用传递参数处理];
    C --> C1[in模式处理];
    C --> C2[out模式处理];
    C --> C3[in out模式处理];
并发Ada程序的自动验证

并发Ada程序的行为由于多任务引入的复杂性而难以理解,传统的测试技术无法使用,正确性只能通过形式化方法来保证。

引言

Ada是构建关键计算机系统软件的参考语言,其并发编程虽然提供了良好的结构模式,但由于非确定性,程序行为难以预测。基于高级Petri网的方法可以实现并发Ada程序属性的自动验证,该方法基于三个步骤的方法论:
1. 翻译 :将Ada程序翻译成等效的高级Petri网。
2. 验证 :使用结构方法和模型检查在Petri网上验证活性或安全性属性。
3. 报告 :当属性未验证时,工具尝试在Ada程序中显示与未遵守属性相关的部分。

高级Petri网

高级Petri网(也称为有色网)比普通Petri网能够建模更复杂的系统。在有色网中,一个位置包含类型化(或有色)的令牌,而不是普通Petri网中的匿名令牌,并且一个转换可以以多种方式触发(即实例化)。每个位置和每个转换都附有一个类型(或颜色)域,从转换到位置(或从位置到转换)的弧用一个线性函数(称为颜色函数)标记。

常见的颜色函数包括:
- 对于类C的恒等(或选择)函数,用XC(或YC, ZC, …)表示。
- 类C上的扩散或全局同步函数,用AllC表示。
- 后继映射函数,用XC ++表示。

以下是一个用餐哲学家问题的示例模型:

give back
take
Chopsticks : D
Eating : D
D.All
< X > + < X++ >
< X > + < X++ >
< X >
< X >
< X >
< X >
D.All
Thinking : D
Domain D=1..N

这个网由三个位置(Thinking, Eating和Chopsticks)和两个转换(take和give back)组成。初始时,所有哲学家处于思考状态,所有筷子都是空闲的。转换take在满足一定条件时可以触发,转换give back在哲学家处于进食状态时可以触发。

graph TD;
    A[高级Petri网] --> B[位置包含有色令牌];
    A --> C[转换可多种方式触发];
    B --> D[附有类型域];
    C --> E[弧用颜色函数标记];
翻译

理论上可以将Ada程序自动翻译成等效的Petri网,但难点在于定义能产生可分析网的翻译规则。之前的一些工作使用普通Petri网,无法处理现实的Ada程序,而高级Petri网理论上可以翻译任何Ada程序。

根据对一些手动翻译示例的分析,得出以下结论:
- 生成的Petri网只对与并发相关的方面进行建模。
- 用非常简化的网对Ada构造进行建模。
- 网非常小,例如60行的程序可以翻译成4个位置的网。
- Ada代码由Petri网表示,其执行由令牌(每个任务一个)在网中的移动表示。
- Ada语句通常由转换表示,其执行由转换的触发表示。
- 任务的局部变量被翻译成表示该任务的令牌中的颜色。
- 受保护的变量由有色位置建模。

基于这些结论,定义了一个三步翻译机制:
1. 简化步骤 :通过移除与并发无关的所有部分来简化Ada程序。
2. 翻译步骤 :将简化后的Ada程序翻译成Petri网,用Petri网片段替换各种Ada构造。
3. 清理步骤 :移除未使用的部分。

简化步骤使用栈和迭代过程,通过一个函数从必须保留的初始部分开始迭代,直到找到所有有用的部分,然后移除其他部分。以下是一个简化算法的示例:

end;
  i : id;
begin
  count.val(i);
end;
task type T is
task body T is
type id is mod 5;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
end;
  end loop;
    end;
      i := c;
      (i : out id) do
    accept val
    c := c + 1;
  loop
begin
  c : id := 0;
task body counter is
end;
  entry val(i : out id);
task type counter is
count : counter;
Ts : array(id) of T;
type id is mod 5
task type counter
c : id := 0
entry val
i : out id
loop
c := c + 1
accept val
i : out id
i := c
count : counter
task type T
i : id
count.val
i
Ts : array(id) of T
8
11
8
6
8
2
11
11
8
4
4
11
8
1
8
14
8
11
4
12
8
11
4
16

初始时,将accept和entry call语句作为可能导致死锁或饥饿的潜在阻塞操作压入栈中,然后通过迭代分析栈中的节点,确定需要保留的部分。

graph TD;
    A[Ada程序] --> B[简化步骤];
    B --> C[移除无关部分];
    C --> D[翻译步骤];
    D --> E[替换为Petri网片段];
    E --> F[清理步骤];
    F --> G[移除未使用部分];

带别名的Ada程序的过程间符号评估与并发Ada程序的自动验证

并发Ada程序自动验证的后续内容
验证过程

在将Ada程序翻译成高级Petri网之后,就可以进行验证步骤。验证主要是使用结构方法和模型检查来验证活性或安全性属性。

结构方法通常基于Petri网的拓扑结构和一些数学性质来判断系统是否满足特定的属性。例如,通过分析网的连通性、可达性等,来确定是否存在死锁、饥饿等问题。

模型检查则是一种更强大的验证技术,它通过对Petri网的状态空间进行遍历,检查是否存在违反属性的状态。具体步骤如下:
1. 状态空间生成 :从Petri网的初始状态开始,通过不断触发可触发的转换,生成所有可能的状态。
2. 属性检查 :对于每个生成的状态,检查是否满足所需的活性或安全性属性。如果发现不满足属性的状态,则记录该状态和相关的转换序列。
3. 结果输出 :如果所有状态都满足属性,则验证通过;否则,输出不满足属性的状态和相关信息。

以下是验证过程的流程图:

graph TD;
    A[高级Petri网] --> B[状态空间生成];
    B --> C[属性检查];
    C --> D{是否满足属性};
    D -- 是 --> E[验证通过];
    D -- 否 --> F[记录不满足状态和序列];
    F --> G[输出结果];
报告生成

当验证过程中发现属性未验证时,工具需要尝试在Ada程序中显示与未遵守属性相关的部分。这一步骤可以帮助开发人员快速定位问题所在。

报告生成的具体操作步骤如下:
1. 状态映射 :将Petri网中不满足属性的状态映射回Ada程序中的相应代码位置。这可以通过在翻译过程中记录的映射关系来实现。
2. 相关代码提取 :根据映射结果,提取Ada程序中与不满足属性的状态相关的代码部分。
3. 报告输出 :将提取的代码部分和相关信息整理成报告,输出给开发人员。

以下是一个报告生成的示例表格:
| 不满足属性的状态 | 对应的Ada代码位置 | 相关代码片段 |
| ---- | ---- | ---- |
| 状态1 | 第10 - 15行 | if condition then ... end if; |
| 状态2 | 第20 - 25行 | task body T is ... end T; |

总结与展望

通过上述对带别名的Ada程序的过程间符号评估和并发Ada程序自动验证的介绍,我们可以看到这些技术在Ada程序开发中的重要性。

在过程间符号评估方面,通过对别名的处理和过程间分析,可以更准确地理解程序的行为,并且可以通过求解SymEval方程得到程序执行后的有效上下文。

在并发Ada程序自动验证方面,基于高级Petri网的方法提供了一种有效的方式来验证程序的活性和安全性属性。通过翻译、验证和报告三个步骤,可以帮助开发人员快速发现和解决并发程序中的问题。

未来,我们可以进一步优化这些技术,例如:
- 在过程间符号评估中,考虑更复杂的指针和别名情况,提高分析的准确性。
- 在并发Ada程序自动验证中,优化翻译规则,减少生成的Petri网的规模,提高验证效率。
- 开发更友好的工具界面,让非专业的开发人员也能方便地使用这些技术。

总之,这些技术为Ada程序的开发和验证提供了有力的支持,有望在未来的软件开发中发挥更大的作用。

以下是一个总结的列表:
1. 带别名的Ada程序过程间符号评估可以准确分析程序行为。
2. 并发Ada程序自动验证基于高级Petri网,通过三步方法论实现。
3. 未来可以进一步优化技术,提高准确性和效率。

希望这些内容能够帮助你更好地理解和应用这些技术。如果你在实际开发中遇到问题,欢迎随时交流。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值