19、通过可达性分析进行残余运行时验证

通过可达性分析进行残余运行时验证

在程序验证领域,我们常常面临着静态验证难以获取完整信息,而运行时验证又会带来较大开销的问题。本文将介绍一种通过可达性分析进行残余运行时验证的方法,旨在平衡静态验证和运行时验证的优势。

背景知识

在深入探讨残余分析之前,我们需要了解一些基础概念。

监控
  • 事件与轨迹 :设 $\Sigma$ 为事件集合,$\Sigma^*$ 和 $\Sigma^\omega$ 分别是 $\Sigma$ 上所有有限和无限轨迹的集合。有限轨迹是事件的序列,可以用函数 $t : [1, n] \to \Sigma$ 来建模,其中 $n$ 是轨迹的长度。
  • 属性与前缀 :属性 $\phi$ 是 $\Sigma$ 上的语言,是 $\Sigma^ $ 的子集。给定轨迹 $t \in \Sigma^ $,其前缀集合 $pre(t)$ 定义为 ${p \in \Sigma^ | \exists s \in \Sigma^ : t = ps}$。匹配前缀集合 $match_L(t)$ 是给定语言 $L$ 中轨迹 $t$ 的前缀集合,即 $match_L(t) = pre(t) \cap L$。
  • 坏前缀与好前缀 :对于语言 $L \subseteq \Sigma^ $(或 $L \subseteq \Sigma^\omega$),有限轨迹 $u \in \Sigma^ $ 是 $L$ 的坏前缀,如果 $\forall w \in \Sigma^ : uw \notin L$(或 $\forall w \in \Sigma^\omega : uw \notin L$);$u$ 是 $L$ 的好前缀,如果 $\forall w \in \Sigma^ : uw \in L$(或 $\forall w \in \Sigma^\omega : uw \in L$)。
  • 属性满足 :轨迹 $t \in \Sigma^ $ 满足属性 $\phi \subseteq \Sigma^ $,记为 $t \vDash \phi$,当且仅当 $t \in \phi$。对于安全属性 $\phi$ 及其坏前缀语言 $L$,$t \vDash \phi$ 当且仅当 $match_L(t) = \emptyset$;对于共安全属性 $\phi’$ 及其好前缀语言 $L’$,$t \vDash \phi$ 当且仅当 $match_{L’}(t) \neq \emptyset$。

例如,SafeIterator 监控器用于检查属性的违反情况。事件 $c$ 表示通过调用 list.iterator() 创建与列表关联的迭代器,事件 $u$ 表示通过调用 list.add(..) 更新列表,事件 $n$ 表示调用迭代器的 next 方法 iterator.next() 。监控器识别从运行程序接收的轨迹中的坏前缀,当看到模式 $c.n^*.u^+.n$ 时,监控器到达接受状态,表明整个运行违反了属性。

参数化监控
  • 参数化事件与轨迹 :参数化监控器接收带有运行时信息的事件,允许分别监控程序中每个相关对象集。我们用 $X$ 表示参数化监控器定义的变量集合,$V$ 表示这些变量可以取的值集合。变量绑定 $\theta : X \rightharpoonup V$ 将监控器参数映射到其值,$B$ 是程序中所有可能绑定的集合。参数化事件 $e\langle\theta\rangle$ 是一个对 $(e, \theta) \in \Sigma \times B$,所有参数化事件的集合记为 $\Sigma\langle X \rangle$,参数化轨迹是 $\Sigma\langle X \rangle^*$ 中的一个单词。
  • 参数化属性与投影 :参数化属性 $\Lambda X.\phi$ 定义在参数化事件轨迹上,即 $\Lambda X.\phi \subseteq \Sigma\langle X \rangle^*$。为了分别监控每个相关对象组,参数化监控器根据事件中携带的监控器参数绑定的值对参数化轨迹进行切片。通过投影函数 $\tau\downarrow\theta$ 将轨迹 $\tau$ 投影到所有看到的绑定上,投影结果是一组轨迹,称为投影轨迹,每个轨迹包含与程序中相关对象对应的非参数化事件,并发送到专门为该切片生成的监控器。
  • 参数化属性满足 :参数化轨迹 $\tau \in \Sigma\langle X \rangle^*$ 满足参数化属性 $\Lambda X.\phi$,记为 $\tau \vDash \Lambda X.\phi$,当且仅当 $\forall t \in Proj(\tau) : t \vDash \phi$。

例如,程序可能生成的参数化轨迹 $\tau = (u, [l \mapsto o(l1)]) (c, [l \mapsto o(l1), i \mapsto o(it)]) (u, [l \mapsto o(l2)]) (u, [l \mapsto o(l2)]) (n, [l \mapsto o(l1), i \mapsto o(it)]) (c, [l \mapsto o(l1), i \mapsto o(it)]) (u, [l \mapsto o(l2)])$。如果 $o(l1) = o(l2)$,则 $Proj(\tau) = {ucuuncu}$;如果 $o(l1) \neq o(l2)$,则 $Proj(\tau) = {ucnc, uuu}$。

向上闭包
  • 子词与超词 :对于单词 $x \in \Sigma^*$,其长度记为 $|x|$,$x_i$ 表示 $x$ 的第 $i$ 个字母,空单词记为 $\epsilon$。子词是通过从单词中任意位置删除某些字母得到的,超词是通过在单词中任意位置插入任意数量的字母得到的。如果存在位置 $0 < p_1 < p_2 < … p_l \leq |y|$ 使得 $x[i] = y[p_i]$ 对于所有 $1 \leq i \leq l = |x|$ 成立,则称单词 $x$ 是 $y$ 的子词,记为 $x \sqsubseteq y$,等价地,$y$ 是 $x$ 的超词。
  • 向上闭包定义 :对于语言 $L \subseteq \Sigma^ $,其向上闭包记为 $\uparrow L$,定义为 ${x \in \Sigma^ | \exists y \in L : y \sqsubseteq x}$。对于任何语言 $L \subseteq \Sigma^*$,有 $L \subseteq \uparrow L$。如果 $L = \uparrow L$,则称语言 $L$ 是向上闭包的。对于由非确定性有限状态自动机(NFA)识别的正则语言 $L$,可以通过简单地添加转换而不增加状态数量来获得识别 $\uparrow L$ 的 NFA。
程序、CFG 和插桩

给定程序 $P$,设 $Methods$ 是其所有方法的集合,$Instructions$ 是所有字节码指令的集合,$Instructions_m$ 是方法 $m$ 的所有指令集合。方法 $m$ 的控制流图 $CFG_m = \langle B_m, E_m \rangle$ 是一个有向图,其中 $B_m$ 是节点集合,每个指令是一个节点,$E_m \subseteq B_m \times B_m$ 是连接节点到其后续节点的边。节点 $b$ 中的指令记为 $b.instr$,$b.entry$(或 $b.exit$)是一个布尔值,表示 $b$ 是否是方法的入口节点(或出口节点)。为了监控程序,我们通过插桩将其执行抽象为在运行时提取的事件轨迹,插桩可以用函数 $instrument : Instructions^ \rightharpoonup \Sigma\langle X \rangle^ $ 来建模。

参数化属性的残余分析

我们的目标是验证程序 $P$ 是否满足某个参数化属性 $\Lambda X.\phi$。程序的行为通过其在运行时可以产生的参数化事件轨迹集合来抽象,记为 $[P] \subseteq \Sigma\langle X \rangle^*$。验证问题可以表述为检查程序的所有轨迹是否满足属性:$P \vDash \Lambda X.\phi \stackrel{def}{=} \forall \tau \in [P] : \tau \vDash \Lambda X.\phi$。

静态地探索参数化轨迹需要程序的完整调用图知识,而探索投影轨迹需要产生它们的对象之间的别名关系知识,这些信息通常在静态时是不可判定的。运行时验证虽然可以获得这些信息,但会给程序的执行带来开销,并且这种开销通常与轨迹的大小正相关。因此,我们的兴趣是静态地验证程序的部分内容,并将残余部分留给运行时验证。

我们提出的残余分析静态地识别程序中一组指令 $S_P$,这些指令在运行时可以从监控器端安全地静默/忽略而不影响验证。忽略指令意味着在其执行时不需要产生事件。我们的目标是构造残余插桩函数 $residual : Instructions^ \to (S_P \to \Sigma\langle X \rangle^ )$。设 $Runs \subseteq Instructions^*$ 是程序 $P$ 的所有可能运行的集合。用 $residual$ 插桩程序理想情况下应该产生比 $instrument$ 更短的轨迹,但对于两者,我们应该得到相同的监控判决。残余分析应满足的条件如下:

$\forall r \in Runs : |residual(r)| \leq |instrument(r)| \land residual(r) \vDash \Lambda X.\phi \Leftrightarrow instrument(r) \vDash \Lambda X.\phi$

为了静态地执行残余分析并产生集合 $S_P$,我们可以通过构造一个集合 $[\hat{P}] \supseteq [P]$ 来过度近似程序行为。这允许我们探索程序可以产生的所有参数化轨迹,但也包括程序可能永远不会产生的轨迹。残余分析应该检查忽略某些指令是否不影响 $[\hat{P}]$ 中任何轨迹的验证判决,并安全地假设在 $[P]$ 中具有相同的效果。然而,由于 $[\hat{P}]$ 是一个过度近似,分析可能会产生误报,即某些指令实际上可以被忽略,但分析结果却相反。在接下来的内容中,我们考虑 $[\hat{P}]$ 的一个子集 $[\check{P}_m]$ 进行残余分析,这些轨迹是在单个方法中完全产生的。

通过过程内可达性分析进行残余分析

我们将展示如何在过程内级别使用可达性分析进行残余分析。由于我们避免了数据流和指针分析,因此我们没有程序的静态调用图和变量别名关系。

捕获行为

我们的分析分别处理每个方法,但需要谨慎。如果一个方法接收一个对象作为参数,该对象的类型能够产生属性字母表中的事件,那么我们不能假设任何先前的行为。因此,我们将此类方法排除在分析之外。出于同样的原因,我们排除所有操作涉及类型的静态实例的方法。

对于每个方法 $m$,我们将两种类型的指令映射到事件,并丢弃所有其他与我们的分析无关的指令。我们保留属性规范中产生 $\Sigma$ 中事件的指令,以及可能允许任何对象引用从方法 $m$ 的上下文中逃逸的指令;我们为这些指令引入新的逃逸事件 (#)。逃逸事件包括对类字段的赋值、通过引用传递对象的方法调用以及返回对象的返回语句。然而,我们的分析允许用户指定一个安全指令列表 $SafeList$,该列表基于编译类型信息(如方法名、包名和类型名以及操作码)定义。例如,调用 System.out.print(l1.toString()) 是一个安全指令。所有逃逸事件且不在 $SafeList$ 中的指令都添加到集合 $Esc_m$ 中。

给定属性的字母表 $\Sigma$ 和方法 $m$ 的控制流图 $CFG_m = \langle B_m, E_m \rangle$,我们将 $B_m$ 中的每个块 $b$ 替换为 $b’$,并将其指令映射到一个事件,构造 CFG 自动机如下:

$b’.instr = b.instr.map\left(\begin{array}{l}i \mapsto \begin{cases}i & \text{if } i \in \Sigma\# & \text{else if } i \in Esc_m\\epsilon & \text{otherwise}\end{cases}\end{array}\right)$

CFG 自动机定义 :给定映射后的 $CFG_m$,CFG 自动机是一个非确定性有限状态自动机 $Ac_m = (\Sigma \cup {#}, Q, \delta, q_0, F)$,构造如下:
- $Q = {q_b | b \in B_m}$
- $q_0 = {q_b | b \in B_m \land b.entry = true }$
- $F = Q$
- $\delta = {\langle q_b, s, q_{b’}\rangle | \langle b, b’ \rangle \in E_m \land b.instr = s}$

每个控制流图中的节点现在表示为 CFG 自动机中的一个状态。我们将所有状态设为接受状态,并合并由 $\epsilon$ 转换连接的状态。通过遍历 CFG 自动机,我们可以探索方法 $m$ 在运行时可以采取的路径,从而探索其可以产生的参数化轨迹。

例如,图 3 展示了从第 2 节中的方法构造的 CFG 自动机,每个状态对应于程序中我们感兴趣的一个指令。从图 3 中的自动机可以探索两条轨迹,$t_1 = ucuuncu$,对应于示例 2 中的参数化轨迹 $\tau$,$t_2 = ucncu$。

graph LR
    classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px
    classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px

    A([q0]):::startend -->|u| B([q1]):::process
    B -->|c| C([q2]):::process
    C -->|u| D([q3]):::process
    D -->|c| E([q4]):::process
    E -->|u| F([q5]):::process
    F -->|n| G([q6]):::process
    G -->|c| H([q7]):::process
    H -->|u| I([q8]):::startend
扩展坏前缀自动机

我们现在描述如何处理过度近似并扩展坏前缀自动机。

处理变量可能别名 :回想一下,参数化轨迹 $\tau \in \Sigma\langle X \rangle^*$ 在运行时根据事件中携带对象之间的别名关系投影到 $Proj(\tau)$ 中可能的多个轨迹。在运行时,参数化监控器可以使用此别名关系进行投影,但在静态残余分析中,此信息不可用。我们的核心思想是避免进行数据流分析,并假设方法中产生事件的对象可能别名。对于两个事件,我们的分析应该考虑它们绑定的对象必须别名和必须不别名的情况。在前一种情况下,两个事件将投影到同一轨迹中,在后一种情况下,它们将投影到不同的轨迹中。

例如,考虑可以从示例 4 中的 CFG 自动机探索的轨迹 $t_1$。在运行时,如果程序采取这样的控制流路径,它会发出一个参数化轨迹,根据 $l_1$ 和 $l_2$ 是否别名产生示例 3 中的投影轨迹之一。由于我们在静态时避免产生别名关系并假设 $l_1$ 和 $l_2$ 可能别名,我们应该在残余分析中考虑这两种情况的析取。因此,残余分析应检查的轨迹 $pt_1 = {ucuuncu, ucnc, uuu}$。对于示例 4 中的 $t_2$,通过相同的推理,应检查的轨迹是 $pt_2 = {ucncu, ucnc, u}$。因此,对于方法 $m$,应检查的轨迹集合是 $pt_1 \cup pt_2$。

CFG 自动机允许我们探索程序在运行时可以采取的不同路径,但其轨迹过于粗糙,可能包含与运行时同一轨迹不对应的事件。我们注意到,这相当于生成并考虑轨迹的所有子词,其中真实轨迹可以是自动机可以探索的轨迹的任何子词。因此,为了安全地处理不同的投影,我们使用第 3.3 节中的坏前缀语言 $L$ 的向上闭包 $\uparrow L$。通过使用向上闭包 $\uparrow L$,我们可以在完整轨迹或其任何子词中识别坏前缀,因为 $L \subseteq \uparrow L$,从而允许我们在所有可能的投影轨迹中找到坏前缀。然而,我们通过从初始和最终状态中移除 $\Sigma$ 自环来限制闭包,因为我们希望找到匹配坏前缀的最短路径。

处理逃逸事件 :在构造 CFG 自动机时,我们引入了逃逸 # 事件。由于我们的分析分别分析每个方法,我们不知道 # 转换中可能发生的情况。我们必须假设它们可能产生方法分析未跟踪的事件。为了安全地处理它们,我们在坏前缀自动机中从每个状态添加一个 # 转换到其所有可达状态。直观地说,这意味着当在路径中遇到 # 事件时,我们假设该路径不再安全,并且可能匹配坏前缀。

扩展坏前缀自动机 :给定由自动机 $A_{bad\phi} = (\Sigma, Q, \delta, Q_0, F)$ 识别的坏前缀语言 $L(bad\phi)$ 及其扩展转换函数 $\hat{\delta}$,扩展坏前缀自动机定义为 $A^{\uparrow}_{bad\phi} = (\Sigma \cup {#}, Q, \delta’, Q_0, F)$,其中:

$\delta’ = \delta \setminus { \langle q, s, q \rangle | s \in \Sigma \land (q \in F \lor q \in Q_0) } \cup { \langle q, s, q \rangle | s \in \Sigma \cup {#} \land q \in Q \land q \notin Q_0 \land q \notin F } \cup { \langle q, #, q’ \rangle | q, q’ \in Q \land \exists w \in \Sigma^*: \hat{\delta}(q, w) = q’ \land q’ \notin F }$

扩展自动机具有相同的状态。我们从初始和最终状态移除自环,以找到匹配坏前缀的最短路径;通过在所有其他状态添加 $\Sigma$ 和 # 自环来添加向上闭包;从每个状态添加 # 转换到其可达状态。

例如,图 4 展示了为 SafeIterator 属性构造的自动机 $A^{\uparrow}_{bad\phi}$。回想示例 1 中的模式 $c.n^*.u^+.n$,新自动机现在将识别这样的模式,同时处理上述两种过度近似。

graph LR
    classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px
    classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px

    A([q0]):::startend -->|c| B([q1]):::process
    B -->|n| B
    B -->|u| C([q2]):::process
    C -->|u| C
    C -->|n| D([q3]):::startend
    A -->|#| E([q4]):::process
    B -->|#| E
    C -->|#| E
    E -->|s| E
    E -->|#| F([q5]):::process
    F -->|s| F
    F -->|#| G([q6]):::process
    G -->|s| G
    G -->|#| H([q7]):::process
    H -->|s| H
    H -->|#| I([q8]):::process
    I -->|s| I
    I -->|#| J([q9]):::process
    J -->|s| J
    J -->|#| K([q10]):::process
    K -->|s| K
    K -->|#| L([q11]):::process
    L -->|s| L
    L -->|#| M([q12]):::process
    M -->|s| M
    M -->|#| N([q13]):::process
    N -->|s| N
    N -->|#| O([q14]):::process
    O -->|s| O
    O -->|#| P([q15]):::process
    P -->|s| P
    P -->|#| Q([q16]):::process
    Q -->|s| Q
    Q -->|#| R([q17]):::process
    R -->|s| R
    R -->|#| S([q18]):::process
    S -->|s| S
    S -->|#| T([q19]):::process
    T -->|s| T
    T -->|#| U([q20]):::process
    U -->|s| U
    U -->|#| V([q21]):::process
    V -->|s| V
    V -->|#| W([q22]):::process
    W -->|s| W
    W -->|#| X([q23]):::process
    X -->|s| X
    X -->|#| Y([q24]):::process
    Y -->|s| Y
    Y -->|#| Z([q25]):::process
    Z -->|s| Z
    Z -->|#| AA([q26]):::process
    AA -->|s| AA
    AA -->|#| AB([q27]):::process
    AB -->|s| AB
    AB -->|#| AC([q28]):::process
    AC -->|s| AC
    AC -->|#| AD([q29]):::process
    AD -->|s| AD
    AD -->|#| AE([q30]):::process
    AE -->|s| AE
    AE -->|#| AF([q31]):::process
    AF -->|s| AF
    AF -->|#| AG([q32]):::process
    AG -->|s| AG
    AG -->|#| AH([q33]):::process
    AH -->|s| AH
    AH -->|#| AI([q34]):::process
    AI -->|s| AI
    AI -->|#| AJ([q35]):::process
    AJ -->|s| AJ
    AJ -->|#| AK([q36]):::process
    AK -->|s| AK
    AK -->|#| AL([q37]):::process
    AL -->|s| AL
    AL -->|#| AM([q38]):::process
    AM -->|s| AM
    AM -->|#| AN([q39]):::process
    AN -->|s| AN
    AN -->|#| AO([q40]):::process
    AO -->|s| AO
    AO -->|#| AP([q41]):::process
    AP -->|s| AP
    AP -->|#| AQ([q42]):::process
    AQ -->|s| AQ
    AQ -->|#| AR([q43]):::process
    AR -->|s| AR
    AR -->|#| AS([q44]):::process
    AS -->|s| AS
    AS -->|#| AT([q45]):::process
    AT -->|s| AT
    AT -->|#| AU([q46]):::process
    AU -->|s| AU
    AU -->|#| AV([q47]):::process
    AV -->|s| AV
    AV -->|#| AW([q48]):::process
    AW -->|s| AW
    AW -->|#| AX([q49]):::process
    AX -->|s| AX
    AX -->|#| AY([q50]):::process
    AY -->|s| AY
    AY -->|#| AZ([q51]):::process
    AZ -->|s| AZ
    AZ -->|#| BA([q52]):::process
    BA -->|s| BA
    BA -->|#| BB([q53]):::process
    BB -->|s| BB
    BB -->|#| BC([q54]):::process
    BC -->|s| BC
    BC -->|#| BD([q55]):::process
    BD -->|s| BD
    BD -->|#| BE([q56]):::process
    BE -->|s| BE
    BE -->|#| BF([q57]):::process
    BF -->|s| BF
    BF -->|#| BG([q58]):::process
    BG -->|s| BG
    BG -->|#| BH([q59]):::process
    BH -->|s| BH
    BH -->|#| BI([q60]):::process
    BI -->|s| BI
    BI -->|#| BJ([q61]):::process
    BJ -->|s| BJ
    BJ -->|#| BK([q62]):::process
    BK -->|s| BK
    BK -->|#| BL([q63]):::process
    BL -->|s| BL
    BL -->|#| BM([q64]):::process
    BM -->|s| BM
    BM -->|#| BN([q65]):::process
    BN -->|s| BN
    BN -->|#| BO([q66]):::process
    BO -->|s| BO
    BO -->|#| BP([q67]):::process
    BP -->|s| BP
    BP -->|#| BQ([q68]):::process
    BQ -->|s| BQ
    BQ -->|#| BR([q69]):::process
    BR -->|s| BR
    BR -->|#| BS([q

### 通过可达性分析进行残余运行时验证(续)

#### 可达性分析算法
在完成了对方法行为的捕获以及坏前缀自动机的扩展后,我们可以进行可达性分析算法的设计,其目的是在控制流图中找到安全和违反路径。

##### 算法思路
可达性分析算法基于模型检查的思想,将控制流图和扩展后的坏前缀自动机结合起来,遍历控制流图中的路径,同时模拟扩展坏前缀自动机的状态转移。通过这种方式,我们可以判断路径是否会导致属性的违反。

##### 具体步骤
1. **初始化**:从控制流图的入口节点开始,将其对应的 CFG 自动机状态和扩展坏前缀自动机的初始状态作为起始状态对。
2. **路径遍历**:
    - 对于当前状态对,根据 CFG 自动机的转移规则,找到所有可能的下一个状态。
    - 对于每个可能的下一个状态,更新扩展坏前缀自动机的状态,根据扩展坏前缀自动机的转移函数进行状态转移。
3. **状态判断**:
    - 如果扩展坏前缀自动机到达接受状态,则说明当前路径是违反路径。
    - 如果遍历完所有可能的路径都没有到达接受状态,则说明当前路径是安全路径。
4. **结果记录**:记录所有找到的安全路径和违反路径。

通过这种方式,我们可以全面地分析方法的控制流图,找出可能导致属性违反的路径。

##### 算法示例
假设我们有一个简单的控制流图,其对应的 CFG 自动机状态转移如下:
| 当前状态 | 输入事件 | 下一个状态 |
| ---- | ---- | ---- |
| q0 | u | q1 |
| q1 | c | q2 |
| q2 | u | q3 |
| q3 | n | q4 |

扩展坏前缀自动机的转移规则如前文所述。从 q0 开始,我们可以按照以下步骤进行可达性分析:
1. 初始状态对为 (q0, A↑badϕ 的初始状态)。
2. 输入事件 u,CFG 自动机转移到 q1,更新扩展坏前缀自动机的状态。
3. 输入事件 c,CFG 自动机转移到 q2,再次更新扩展坏前缀自动机的状态。
4. 依次类推,直到遍历完所有可能的路径。

```mermaid
graph LR
    classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px
    classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px

    A([(q0, 初始状态)]):::startend -->|u| B([(q1, 状态 1)]):::process
    B -->|c| C([(q2, 状态 2)]):::process
    C -->|u| D([(q3, 状态 3)]):::process
    D -->|n| E([(q4, 状态 4)]):::startend
分析的正确性

我们需要确保通过可达性分析得到的结果是可靠的,即分析具有正确性。

正确性的定义

分析的正确性意味着:
- 如果分析判定某条路径是违反路径,那么在实际运行中,该路径确实会导致属性的违反。
- 如果分析判定某条路径是安全路径,那么在实际运行中,该路径不会导致属性的违反。

正确性的保证

为了保证分析的正确性,我们采取了以下措施:
1. 过度近似 :通过构造 $[\hat{P}] \supseteq [P]$ 对程序行为进行过度近似,虽然可能会产生误报,但可以确保不会遗漏真正的违反路径。
2. 扩展坏前缀自动机 :通过处理变量可能别名和逃逸事件,扩展坏前缀自动机能够更准确地识别违反路径。
3. 可达性分析算法 :算法基于模型检查的思想,全面遍历控制流图中的路径,确保不会遗漏任何可能的情况。

通过这些措施的综合作用,我们可以保证分析的正确性,从而为程序的验证提供可靠的依据。

总结与展望

本文介绍了一种通过可达性分析进行残余运行时验证的方法,旨在平衡静态验证和运行时验证的优势。通过对参数化属性的残余分析,我们可以静态地识别程序中可以安全忽略的指令,减少运行时验证的开销。具体步骤如下:
1. 背景知识学习 :了解监控、参数化监控、向上闭包、程序、CFG 和插桩等相关概念。
2. 参数化属性的残余分析 :明确验证目标,通过过度近似程序行为,静态地识别可以忽略的指令。
3. 过程内可达性分析
- 捕获方法的行为,构造 CFG 自动机。
- 扩展坏前缀自动机,处理变量可能别名和逃逸事件。
- 进行可达性分析,找到安全和违反路径。
4. 确保分析的正确性 :通过过度近似、扩展坏前缀自动机和可达性分析算法保证分析结果的可靠性。

未来的研究方向可以包括:
- 进一步优化过度近似的方法,减少误报的发生。
- 扩展分析方法,使其能够处理更复杂的程序结构和属性。
- 结合机器学习等技术,提高分析的效率和准确性。

通过不断的研究和改进,我们可以更好地利用残余运行时验证技术,提高程序的可靠性和性能。

【四旋翼无人机】具备螺旋桨倾斜机构的全驱动四旋翼无人机:建模与控制研究(Matlab代码、Simulink仿真实现)内容概要:本文围绕具备螺旋桨倾斜机构的全驱动四旋翼无人机展开研究,重点探讨其系统建模与控制策略,结合Matlab代码与Simulink仿真实现。文章详细分析了无人机的动力学模型,特别是引入螺旋桨倾斜机构后带来的全驱动特性,使其在姿态与位置控制上具备更强的机动性与自由度。研究涵盖了非线性系统建模、控制器设计(如PID、MPC、非线性控制等)、仿真验证及动态响应分析,旨在提升无人机在复杂环境下的稳定性和控制精度。同,文中提供的Matlab/Simulink资源便于读者复现实验并进一步优化控制算法。; 适合人群:具备一定控制理论基础和Matlab/Simulink仿真经验的研究生、科研人员及无人机控制系统开发工程师,尤其适合从事飞行器建模与先进控制算法研究的专业人员。; 使用场景及目标:①用于全驱动四旋翼无人机的动力学建模与仿真平台搭建;②研究先进控制算法(如模型预测控制、非线性控制)在无人机系统中的应用;③支持科研论文复现、课程设计或毕业课题开发,推动无人机高机动控制技术的研究进展。; 阅读建议:建议读者结合文档提供的Matlab代码与Simulink模型,逐步实现建模与控制算法,重点关注坐标系定义、力矩分配逻辑及控制闭环的设计细节,同可通过修改参数和添加扰动来验证系统的鲁棒性与适应性。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值